20
src/ADSR.cpp
20
src/ADSR.cpp
@@ -12,33 +12,33 @@ ADSR::ADSR(/* args */) {
|
||||
|
||||
ADSR::~ADSR() { delete m_ramp; }
|
||||
|
||||
bool ADSR::is_attack_elapsed() {
|
||||
bool ADSR::IsAttackElapsed() {
|
||||
return m_state == sAttack && m_ramp->IsCompleted();
|
||||
}
|
||||
|
||||
bool ADSR::is_decay_elapsed() {
|
||||
bool ADSR::IsDecayElapsed() {
|
||||
return m_state == sDecay && m_ramp->IsCompleted();
|
||||
}
|
||||
|
||||
bool ADSR::is_release_elapsed() {
|
||||
bool ADSR::IsReleaseElapsed() {
|
||||
return m_state == sRelease && m_ramp->IsCompleted();
|
||||
}
|
||||
|
||||
void ADSR::recheck_state() {
|
||||
void ADSR::RecheckState() {
|
||||
switch (m_state) {
|
||||
case sAttack:
|
||||
if (is_attack_elapsed()) {
|
||||
if (IsAttackElapsed()) {
|
||||
m_state = sDecay;
|
||||
m_ramp->RampTo(m_sustain_level, m_decay_time);
|
||||
}
|
||||
break;
|
||||
case sDecay:
|
||||
if (is_decay_elapsed()) {
|
||||
if (IsDecayElapsed()) {
|
||||
m_state = sSustain;
|
||||
}
|
||||
break;
|
||||
case sRelease:
|
||||
if (is_release_elapsed()) {
|
||||
if (IsReleaseElapsed()) {
|
||||
m_state = sOff;
|
||||
}
|
||||
break;
|
||||
@@ -47,7 +47,7 @@ void ADSR::recheck_state() {
|
||||
}
|
||||
}
|
||||
|
||||
void ADSR::process_sample(float* sample) {
|
||||
void ADSR::ProcessSample(float* sample) {
|
||||
if (m_state == sOff) {
|
||||
(*sample) = 0;
|
||||
} else if (m_state == sAttack) {
|
||||
@@ -80,8 +80,8 @@ void ADSR::Release() {
|
||||
|
||||
void ADSR::Process(std::vector<float>& samples) {
|
||||
for (std::size_t i = 0; i < samples.size(); i++) {
|
||||
recheck_state();
|
||||
process_sample(&samples[i]);
|
||||
RecheckState();
|
||||
ProcessSample(&samples[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ void Application::InitSynth() {
|
||||
assert(osc);
|
||||
|
||||
OscillatorGuiState* ui =
|
||||
new OscillatorGuiState{.freq = osc->GetFreq(),
|
||||
new OscillatorGuiState{.fine = osc->GetFine(),
|
||||
.waveshape = osc->GetType(),
|
||||
.volume = osc->GetVolume()};
|
||||
m_synth_gui_state.oscillators.push_back(ui);
|
||||
@@ -94,7 +94,7 @@ void Application::UpdateOnNoteInput() {
|
||||
if (!m_synth.GetIsNoteTriggered()) {
|
||||
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()) {
|
||||
m_synth.Release();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#include "Oscillator.h"
|
||||
#include "Settings.h"
|
||||
#include "KeyBoard.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#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);
|
||||
m_freq = freq;
|
||||
m_fine = fine;
|
||||
m_volume = volume;
|
||||
}
|
||||
|
||||
@@ -21,26 +25,27 @@ void Oscillator::SetType(OscillatorType osc) {
|
||||
m_osc = osc;
|
||||
switch (m_osc) {
|
||||
case Sine:
|
||||
m_osc_function = &Oscillator::sineosc;
|
||||
m_dt_function = &Oscillator::calc_sine_phase_delta;
|
||||
m_osc_function = &Oscillator::SineOsc;
|
||||
m_dt_function = &Oscillator::CalcSinePhaseDelta;
|
||||
break;
|
||||
case Triangle:
|
||||
m_osc_function = &Oscillator::triangleosc;
|
||||
m_dt_function = &Oscillator::calc_saw_phase_delta;
|
||||
m_osc_function = &Oscillator::TriangleOsc;
|
||||
m_dt_function = &Oscillator::CalcSawPhaseDelta;
|
||||
break;
|
||||
case Square:
|
||||
m_osc_function = &Oscillator::squareosc;
|
||||
m_dt_function = &Oscillator::calc_sine_phase_delta;
|
||||
m_osc_function = &Oscillator::SquareOsc;
|
||||
m_dt_function = &Oscillator::CalcSinePhaseDelta;
|
||||
break;
|
||||
case Saw:
|
||||
m_osc_function = &Oscillator::sawosc;
|
||||
m_dt_function = &Oscillator::calc_saw_phase_delta;
|
||||
m_osc_function = &Oscillator::SawOsc;
|
||||
m_dt_function = &Oscillator::CalcSawPhaseDelta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Oscillator::SetFreq(float freq) {
|
||||
m_freq = freq;
|
||||
void Oscillator::SetKey(float key) {
|
||||
m_key = key;
|
||||
float freq = KeyBoard::GetHzBySemitone(m_key + m_fine);
|
||||
m_phase = 0;
|
||||
m_phase_dt = (this->*m_dt_function)(freq);
|
||||
}
|
||||
@@ -49,44 +54,44 @@ float Oscillator::Process() {
|
||||
return (this->*m_osc_function)() * m_volume;
|
||||
}
|
||||
|
||||
void Oscillator::sine_osc_phase_incr() {
|
||||
void Oscillator::SineOscPhaseIncr() {
|
||||
m_phase += m_phase_dt;
|
||||
if (m_phase >= TWO_PI)
|
||||
m_phase -= TWO_PI;
|
||||
}
|
||||
|
||||
void Oscillator::saw_osc_phase_incr() {
|
||||
void Oscillator::SawOscPhaseIncr() {
|
||||
m_phase += m_phase_dt;
|
||||
if (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;
|
||||
}
|
||||
|
||||
float Oscillator::calc_sine_phase_delta(float freq) {
|
||||
float Oscillator::CalcSinePhaseDelta(float freq) {
|
||||
return (TWO_PI * freq) / SAMPLE_RATE;
|
||||
}
|
||||
|
||||
float Oscillator::sineosc() {
|
||||
float Oscillator::SineOsc() {
|
||||
float result = sinf(m_phase);
|
||||
sine_osc_phase_incr();
|
||||
SineOscPhaseIncr();
|
||||
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;
|
||||
saw_osc_phase_incr();
|
||||
SawOscPhaseIncr();
|
||||
return result;
|
||||
}
|
||||
|
||||
float Oscillator::sawosc() {
|
||||
float Oscillator::SawOsc() {
|
||||
float result = m_phase * 2.f - 1.f;
|
||||
saw_osc_phase_incr();
|
||||
SawOscPhaseIncr();
|
||||
return result;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ float Renderer::draw_oscillators_panels(
|
||||
|
||||
// Draw Oscillator Panel
|
||||
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_y = panel_bounds.y + 50 + panel_y_offset;
|
||||
panel_y_offset += osc_panel_height + 5;
|
||||
@@ -112,13 +112,23 @@ float Renderer::draw_oscillators_panels(
|
||||
decibels =
|
||||
GuiSlider(el_rect, amp_slider_label, "", decibels, -60.0f, 0.0f);
|
||||
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;
|
||||
|
||||
// Defer shape drop-down box.
|
||||
ui_osc->shape_dropdown_rect = el_rect;
|
||||
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;
|
||||
@@ -191,7 +201,7 @@ void Renderer::draw_second_panel(Rectangle& bounds) {
|
||||
}
|
||||
|
||||
float Renderer::DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter,
|
||||
const Rectangle& panel_bounds) {
|
||||
const Rectangle& panel_bounds) {
|
||||
#define FILTER_TYPE_OPTIONS "LP;BP;HP"
|
||||
Filter* filter = synth.GetFilter();
|
||||
float panel_y_offset = 0;
|
||||
@@ -221,20 +231,20 @@ float Renderer::DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter,
|
||||
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;
|
||||
// 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);
|
||||
GuiDropdownBox(el_rect, FILTER_TYPE_OPTIONS, &shape_index,
|
||||
gui_filter.is_dropdown_open);
|
||||
|
||||
if (is_dropdown_click) {
|
||||
write_log("Dropdown clicked!\n");
|
||||
@@ -247,7 +257,8 @@ float Renderer::DrawFilterPanel(Synth& synth, FilterGuiState& gui_filter,
|
||||
// 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());
|
||||
filter->SetParameters(gui_filter.freq, filter->GetRes(),
|
||||
filter->GetPeakGain());
|
||||
|
||||
return panel_y_offset;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
#include "OscillatorType.h"
|
||||
#include "Settings.h"
|
||||
#include "FilterFactory.h"
|
||||
#include "LFO.h"
|
||||
|
||||
Synth::Synth(/* args */) {
|
||||
m_lfo = new Oscillator(OscillatorType::Sine, 5.f, VOLUME);
|
||||
add_oscillator();
|
||||
add_oscillator();
|
||||
m_lfo = new LFO();
|
||||
AddOscillator();
|
||||
AddOscillator();
|
||||
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);
|
||||
}
|
||||
zero_signal();
|
||||
ZeroSignal();
|
||||
}
|
||||
|
||||
Synth::~Synth() {
|
||||
@@ -24,54 +25,53 @@ Synth::~Synth() {
|
||||
m_out_signal.clear();
|
||||
}
|
||||
|
||||
void Synth::zero_signal() {
|
||||
void Synth::ZeroSignal() {
|
||||
float sample = 0.0f;
|
||||
for (size_t i = 0; i < STREAM_BUFFER_SIZE; i++) {
|
||||
m_out_signal[i] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::get_note() {
|
||||
zero_signal();
|
||||
void Synth::GetNote() {
|
||||
ZeroSignal();
|
||||
Adder::SumOscillators(m_oscillators, m_out_signal);
|
||||
}
|
||||
|
||||
void Synth::apply_effects() {
|
||||
for (Effect* effect : m_effects) {
|
||||
void Synth::ApplyEffects() {
|
||||
for (IEffect* effect : m_effects) {
|
||||
effect->Process(m_out_signal);
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::trigger_note_on_effects() {
|
||||
for (Effect* effect : m_effects) {
|
||||
void Synth::TriggerNoteOnEffects() {
|
||||
for (IEffect* effect : m_effects) {
|
||||
effect->Trigger();
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::untrigger_note_on_effects() {
|
||||
for (Effect* effect : m_effects) {
|
||||
void Synth::UntriggerNoteOnEffects() {
|
||||
for (IEffect* effect : m_effects) {
|
||||
effect->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::add_oscillator() {
|
||||
void Synth::AddOscillator() {
|
||||
m_oscillators.push_back(
|
||||
new Oscillator(OscillatorType::Sine, 440.f, VOLUME));
|
||||
new Oscillator(OscillatorType::Sine, 0.0f, VOLUME));
|
||||
}
|
||||
|
||||
void Synth::Trigger(Note input) {
|
||||
int semitone_shift = KeyBoard::GetSemitoneShift(input.name);
|
||||
float hz = KeyBoard::GetHzBySemitone(semitone_shift);
|
||||
|
||||
for (Oscillator* osc : m_oscillators) {
|
||||
osc->SetFreq(hz);
|
||||
osc->SetKey(semitone_shift);
|
||||
}
|
||||
is_note_triggered = true;
|
||||
trigger_note_on_effects();
|
||||
TriggerNoteOnEffects();
|
||||
}
|
||||
|
||||
// todo: fix this
|
||||
void Synth::apply_filter_lfo() {
|
||||
void Synth::ApplyFilterLfo() {
|
||||
float dt = m_lfo->Process();
|
||||
Filter* filter = (Filter*)m_effects[1];
|
||||
float freq = filter->GetFreq();
|
||||
@@ -82,18 +82,18 @@ void Synth::apply_filter_lfo() {
|
||||
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();
|
||||
//ApplyFilterLfo();
|
||||
GetNote();
|
||||
ApplyEffects();
|
||||
}
|
||||
|
||||
void Synth::Release() {
|
||||
zero_signal();
|
||||
ZeroSignal();
|
||||
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) {
|
||||
Filter* old_filter = this->GetFilter();
|
||||
|
||||
Reference in New Issue
Block a user