wip: play notes only on press

This commit is contained in:
2023-08-13 00:55:47 +04:00
parent c16447f30e
commit 635de894ad
6 changed files with 68 additions and 44 deletions

View File

@@ -6,23 +6,21 @@
#include <vector> #include <vector>
struct Adder { struct Adder {
static std::vector<float>& static void
SumOscillators(const std::vector<Oscillator*>& oscillators, SumOscillators(const std::vector<Oscillator*>& oscillators,
float duration) { std::vector<float>& signal) {
size_t sample_count = (size_t)(1.f/FPS * SAMPLE_RATE); size_t sample_count = STREAM_BUFFER_SIZE;//(size_t)(1.f/FPS * SAMPLE_RATE);
std::vector<float>* output = new std::vector<float>(); //std::vector<float>* output = new std::vector<float>();
output->reserve(sample_count); //output->reserve(sample_count);
for (size_t i = 0; i < sample_count; i++) { for (size_t i = 0; i < sample_count; i++) {
float sample = 0.0f; float sample = 0.0f;
for (Oscillator* osc : oscillators) { for (Oscillator* osc : oscillators) {
sample += osc->GenerateSample(duration); sample += osc->GenerateSample(1.f);
} }
output->push_back(sample); signal[i] = sample;
} }
return (*output);
} }
}; };

View File

@@ -16,7 +16,7 @@ class Application {
float* m_temp_buffer; float* m_temp_buffer;
Note* m_current_note; Note* m_current_note;
Renderer m_renderer; Renderer m_renderer;
std::size_t detect_note_pressed(Note* note); bool detect_note_pressed(Note* note);
void init_synth(); void init_synth();
void init_audio(); void init_audio();
void update_on_note_input(); void update_on_note_input();

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#define SAMPLE_RATE 48000.f #define SAMPLE_RATE 44100.f
#define BPM 120.f #define BPM 120.f
#define BEAT_DURATION 60.f/BPM #define BEAT_DURATION 60.f/BPM
#define PITCH_STANDARD 440.f #define PITCH_STANDARD 440.f

View File

@@ -15,13 +15,14 @@ class Synth {
// OscillatorUI* ui_oscillators; // OscillatorUI* ui_oscillators;
// Note m_current_note; // Note m_current_note;
std::vector<float> m_out_signal; std::vector<float> m_out_signal;
std::vector<float>& get_note(int semitone, float beats); void get_note(int semitone, float beats);
void apply_effects(); void apply_effects();
public: public:
Synth(/* args */); Synth(/* args */);
~Synth(); ~Synth();
void ProduceNoteSound(Note input); void ProduceNoteSound(Note input);
void StopNoteSound();
void AddOscillator(); void AddOscillator();
void AddEffect(Effect* fx); void AddEffect(Effect* fx);
const std::vector<float>& GetOutSignal() { return m_out_signal; } const std::vector<float>& GetOutSignal() { return m_out_signal; }

View File

@@ -55,72 +55,82 @@ void Application::init_synth() {
} }
} }
std::size_t Application::detect_note_pressed(Note* note) { bool Application::detect_note_pressed(Note* note) {
std::size_t is_pressed = 0; std::size_t is_pressed = 0;
note->length = 8; note->length = 8;
if (IsKeyPressed(KEY_A)) { if (IsKeyDown(KEY_A)) {
note->name.assign("A4"); note->name.assign("A4");
is_pressed = 1; is_pressed = 1;
} }
if (IsKeyPressed(KEY_B)) { if (IsKeyDown(KEY_B)) {
note->name.assign("B4"); note->name.assign("B4");
is_pressed = 1; is_pressed = 1;
} }
if (IsKeyPressed(KEY_C)) { if (IsKeyDown(KEY_C)) {
note->name.assign("C4"); note->name.assign("C5");
is_pressed = 1; is_pressed = 1;
} }
if (IsKeyPressed(KEY_D)) { if (IsKeyDown(KEY_D)) {
note->name.assign("D4"); note->name.assign("D5");
is_pressed = 1; is_pressed = 1;
} }
if (IsKeyPressed(KEY_E)) { if (IsKeyDown(KEY_E)) {
note->name.assign("E4"); note->name.assign("E5");
is_pressed = 1; is_pressed = 1;
} }
if (IsKeyPressed(KEY_F)) { if (IsKeyDown(KEY_F)) {
note->name.assign("F4"); note->name.assign("F5");
is_pressed = 1; is_pressed = 1;
} }
if (IsKeyPressed(KEY_G)) { if (IsKeyDown(KEY_G)) {
note->name.assign("G4"); note->name.assign("G5");
is_pressed = 1; is_pressed = 1;
} }
return is_pressed; return is_pressed == 1;
} }
// Update On Input // Update On Input
void Application::update_on_note_input() { void Application::update_on_note_input() {
detect_note_pressed(m_current_note); if (detect_note_pressed(m_current_note)) {
// if (detect_note_pressed(m_current_note)) { // if (detect_note_pressed(m_current_note)) {
m_synth.ProduceNoteSound((*m_current_note)); m_synth.ProduceNoteSound((*m_current_note));
//m_sound_played_count = 0; //m_sound_played_count = 0;
write_log("Note played: %s\n", m_current_note->name.c_str()); write_log("Note played: %s\n", m_current_note->name.c_str());
//} //}
}
else {
m_synth.StopNoteSound();
}
} }
// Play ring-buffered audio // Play ring-buffered audio
void Application::play_buffered_audio() { void Application::play_buffered_audio() {
std::size_t size_to_read = m_ring_buffer->GetSize(); //std::size_t size_to_read = m_ring_buffer->GetSize();
size_t sample_count = (size_t)(1.f/FPS * SAMPLE_RATE); size_t sample_count = STREAM_BUFFER_SIZE;//(size_t)(1.f/FPS * SAMPLE_RATE);
if (IsAudioStreamProcessed(m_synth_stream)) { if (IsAudioStreamProcessed(m_synth_stream)) {
write_log("Samples to play:%zu \n", size_to_read); //write_log("Samples to play:%zu \n", size_to_read);
// todo: try to start reading directly from ring buffer, avoiding // todo: try to start reading directly from ring buffer, avoiding
// temp_buffer // temp_buffer
//todo: can be optimized to only move pointers, without the usage of temp buffer //todo: can be optimized to only move pointers, without the usage of temp buffer
//m_synth.ProduceNoteSound((*m_current_note));
// can try the SetAudioStreamCallback // can try the SetAudioStreamCallback
UpdateAudioStream(m_synth_stream, m_temp_buffer, sample_count); const float audio_frame_start_time = GetTime();
update_on_note_input();
UpdateAudioStream(m_synth_stream, m_synth.GetOutSignal().data(), sample_count);
// can overwrite the ring buffer to avoid that // can overwrite the ring buffer to avoid that
const float audio_freme_duration = GetTime() - audio_frame_start_time;
write_log("Frame time: %.3f%% \n", 100.0f / ((1.0f / audio_freme_duration) / ((float)SAMPLE_RATE/STREAM_BUFFER_SIZE)));
// if (m_synth.GetOutSignal().size() == m_sound_played_count) { // if (m_synth.GetOutSignal().size() == m_sound_played_count) {
// m_ring_buffer->Reset(); // m_ring_buffer->Reset();
// } // }
} }
m_ring_buffer->Read(m_temp_buffer, sample_count); //m_ring_buffer->Read(m_temp_buffer, sample_count);
m_ring_buffer->Reset(); //m_ring_buffer->Reset();
if (m_ring_buffer->IsFull() || m_ring_buffer->IsEmpty()) { //if (m_ring_buffer->IsFull() || m_ring_buffer->IsEmpty()) {
} //}
} }
// Fill ring buffer from current sound // Fill ring buffer from current sound
@@ -154,9 +164,9 @@ void Application::Run() {
// Main game loop // Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key while (!WindowShouldClose()) // Detect window close button or ESC key
{ {
fill_audio_buffer(); //fill_audio_buffer();
//update_on_note_input();
play_buffered_audio(); play_buffered_audio();
update_on_note_input();
m_renderer.Draw(m_synth, m_synth_gui_state); m_renderer.Draw(m_synth, m_synth_gui_state);
} }

View File

@@ -7,6 +7,10 @@
Synth::Synth(/* args */) { Synth::Synth(/* args */) {
AddOscillator(); AddOscillator();
AddEffect(new ADSR()); AddEffect(new ADSR());
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
float sample = 0.0f;
m_out_signal.push_back(sample);
}
} }
Synth::~Synth() { Synth::~Synth() {
@@ -15,9 +19,13 @@ Synth::~Synth() {
m_out_signal.clear(); m_out_signal.clear();
} }
std::vector<float>& Synth::get_note(int semitone, float beats) { void Synth::get_note(int semitone, float beats) {
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
float sample = 0.0f;
m_out_signal[i] = sample;
}
float hz = KeyBoard::GetHzBySemitone(semitone); float hz = KeyBoard::GetHzBySemitone(semitone);
float duration = beats * BEAT_DURATION;
// will change after oscillator starts to be more autonomous // will change after oscillator starts to be more autonomous
for (Oscillator* osc : m_oscillators) { for (Oscillator* osc : m_oscillators) {
@@ -25,7 +33,7 @@ std::vector<float>& Synth::get_note(int semitone, float beats) {
} }
// todo: add other pipeline steps (e.g ADSR, Filters, FX); // todo: add other pipeline steps (e.g ADSR, Filters, FX);
return m_adder.SumOscillators(m_oscillators, duration); Adder::SumOscillators(m_oscillators, m_out_signal);
} }
void Synth::apply_effects() { void Synth::apply_effects() {
@@ -39,10 +47,17 @@ void Synth::apply_effects() {
void Synth::ProduceNoteSound(Note input) { void Synth::ProduceNoteSound(Note input) {
float length = 1.f / input.length; float length = 1.f / input.length;
int semitone_shift = KeyBoard::GetSemitoneShift(input.name); int semitone_shift = KeyBoard::GetSemitoneShift(input.name);
m_out_signal = get_note(semitone_shift, length); get_note(semitone_shift, length);
apply_effects(); apply_effects();
} }
void Synth::StopNoteSound() {
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
float sample = 0.0f;
m_out_signal[i] = sample;
}
}
void Synth::AddOscillator() { void Synth::AddOscillator() {
m_oscillators.push_back( m_oscillators.push_back(
new Oscillator(OscillatorType::Sine, 440.f, VOLUME)); new Oscillator(OscillatorType::Sine, 440.f, VOLUME));