From 635de894ad5ce068540a08c85806a4e94f5649bc Mon Sep 17 00:00:00 2001 From: HiveBeats Date: Sun, 13 Aug 2023 00:55:47 +0400 Subject: [PATCH] wip: play notes only on press --- inc/Adder.h | 16 +++++------ inc/Application.h | 2 +- inc/Settings.h | 2 +- inc/Synth.h | 3 ++- src/Application.cpp | 66 ++++++++++++++++++++++++++------------------- src/Synth.cpp | 23 +++++++++++++--- 6 files changed, 68 insertions(+), 44 deletions(-) diff --git a/inc/Adder.h b/inc/Adder.h index fbf0114..e951ab8 100644 --- a/inc/Adder.h +++ b/inc/Adder.h @@ -6,23 +6,21 @@ #include struct Adder { - static std::vector& + static void SumOscillators(const std::vector& oscillators, - float duration) { - size_t sample_count = (size_t)(1.f/FPS * SAMPLE_RATE); + std::vector& signal) { + size_t sample_count = STREAM_BUFFER_SIZE;//(size_t)(1.f/FPS * SAMPLE_RATE); - std::vector* output = new std::vector(); - output->reserve(sample_count); + //std::vector* output = new std::vector(); + //output->reserve(sample_count); for (size_t i = 0; i < sample_count; i++) { float sample = 0.0f; for (Oscillator* osc : oscillators) { - sample += osc->GenerateSample(duration); + sample += osc->GenerateSample(1.f); } - output->push_back(sample); + signal[i] = sample; } - - return (*output); } }; diff --git a/inc/Application.h b/inc/Application.h index 7b649c3..bb2de7f 100644 --- a/inc/Application.h +++ b/inc/Application.h @@ -16,7 +16,7 @@ class Application { float* m_temp_buffer; Note* m_current_note; Renderer m_renderer; - std::size_t detect_note_pressed(Note* note); + bool detect_note_pressed(Note* note); void init_synth(); void init_audio(); void update_on_note_input(); diff --git a/inc/Settings.h b/inc/Settings.h index 4317479..a6fc760 100644 --- a/inc/Settings.h +++ b/inc/Settings.h @@ -1,6 +1,6 @@ #pragma once -#define SAMPLE_RATE 48000.f +#define SAMPLE_RATE 44100.f #define BPM 120.f #define BEAT_DURATION 60.f/BPM #define PITCH_STANDARD 440.f diff --git a/inc/Synth.h b/inc/Synth.h index 625d4c8..dc84225 100644 --- a/inc/Synth.h +++ b/inc/Synth.h @@ -15,13 +15,14 @@ class Synth { // OscillatorUI* ui_oscillators; // Note m_current_note; std::vector m_out_signal; - std::vector& get_note(int semitone, float beats); + void get_note(int semitone, float beats); void apply_effects(); public: Synth(/* args */); ~Synth(); void ProduceNoteSound(Note input); + void StopNoteSound(); void AddOscillator(); void AddEffect(Effect* fx); const std::vector& GetOutSignal() { return m_out_signal; } diff --git a/src/Application.cpp b/src/Application.cpp index 1cbda5e..633b869 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -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; note->length = 8; - if (IsKeyPressed(KEY_A)) { + if (IsKeyDown(KEY_A)) { note->name.assign("A4"); is_pressed = 1; } - if (IsKeyPressed(KEY_B)) { + if (IsKeyDown(KEY_B)) { note->name.assign("B4"); is_pressed = 1; } - if (IsKeyPressed(KEY_C)) { - note->name.assign("C4"); + if (IsKeyDown(KEY_C)) { + note->name.assign("C5"); is_pressed = 1; } - if (IsKeyPressed(KEY_D)) { - note->name.assign("D4"); + if (IsKeyDown(KEY_D)) { + note->name.assign("D5"); is_pressed = 1; } - if (IsKeyPressed(KEY_E)) { - note->name.assign("E4"); + if (IsKeyDown(KEY_E)) { + note->name.assign("E5"); is_pressed = 1; } - if (IsKeyPressed(KEY_F)) { - note->name.assign("F4"); + if (IsKeyDown(KEY_F)) { + note->name.assign("F5"); is_pressed = 1; } - if (IsKeyPressed(KEY_G)) { - note->name.assign("G4"); + if (IsKeyDown(KEY_G)) { + note->name.assign("G5"); is_pressed = 1; } - return is_pressed; + return is_pressed == 1; } // Update On 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_sound_played_count = 0; write_log("Note played: %s\n", m_current_note->name.c_str()); - //} + //} + } + else { + m_synth.StopNoteSound(); + } + } // Play ring-buffered audio void Application::play_buffered_audio() { - std::size_t size_to_read = m_ring_buffer->GetSize(); - size_t sample_count = (size_t)(1.f/FPS * SAMPLE_RATE); + //std::size_t size_to_read = m_ring_buffer->GetSize(); + size_t sample_count = STREAM_BUFFER_SIZE;//(size_t)(1.f/FPS * SAMPLE_RATE); 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 // 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 - 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 + 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) { // m_ring_buffer->Reset(); // } } - m_ring_buffer->Read(m_temp_buffer, sample_count); - m_ring_buffer->Reset(); - if (m_ring_buffer->IsFull() || m_ring_buffer->IsEmpty()) { - } + //m_ring_buffer->Read(m_temp_buffer, sample_count); + //m_ring_buffer->Reset(); + //if (m_ring_buffer->IsFull() || m_ring_buffer->IsEmpty()) { + //} } // Fill ring buffer from current sound @@ -154,9 +164,9 @@ void Application::Run() { // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { - fill_audio_buffer(); + //fill_audio_buffer(); + //update_on_note_input(); play_buffered_audio(); - update_on_note_input(); m_renderer.Draw(m_synth, m_synth_gui_state); } diff --git a/src/Synth.cpp b/src/Synth.cpp index 03c0b03..67fa36c 100644 --- a/src/Synth.cpp +++ b/src/Synth.cpp @@ -7,6 +7,10 @@ Synth::Synth(/* args */) { AddOscillator(); 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() { @@ -15,9 +19,13 @@ Synth::~Synth() { m_out_signal.clear(); } -std::vector& 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 duration = beats * BEAT_DURATION; // will change after oscillator starts to be more autonomous for (Oscillator* osc : m_oscillators) { @@ -25,7 +33,7 @@ std::vector& Synth::get_note(int semitone, float beats) { } // 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() { @@ -39,10 +47,17 @@ void Synth::apply_effects() { void Synth::ProduceNoteSound(Note input) { float length = 1.f / input.length; int semitone_shift = KeyBoard::GetSemitoneShift(input.name); - m_out_signal = get_note(semitone_shift, length); + get_note(semitone_shift, length); 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() { m_oscillators.push_back( new Oscillator(OscillatorType::Sine, 440.f, VOLUME));