From bb3ccc296a7fa51c6ca07e5d0dffc5755d8a65a2 Mon Sep 17 00:00:00 2001 From: e1lama Date: Sun, 10 Sep 2023 00:56:47 +0300 Subject: [PATCH] [feat]: Filter (#18) closes #16 Reviewed-on: https://gitea.e1lama.ru/e1lama/SeeSynth/pulls/18 --- inc/ADSR.h | 17 ++++------ inc/Adder.h | 2 +- inc/Application.h | 10 +++--- inc/BandPassFilter.h | 14 +++++++++ inc/Filter.h | 35 +++++++++++++++++++++ inc/FilterFactory.h | 29 +++++++++++++++++ inc/HighPassFilter.h | 14 +++++++++ inc/KeyBoard.h | 4 +-- inc/LowPassFilter.h | 15 +++++++++ inc/Oscillator.h | 2 +- inc/Renderer.h | 4 +++ inc/Synth.h | 6 +++- inc/SynthGuiState.h | 9 ++++++ src/ADSR.cpp | 27 ++++++++-------- src/Application.cpp | 20 ++++++------ src/BandPassFilter.cpp | 23 ++++++++++++++ src/Filter.cpp | 36 ++++++++++++++++++++++ src/HighPassFilter.cpp | 23 ++++++++++++++ src/LowPassFilter.cpp | 33 ++++++++++++++++++++ src/Oscillator.cpp | 2 +- src/Renderer.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++ src/Synth.cpp | 25 ++++++++++++++- 22 files changed, 372 insertions(+), 48 deletions(-) create mode 100644 inc/BandPassFilter.h create mode 100644 inc/Filter.h create mode 100644 inc/FilterFactory.h create mode 100644 inc/HighPassFilter.h create mode 100644 inc/LowPassFilter.h create mode 100644 src/BandPassFilter.cpp create mode 100644 src/Filter.cpp create mode 100644 src/HighPassFilter.cpp create mode 100644 src/LowPassFilter.cpp diff --git a/inc/ADSR.h b/inc/ADSR.h index a33aa8d..71c3acf 100644 --- a/inc/ADSR.h +++ b/inc/ADSR.h @@ -3,18 +3,14 @@ #include "Ramp.h" #include -struct ADSRParameters { - float attack_time; // Attack time in seconds - float decay_time; // Decay time in seconds - float sustain_level; // Sustain level (0 to 1) - float release_time; -}; - -enum ADSRState { sOff, sAttack, sDecay, sSustain, sRelease }; - class ADSR : public Effect { + enum ADSRState { sOff, sAttack, sDecay, sSustain, sRelease }; + private: - ADSRParameters m_parameters; + float m_attack_time; + float m_decay_time; + float m_sustain_level; + float m_release_time; ADSRState m_state; Ramp* m_ramp; @@ -26,7 +22,6 @@ class ADSR : public Effect { public: ADSR(/* args */); - ADSR(ADSRParameters param); ~ADSR(); void Trigger() override; void Release() override; diff --git a/inc/Adder.h b/inc/Adder.h index 3052b15..e12a3eb 100644 --- a/inc/Adder.h +++ b/inc/Adder.h @@ -13,7 +13,7 @@ struct Adder { for (size_t i = 0; i < sample_count; i++) { float sample = 0.0f; for (Oscillator* osc : oscillators) { - sample += osc->GenerateSample(1.f); + sample += osc->Process(); } signal[i] = sample; diff --git a/inc/Application.h b/inc/Application.h index a98ba7c..883a3ad 100644 --- a/inc/Application.h +++ b/inc/Application.h @@ -13,11 +13,11 @@ class Application { int m_sound_played_count; Note* m_current_note; Renderer m_renderer; - bool detect_note_pressed(Note* note); - void init_synth(); - void init_audio(); - void update_on_note_input(); - void play_buffered_audio(); + bool DetectNotePressed(Note* note); + void InitSynth(); + void InitAudio(); + void UpdateOnNoteInput(); + void PlayBufferedAudio(); public: Application(/* args */); diff --git a/inc/BandPassFilter.h b/inc/BandPassFilter.h new file mode 100644 index 0000000..e83c929 --- /dev/null +++ b/inc/BandPassFilter.h @@ -0,0 +1,14 @@ +#pragma once +#include "Filter.h" + +class BandPassFilter : public Filter { + private: + void CalculateCoefficients() override; + + public: + BandPassFilter(Filter* filter); + BandPassFilter(float freq, float res, float q); + BandPassFilter(/* args */); + ~BandPassFilter(); + bool IsSameFilterType(FilterType type) override { return type == BandPass; }; +}; diff --git a/inc/Filter.h b/inc/Filter.h new file mode 100644 index 0000000..7b5f567 --- /dev/null +++ b/inc/Filter.h @@ -0,0 +1,35 @@ +#pragma once +#include "Effect.h" + +enum FilterType { + LowPass, + BandPass, + HighPass +}; + +class Filter : public Effect { + protected: + float m_freq; // cutoff frequency + float m_q; // filter quantity (resonance) + float m_order; // filter order (peakGain) + /* todo: filter adsr */ + float m_norm, m_v, m_k; + float m_a0, m_a1, m_a2, m_b1, m_b2; + float m_z1, m_z2; + + void CalculateNormals(); + virtual void CalculateCoefficients(){}; + + public: + Filter(/* args */); + virtual ~Filter(); + void Trigger() override; + void Release() override; + float Process(float in); + void Process(std::vector& samples) override; + void SetParameters(float freq, float res, float q); + float GetFreq() { return m_freq; } + float GetRes() { return m_q; } + float GetPeakGain() { return m_norm; } + virtual bool IsSameFilterType(FilterType type){ return false; }; +}; diff --git a/inc/FilterFactory.h b/inc/FilterFactory.h new file mode 100644 index 0000000..1fe471c --- /dev/null +++ b/inc/FilterFactory.h @@ -0,0 +1,29 @@ +#pragma once +#include "Filter.h" +#include "LowPassFilter.h" +#include "BandPassFilter.h" +#include "HighPassFilter.h" + +struct FilterFactory { + static Filter* CreateFilter(Filter* old_filter, FilterType new_type) { + Filter* new_filter; + switch (new_type) { + case LowPass: + new_filter = new LowPassFilter(old_filter); + break; + case BandPass: + new_filter = new BandPassFilter(old_filter); + break; + case HighPass: + new_filter = new HighPassFilter(old_filter); + break; + default: + break; + } + return new_filter; + } + + static Filter* GetDefaultFilter() { + return new LowPassFilter(); + } +}; \ No newline at end of file diff --git a/inc/HighPassFilter.h b/inc/HighPassFilter.h new file mode 100644 index 0000000..69556a5 --- /dev/null +++ b/inc/HighPassFilter.h @@ -0,0 +1,14 @@ +#pragma once +#include "Filter.h" + +class HighPassFilter : public Filter { + private: + void CalculateCoefficients() override; + + public: + HighPassFilter(); + HighPassFilter(Filter* filter); + HighPassFilter(float freq, float res, float q); + ~HighPassFilter(); + bool IsSameFilterType(FilterType type) override { return type == HighPass; }; +}; diff --git a/inc/KeyBoard.h b/inc/KeyBoard.h index 85fdc97..b6b3d7a 100644 --- a/inc/KeyBoard.h +++ b/inc/KeyBoard.h @@ -7,7 +7,7 @@ class KeyBoard { private: - static int get_semitone_shift_internal(const char* root_note, + static int GetSemitoneShiftInternal(const char* root_note, char* target_note) { const char* pitch_classes[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; @@ -65,7 +65,7 @@ class KeyBoard { char* target_note_cstr = new char[target_note.length() + 1]; strcpy(target_note_cstr, target_note.c_str()); - int result = get_semitone_shift_internal("A4", target_note_cstr); + int result = GetSemitoneShiftInternal("A4", target_note_cstr); delete[] target_note_cstr; return result; diff --git a/inc/LowPassFilter.h b/inc/LowPassFilter.h new file mode 100644 index 0000000..1ee043b --- /dev/null +++ b/inc/LowPassFilter.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Filter.h" + +class LowPassFilter : public Filter { + protected: + void CalculateCoefficients() override; + + public: + LowPassFilter(); + LowPassFilter(Filter* filter); + LowPassFilter(float freq, float res, float q); + ~LowPassFilter(); + bool IsSameFilterType(FilterType type) override { return type == LowPass; }; +}; diff --git a/inc/Oscillator.h b/inc/Oscillator.h index 1e33fa8..d655075 100644 --- a/inc/Oscillator.h +++ b/inc/Oscillator.h @@ -31,5 +31,5 @@ class Oscillator { float GetFreq() { return m_freq; } void SetFreq(float freq); void Reset(); - float GenerateSample(float duration); + float Process(); }; diff --git a/inc/Renderer.h b/inc/Renderer.h index fccd7a6..06454cb 100644 --- a/inc/Renderer.h +++ b/inc/Renderer.h @@ -1,5 +1,6 @@ #pragma once #include "ADSR.h" +#include "Filter.h" #include "Synth.h" #include "SynthGuiState.h" #include "raylib.h" @@ -19,6 +20,9 @@ class Renderer { void draw_signal(Synth& synth, SynthGuiState& synth_gui); void draw_adsr_panel(ADSR* adsr, ADSRGuiState& gui_adsr, const Rectangle& panel_bounds, float panel_y_offset); + void draw_second_panel(Rectangle& bounds); + float DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter, + const Rectangle& panel_bounds); public: Renderer(/* args */); diff --git a/inc/Synth.h b/inc/Synth.h index eb12ea0..c9bc8d8 100644 --- a/inc/Synth.h +++ b/inc/Synth.h @@ -1,6 +1,7 @@ #pragma once #include "ADSR.h" +#include "Filter.h" #include "Adder.h" #include "Effect.h" #include "Note.h" @@ -14,13 +15,14 @@ class Synth { std::vector m_oscillators; std::vector m_effects; std::vector m_out_signal; + Oscillator* m_lfo; void zero_signal(); void get_note(); void trigger_note_on_effects(); void untrigger_note_on_effects(); void apply_effects(); void add_oscillator(); - + void apply_filter_lfo(); public: Synth(/* args */); ~Synth(); @@ -32,4 +34,6 @@ class Synth { const std::vector& GetOscillators() { return m_oscillators; } const bool& GetIsNoteTriggered() { return is_note_triggered; } ADSR* GetADSR() { return (ADSR*)m_effects[0]; } + Filter* GetFilter() { return (Filter*)m_effects[1]; } + void SetFilter(FilterType type); }; \ No newline at end of file diff --git a/inc/SynthGuiState.h b/inc/SynthGuiState.h index f07a21d..6d404ed 100644 --- a/inc/SynthGuiState.h +++ b/inc/SynthGuiState.h @@ -2,6 +2,7 @@ #include "OscillatorType.h" #include "raygui.h" #include +#include "Filter.h" struct OscillatorGuiState { float volume; @@ -18,7 +19,15 @@ struct ADSRGuiState { float release; }; +struct FilterGuiState { + float freq; + float res; //todo: res + FilterType type; + bool is_dropdown_open; +}; + struct SynthGuiState { std::vector oscillators; ADSRGuiState adsr; + FilterGuiState filter; }; \ No newline at end of file diff --git a/src/ADSR.cpp b/src/ADSR.cpp index ad9c140..9f043a9 100644 --- a/src/ADSR.cpp +++ b/src/ADSR.cpp @@ -3,15 +3,13 @@ #include "Settings.h" ADSR::ADSR(/* args */) { - m_parameters.attack_time = 1.f; - m_parameters.decay_time = 0.4f; - m_parameters.sustain_level = 0.6f; - m_parameters.release_time = 0.8f; + m_attack_time = 1.f; + m_decay_time = 0.4f; + m_sustain_level = 0.6f; + m_release_time = 0.8f; m_ramp = new Ramp(0, SAMPLE_RATE); } -ADSR::ADSR(ADSRParameters param) { m_parameters = param; } - ADSR::~ADSR() { delete m_ramp; } bool ADSR::is_attack_elapsed() { @@ -31,8 +29,7 @@ void ADSR::recheck_state() { case sAttack: if (is_attack_elapsed()) { m_state = sDecay; - m_ramp->RampTo(m_parameters.sustain_level, - m_parameters.decay_time); + m_ramp->RampTo(m_sustain_level, m_decay_time); } break; case sDecay: @@ -58,7 +55,7 @@ void ADSR::process_sample(float* sample) { } else if (m_state == sDecay) { (*sample) = (*sample) * m_ramp->Process(); } else if (m_state == sSustain) { - (*sample) = (*sample) * m_parameters.sustain_level; + (*sample) = (*sample) * m_sustain_level; } else if (m_state == sRelease) { (*sample) = (*sample) * m_ramp->Process(); } @@ -72,13 +69,13 @@ void ADSR::Trigger() { m_state = sAttack; }; - m_ramp->RampTo(1, m_parameters.attack_time); + m_ramp->RampTo(1, m_attack_time); } void ADSR::Release() { write_log("Unset ADSR\n"); m_state = sRelease; - m_ramp->RampTo(0, m_parameters.release_time); + m_ramp->RampTo(0, m_release_time); } void ADSR::Process(std::vector& samples) { @@ -90,8 +87,8 @@ void ADSR::Process(std::vector& samples) { void ADSR::SetParameters(float attack, float decay, float sustain, float release) { - m_parameters.attack_time = attack; - m_parameters.decay_time = decay; - m_parameters.sustain_level = sustain; - m_parameters.release_time = release; + m_attack_time = attack; + m_decay_time = decay; + m_sustain_level = sustain; + m_release_time = release; } \ No newline at end of file diff --git a/src/Application.cpp b/src/Application.cpp index 9866190..53a91ca 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -4,8 +4,8 @@ #include Application::Application(/* args */) { - init_synth(); - init_audio(); + InitSynth(); + InitAudio(); } Application::~Application() { @@ -19,7 +19,7 @@ Application::~Application() { } } -void Application::init_audio() { +void Application::InitAudio() { m_sound_played_count = 0; InitAudioDevice(); @@ -31,7 +31,7 @@ void Application::init_audio() { PlayAudioStream(m_synth_stream); } -void Application::init_synth() { +void Application::InitSynth() { std::string* nameString = new std::string(std::string(new char[3])); m_current_note = new Note{.length = 1, .name = (*nameString)}; m_current_note->name.assign("G4"); @@ -50,7 +50,7 @@ void Application::init_synth() { } } -bool Application::detect_note_pressed(Note* note) { +bool Application::DetectNotePressed(Note* note) { std::size_t is_pressed = 0; note->length = 8; if (IsKeyDown(KEY_A)) { @@ -89,8 +89,8 @@ bool is_note_up() { IsKeyUp(KEY_D) || IsKeyUp(KEY_E) || IsKeyUp(KEY_F) || IsKeyUp(KEY_G); } -void Application::update_on_note_input() { - if (detect_note_pressed(m_current_note)) { +void Application::UpdateOnNoteInput() { + if (DetectNotePressed(m_current_note)) { if (!m_synth.GetIsNoteTriggered()) { m_synth.Trigger((*m_current_note)); } @@ -103,9 +103,9 @@ void Application::update_on_note_input() { } // Play ring-buffered audio -void Application::play_buffered_audio() { +void Application::PlayBufferedAudio() { if (IsAudioStreamProcessed(m_synth_stream)) { - update_on_note_input(); + UpdateOnNoteInput(); UpdateAudioStream(m_synth_stream, m_synth.GetOutSignal().data(), STREAM_BUFFER_SIZE); } @@ -114,7 +114,7 @@ void Application::play_buffered_audio() { void Application::Run() { // Main game loop while (!WindowShouldClose()) { - play_buffered_audio(); + PlayBufferedAudio(); m_renderer.Draw(m_synth, m_synth_gui_state); } } diff --git a/src/BandPassFilter.cpp b/src/BandPassFilter.cpp new file mode 100644 index 0000000..c751e3d --- /dev/null +++ b/src/BandPassFilter.cpp @@ -0,0 +1,23 @@ +#include "BandPassFilter.h" + +BandPassFilter::BandPassFilter(/* args */) {} + +BandPassFilter::BandPassFilter(Filter* filter) { + m_freq = filter->GetFreq(); + m_q = filter->GetRes(); + m_order = filter->GetPeakGain(); +} + +BandPassFilter::BandPassFilter(float freq, float res, float q) {} + +BandPassFilter::~BandPassFilter() {} + +void BandPassFilter::CalculateCoefficients() { + CalculateNormals(); + m_norm = 1 / (1 + m_k / m_q + m_k * m_k); + m_a0 = m_k / m_q * m_norm; + m_a1 = 0; + m_a2 = -m_a0; + m_b1 = 2 * (m_k * m_k - 1) * m_norm; + m_b2 = (1 - m_k / m_q + m_k * m_k) * m_norm; +} \ No newline at end of file diff --git a/src/Filter.cpp b/src/Filter.cpp new file mode 100644 index 0000000..4beecce --- /dev/null +++ b/src/Filter.cpp @@ -0,0 +1,36 @@ +#include "Filter.h" +#include "Settings.h" + +Filter::Filter(/* args */) {} + +Filter::~Filter() {} + +void Filter::CalculateNormals() { + m_v = powf(10, fabs(m_order) / 20.0); + m_k = tanf(M_PI * m_freq); +} + +void Filter::Trigger() {} + +void Filter::Release() {} + +float Filter::Process(float in) { + // may move to a compile-time dictionary calculation, if needed + CalculateCoefficients(); + float out = in * m_a0 + m_z1; + m_z1 = in * m_a1 + m_z2 - m_b1 * out; + m_z2 = in * m_a2 - m_b2 * out; + return out; +} + +void Filter::Process(std::vector& samples) { + for (std::size_t i = 0; i < samples.size(); i++) { + samples[i] = Process(samples[i]); + } +} + +void Filter::SetParameters(float freq, float res, float q) { + m_freq = freq / SAMPLE_RATE; + m_q = res; + m_order = q; +} diff --git a/src/HighPassFilter.cpp b/src/HighPassFilter.cpp new file mode 100644 index 0000000..587d520 --- /dev/null +++ b/src/HighPassFilter.cpp @@ -0,0 +1,23 @@ +#include "HighPassFilter.h" + +HighPassFilter::HighPassFilter(/* args */) {} + +HighPassFilter::HighPassFilter(Filter* filter) { + m_freq = filter->GetFreq(); + m_q = filter->GetRes(); + m_order = filter->GetPeakGain(); +} + +HighPassFilter::HighPassFilter(float freq, float res, float q) {} + +HighPassFilter::~HighPassFilter() {} + +void HighPassFilter::CalculateCoefficients() { + CalculateNormals(); + m_norm = 1 / (1 + m_k / m_q + m_k * m_k); + m_a0 = 1 * m_norm; + m_a1 = -2 * m_a0; + m_a2 = m_a0; + m_b1 = 2 * (m_k * m_k - 1) * m_norm; + m_b2 = (1 - m_k / m_q + m_k * m_k) * m_norm; +} \ No newline at end of file diff --git a/src/LowPassFilter.cpp b/src/LowPassFilter.cpp new file mode 100644 index 0000000..2ee08dd --- /dev/null +++ b/src/LowPassFilter.cpp @@ -0,0 +1,33 @@ +#include "LowPassFilter.h" +#include "Settings.h" + +LowPassFilter::LowPassFilter() { + // todo: defaults + m_freq = 200.f / SAMPLE_RATE; + m_q = 1.0f;//0.707f; + m_order = 0; +} + +LowPassFilter::LowPassFilter(float freq, float res, float q) { + m_freq = freq / SAMPLE_RATE; + m_q = res; + m_order = q; +} + +LowPassFilter::LowPassFilter(Filter* filter) { + m_freq = filter->GetFreq(); + m_q = filter->GetRes(); + m_order = filter->GetPeakGain(); +} + +LowPassFilter::~LowPassFilter() {} + +void LowPassFilter::CalculateCoefficients() { + CalculateNormals(); + m_norm = 1 / (1 + m_k / m_q + m_k * m_k); + m_a0 = m_k * m_k * m_norm; + m_a1 = 2 * m_a0; + m_a2 = m_a0; + m_b1 = 2 * (m_k * m_k - 1) * m_norm; + m_b2 = (1 - m_k / m_q + m_k * m_k) * m_norm; +} \ No newline at end of file diff --git a/src/Oscillator.cpp b/src/Oscillator.cpp index cf6e940..6abe4b7 100644 --- a/src/Oscillator.cpp +++ b/src/Oscillator.cpp @@ -45,7 +45,7 @@ void Oscillator::SetFreq(float freq) { m_phase_dt = (this->*m_dt_function)(freq); } -float Oscillator::GenerateSample(float duration) { +float Oscillator::Process() { return (this->*m_osc_function)() * m_volume; } diff --git a/src/Renderer.cpp b/src/Renderer.cpp index e3db365..5032745 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -185,6 +185,73 @@ void Renderer::draw_adsr_panel(ADSR* adsr, ADSRGuiState& gui_adsr, gui_adsr.release); } +void Renderer::draw_second_panel(Rectangle& bounds) { + bounds.x += bounds.width; + GuiPanel(bounds, ""); +} + +float Renderer::DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter, + const Rectangle& panel_bounds) { +#define FILTER_TYPE_OPTIONS "LP;BP;HP" + Filter* filter = synth.GetFilter(); + float panel_y_offset = 0; + + // Draw Filter Panel + const int osc_panel_width = panel_bounds.width - 20; + const int osc_panel_height = 100; + const int osc_panel_x = panel_bounds.x + 10; + const int osc_panel_y = panel_bounds.y + 50; + panel_y_offset += osc_panel_height + 5; + GuiPanel((Rectangle){(float)osc_panel_x, (float)osc_panel_y, + (float)osc_panel_width, (float)osc_panel_height}, + "Filter"); + + const float slider_padding = 50.f; + const float el_spacing = 5.f; + Rectangle el_rect = {.x = (float)osc_panel_x + slider_padding + 30, + .y = (float)osc_panel_y + 10, + .width = (float)osc_panel_width - (slider_padding * 2), + .height = 25.f}; + + // Frequency slider + float freq = log10f(gui_filter.freq); + char freq_slider_label[32]; + snprintf(freq_slider_label, 10, "%.1f hz", powf(10.f, freq)); + freq = GuiSlider(el_rect, freq_slider_label, "", freq, 0.f, 4.f); + gui_filter.freq = powf(10.f, freq); + el_rect.y += el_rect.height + el_spacing; + + //todo: implement that when Res will be fixed + // Resonance slider + // float res = gui_filter.res; + // char res_slider_label[32]; + // snprintf(res_slider_label, 7, "%.1f u", res); + // res = GuiSlider(el_rect, res_slider_label, "", res, 0.0f, 1.0f); + // gui_filter.res = res; + // el_rect.y += el_rect.height + el_spacing; + + // Shape select + int shape_index = (int)(gui_filter.type); + bool is_dropdown_click = + GuiDropdownBox(el_rect, FILTER_TYPE_OPTIONS, + &shape_index, gui_filter.is_dropdown_open); + + if (is_dropdown_click) { + write_log("Dropdown clicked!\n"); + gui_filter.is_dropdown_open = !gui_filter.is_dropdown_open; + gui_filter.type = (FilterType)(shape_index); + // APPLY STATE TO REAL SYNTH + synth.SetFilter(gui_filter.type); + } + + // apply values to real one + // todo: thrid (order) parameter + // todo: why resonance changing does not work? + filter->SetParameters(gui_filter.freq, filter->GetRes(), filter->GetPeakGain()); + + return panel_y_offset; +} + void Renderer::draw_ui(Synth& synth, SynthGuiState& synth_gui) { Rectangle panel_bounds = {.x = 0, .y = 0, @@ -200,4 +267,7 @@ void Renderer::draw_ui(Synth& synth, SynthGuiState& synth_gui) { draw_adsr_panel(synth.GetADSR(), synth_gui.adsr, panel_bounds, panel_y_offset); draw_oscillators_shape_inputs(oscillators, gui_oscillators); + + draw_second_panel(panel_bounds); + DrawFilterPanel(synth, synth_gui.filter, panel_bounds); } diff --git a/src/Synth.cpp b/src/Synth.cpp index fc99405..59b1efa 100644 --- a/src/Synth.cpp +++ b/src/Synth.cpp @@ -1,14 +1,16 @@ #include "Synth.h" -#include "ADSR.h" #include "KeyBoard.h" #include "Logger.h" #include "OscillatorType.h" #include "Settings.h" +#include "FilterFactory.h" Synth::Synth(/* args */) { + m_lfo = new Oscillator(OscillatorType::Sine, 5.f, VOLUME); add_oscillator(); add_oscillator(); AddEffect(new ADSR()); + AddEffect(FilterFactory::GetDefaultFilter()); for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) { float sample = 0.0f; m_out_signal.push_back(sample); @@ -68,7 +70,19 @@ void Synth::Trigger(Note input) { trigger_note_on_effects(); } +// todo: fix this +void Synth::apply_filter_lfo() { + float dt = m_lfo->Process(); + Filter* filter = (Filter*)m_effects[1]; + float freq = filter->GetFreq(); + //todo: check formula + //filter->SetParameters(freq + dt * 0.2f, filter->GetRes(), filter->GetPeakGain()); +} + void Synth::Process() { + //todo: on each sample. + //in order to do that, we need to move to per-sample processing + apply_filter_lfo(); get_note(); apply_effects(); } @@ -80,3 +94,12 @@ void Synth::Release() { } void Synth::AddEffect(Effect* fx) { m_effects.push_back(fx); } + +void Synth::SetFilter(FilterType type) { + Filter* old_filter = this->GetFilter(); + if (!old_filter->IsSameFilterType(type)) { + Filter* new_filter = FilterFactory::CreateFilter(old_filter, type); + delete old_filter; + m_effects[1] = new_filter; + } +}