AD envelope with splitting

This commit is contained in:
Christian Colglazier 2021-11-13 14:16:41 -05:00
parent 1ab75579c5
commit 5cc3195db3
14 changed files with 148 additions and 64 deletions

View File

@ -2,16 +2,15 @@
void AD::Init(DaisyPatch* m_patch, void AD::Init(DaisyPatch* m_patch,
float sample_rate, float sample_rate,
AnalogControl attack_knob, DropletState* m_state) {
AnalogControl decay_knob) {
patch = m_patch; patch = m_patch;
state = m_state;
env.Init(sample_rate); env.Init(sample_rate);
env.SetMax(1.0f); env.SetMax(1.0f);
env.SetMin(0.0f); env.SetMin(0.0f);
env.SetCurve(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); SetControls();
curve_param.Init(attack_knob, -10.f, 10.0f, Parameter::LINEAR);
} }
void AD::Process(DacHandle::Channel chn, void AD::Process(DacHandle::Channel chn,
@ -19,19 +18,26 @@ void AD::Process(DacHandle::Channel chn,
if(patch->gate_input[gate].Trig()) { if(patch->gate_input[gate].Trig()) {
env.Trigger(); env.Trigger();
} }
if (curve_menu) { if (*state == DropletState::kFull) {
attack = attack_param.Process();
decay = decay_param.Process();
curve = curve_param.Process(); curve = curve_param.Process();
amp = amp_param.Process();
} else if (curve_menu) {
curve = curve_param.Process();
amp = amp_param.Process();
} else { } else {
attack = attack_param.Process(); attack = attack_param.Process();
decay = decay_param.Process();
} }
decay = decay_param.Process();
env.SetTime(ADENV_SEG_ATTACK, attack); env.SetTime(ADENV_SEG_ATTACK, attack);
env.SetTime(ADENV_SEG_DECAY, decay); env.SetTime(ADENV_SEG_DECAY, decay);
env.SetCurve(curve); env.SetCurve(curve);
sig = env.Process(); sig = env.Process();
patch->seed.dac.WriteValue(chn, patch->seed.dac.WriteValue(chn,
sig * 4095.0f); sig * amp * 4095.0f);
} }
float AD::GetSignal() { float AD::GetSignal() {
@ -50,6 +56,10 @@ float AD::GetCurve() {
return curve; return curve;
} }
float AD::GetAmp() {
return amp;
}
bool AD::GetMenu() { bool AD::GetMenu() {
return curve_menu; return curve_menu;
} }
@ -58,36 +68,51 @@ void AD::ToggleCurve() {
curve_menu = !curve_menu; curve_menu = !curve_menu;
} }
ADDroplet::ADDroplet(DaisyPatch* m_patch, void AD::SetControls() {
DropletState m_state, AnalogControl attack_knob, decay_knob, curve_knob, amp_knob;
float sample_rate) :
Droplet(m_patch, switch (*state) {
m_state) {
switch (GetState()) {
default: default:
case DropletState::kFull: case DropletState::kFull:
ad[0].Init(Patch(), attack_knob = patch->controls[patch->CTRL_1];
sample_rate, decay_knob = patch->controls[patch->CTRL_2];
Patch()->controls[Patch()->CTRL_1], curve_knob = patch->controls[patch->CTRL_3];
Patch()->controls[Patch()->CTRL_2]); amp_knob = patch->controls[patch->CTRL_4];
ad[1].Init(Patch(),
sample_rate,
Patch()->controls[Patch()->CTRL_3],
Patch()->controls[Patch()->CTRL_4]);
break; break;
case DropletState::kLeft: case DropletState::kLeft:
ad[0].Init(Patch(), attack_knob = patch->controls[patch->CTRL_1];
sample_rate, decay_knob = patch->controls[patch->CTRL_2];
Patch()->controls[Patch()->CTRL_1], curve_knob = patch->controls[patch->CTRL_1];
Patch()->controls[Patch()->CTRL_2]); amp_knob = patch->controls[patch->CTRL_2];
break; break;
case DropletState::kRight: case DropletState::kRight:
ad[0].Init(Patch(), attack_knob = patch->controls[patch->CTRL_3];
sample_rate, decay_knob = patch->controls[patch->CTRL_4];
Patch()->controls[Patch()->CTRL_3], curve_knob = patch->controls[patch->CTRL_3];
Patch()->controls[Patch()->CTRL_4]); amp_knob = patch->controls[patch->CTRL_4];
break; 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() {} ADDroplet::~ADDroplet() {}
@ -105,7 +130,6 @@ void ADDroplet::Control() {
void ADDroplet::Process(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size) { void ADDroplet::Process(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size) {
Patch()->ProcessAnalogControls(); Patch()->ProcessAnalogControls();
for(size_t i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
if (GetState() == DropletState::kRight) { if (GetState() == DropletState::kRight) {
ad[0].Process(DacHandle::Channel::TWO, DaisyPatch::GATE_IN_2); 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) { if(GetState() == DropletState::kFull && chn > 1) {
env_sel = 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, Font_6x8,
"C: " + "C: " +
FloatToString(ad[0].GetCurve(), 2)); FloatToString(ad[0].GetCurve(), 2));
if(GetState() == DropletState::kFull) { WriteString(Patch(),
int mid = (GetScreenMax() - GetScreenMin())/2; GetScreenMin()+3,
WriteString(Patch(), 41,
mid, Font_6x8,
11, "Amp: " +
Font_6x8, FloatToString(ad[0].GetAmp(), 2));
"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));
}
if (ad[0].GetMenu()) { if (GetState() != DropletState::kFull) {
DrawSolidRect(Patch(), GetScreenMin(), 30, GetScreenMin()+1, 39, true); if (ad[0].GetMenu()) {
} else { DrawSolidRect(Patch(), GetScreenMin(), 30, GetScreenMin()+1, 49, true);
DrawSolidRect(Patch(), GetScreenMin(), 10, GetScreenMin()+1, 19, true); } else {
DrawSolidRect(Patch(), GetScreenMin(), 10, GetScreenMin()+1, 29, true);
}
} }
DrawSolidRect(Patch(), GetScreenMin(), 20, GetScreenMin()+1, 29, true);
DrawName("AD"); DrawName("AD");
} }
void ADDroplet::UpdateStateCallback() {
ad[0].Init(Patch(),
sample_rate,
State());
if (GetState() == DropletState::kFull) {
ad[1].Init(Patch(),
sample_rate,
State());
}
}

View File

@ -16,17 +16,20 @@ class AD {
private: private:
AdEnv env; AdEnv env;
float attack, decay, curve = 0; float attack, decay, curve = 0;
float amp = 1.0f;
Parameter attack_param; Parameter attack_param;
Parameter decay_param; Parameter decay_param;
Parameter curve_param; Parameter curve_param;
Parameter amp_param;
float sig; float sig;
DaisyPatch* patch; DaisyPatch* patch;
bool curve_menu = false; bool curve_menu = false;
DropletState* state;
public: public:
void Init(DaisyPatch* m_patch, void Init(DaisyPatch* m_patch,
float sample_rate, float sample_rate,
AnalogControl attack_knob, DropletState* state);
AnalogControl decay_knob);
void Process(DacHandle::Channel chn, DaisyPatch::GateInput gate); void Process(DacHandle::Channel chn, DaisyPatch::GateInput gate);
@ -34,13 +37,16 @@ public:
float GetAttack(); float GetAttack();
float GetDecay(); float GetDecay();
float GetCurve(); float GetCurve();
float GetAmp();
bool GetMenu(); bool GetMenu();
void ToggleCurve(); void ToggleCurve();
void SetControls();
}; };
class ADDroplet: public Droplet { class ADDroplet: public Droplet {
private: private:
AD ad[2]; AD ad[2];
float sample_rate;
public: public:
/* /*
@ -78,6 +84,11 @@ public:
* Processes information to be shown on the display. * Processes information to be shown on the display.
*/ */
void Draw(); void Draw();
/*
* Runs when droplet state is updated.
*/
void UpdateStateCallback();
}; };
#endif // CASCADE_DROPLETS_AD_DROPLET_H_ #endif // CASCADE_DROPLETS_AD_DROPLET_H_

View File

@ -9,6 +9,10 @@ DaisyPatch* Droplet::Patch() {
return patch; return patch;
} }
DropletState* Droplet::State() {
return &state;
}
DropletState Droplet::GetState() { DropletState Droplet::GetState() {
return state; return state;
} }
@ -51,6 +55,7 @@ void Droplet::UpdateState(DropletState m_state) {
chn_min = 2; chn_min = 2;
screen_min = SSD1309_WIDTH / 2; screen_min = SSD1309_WIDTH / 2;
} }
UpdateStateCallback();
} }
void Droplet::AnimationInc() { void Droplet::AnimationInc() {

View File

@ -47,7 +47,7 @@ public:
/* /*
* Processes audio input and outputs. * Processes audio input and outputs.
* 2 *
* @param in the audio inputs for the patch * @param in the audio inputs for the patch
* @param out the audio outputs for the patch * @param out the audio outputs for the patch
* @param size the number of inputs and outputs * @param size the number of inputs and outputs
@ -62,12 +62,24 @@ public:
virtual void Draw()=0; virtual void Draw()=0;
/* /*
* Returns patch * Runs when droplet state is updated.
*/
virtual void UpdateStateCallback() {}
/*
* Returns patch.
* *
* @return pointer to patch * @return pointer to patch
*/ */
DaisyPatch* Patch(); DaisyPatch* Patch();
/*
* Returns droplet state.
*
* @return pointer to state
*/
DropletState* State();
/* /*
* Returns the size of the droplet. * Returns the size of the droplet.
* *

View File

@ -106,3 +106,5 @@ void LFODroplet::Draw() {
} }
DrawName("LFO"); DrawName("LFO");
} }
void LFODroplet::UpdateStateCallback() {}

View File

@ -77,6 +77,11 @@ public:
* Processes information to be shown on the display. * Processes information to be shown on the display.
*/ */
void Draw(); void Draw();
/*
* Runs when droplet state is updated.
*/
void UpdateStateCallback();
}; };
#endif // CASCADE_DROPLETS_LFO_DROPLET_H_ #endif // CASCADE_DROPLETS_LFO_DROPLET_H_

View File

@ -58,3 +58,5 @@ void MixerDroplet::Process(AudioHandle::InputBuffer in, AudioHandle::OutputBuffe
void MixerDroplet::Draw() { void MixerDroplet::Draw() {
DrawName("Mixer"); DrawName("Mixer");
} }
void MixerDroplet::UpdateStateCallback() {}

View File

@ -51,6 +51,11 @@ public:
* Processes information to be shown on the display. * Processes information to be shown on the display.
*/ */
void Draw(); void Draw();
/*
* Runs when droplet state is updated.
*/
void UpdateStateCallback();
}; };
#endif // CASCADE_DROPLETS_VCA_DROPLET_H_ #endif // CASCADE_DROPLETS_VCA_DROPLET_H_

View File

@ -26,3 +26,5 @@ void NoiseDroplet::Draw() {
} }
DrawName("Noise"); DrawName("Noise");
} }
void NoiseDroplet::UpdateStateCallback() {}

View File

@ -41,6 +41,11 @@ public:
* Processes information to be shown on the display. * Processes information to be shown on the display.
*/ */
void Draw(); void Draw();
/*
* Runs when droplet state is updated.
*/
void UpdateStateCallback();
}; };
#endif // CASCADE_DROPLETS_NOISE_DROPLET_H_ #endif // CASCADE_DROPLETS_NOISE_DROPLET_H_

View File

@ -109,3 +109,5 @@ void VCADroplet::Draw() {
} }
DrawName("VCA"); DrawName("VCA");
} }
void VCADroplet::UpdateStateCallback() {}

View File

@ -51,6 +51,11 @@ public:
* Processes information to be shown on the display. * Processes information to be shown on the display.
*/ */
void Draw(); void Draw();
/*
* Runs when droplet state is updated.
*/
void UpdateStateCallback();
}; };
#endif // CASCADE_DROPLETS_VCA_DROPLET_H_ #endif // CASCADE_DROPLETS_VCA_DROPLET_H_

View File

@ -144,3 +144,5 @@ void VCODroplet::SetWaveShape(int ws) {
wave = ws % Oscillator::WAVE_LAST; wave = ws % Oscillator::WAVE_LAST;
last_wave_ctrl = ws; last_wave_ctrl = ws;
} }
void VCODroplet::UpdateStateCallback() {}

View File

@ -68,6 +68,12 @@ public:
*/ */
void Draw(); void Draw();
/*
* Runs when droplet state is updated.
*/
void UpdateStateCallback();
/* /*
* Changes the wave shape of the VCO. * Changes the wave shape of the VCO.
* *