mirror of
https://codeberg.org/armin/chromaflock.git
synced 2026-09-01 04:10:47 +02:00
Smooth filter coefficient transitions to eliminate low-cutoff bump
This commit is contained in:
parent
4d8a746f69
commit
24579e313c
1 changed files with 33 additions and 68 deletions
|
|
@ -12,9 +12,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i)
|
||||||
stage[i] = 0.0f;
|
stage[i] = 0.0f;
|
||||||
}
|
gCoeff = 0.0f;
|
||||||
|
gTarget = 0.0f;
|
||||||
|
kCoeff = 2.0f;
|
||||||
|
kTarget = 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCoefficients(float cutoff, float res, FilterType type) {
|
void setCoefficients(float cutoff, float res, FilterType type) {
|
||||||
|
|
@ -22,80 +25,42 @@ public:
|
||||||
resonance = std::clamp(res, 0.0f, 1.0f);
|
resonance = std::clamp(res, 0.0f, 1.0f);
|
||||||
filterType = type;
|
filterType = type;
|
||||||
|
|
||||||
float g = std::tan(static_cast<float>(pi) * cutoff / static_cast<float>(sampleRate));
|
gTarget = std::tan(static_cast<float>(pi) * cutoff / static_cast<float>(sampleRate));
|
||||||
float k = 2.0f - 2.0f * resonance;
|
kTarget = 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float process(float input) {
|
float process(float input) {
|
||||||
float denom = 1.0f + kCoeff * gCoeff + gCoeff * gCoeff;
|
// Per-sample coefficient smoothing (one-pole, ~0.002 = ~44 samples to ~63%)
|
||||||
float hp = (input - (kCoeff + gCoeff) * stage[0] - stage[1]) / denom;
|
gCoeff += (gTarget - gCoeff) * 0.002f;
|
||||||
float bp = gCoeff * hp + stage[0];
|
kCoeff += (kTarget - kCoeff) * 0.002f;
|
||||||
float lp = gCoeff * bp + stage[1];
|
|
||||||
|
|
||||||
stage[0] = gCoeff * hp + bp;
|
float g = gCoeff;
|
||||||
stage[1] = gCoeff * bp + lp;
|
float k = kCoeff;
|
||||||
|
float denom = 1.0f + k * g + g * g;
|
||||||
|
|
||||||
float hp2 = (lp - (kCoeff + gCoeff) * stage[2] - stage[3]) / denom;
|
float hp = (input - (k + g) * stage[0] - stage[1]) / denom;
|
||||||
float bp2 = gCoeff * hp2 + stage[2];
|
float bp = g * hp + stage[0];
|
||||||
float lp2 = gCoeff * bp2 + stage[3];
|
float lp = g * bp + stage[1];
|
||||||
|
|
||||||
stage[2] = gCoeff * hp2 + bp2;
|
stage[0] = g * hp + bp;
|
||||||
stage[3] = gCoeff * bp2 + lp2;
|
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) {
|
switch (filterType) {
|
||||||
case FilterType::LowPass12:
|
case FilterType::LowPass12: return lp;
|
||||||
output = lp;
|
case FilterType::LowPass24: return lp2;
|
||||||
break;
|
case FilterType::BandPass: return bp;
|
||||||
case FilterType::LowPass24:
|
case FilterType::HighPass: return hp;
|
||||||
output = lp2;
|
case FilterType::Notch: return input - bp;
|
||||||
break;
|
case FilterType::NumTypes: return input;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return lp;
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -103,8 +68,8 @@ private:
|
||||||
double sampleRate = 44100.0;
|
double sampleRate = 44100.0;
|
||||||
float stage[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
float stage[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
float gCoeff = 0.0f, kCoeff = 0.0f;
|
float gCoeff = 0.0f, gTarget = 0.0f;
|
||||||
float m0 = 0.0f, m1 = 0.0f, m2 = 0.0f, m3 = 0.0f;
|
float kCoeff = 2.0f, kTarget = 2.0f;
|
||||||
float resonance = 0.0f;
|
float resonance = 0.0f;
|
||||||
FilterType filterType = FilterType::LowPass12;
|
FilterType filterType = FilterType::LowPass12;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue