diff --git a/docs/StateVariableFilter.md b/docs/StateVariableFilter.md index 8cbb142..9a57aa4 100644 --- a/docs/StateVariableFilter.md +++ b/docs/StateVariableFilter.md @@ -49,4 +49,166 @@ for (i=0; i + class MoogFilter + { + public: + MoogFilter(); + ~MoogFilter() {}; + + T getSampleRate() const { return sampleRate; } + void setSampleRate(T fs) { sampleRate = fs; calc(); } + T getResonance() const { return resonance; } + void setResonance(T filterRezo) { resonance = filterRezo; calc(); } + T getCutoff() const { return cutoff; } + T getCutoffHz() const { return cutoff * sampleRate * 0.5; } + void setCutoff(T filterCutoff) { cutoff = filterCutoff; calc(); } + + void init(); + void calc(); + T process(T input); + // filter an input sample using normalized params + T filter(T input, T cutoff, T resonance); + + protected: + // cutoff and resonance [0 - 1] + T cutoff; + T resonance; + T sampleRate; + T fs; + T y1,y2,y3,y4; + T oldx; + T oldy1,oldy2,oldy3; + T x; + T r; + T p; + T k; + }; + + /** + * Construct Moog-filter. + */ + template + MoogFilter::MoogFilter() + : sampleRate(T(44100.0)) + , cutoff(T(1.0)) + , resonance(T(0.0)) + { + init(); + } + + /** + * Initialize filter buffers. + */ + template + void MoogFilter::init() + { + // initialize values + y1=y2=y3=y4=oldx=oldy1=oldy2=oldy3=T(0.0); + calc(); + } + + /** + * Calculate coefficients. + */ + template + void MoogFilter::calc() + { + // TODO: replace with your constant + const double kPi = 3.1415926535897931; + + // empirical tuning + p = cutoff * (T(1.8) - T(0.8) * cutoff); + // k = p + p - T(1.0); + // A much better tuning seems to be: + k = T(2.0) * sin(cutoff * kPi * T(0.5)) - T(1.0); + + T t1 = (T(1.0) - p) * T(1.386249); + T t2 = T(12.0) + t1 * t1; + r = resonance * (t2 + T(6.0) * t1) / (t2 - T(6.0) * t1); + }; + + /** + * Process single sample. + */ + template + T MoogFilter::process(T input) + { + // process input + x = input - r * y4; + + // four cascaded one-pole filters (bilinear transform) + y1 = x * p + oldx * p - k * y1; + y2 = y1 * p + oldy1 * p - k * y2; + y3 = y2 * p + oldy2 * p - k * y3; + y4 = y3 * p + oldy3 * p - k * y4; + + // clipper band limited sigmoid + y4 -= (y4 * y4 * y4) / T(6.0); + + oldx = x; oldy1 = y1; oldy2 = y2; oldy3 = y3; + + return y4; + } + + /** + * Filter single sample using specified params. + */ + template + T MoogFilter::filter(T input, T filterCutoff, T filterRezo) + { + // set params first + cutoff = filterCutoff; + resonance = filterRezo; + calc(); + + return process(input); + } +} ``` \ No newline at end of file