From 5cc3195db314f0ba8361db460d21e9ba7783511f Mon Sep 17 00:00:00 2001 From: Christian Colglazier Date: Sat, 13 Nov 2021 14:16:41 -0500 Subject: [PATCH] AD envelope with splitting --- src/droplets/ad_droplet.cpp | 140 +++++++++++++++++++-------------- src/droplets/ad_droplet.h | 15 +++- src/droplets/droplet.cpp | 5 ++ src/droplets/droplet.h | 16 +++- src/droplets/lfo_droplet.cpp | 2 + src/droplets/lfo_droplet.h | 5 ++ src/droplets/mixer_droplet.cpp | 2 + src/droplets/mixer_droplet.h | 5 ++ src/droplets/noise_droplet.cpp | 2 + src/droplets/noise_droplet.h | 5 ++ src/droplets/vca_droplet.cpp | 2 + src/droplets/vca_droplet.h | 5 ++ src/droplets/vco_droplet.cpp | 2 + src/droplets/vco_droplet.h | 6 ++ 14 files changed, 148 insertions(+), 64 deletions(-) diff --git a/src/droplets/ad_droplet.cpp b/src/droplets/ad_droplet.cpp index b3c766b..fe1b100 100644 --- a/src/droplets/ad_droplet.cpp +++ b/src/droplets/ad_droplet.cpp @@ -2,16 +2,15 @@ void AD::Init(DaisyPatch* m_patch, float sample_rate, - AnalogControl attack_knob, - AnalogControl decay_knob) { + DropletState* m_state) { patch = m_patch; + state = m_state; env.Init(sample_rate); env.SetMax(1.0f); env.SetMin(0.0f); env.SetCurve(0.0f); - attack_param.Init(attack_knob, .01f, 3.0f, Parameter::EXPONENTIAL); - decay_param.Init(decay_knob, .01f, 3.0f, Parameter::EXPONENTIAL); - curve_param.Init(attack_knob, -10.f, 10.0f, Parameter::LINEAR); + + SetControls(); } void AD::Process(DacHandle::Channel chn, @@ -19,19 +18,26 @@ void AD::Process(DacHandle::Channel chn, if(patch->gate_input[gate].Trig()) { env.Trigger(); } - if (curve_menu) { + if (*state == DropletState::kFull) { + attack = attack_param.Process(); + decay = decay_param.Process(); curve = curve_param.Process(); + amp = amp_param.Process(); + } else if (curve_menu) { + curve = curve_param.Process(); + amp = amp_param.Process(); } else { attack = attack_param.Process(); + decay = decay_param.Process(); } - decay = decay_param.Process(); + env.SetTime(ADENV_SEG_ATTACK, attack); env.SetTime(ADENV_SEG_DECAY, decay); env.SetCurve(curve); sig = env.Process(); patch->seed.dac.WriteValue(chn, - sig * 4095.0f); + sig * amp * 4095.0f); } float AD::GetSignal() { @@ -50,6 +56,10 @@ float AD::GetCurve() { return curve; } +float AD::GetAmp() { + return amp; +} + bool AD::GetMenu() { return curve_menu; } @@ -58,36 +68,51 @@ void AD::ToggleCurve() { curve_menu = !curve_menu; } -ADDroplet::ADDroplet(DaisyPatch* m_patch, - DropletState m_state, - float sample_rate) : - Droplet(m_patch, - m_state) { - switch (GetState()) { +void AD::SetControls() { + AnalogControl attack_knob, decay_knob, curve_knob, amp_knob; + + switch (*state) { default: case DropletState::kFull: - ad[0].Init(Patch(), - sample_rate, - Patch()->controls[Patch()->CTRL_1], - Patch()->controls[Patch()->CTRL_2]); - ad[1].Init(Patch(), - sample_rate, - Patch()->controls[Patch()->CTRL_3], - Patch()->controls[Patch()->CTRL_4]); + attack_knob = patch->controls[patch->CTRL_1]; + decay_knob = patch->controls[patch->CTRL_2]; + curve_knob = patch->controls[patch->CTRL_3]; + amp_knob = patch->controls[patch->CTRL_4]; break; case DropletState::kLeft: - ad[0].Init(Patch(), - sample_rate, - Patch()->controls[Patch()->CTRL_1], - Patch()->controls[Patch()->CTRL_2]); + attack_knob = patch->controls[patch->CTRL_1]; + decay_knob = patch->controls[patch->CTRL_2]; + curve_knob = patch->controls[patch->CTRL_1]; + amp_knob = patch->controls[patch->CTRL_2]; break; case DropletState::kRight: - ad[0].Init(Patch(), - sample_rate, - Patch()->controls[Patch()->CTRL_3], - Patch()->controls[Patch()->CTRL_4]); + attack_knob = patch->controls[patch->CTRL_3]; + decay_knob = patch->controls[patch->CTRL_4]; + curve_knob = patch->controls[patch->CTRL_3]; + amp_knob = patch->controls[patch->CTRL_4]; break; } + + attack_param.Init(attack_knob, .01f, 3.0f, Parameter::EXPONENTIAL); + decay_param.Init(decay_knob, .01f, 3.0f, Parameter::EXPONENTIAL); + curve_param.Init(curve_knob, -10.f, 10.0f, Parameter::LINEAR); + amp_param.Init(amp_knob, 0.0f, 1.0f, Parameter::LINEAR); +} + +ADDroplet::ADDroplet(DaisyPatch* m_patch, + DropletState m_state, + float m_sample_rate) : + Droplet(m_patch, + m_state) { + sample_rate = m_sample_rate; + ad[0].Init(Patch(), + sample_rate, + &m_state); + if (m_state == DropletState::kFull) { + ad[1].Init(Patch(), + sample_rate, + &m_state); + } } ADDroplet::~ADDroplet() {} @@ -105,7 +130,6 @@ void ADDroplet::Control() { void ADDroplet::Process(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size) { Patch()->ProcessAnalogControls(); - for(size_t i = 0; i < size; i++) { if (GetState() == DropletState::kRight) { ad[0].Process(DacHandle::Channel::TWO, DaisyPatch::GATE_IN_2); @@ -120,7 +144,8 @@ void ADDroplet::Process(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer o if(GetState() == DropletState::kFull && chn > 1) { env_sel = 1; } - out[chn][i] = in[chn][i] * ad[env_sel].GetSignal(); + out[chn][i] = in[chn][i] * ad[env_sel].GetSignal() * + ad[env_sel].GetAmp(); } } } @@ -146,36 +171,31 @@ void ADDroplet::Draw() { Font_6x8, "C: " + FloatToString(ad[0].GetCurve(), 2)); - if(GetState() == DropletState::kFull) { - int mid = (GetScreenMax() - GetScreenMin())/2; - WriteString(Patch(), - mid, - 11, - Font_6x8, - "A: " + - FloatToString(ad[1].GetAttack(), 2) + - "s"); - WriteString(Patch(), - mid, - 21, - Font_6x8, - "D: " + - FloatToString(ad[1].GetDecay(), 2) + - "s"); - WriteString(Patch(), - mid, - 31, - Font_6x8, - "C: " + - FloatToString(ad[1].GetCurve(), 2)); - } + WriteString(Patch(), + GetScreenMin()+3, + 41, + Font_6x8, + "Amp: " + + FloatToString(ad[0].GetAmp(), 2)); - if (ad[0].GetMenu()) { - DrawSolidRect(Patch(), GetScreenMin(), 30, GetScreenMin()+1, 39, true); - } else { - DrawSolidRect(Patch(), GetScreenMin(), 10, GetScreenMin()+1, 19, true); + if (GetState() != DropletState::kFull) { + if (ad[0].GetMenu()) { + DrawSolidRect(Patch(), GetScreenMin(), 30, GetScreenMin()+1, 49, true); + } else { + DrawSolidRect(Patch(), GetScreenMin(), 10, GetScreenMin()+1, 29, true); + } } - DrawSolidRect(Patch(), GetScreenMin(), 20, GetScreenMin()+1, 29, true); DrawName("AD"); } + +void ADDroplet::UpdateStateCallback() { + ad[0].Init(Patch(), + sample_rate, + State()); + if (GetState() == DropletState::kFull) { + ad[1].Init(Patch(), + sample_rate, + State()); + } +} diff --git a/src/droplets/ad_droplet.h b/src/droplets/ad_droplet.h index 62e2ae7..5eb1048 100644 --- a/src/droplets/ad_droplet.h +++ b/src/droplets/ad_droplet.h @@ -16,17 +16,20 @@ class AD { private: AdEnv env; float attack, decay, curve = 0; + float amp = 1.0f; Parameter attack_param; Parameter decay_param; Parameter curve_param; + Parameter amp_param; float sig; DaisyPatch* patch; bool curve_menu = false; + DropletState* state; + public: void Init(DaisyPatch* m_patch, float sample_rate, - AnalogControl attack_knob, - AnalogControl decay_knob); + DropletState* state); void Process(DacHandle::Channel chn, DaisyPatch::GateInput gate); @@ -34,13 +37,16 @@ public: float GetAttack(); float GetDecay(); float GetCurve(); + float GetAmp(); bool GetMenu(); void ToggleCurve(); + void SetControls(); }; class ADDroplet: public Droplet { private: AD ad[2]; + float sample_rate; public: /* @@ -78,6 +84,11 @@ public: * Processes information to be shown on the display. */ void Draw(); + + /* + * Runs when droplet state is updated. + */ + void UpdateStateCallback(); }; #endif // CASCADE_DROPLETS_AD_DROPLET_H_ diff --git a/src/droplets/droplet.cpp b/src/droplets/droplet.cpp index 011fb8a..7ef2f31 100644 --- a/src/droplets/droplet.cpp +++ b/src/droplets/droplet.cpp @@ -9,6 +9,10 @@ DaisyPatch* Droplet::Patch() { return patch; } +DropletState* Droplet::State() { + return &state; +} + DropletState Droplet::GetState() { return state; } @@ -51,6 +55,7 @@ void Droplet::UpdateState(DropletState m_state) { chn_min = 2; screen_min = SSD1309_WIDTH / 2; } + UpdateStateCallback(); } void Droplet::AnimationInc() { diff --git a/src/droplets/droplet.h b/src/droplets/droplet.h index 31db0a1..c74bfb2 100644 --- a/src/droplets/droplet.h +++ b/src/droplets/droplet.h @@ -47,7 +47,7 @@ public: /* * Processes audio input and outputs. - * +2 * * @param in the audio inputs for the patch * @param out the audio outputs for the patch * @param size the number of inputs and outputs @@ -62,12 +62,24 @@ public: virtual void Draw()=0; /* - * Returns patch + * Runs when droplet state is updated. + */ + virtual void UpdateStateCallback() {} + + /* + * Returns patch. * * @return pointer to patch */ DaisyPatch* Patch(); + /* + * Returns droplet state. + * + * @return pointer to state + */ + DropletState* State(); + /* * Returns the size of the droplet. * diff --git a/src/droplets/lfo_droplet.cpp b/src/droplets/lfo_droplet.cpp index c3c99f3..aa6ff8a 100644 --- a/src/droplets/lfo_droplet.cpp +++ b/src/droplets/lfo_droplet.cpp @@ -106,3 +106,5 @@ void LFODroplet::Draw() { } DrawName("LFO"); } + +void LFODroplet::UpdateStateCallback() {} diff --git a/src/droplets/lfo_droplet.h b/src/droplets/lfo_droplet.h index 48eb286..20d7504 100644 --- a/src/droplets/lfo_droplet.h +++ b/src/droplets/lfo_droplet.h @@ -77,6 +77,11 @@ public: * Processes information to be shown on the display. */ void Draw(); + + /* + * Runs when droplet state is updated. + */ + void UpdateStateCallback(); }; #endif // CASCADE_DROPLETS_LFO_DROPLET_H_ diff --git a/src/droplets/mixer_droplet.cpp b/src/droplets/mixer_droplet.cpp index 41a8159..9f9777b 100644 --- a/src/droplets/mixer_droplet.cpp +++ b/src/droplets/mixer_droplet.cpp @@ -58,3 +58,5 @@ void MixerDroplet::Process(AudioHandle::InputBuffer in, AudioHandle::OutputBuffe void MixerDroplet::Draw() { DrawName("Mixer"); } + +void MixerDroplet::UpdateStateCallback() {} diff --git a/src/droplets/mixer_droplet.h b/src/droplets/mixer_droplet.h index f68f9e5..c07b468 100644 --- a/src/droplets/mixer_droplet.h +++ b/src/droplets/mixer_droplet.h @@ -51,6 +51,11 @@ public: * Processes information to be shown on the display. */ void Draw(); + + /* + * Runs when droplet state is updated. + */ + void UpdateStateCallback(); }; #endif // CASCADE_DROPLETS_VCA_DROPLET_H_ diff --git a/src/droplets/noise_droplet.cpp b/src/droplets/noise_droplet.cpp index 7cff786..c0b64b6 100644 --- a/src/droplets/noise_droplet.cpp +++ b/src/droplets/noise_droplet.cpp @@ -26,3 +26,5 @@ void NoiseDroplet::Draw() { } DrawName("Noise"); } + +void NoiseDroplet::UpdateStateCallback() {} diff --git a/src/droplets/noise_droplet.h b/src/droplets/noise_droplet.h index 9c402cc..a862860 100644 --- a/src/droplets/noise_droplet.h +++ b/src/droplets/noise_droplet.h @@ -41,6 +41,11 @@ public: * Processes information to be shown on the display. */ void Draw(); + + /* + * Runs when droplet state is updated. + */ + void UpdateStateCallback(); }; #endif // CASCADE_DROPLETS_NOISE_DROPLET_H_ diff --git a/src/droplets/vca_droplet.cpp b/src/droplets/vca_droplet.cpp index 607d800..27088b1 100644 --- a/src/droplets/vca_droplet.cpp +++ b/src/droplets/vca_droplet.cpp @@ -109,3 +109,5 @@ void VCADroplet::Draw() { } DrawName("VCA"); } + +void VCADroplet::UpdateStateCallback() {} diff --git a/src/droplets/vca_droplet.h b/src/droplets/vca_droplet.h index a00ce64..83fa83d 100644 --- a/src/droplets/vca_droplet.h +++ b/src/droplets/vca_droplet.h @@ -51,6 +51,11 @@ public: * Processes information to be shown on the display. */ void Draw(); + + /* + * Runs when droplet state is updated. + */ + void UpdateStateCallback(); }; #endif // CASCADE_DROPLETS_VCA_DROPLET_H_ diff --git a/src/droplets/vco_droplet.cpp b/src/droplets/vco_droplet.cpp index 68489ba..e65dc88 100644 --- a/src/droplets/vco_droplet.cpp +++ b/src/droplets/vco_droplet.cpp @@ -144,3 +144,5 @@ void VCODroplet::SetWaveShape(int ws) { wave = ws % Oscillator::WAVE_LAST; last_wave_ctrl = ws; } + +void VCODroplet::UpdateStateCallback() {} diff --git a/src/droplets/vco_droplet.h b/src/droplets/vco_droplet.h index 77265d3..d0da12a 100644 --- a/src/droplets/vco_droplet.h +++ b/src/droplets/vco_droplet.h @@ -68,6 +68,12 @@ public: */ void Draw(); + + /* + * Runs when droplet state is updated. + */ + void UpdateStateCallback(); + /* * Changes the wave shape of the VCO. *