zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 030f749f5f6cb6570165039015d483c47454c18e
parent 21bb18780c6d149e53ca50ea21423e2349341571
Author: Friedolino <mkirchn@freenet.de>
Date:   Sat, 14 Sep 2019 23:11:11 +0200

Optional LP filter for RND and SQR LFO (127=off)

Diffstat:
Msrc/Params/LFOParams.cpp | 25+++++++++++++++++--------
Msrc/Params/LFOParams.h | 3+++
Msrc/Synth/LFO.cpp | 37+++++++++++++++++++++++++++++++++----
Msrc/Synth/LFO.h | 11+++++++++++
Msrc/UI/LFOUI.fl | 11+++++++++--
5 files changed, 73 insertions(+), 14 deletions(-)

diff --git a/src/Params/LFOParams.cpp b/src/Params/LFOParams.cpp @@ -68,6 +68,8 @@ static const rtosc::Ports _ports = { rParamZyn(Pstartphase, rShort("start"), rSpecial(random), rDefaultDepends(loc), rDefault(64), rPreset(ad_voice_freq, 0), "Starting Phase"), + rParamZyn(Pcutoff, rShort("lp"), rDefault(127), + "RND/SQR lp-filter freq"), rOption(PLFOtype, rShort("type"), rOptions(sine, triangle, square, up, down, exp1, exp2, random), rDefault(sine), "Shape of LFO"), rParamZyn(Prandomness, rShort("a.r."), rSpecial(disable), rDefault(0), @@ -143,13 +145,14 @@ void LFOParams::setup() // TODO: reuse LFOParams::LFOParams(const AbsTime *time_) : - LFOParams(2.65, 0, 0, 0, 0, 0, 0, loc_unspecified, time_) + LFOParams(2.65, 0, 0, 127, 0, 0, 0, 0, loc_unspecified, time_) { } LFOParams::LFOParams(float freq_, char Pintensity_, char Pstartphase_, + char Pcutoff_, char PLFOtype_, char Prandomness_, float Pdelay_, @@ -161,6 +164,7 @@ LFOParams::LFOParams(float freq_, Dfreq = freq_; Dintensity = Pintensity_; Dstartphase = Pstartphase_; + Dcutoff = Pcutoff_; DLFOtype = PLFOtype_; Drandomness = Prandomness_; Ddelay = Pdelay_; @@ -175,12 +179,13 @@ LFOParams::LFOParams(consumer_location_t loc, last_update_timestamp(0) { auto init = - [&](float freq_, char Pintensity_, char Pstartphase_, char PLFOtype_, + [&](float freq_, char Pintensity_, char Pstartphase_, char Pcutoff_, char PLFOtype_, char Prandomness_, float delay_, char Pcontinous_) { Dfreq = freq_; Dintensity = Pintensity_; Dstartphase = Pstartphase_; + Dcutoff = Pcutoff_; DLFOtype = PLFOtype_; Drandomness = Prandomness_; Ddelay = delay_; @@ -189,12 +194,12 @@ LFOParams::LFOParams(consumer_location_t loc, switch(loc) { - case ad_global_amp: init(6.49, 0, 64, 0, 0, 0, 0); break; - case ad_global_freq: init(3.71, 0, 64, 0, 0, 0, 0); break; - case ad_global_filter: init(6.49, 0, 64, 0, 0, 0, 0); break; - case ad_voice_amp: init(11.25, 32, 64, 0, 0, 0.94, 0); break; - case ad_voice_freq: init(1.19, 40, 0, 0, 0, 0, 0); break; - case ad_voice_filter: init(1.19, 20, 64, 0, 0, 0, 0); break; + case ad_global_amp: init(6.49, 0, 64, 127, 0, 0, 0, 0); break; + case ad_global_freq: init(3.71, 0, 64, 127, 0, 0, 0, 0); break; + case ad_global_filter: init(6.49, 0, 64, 127, 0, 0, 0, 0); break; + case ad_voice_amp: init(11.25, 32, 64, 127, 0, 0, 0.94, 0); break; + case ad_voice_freq: init(1.19, 40, 0, 127, 0, 0, 0, 0); break; + case ad_voice_filter: init(1.19, 20, 64, 127, 0, 0, 0, 0); break; default: throw std::logic_error("Invalid LFO consumer location"); } @@ -209,6 +214,7 @@ void LFOParams::defaults() freq = Dfreq; Pintensity = Dintensity; Pstartphase = Dstartphase; + Pcutoff = Dcutoff; PLFOtype = DLFOtype; Prandomness = Drandomness; delay = Ddelay; @@ -223,6 +229,7 @@ void LFOParams::add2XML(XMLwrapper& xml) xml.addparreal("freq", freq); xml.addpar("intensity", Pintensity); xml.addpar("start_phase", Pstartphase); + xml.addpar("cutoff", Pcutoff); xml.addpar("lfo_type", PLFOtype); xml.addpar("randomness_amplitude", Prandomness); xml.addpar("randomness_frequency", Pfreqrand); @@ -240,6 +247,7 @@ void LFOParams::getfromXML(XMLwrapper& xml) } Pintensity = xml.getpar127("intensity", Pintensity); Pstartphase = xml.getpar127("start_phase", Pstartphase); + Pcutoff = xml.getpar127("cutoff", Pcutoff); PLFOtype = xml.getpar127("lfo_type", PLFOtype); Prandomness = xml.getpar127("randomness_amplitude", Prandomness); Pfreqrand = xml.getpar127("randomness_frequency", Pfreqrand); @@ -259,6 +267,7 @@ void LFOParams::paste(LFOParams &x) COPY(freq); COPY(Pintensity); COPY(Pstartphase); + COPY(Pcutoff); COPY(PLFOtype); COPY(Prandomness); COPY(Pfreqrand); diff --git a/src/Params/LFOParams.h b/src/Params/LFOParams.h @@ -40,6 +40,7 @@ class LFOParams:public Presets LFOParams(float freq_, char Pintensity_, char Pstartphase_, + char Pcutoff_, char PLFOtype_, char Prandomness_, float delay_, @@ -58,6 +59,7 @@ class LFOParams:public Presets float freq; /**<frequency*/ unsigned char Pintensity; /**<intensity*/ unsigned char Pstartphase; /**<start phase (0=random)*/ + unsigned char Pcutoff; /**<cutoff */ unsigned char PLFOtype; /**<LFO type (sin,triangle,square,ramp,...)*/ unsigned char Prandomness; /**<randomness (0=off)*/ unsigned char Pfreqrand; /**<frequency randomness (0=off)*/ @@ -81,6 +83,7 @@ class LFOParams:public Presets float Dfreq; unsigned char Dintensity; unsigned char Dstartphase; + unsigned char Dcutoff; unsigned char DLFOtype; unsigned char Drandomness; float Ddelay; diff --git a/src/Synth/LFO.cpp b/src/Synth/LFO.cpp @@ -79,6 +79,8 @@ LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t, WatchManage incrnd = nextincrnd = 1.0f; computeNextFreqRnd(); computeNextFreqRnd(); //twice because I want incrnd & nextincrnd to be random + z1 = 0.0; + z2 = 0.0; } LFO::~LFO() @@ -86,6 +88,7 @@ LFO::~LFO() float LFO::baseOut(const char waveShape, const float phase) { + float lfo_out; switch(waveShape) { case LFO_TRIANGLE: if(phase >= 0.0f && phase < 0.25f) @@ -97,9 +100,11 @@ float LFO::baseOut(const char waveShape, const float phase) break; case LFO_SQUARE: if(phase < 0.5f) - return -1; + lfo_out = -1; else - return 1; + lfo_out = 1; + + return biquad(lfo_out); break; case LFO_RAMPUP: return (phase - 0.5f) * 2.0f; case LFO_RAMPDOWN: return (0.5f - phase) * 2.0f; @@ -110,12 +115,36 @@ float LFO::baseOut(const char waveShape, const float phase) first_half = phase < 0.5; last_random = 2*RND-1; } - return last_random; - default: return cosf(phase * 2.0f * PI); //LFO_SINE + + + return biquad(last_random); + break; + default: + return cosf(phase * 2.0f * PI); //LFO_SINE } } +float LFO::biquad(float input) +{ + float output; + // calculate biquad coefficients + Fc = powf(lfopars_.Pcutoff + 7.0f, 2.0f)/127.0f; + K = tan(PI * Fc * dt_); + norm = 1 / (1 + K / 0.7071f + K * K); + a0 = K * K * norm; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / 0.7071f + K * K) * norm; + // lp filter the (s&h) random LFO + output = input * a0 + z1; + z1 = input * a1 + z2 - b1 * output; + z2 = input * a2 - b2 * output; + return (lfopars_.Pcutoff==127) ? input : output; +} + + float LFO::lfoout() { //update internals XXX TODO cleanup diff --git a/src/Synth/LFO.h b/src/Synth/LFO.h @@ -37,6 +37,7 @@ class LFO float amplfoout(); private: float baseOut(const char waveShape, const float phase); + float biquad(float input); //Phase of Oscillator float phase; //Phase Increment Per Frame @@ -49,6 +50,7 @@ class LFO // RND mode int first_half; float last_random; + float z1, z2, noisy_out; //Intensity of the wave float lfointensity; @@ -66,6 +68,15 @@ class LFO const float dt_; const LFOParams &lfopars_; const float basefreq_; + + float Fc, K, norm; + + //biquad coefficients for lp filtering in noise-LFO + float a0 = 0.0007508914611009499; + float a1 = 0.0015017829222018998; + float a2 = 0.0007508914611009499; + float b1 = -1.519121359805288; + float b2 = 0.5221249256496917; VecWatchPoint watchOut; diff --git a/src/UI/LFOUI.fl b/src/UI/LFOUI.fl @@ -79,15 +79,21 @@ hide();} {} code0 {o->init("Pintensity");} class Fl_Osc_Dial } + Fl_Dial cutoff { + label LP + tooltip {LP cutoff} xywh {70 30 20 20} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 + code0 {o->init("Pcutoff");} + class Fl_Osc_Dial + } Fl_Dial delay { label Delay - tooltip {LFO delay} xywh {110 20 30 30} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 + tooltip {LFO delay} xywh {120 30 20 20} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 code0 {o->init("Pdelay");} class Fl_Osc_Dial } Fl_Dial startphase { label Start - tooltip {LFO Startphase (leftmost is Random)} xywh {75 20 30 30} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 + tooltip {LFO Startphase (leftmost is Random)} xywh {95 20 20 20} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 code0 {o->init("Pstartphase");} class Fl_Osc_Dial } @@ -172,6 +178,7 @@ hide();} {} code {freq->update(); intensity->update(); startphase->update(); +cutoff->update(); delay->update(); continous->update(); stretch->update();