diff --git a/Source/DSP/Filter.h b/Source/DSP/Filter.h index cc3ce4a..bbbb138 100644 --- a/Source/DSP/Filter.h +++ b/Source/DSP/Filter.h @@ -12,9 +12,12 @@ public: } void reset() { - for (int i = 0; i < 4; ++i) { + for (int i = 0; i < 4; ++i) stage[i] = 0.0f; - } + gCoeff = 0.0f; + gTarget = 0.0f; + kCoeff = 2.0f; + kTarget = 2.0f; } void setCoefficients(float cutoff, float res, FilterType type) { @@ -22,80 +25,42 @@ public: resonance = std::clamp(res, 0.0f, 1.0f); filterType = type; - float g = std::tan(static_cast(pi) * cutoff / static_cast(sampleRate)); - float k = 2.0f - 2.0f * resonance; - float a1 = 1.0f / (1.0f + g * (g + k)); - float a2 = g * a1; - - gCoeff = g; - kCoeff = k; - - m0 = 0.0f; - m1 = 0.0f; - m2 = 0.0f; - m3 = 0.0f; - - switch (filterType) { - case FilterType::LowPass12: - m0 = 0.0f; m1 = 0.0f; m2 = a2; m3 = 0.0f; - break; - case FilterType::LowPass24: - m0 = 0.0f; m1 = 0.0f; m2 = 0.0f; m3 = a2 * a2; - break; - case FilterType::BandPass: - m0 = 0.0f; m1 = a2; m2 = 0.0f; m3 = 0.0f; - break; - case FilterType::HighPass: - m0 = 1.0f; m1 = -a1; m2 = -a2; m3 = 0.0f; - break; - case FilterType::Notch: - m0 = 1.0f; m1 = -a1 * k; m2 = -a2; m3 = 0.0f; - break; - case FilterType::NumTypes: - break; - } + gTarget = std::tan(static_cast(pi) * cutoff / static_cast(sampleRate)); + kTarget = 2.0f - 2.0f * resonance; } float process(float input) { - float denom = 1.0f + kCoeff * gCoeff + gCoeff * gCoeff; - float hp = (input - (kCoeff + gCoeff) * stage[0] - stage[1]) / denom; - float bp = gCoeff * hp + stage[0]; - float lp = gCoeff * bp + stage[1]; + // Per-sample coefficient smoothing (one-pole, ~0.002 = ~44 samples to ~63%) + gCoeff += (gTarget - gCoeff) * 0.002f; + kCoeff += (kTarget - kCoeff) * 0.002f; - stage[0] = gCoeff * hp + bp; - stage[1] = gCoeff * bp + lp; + float g = gCoeff; + float k = kCoeff; + float denom = 1.0f + k * g + g * g; - float hp2 = (lp - (kCoeff + gCoeff) * stage[2] - stage[3]) / denom; - float bp2 = gCoeff * hp2 + stage[2]; - float lp2 = gCoeff * bp2 + stage[3]; + float hp = (input - (k + g) * stage[0] - stage[1]) / denom; + float bp = g * hp + stage[0]; + float lp = g * bp + stage[1]; - stage[2] = gCoeff * hp2 + bp2; - stage[3] = gCoeff * bp2 + lp2; + stage[0] = g * hp + bp; + stage[1] = g * bp + lp; - float output = 0.0f; + float hp2 = (lp - (k + g) * stage[2] - stage[3]) / denom; + float bp2 = g * hp2 + stage[2]; + float lp2 = g * bp2 + stage[3]; + + stage[2] = g * hp2 + bp2; + stage[3] = g * bp2 + lp2; switch (filterType) { - case FilterType::LowPass12: - output = lp; - break; - case FilterType::LowPass24: - output = lp2; - break; - case FilterType::BandPass: - output = bp; - break; - case FilterType::HighPass: - output = hp; - break; - case FilterType::Notch: - output = input - bp; - break; - case FilterType::NumTypes: - output = input; - break; + case FilterType::LowPass12: return lp; + case FilterType::LowPass24: return lp2; + case FilterType::BandPass: return bp; + case FilterType::HighPass: return hp; + case FilterType::Notch: return input - bp; + case FilterType::NumTypes: return input; } - - return output; + return lp; } private: @@ -103,8 +68,8 @@ private: double sampleRate = 44100.0; float stage[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - float gCoeff = 0.0f, kCoeff = 0.0f; - float m0 = 0.0f, m1 = 0.0f, m2 = 0.0f, m3 = 0.0f; + float gCoeff = 0.0f, gTarget = 0.0f; + float kCoeff = 2.0f, kTarget = 2.0f; float resonance = 0.0f; FilterType filterType = FilterType::LowPass12; };