diff --git a/plugin/chorus.cpp b/plugin/chorus.cpp index 1f6b779..9ec57f6 100644 --- a/plugin/chorus.cpp +++ b/plugin/chorus.cpp @@ -21,24 +21,21 @@ #include #include -#include - Chorus::Chorus() { lpfOut1 = new float[bufferSize]; lpfOut2 = new float[bufferSize]; - ram = new float[DELAYSIZE]; // probably needs to be calculated based on sample rate + ram = new float[DELAYSIZE]; - fastPhase = 0; + lfoPhase = 1; + lfoSpeed = 6.283 * 10.7 / sampleRate; // plainly silly value to show if it hasn't been set // not quite Butterworth but you'd never hear the difference + // these are calculated from the real-world component values postFilter1l = new SVF(9688, .549); postFilter2l = new SVF(10377, 1.291); postFilter1r = new SVF(9688, .549); postFilter2r = new SVF(10377, 1.291); - // lfo values taken from a rough simulation - fastOmega = 6.283 * 0.7 / sampleRate; // approximate, can be adjusted - // zero out the delay buffer memset(ram, 0, sizeof(float) * DELAYSIZE); memset(lpfOut1, 0, sizeof(float) * bufferSize); @@ -56,32 +53,33 @@ Chorus::~Chorus() { } void Chorus::run(float* input, float** outputs, uint32_t frames) { - // actual effects here + // run highpass / bass boost and stereo chorus effect for one full block - // FIXME add highpass filter - - // now run the DSP float s0 = 0, s1 = 0; float lfoMod, dly1, frac, flt; uint16_t tap, delay; for (uint32_t i = 0; i < frames; i++) { // run a step of LFO - fastPhase += fastOmega; - if (fastPhase > 6.283) fastPhase -= 6.283; + lfoPhase += (lfoState & 0x01) ? lfoSpeed : -lfoSpeed; - flt = ((hpdelay - input[i]) * hpcut) + input[i]; - hpdelay = flt; - input[i] += (flt * hpgain); + if (abs(lfoPhase) > 1) { + // lfoPhase -= 2; + lfoState++; + } + + // highpass/bass boost + flt = ((input[i] - hpDelay) * hpCut) + hpDelay; + hpDelay = flt; + input[i] += (flt * hpGain); ram[delayptr] = input[i]; +// delays in milliseconds #define BASE 0.005 #define AMT 0.00175 - // FIXME make this triangle not sine, and move arithmetic out of mainloop - lfoMod = sin(fastPhase); - dly1 = (BASE + (AMT * lfoMod)) * sampleRate; + dly1 = (BASE + (AMT * lfoPhase)) * sampleRate; delay = (int)dly1; frac = dly1 - delay; @@ -90,7 +88,7 @@ void Chorus::run(float* input, float** outputs, uint32_t frames) { s0 = ram[tap & 0x3ff]; lpfOut1[i] = ((s1 - s0) * frac) + s0; - dly1 = (BASE - (AMT * lfoMod)) * sampleRate; + dly1 = (BASE - (AMT * lfoPhase)) * sampleRate; delay = (int)dly1; frac = dly1 - delay; @@ -99,9 +97,6 @@ void Chorus::run(float* input, float** outputs, uint32_t frames) { s0 = ram[tap & 0x3ff]; lpfOut2[i] = ((s1 - s0) * frac) + s0; - // lpfOut1[i] = input[i] + 1.2 * out0; //(out0 + (out120 * 0.66) + (out240 * 0.33)); - // lpfOut2[i] = input[i] + 1.2 * out120; //(out0 + (out120 * 0.33) + (out240 * 0.66)); - delayptr++; delayptr &= 0x3ff; } @@ -119,22 +114,27 @@ void Chorus::run(float* input, float** outputs, uint32_t frames) { } void Chorus::setHpf(uint8_t mode) { + // the simple 1-pole lowpass has its output + // subtracted from input for the highpass + // or added for bass boost + // cutoff is calculated as + // k = 1-exp(-2pi * Fc * sampleRate) switch (mode) { case 0x00: - hpcut = 0.91245; - hpgain = -1; + hpCut = 1 - exp(-6.283 * 720 / sampleRate); + hpGain = -1; break; case 0x08: - hpcut = 0.97097; - hpgain = -1; + hpCut = 1 - exp(-6.283 * 225 / sampleRate); + hpGain = -1; break; case 0x10: - hpcut = 1; - hpgain = 0; + hpCut = 1; + hpGain = 0; break; case 0x18: - hpcut = 0.99088; - hpgain = 1; + hpCut = 1 - exp(-6.283 * 85 / sampleRate); + hpGain = 1.707; break; } } @@ -147,11 +147,11 @@ void Chorus::setChorus(uint8_t mode) { break; case 0x40: gain = 1.2; - fastOmega = 6.283 * 0.5 / sampleRate; - break; // approximate, can be adjusted + lfoSpeed = 6.283 * 0.5 / sampleRate; + break; case 0x00: gain = 1.2; - fastOmega = 6.283 * 0.9 / sampleRate; - break; // approximate, can be adjusted + lfoSpeed = 6.283 * 0.9 / sampleRate; + break; } } diff --git a/plugin/chorus.hpp b/plugin/chorus.hpp index 5596fc2..49748ad 100644 --- a/plugin/chorus.hpp +++ b/plugin/chorus.hpp @@ -38,16 +38,18 @@ class Chorus { void setChorus(uint8_t mode); private: - double fastPhase = 0, fastOmega = 0; + double lfoPhase = 0, lfoSpeed = 0; + uint8_t lfoState=0; float gain = 1.2; + uint16_t delayptr = 0; float* ram; float* lpfIn; float *lpfOut1, *lpfOut2; - float hpdelay=0, hpcut=0, hpgain=1; + float hpDelay=0, hpCut=0, hpGain=0; SVF *postFilter1l, *postFilter2l, *postFilter1r, *postFilter2r; };