chromaflock/Source/DSP/Filter.h

94 lines
3 KiB
C
Raw Permalink Normal View History

2026-07-13 20:57:38 +02:00
#pragma once
#include <cmath>
#include <algorithm>
enum class FilterType { LowPass12 = 0, LowPass24, BandPass, HighPass, Notch,
BandPass24, HighPass24, Notch24, LowPass48, NumTypes };
2026-07-13 20:57:38 +02:00
class Filter {
public:
void prepare(double sr) {
sampleRate = sr;
reset();
}
void reset() {
for (int i = 0; i < 8; ++i)
2026-07-13 20:57:38 +02:00
stage[i] = 0.0f;
gCoeff = 0.0f;
gTarget = 0.0f;
kCoeff = 2.0f;
kTarget = 2.0f;
2026-07-13 20:57:38 +02:00
}
void setCoefficients(float cutoff, float res, FilterType type) {
cutoff = std::clamp(cutoff, 20.0f, static_cast<float>(sampleRate * 0.49));
2026-07-13 20:57:38 +02:00
resonance = std::clamp(res, 0.0f, 1.0f);
filterType = type;
gTarget = std::tan(static_cast<float>(pi) * cutoff / static_cast<float>(sampleRate));
kTarget = 2.0f - 2.0f * resonance;
2026-07-13 20:57:38 +02:00
}
float process(float input) {
// Per-sample coefficient smoothing (one-pole, ~0.002 = ~44 samples to ~63%)
gCoeff += (gTarget - gCoeff) * 0.002f;
kCoeff += (kTarget - kCoeff) * 0.002f;
2026-07-13 20:57:38 +02:00
float g = gCoeff;
float k = kCoeff;
float denom = 1.0f + k * g + g * g;
2026-07-13 20:57:38 +02:00
float hp = (input - (k + g) * stage[0] - stage[1]) / denom;
float bp = g * hp + stage[0];
float lp = g * bp + stage[1];
2026-07-13 20:57:38 +02:00
stage[0] = g * hp + bp;
stage[1] = g * bp + lp;
2026-07-13 20:57:38 +02:00
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;
2026-07-13 20:57:38 +02:00
// Stage 3 (fed by the stage-2 lowpass) — 36 dB
float hp3 = (lp2 - (k + g) * stage[4] - stage[5]) / denom;
float bp3 = g * hp3 + stage[4];
float lp3 = g * bp3 + stage[5];
stage[4] = g * hp3 + bp3;
stage[5] = g * bp3 + lp3;
// Stage 4 (fed by the stage-3 lowpass) — 48 dB
float hp4 = (lp3 - (k + g) * stage[6] - stage[7]) / denom;
float bp4 = g * hp4 + stage[6];
float lp4 = g * bp4 + stage[7];
stage[6] = g * hp4 + bp4;
stage[7] = g * bp4 + lp4;
2026-07-13 20:57:38 +02:00
switch (filterType) {
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::BandPass24: return bp2;
case FilterType::HighPass24: return hp2;
case FilterType::Notch24: return input - bp2;
case FilterType::LowPass48: return lp4;
case FilterType::NumTypes: return input;
2026-07-13 20:57:38 +02:00
}
return lp;
2026-07-13 20:57:38 +02:00
}
private:
static constexpr float pi = 3.14159265358979323846f;
double sampleRate = 44100.0;
float stage[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
2026-07-13 20:57:38 +02:00
float gCoeff = 0.0f, gTarget = 0.0f;
float kCoeff = 2.0f, kTarget = 2.0f;
2026-07-13 20:57:38 +02:00
float resonance = 0.0f;
FilterType filterType = FilterType::LowPass12;
};