[feat]: Oscillator fine-tune #22

Merged
e1lama merged 6 commits from feature/osc-19 into master 2023-09-16 23:26:45 +00:00
16 changed files with 209 additions and 132 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@
*.wav *.wav
*.dSYM *.dSYM
/lib /lib
/build

37
CMakeLists.txt Normal file
View File

@@ -0,0 +1,37 @@
cmake_minimum_required(VERSION 3.5)
project(SeeSynth)
#set(CMAKE_C_STANDARD 99)
# Adding Raylib
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples
set(BUILD_GAMES OFF CACHE BOOL "" FORCE) # don't build the supplied example games
FetchContent_Declare(
raylib
GIT_REPOSITORY "https://github.com/raysan5/raylib.git"
GIT_TAG "4.5.0"
GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(raylib)
# Adding our source files
file(GLOB_RECURSE PROJECT_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_LIST_DIR}/src/*.cpp") # Define PROJECT_SOURCES as a list of all source files
set(PROJECT_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/inc/") # Define PROJECT_INCLUDE to be the path to the include directory of the project
# Declaring our executable
add_executable(${PROJECT_NAME})
set_target_properties(
${PROJECT_NAME} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON)
target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDE})
target_link_libraries(${PROJECT_NAME} PRIVATE raylib)
# Setting ASSETS_PATH
target_compile_definitions(${PROJECT_NAME} PUBLIC ASSETS_PATH="${CMAKE_CURRENT_SOURCE_DIR}/assets/") # Set the asset path macro to the absolute path on the dev machine
#target_compile_definitions(${PROJECT_NAME} PUBLIC ASSETS_PATH="./assets") # Set the asset path macro in release mode to a relative path that assumes the assets folder is in the same directory as the game executable

View File

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

View File

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

View File

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

View File

@@ -54,10 +54,9 @@ class KeyBoard {
} }
public: public:
KeyBoard(/* args */);
~KeyBoard();
static float GetHzBySemitone(int semitone) { static float GetHzBySemitone(float semitone) {
//440 * Math.Pow(2, (note - 69) / 12.0) would it be better?
return PITCH_STANDARD * powf(powf(2.f, (1.f / 12.f)), semitone); return PITCH_STANDARD * powf(powf(2.f, (1.f / 12.f)), semitone);
} }
@@ -71,7 +70,3 @@ class KeyBoard {
return result; return result;
} }
}; };
KeyBoard::KeyBoard(/* args */) {}
KeyBoard::~KeyBoard() {}

20
inc/LFO.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "Oscillator.h"
class LFO: public Oscillator
{
private:
/* data */
public:
LFO(/* args */);
~LFO();
void SetFreq(float freq) { m_phase_dt = (this->*m_dt_function)(freq); }
};
LFO::LFO(/* args */): Oscillator(Sine, 0.f, 0.5f)
{
}
LFO::~LFO()
{
}

View File

@@ -5,31 +5,41 @@
class Oscillator { class Oscillator {
private: private:
OscillatorType m_osc; OscillatorType m_osc;
float m_freq; float m_fine;
float m_key;
float m_volume; float m_volume;
float m_phase; float m_phase;
float m_phase_dt;
float (Oscillator::*m_osc_function)(void); float (Oscillator::*m_osc_function)(void);
void SineOscPhaseIncr();
void SawOscPhaseIncr();
float CalcSawPhaseDelta(float freq);
float CalcSinePhaseDelta(float freq);
float SawOsc();
float TriangleOsc();
float SquareOsc();
float Sign(float v);
float SineOsc();
protected:
float m_phase_dt;
float (Oscillator::*m_dt_function)(float freq); float (Oscillator::*m_dt_function)(float freq);
void sine_osc_phase_incr();
void saw_osc_phase_incr();
float calc_saw_phase_delta(float freq);
float calc_sine_phase_delta(float freq);
float sawosc();
float triangleosc();
float squareosc();
float sign(float v);
float sineosc();
public: public:
Oscillator(OscillatorType osc, float freq, float volume); Oscillator(OscillatorType osc, float fine, float volume);
~Oscillator(); ~Oscillator();
OscillatorType GetType() { return m_osc; } OscillatorType GetType() { return m_osc; }
void SetType(OscillatorType osc); void SetType(OscillatorType osc);
float GetVolume() { return m_volume; } float GetVolume() { return m_volume; }
void SetVolume(float volume) { m_volume = volume; } void SetVolume(float volume) { m_volume = volume; }
float GetFreq() { return m_freq; } float GetKey() { return m_key; }
void SetFreq(float freq); void SetKey(float key);
float GetFine() { return m_fine; }
void SetFine(float fine) {
if (fine != m_fine) {
assert(fine >= -2.f && fine <= 2.f);
m_fine = fine;
}
}
void Reset(); void Reset();
float Process(); float Process();
}; };

View File

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

View File

@@ -6,7 +6,7 @@
struct OscillatorGuiState { struct OscillatorGuiState {
float volume; float volume;
float freq; // todo: remove or change to pitch shift float fine;
OscillatorType waveshape; OscillatorType waveshape;
bool is_dropdown_open; bool is_dropdown_open;
Rectangle shape_dropdown_rect; Rectangle shape_dropdown_rect;

View File

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

View File

@@ -43,7 +43,7 @@ void Application::InitSynth() {
assert(osc); assert(osc);
OscillatorGuiState* ui = OscillatorGuiState* ui =
new OscillatorGuiState{.freq = osc->GetFreq(), new OscillatorGuiState{.fine = osc->GetFine(),
.waveshape = osc->GetType(), .waveshape = osc->GetType(),
.volume = osc->GetVolume()}; .volume = osc->GetVolume()};
m_synth_gui_state.oscillators.push_back(ui); m_synth_gui_state.oscillators.push_back(ui);
@@ -94,7 +94,7 @@ void Application::UpdateOnNoteInput() {
if (!m_synth.GetIsNoteTriggered()) { if (!m_synth.GetIsNoteTriggered()) {
m_synth.Trigger((*m_current_note)); m_synth.Trigger((*m_current_note));
} }
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 if (is_note_up() && m_synth.GetIsNoteTriggered()) { } else if (is_note_up() && m_synth.GetIsNoteTriggered()) {
m_synth.Release(); m_synth.Release();
} }

View File

@@ -1,11 +1,15 @@
#include "Oscillator.h" #include "Oscillator.h"
#include "Settings.h" #include "Settings.h"
#include "KeyBoard.h"
#include "Logger.h"
#define TWO_PI 2 * SYNTH_PI #define TWO_PI 2 * SYNTH_PI
Oscillator::Oscillator(OscillatorType osc, float freq, float volume) { Oscillator::Oscillator(OscillatorType osc, float fine, float volume) {
assert(fine >= -2.f && fine <= 2.f);
assert(volume >= 0.f && volume <= 1.f);
SetType(osc); SetType(osc);
m_freq = freq; m_fine = fine;
m_volume = volume; m_volume = volume;
} }
@@ -21,26 +25,27 @@ void Oscillator::SetType(OscillatorType osc) {
m_osc = osc; m_osc = osc;
switch (m_osc) { switch (m_osc) {
case Sine: case Sine:
m_osc_function = &Oscillator::sineosc; m_osc_function = &Oscillator::SineOsc;
m_dt_function = &Oscillator::calc_sine_phase_delta; m_dt_function = &Oscillator::CalcSinePhaseDelta;
break; break;
case Triangle: case Triangle:
m_osc_function = &Oscillator::triangleosc; m_osc_function = &Oscillator::TriangleOsc;
m_dt_function = &Oscillator::calc_saw_phase_delta; m_dt_function = &Oscillator::CalcSawPhaseDelta;
break; break;
case Square: case Square:
m_osc_function = &Oscillator::squareosc; m_osc_function = &Oscillator::SquareOsc;
m_dt_function = &Oscillator::calc_sine_phase_delta; m_dt_function = &Oscillator::CalcSinePhaseDelta;
break; break;
case Saw: case Saw:
m_osc_function = &Oscillator::sawosc; m_osc_function = &Oscillator::SawOsc;
m_dt_function = &Oscillator::calc_saw_phase_delta; m_dt_function = &Oscillator::CalcSawPhaseDelta;
break; break;
} }
} }
void Oscillator::SetFreq(float freq) { void Oscillator::SetKey(float key) {
m_freq = freq; m_key = key;
float freq = KeyBoard::GetHzBySemitone(m_key + m_fine);
m_phase = 0; m_phase = 0;
m_phase_dt = (this->*m_dt_function)(freq); m_phase_dt = (this->*m_dt_function)(freq);
} }
@@ -49,44 +54,44 @@ float Oscillator::Process() {
return (this->*m_osc_function)() * m_volume; return (this->*m_osc_function)() * m_volume;
} }
void Oscillator::sine_osc_phase_incr() { void Oscillator::SineOscPhaseIncr() {
m_phase += m_phase_dt; m_phase += m_phase_dt;
if (m_phase >= TWO_PI) if (m_phase >= TWO_PI)
m_phase -= TWO_PI; m_phase -= TWO_PI;
} }
void Oscillator::saw_osc_phase_incr() { void Oscillator::SawOscPhaseIncr() {
m_phase += m_phase_dt; m_phase += m_phase_dt;
if (m_phase >= 1.0f) if (m_phase >= 1.0f)
m_phase -= 1.0f; m_phase -= 1.0f;
} }
float Oscillator::calc_saw_phase_delta(float freq) { float Oscillator::CalcSawPhaseDelta(float freq) {
return freq / SAMPLE_RATE; return freq / SAMPLE_RATE;
} }
float Oscillator::calc_sine_phase_delta(float freq) { float Oscillator::CalcSinePhaseDelta(float freq) {
return (TWO_PI * freq) / SAMPLE_RATE; return (TWO_PI * freq) / SAMPLE_RATE;
} }
float Oscillator::sineosc() { float Oscillator::SineOsc() {
float result = sinf(m_phase); float result = sinf(m_phase);
sine_osc_phase_incr(); SineOscPhaseIncr();
return result; return result;
} }
float Oscillator::sign(float v) { return (v > 0.0) ? 1.f : -1.f; } float Oscillator::Sign(float v) { return (v > 0.0) ? 1.f : -1.f; }
float Oscillator::squareosc() { return sign(sineosc()); } float Oscillator::SquareOsc() { return Sign(SineOsc()); }
float Oscillator::triangleosc() { float Oscillator::TriangleOsc() {
float result = 1.f - fabsf(m_phase - 0.5f) * 4.f; float result = 1.f - fabsf(m_phase - 0.5f) * 4.f;
saw_osc_phase_incr(); SawOscPhaseIncr();
return result; return result;
} }
float Oscillator::sawosc() { float Oscillator::SawOsc() {
float result = m_phase * 2.f - 1.f; float result = m_phase * 2.f - 1.f;
saw_osc_phase_incr(); SawOscPhaseIncr();
return result; return result;
} }

View File

@@ -89,7 +89,7 @@ float Renderer::draw_oscillators_panels(
// Draw Oscillator Panel // Draw Oscillator Panel
const int osc_panel_width = panel_bounds.width - 20; const int osc_panel_width = panel_bounds.width - 20;
const int osc_panel_height = has_shape_param ? 130 : 100; const int osc_panel_height = has_shape_param ? 150 : 120;
const int osc_panel_x = panel_bounds.x + 10; const int osc_panel_x = panel_bounds.x + 10;
const int osc_panel_y = panel_bounds.y + 50 + panel_y_offset; const int osc_panel_y = panel_bounds.y + 50 + panel_y_offset;
panel_y_offset += osc_panel_height + 5; panel_y_offset += osc_panel_height + 5;
@@ -112,13 +112,23 @@ float Renderer::draw_oscillators_panels(
decibels = decibels =
GuiSlider(el_rect, amp_slider_label, "", decibels, -60.0f, 0.0f); GuiSlider(el_rect, amp_slider_label, "", decibels, -60.0f, 0.0f);
ui_osc->volume = powf(10.f, decibels * (1.f / 20.f)); ui_osc->volume = powf(10.f, decibels * (1.f / 20.f));
osc->SetVolume(ui_osc->volume); el_rect.y += el_rect.height + el_spacing;
// Fine slider
float fine = osc->GetFine();
char fine_slider_label[10];
snprintf(fine_slider_label, 9, "%.3f u", fine);
fine = GuiSlider(el_rect, fine_slider_label, "", fine, -2.f, 2.f);
ui_osc->fine = fine;
el_rect.y += el_rect.height + el_spacing; el_rect.y += el_rect.height + el_spacing;
// Defer shape drop-down box. // Defer shape drop-down box.
ui_osc->shape_dropdown_rect = el_rect; ui_osc->shape_dropdown_rect = el_rect;
el_rect.y += el_rect.height + el_spacing; el_rect.y += el_rect.height + el_spacing;
// Apply values to real
osc->SetVolume(ui_osc->volume);
osc->SetFine(ui_osc->fine);
} }
return panel_y_offset; return panel_y_offset;
@@ -221,7 +231,7 @@ float Renderer::DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter,
gui_filter.freq = powf(10.f, freq); gui_filter.freq = powf(10.f, freq);
el_rect.y += el_rect.height + el_spacing; el_rect.y += el_rect.height + el_spacing;
//todo: implement that when Res will be fixed // todo: implement that when Res will be fixed
// Resonance slider // Resonance slider
// float res = gui_filter.res; // float res = gui_filter.res;
// char res_slider_label[32]; // char res_slider_label[32];
@@ -233,8 +243,8 @@ float Renderer::DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter,
// Shape select // Shape select
int shape_index = (int)(gui_filter.type); int shape_index = (int)(gui_filter.type);
bool is_dropdown_click = bool is_dropdown_click =
GuiDropdownBox(el_rect, FILTER_TYPE_OPTIONS, GuiDropdownBox(el_rect, FILTER_TYPE_OPTIONS, &shape_index,
&shape_index, gui_filter.is_dropdown_open); gui_filter.is_dropdown_open);
if (is_dropdown_click) { if (is_dropdown_click) {
write_log("Dropdown clicked!\n"); write_log("Dropdown clicked!\n");
@@ -247,7 +257,8 @@ float Renderer::DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter,
// apply values to real one // apply values to real one
// todo: thrid (order) parameter // todo: thrid (order) parameter
// todo: why resonance changing does not work? // todo: why resonance changing does not work?
filter->SetParameters(gui_filter.freq, filter->GetRes(), filter->GetPeakGain()); filter->SetParameters(gui_filter.freq, filter->GetRes(),
filter->GetPeakGain());
return panel_y_offset; return panel_y_offset;
} }

View File

@@ -4,18 +4,19 @@
#include "OscillatorType.h" #include "OscillatorType.h"
#include "Settings.h" #include "Settings.h"
#include "FilterFactory.h" #include "FilterFactory.h"
#include "LFO.h"
Synth::Synth(/* args */) { Synth::Synth(/* args */) {
m_lfo = new Oscillator(OscillatorType::Sine, 5.f, VOLUME); m_lfo = new LFO();
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,54 +25,53 @@ 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, 0.0f, VOLUME));
} }
void Synth::Trigger(Note input) { void Synth::Trigger(Note input) {
int semitone_shift = KeyBoard::GetSemitoneShift(input.name); int semitone_shift = KeyBoard::GetSemitoneShift(input.name);
float hz = KeyBoard::GetHzBySemitone(semitone_shift);
for (Oscillator* osc : m_oscillators) { for (Oscillator* osc : m_oscillators) {
osc->SetFreq(hz); osc->SetKey(semitone_shift);
} }
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();