[feat]: Filter (#18)

closes #16

Reviewed-on: #18
This commit is contained in:
2023-09-10 00:56:47 +03:00
parent 868a59da0e
commit bb3ccc296a
22 changed files with 372 additions and 48 deletions

View File

@@ -3,18 +3,14 @@
#include "Ramp.h"
#include <cstddef>
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;

View File

@@ -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;

View File

@@ -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 */);

14
inc/BandPassFilter.h Normal file
View File

@@ -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; };
};

35
inc/Filter.h Normal file
View File

@@ -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<float>& 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; };
};

29
inc/FilterFactory.h Normal file
View File

@@ -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();
}
};

14
inc/HighPassFilter.h Normal file
View File

@@ -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; };
};

View File

@@ -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;

15
inc/LowPassFilter.h Normal file
View File

@@ -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; };
};

View File

@@ -31,5 +31,5 @@ class Oscillator {
float GetFreq() { return m_freq; }
void SetFreq(float freq);
void Reset();
float GenerateSample(float duration);
float Process();
};

View File

@@ -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 */);

View File

@@ -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<Oscillator*> m_oscillators;
std::vector<Effect*> m_effects;
std::vector<float> 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<Oscillator*>& 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);
};

View File

@@ -2,6 +2,7 @@
#include "OscillatorType.h"
#include "raygui.h"
#include <vector>
#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<OscillatorGuiState*> oscillators;
ADSRGuiState adsr;
FilterGuiState filter;
};