refactor: IEffect interface
This commit is contained in:
14
inc/ADSR.h
14
inc/ADSR.h
@@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Effect.h"
|
#include "IEffect.h"
|
||||||
#include "Ramp.h"
|
#include "Ramp.h"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
class ADSR : public Effect {
|
class ADSR : public IEffect {
|
||||||
enum ADSRState { sOff, sAttack, sDecay, sSustain, sRelease };
|
enum ADSRState { sOff, sAttack, sDecay, sSustain, sRelease };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -14,11 +14,11 @@ class ADSR : public Effect {
|
|||||||
ADSRState m_state;
|
ADSRState m_state;
|
||||||
Ramp* m_ramp;
|
Ramp* m_ramp;
|
||||||
|
|
||||||
void process_sample(float* sample);
|
void ProcessSample(float* sample);
|
||||||
bool is_attack_elapsed();
|
bool IsAttackElapsed();
|
||||||
bool is_decay_elapsed();
|
bool IsDecayElapsed();
|
||||||
bool is_release_elapsed();
|
bool IsReleaseElapsed();
|
||||||
void recheck_state();
|
void RecheckState();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ADSR(/* args */);
|
ADSR(/* args */);
|
||||||
|
|||||||
12
inc/Effect.h
12
inc/Effect.h
@@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
class Effect {
|
|
||||||
private:
|
|
||||||
/* data */
|
|
||||||
public:
|
|
||||||
Effect(/* args */){};
|
|
||||||
~Effect(){};
|
|
||||||
virtual void Trigger(){};
|
|
||||||
virtual void Release(){};
|
|
||||||
virtual void Process(std::vector<float>& samples){};
|
|
||||||
};
|
|
||||||
10
inc/Filter.h
10
inc/Filter.h
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Effect.h"
|
#include "IEffect.h"
|
||||||
|
|
||||||
enum FilterType {
|
enum FilterType {
|
||||||
LowPass,
|
LowPass,
|
||||||
@@ -7,7 +7,7 @@ enum FilterType {
|
|||||||
HighPass
|
HighPass
|
||||||
};
|
};
|
||||||
|
|
||||||
class Filter : public Effect {
|
class Filter : public IEffect {
|
||||||
protected:
|
protected:
|
||||||
float m_freq; // cutoff frequency
|
float m_freq; // cutoff frequency
|
||||||
float m_q; // filter quantity (resonance)
|
float m_q; // filter quantity (resonance)
|
||||||
@@ -23,10 +23,10 @@ class Filter : public Effect {
|
|||||||
public:
|
public:
|
||||||
Filter(/* args */);
|
Filter(/* args */);
|
||||||
virtual ~Filter();
|
virtual ~Filter();
|
||||||
void Trigger() override;
|
void Trigger() override final;
|
||||||
void Release() override;
|
void Release() override final;
|
||||||
float Process(float in);
|
float Process(float in);
|
||||||
void Process(std::vector<float>& samples) override;
|
void Process(std::vector<float>& samples) override final;
|
||||||
void SetParameters(float freq, float res, float q);
|
void SetParameters(float freq, float res, float q);
|
||||||
float GetFreq() { return m_freq; }
|
float GetFreq() { return m_freq; }
|
||||||
float GetRes() { return m_q; }
|
float GetRes() { return m_q; }
|
||||||
|
|||||||
10
inc/IEffect.h
Normal file
10
inc/IEffect.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
class IEffect {
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
public:
|
||||||
|
virtual void Trigger() = 0;
|
||||||
|
virtual void Release() = 0;
|
||||||
|
virtual void Process(std::vector<float>& samples) = 0;
|
||||||
|
};
|
||||||
20
inc/Synth.h
20
inc/Synth.h
@@ -3,7 +3,7 @@
|
|||||||
#include "ADSR.h"
|
#include "ADSR.h"
|
||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
#include "Adder.h"
|
#include "Adder.h"
|
||||||
#include "Effect.h"
|
#include "IEffect.h"
|
||||||
#include "Note.h"
|
#include "Note.h"
|
||||||
#include "Oscillator.h"
|
#include "Oscillator.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
@@ -13,23 +13,23 @@ class Synth {
|
|||||||
private:
|
private:
|
||||||
bool is_note_triggered;
|
bool is_note_triggered;
|
||||||
std::vector<Oscillator*> m_oscillators;
|
std::vector<Oscillator*> m_oscillators;
|
||||||
std::vector<Effect*> m_effects;
|
std::vector<IEffect*> m_effects;
|
||||||
std::vector<float> m_out_signal;
|
std::vector<float> m_out_signal;
|
||||||
Oscillator* m_lfo;
|
Oscillator* m_lfo;
|
||||||
void zero_signal();
|
void ZeroSignal();
|
||||||
void get_note();
|
void GetNote();
|
||||||
void trigger_note_on_effects();
|
void TriggerNoteOnEffects();
|
||||||
void untrigger_note_on_effects();
|
void UntriggerNoteOnEffects();
|
||||||
void apply_effects();
|
void ApplyEffects();
|
||||||
void add_oscillator();
|
void AddOscillator();
|
||||||
void apply_filter_lfo();
|
void ApplyFilterLfo();
|
||||||
public:
|
public:
|
||||||
Synth(/* args */);
|
Synth(/* args */);
|
||||||
~Synth();
|
~Synth();
|
||||||
void Trigger(Note input);
|
void Trigger(Note input);
|
||||||
void Process();
|
void Process();
|
||||||
void Release();
|
void Release();
|
||||||
void AddEffect(Effect* fx);
|
void AddEffect(IEffect* fx);
|
||||||
const std::vector<float>& GetOutSignal() { return m_out_signal; }
|
const std::vector<float>& GetOutSignal() { return m_out_signal; }
|
||||||
const std::vector<Oscillator*>& GetOscillators() { return m_oscillators; }
|
const std::vector<Oscillator*>& GetOscillators() { return m_oscillators; }
|
||||||
const bool& GetIsNoteTriggered() { return is_note_triggered; }
|
const bool& GetIsNoteTriggered() { return is_note_triggered; }
|
||||||
|
|||||||
20
src/ADSR.cpp
20
src/ADSR.cpp
@@ -12,33 +12,33 @@ ADSR::ADSR(/* args */) {
|
|||||||
|
|
||||||
ADSR::~ADSR() { delete m_ramp; }
|
ADSR::~ADSR() { delete m_ramp; }
|
||||||
|
|
||||||
bool ADSR::is_attack_elapsed() {
|
bool ADSR::IsAttackElapsed() {
|
||||||
return m_state == sAttack && m_ramp->IsCompleted();
|
return m_state == sAttack && m_ramp->IsCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADSR::is_decay_elapsed() {
|
bool ADSR::IsDecayElapsed() {
|
||||||
return m_state == sDecay && m_ramp->IsCompleted();
|
return m_state == sDecay && m_ramp->IsCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADSR::is_release_elapsed() {
|
bool ADSR::IsReleaseElapsed() {
|
||||||
return m_state == sRelease && m_ramp->IsCompleted();
|
return m_state == sRelease && m_ramp->IsCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADSR::recheck_state() {
|
void ADSR::RecheckState() {
|
||||||
switch (m_state) {
|
switch (m_state) {
|
||||||
case sAttack:
|
case sAttack:
|
||||||
if (is_attack_elapsed()) {
|
if (IsAttackElapsed()) {
|
||||||
m_state = sDecay;
|
m_state = sDecay;
|
||||||
m_ramp->RampTo(m_sustain_level, m_decay_time);
|
m_ramp->RampTo(m_sustain_level, m_decay_time);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case sDecay:
|
case sDecay:
|
||||||
if (is_decay_elapsed()) {
|
if (IsDecayElapsed()) {
|
||||||
m_state = sSustain;
|
m_state = sSustain;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case sRelease:
|
case sRelease:
|
||||||
if (is_release_elapsed()) {
|
if (IsReleaseElapsed()) {
|
||||||
m_state = sOff;
|
m_state = sOff;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -47,7 +47,7 @@ void ADSR::recheck_state() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ADSR::process_sample(float* sample) {
|
void ADSR::ProcessSample(float* sample) {
|
||||||
if (m_state == sOff) {
|
if (m_state == sOff) {
|
||||||
(*sample) = 0;
|
(*sample) = 0;
|
||||||
} else if (m_state == sAttack) {
|
} else if (m_state == sAttack) {
|
||||||
@@ -80,8 +80,8 @@ void ADSR::Release() {
|
|||||||
|
|
||||||
void ADSR::Process(std::vector<float>& samples) {
|
void ADSR::Process(std::vector<float>& samples) {
|
||||||
for (std::size_t i = 0; i < samples.size(); i++) {
|
for (std::size_t i = 0; i < samples.size(); i++) {
|
||||||
recheck_state();
|
RecheckState();
|
||||||
process_sample(&samples[i]);
|
ProcessSample(&samples[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,15 @@
|
|||||||
|
|
||||||
Synth::Synth(/* args */) {
|
Synth::Synth(/* args */) {
|
||||||
m_lfo = new Oscillator(OscillatorType::Sine, 5.f, VOLUME);
|
m_lfo = new Oscillator(OscillatorType::Sine, 5.f, VOLUME);
|
||||||
add_oscillator();
|
AddOscillator();
|
||||||
add_oscillator();
|
AddOscillator();
|
||||||
AddEffect(new ADSR());
|
AddEffect(new ADSR());
|
||||||
AddEffect(FilterFactory::GetDefaultFilter());
|
AddEffect(FilterFactory::GetDefaultFilter());
|
||||||
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
||||||
float sample = 0.0f;
|
float sample = 0.0f;
|
||||||
m_out_signal.push_back(sample);
|
m_out_signal.push_back(sample);
|
||||||
}
|
}
|
||||||
zero_signal();
|
ZeroSignal();
|
||||||
}
|
}
|
||||||
|
|
||||||
Synth::~Synth() {
|
Synth::~Synth() {
|
||||||
@@ -24,37 +24,37 @@ Synth::~Synth() {
|
|||||||
m_out_signal.clear();
|
m_out_signal.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::zero_signal() {
|
void Synth::ZeroSignal() {
|
||||||
float sample = 0.0f;
|
float sample = 0.0f;
|
||||||
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
||||||
m_out_signal[i] = sample;
|
m_out_signal[i] = sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::get_note() {
|
void Synth::GetNote() {
|
||||||
zero_signal();
|
ZeroSignal();
|
||||||
Adder::SumOscillators(m_oscillators, m_out_signal);
|
Adder::SumOscillators(m_oscillators, m_out_signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::apply_effects() {
|
void Synth::ApplyEffects() {
|
||||||
for (Effect* effect : m_effects) {
|
for (IEffect* effect : m_effects) {
|
||||||
effect->Process(m_out_signal);
|
effect->Process(m_out_signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::trigger_note_on_effects() {
|
void Synth::TriggerNoteOnEffects() {
|
||||||
for (Effect* effect : m_effects) {
|
for (IEffect* effect : m_effects) {
|
||||||
effect->Trigger();
|
effect->Trigger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::untrigger_note_on_effects() {
|
void Synth::UntriggerNoteOnEffects() {
|
||||||
for (Effect* effect : m_effects) {
|
for (IEffect* effect : m_effects) {
|
||||||
effect->Release();
|
effect->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::add_oscillator() {
|
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));
|
||||||
}
|
}
|
||||||
@@ -67,11 +67,11 @@ void Synth::Trigger(Note input) {
|
|||||||
osc->SetFreq(hz);
|
osc->SetFreq(hz);
|
||||||
}
|
}
|
||||||
is_note_triggered = true;
|
is_note_triggered = true;
|
||||||
trigger_note_on_effects();
|
TriggerNoteOnEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: fix this
|
// todo: fix this
|
||||||
void Synth::apply_filter_lfo() {
|
void Synth::ApplyFilterLfo() {
|
||||||
float dt = m_lfo->Process();
|
float dt = m_lfo->Process();
|
||||||
Filter* filter = (Filter*)m_effects[1];
|
Filter* filter = (Filter*)m_effects[1];
|
||||||
float freq = filter->GetFreq();
|
float freq = filter->GetFreq();
|
||||||
@@ -82,18 +82,18 @@ void Synth::apply_filter_lfo() {
|
|||||||
void Synth::Process() {
|
void Synth::Process() {
|
||||||
//todo: on each sample.
|
//todo: on each sample.
|
||||||
//in order to do that, we need to move to per-sample processing
|
//in order to do that, we need to move to per-sample processing
|
||||||
apply_filter_lfo();
|
ApplyFilterLfo();
|
||||||
get_note();
|
GetNote();
|
||||||
apply_effects();
|
ApplyEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::Release() {
|
void Synth::Release() {
|
||||||
zero_signal();
|
ZeroSignal();
|
||||||
is_note_triggered = false;
|
is_note_triggered = false;
|
||||||
untrigger_note_on_effects();
|
UntriggerNoteOnEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::AddEffect(Effect* fx) { m_effects.push_back(fx); }
|
void Synth::AddEffect(IEffect* fx) { m_effects.push_back(fx); }
|
||||||
|
|
||||||
void Synth::SetFilter(FilterType type) {
|
void Synth::SetFilter(FilterType type) {
|
||||||
Filter* old_filter = this->GetFilter();
|
Filter* old_filter = this->GetFilter();
|
||||||
|
|||||||
Reference in New Issue
Block a user