#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FilterType {
LowPass,
HighPass,
BandPass,
Notch,
Peaking,
LowShelf,
HighShelf,
}
#[derive(Debug, Clone, Copy)]
pub struct Biquad {
b0: f32,
b1: f32,
b2: f32,
a1: f32,
a2: f32,
s1: f32,
s2: f32,
}
impl Default for Biquad {
fn default() -> Self {
Self {
b0: 1.0,
b1: 0.0,
b2: 0.0,
a1: 0.0,
a2: 0.0,
s1: 0.0,
s2: 0.0,
}
}
}
impl Biquad {
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
self.s1 = 0.0;
self.s2 = 0.0;
}
pub fn configure(
&mut self,
filter_type: FilterType,
freq_hz: f32,
q: f32,
gain_db: f32,
sample_rate: f32,
) {
let f0 = freq_hz.clamp(10.0, sample_rate * 0.499);
let q = q.max(0.01);
let w0 = 2.0 * std::f32::consts::PI * f0 / sample_rate;
let cos_w0 = w0.cos();
let sin_w0 = w0.sin();
let alpha = sin_w0 / (2.0 * q);
let a = 10.0f32.powf(gain_db / 40.0);
let (b0, b1, b2, a0, a1, a2) = match filter_type {
FilterType::LowPass => (
(1.0 - cos_w0) * 0.5,
1.0 - cos_w0,
(1.0 - cos_w0) * 0.5,
1.0 + alpha,
-2.0 * cos_w0,
1.0 - alpha,
),
FilterType::HighPass => (
(1.0 + cos_w0) * 0.5,
-(1.0 + cos_w0),
(1.0 + cos_w0) * 0.5,
1.0 + alpha,
-2.0 * cos_w0,
1.0 - alpha,
),
FilterType::BandPass => (alpha, 0.0, -alpha, 1.0 + alpha, -2.0 * cos_w0, 1.0 - alpha),
FilterType::Notch => (
1.0,
-2.0 * cos_w0,
1.0,
1.0 + alpha,
-2.0 * cos_w0,
1.0 - alpha,
),
FilterType::Peaking => (
1.0 + alpha * a,
-2.0 * cos_w0,
1.0 - alpha * a,
1.0 + alpha / a,
-2.0 * cos_w0,
1.0 - alpha / a,
),
FilterType::LowShelf => {
let two_sqrt_a_alpha = 2.0 * a.sqrt() * alpha;
(
a * ((a + 1.0) - (a - 1.0) * cos_w0 + two_sqrt_a_alpha),
2.0 * a * ((a - 1.0) - (a + 1.0) * cos_w0),
a * ((a + 1.0) - (a - 1.0) * cos_w0 - two_sqrt_a_alpha),
(a + 1.0) + (a - 1.0) * cos_w0 + two_sqrt_a_alpha,
-2.0 * ((a - 1.0) + (a + 1.0) * cos_w0),
(a + 1.0) + (a - 1.0) * cos_w0 - two_sqrt_a_alpha,
)
}
FilterType::HighShelf => {
let two_sqrt_a_alpha = 2.0 * a.sqrt() * alpha;
(
a * ((a + 1.0) + (a - 1.0) * cos_w0 + two_sqrt_a_alpha),
-2.0 * a * ((a - 1.0) + (a + 1.0) * cos_w0),
a * ((a + 1.0) + (a - 1.0) * cos_w0 - two_sqrt_a_alpha),
(a + 1.0) - (a - 1.0) * cos_w0 + two_sqrt_a_alpha,
2.0 * ((a - 1.0) - (a + 1.0) * cos_w0),
(a + 1.0) - (a - 1.0) * cos_w0 - two_sqrt_a_alpha,
)
}
};
let inv_a0 = 1.0 / a0;
self.b0 = b0 * inv_a0;
self.b1 = b1 * inv_a0;
self.b2 = b2 * inv_a0;
self.a1 = a1 * inv_a0;
self.a2 = a2 * inv_a0;
}
#[inline(always)]
pub fn process(&mut self, x: f32) -> f32 {
let y = self.b0 * x + self.s1;
self.s1 = self.b1 * x - self.a1 * y + self.s2;
self.s2 = self.b2 * x - self.a2 * y;
y
}
}