use super::{coefficients::DenseStc, DiffEq};
use crate::prelude::*;
pub type LoDiffEq<const T: usize, const U: usize> = DiffEq<DenseStc<T>, DenseStc<U>>;
pub type SingleZero = LoDiffEq<2, 0>;
impl SingleZero {
#[must_use]
pub const fn new_normalized(b0: f64, b1: f64) -> Self {
Self::new_fir(DenseStc::new([b0, b1]))
}
#[must_use]
pub fn new(a0: f64, b0: f64, b1: f64) -> Self {
Self::new_normalized(b0 / a0, b1 / a0)
}
#[must_use]
pub fn single_zero(a: f64) -> Self {
let norm = 1.0 / (1.0 + a.abs());
Self::new_normalized(-norm, norm * a)
}
}
pub type SinglePole = LoDiffEq<1, 1>;
impl SinglePole {
#[must_use]
pub const fn new_normalized(a1: f64, b0: f64) -> Self {
Self::new_raw(DenseStc::new([b0]), DenseStc::new([a1]))
}
#[must_use]
pub fn new(a0: f64, a1: f64, b0: f64) -> Self {
Self::new_normalized(a1 / a0, b0 / a0)
}
#[must_use]
pub fn single_pole(a: f64) -> Self {
let norm = 1.0 - a.abs();
Self::new_normalized(norm, norm * a)
}
}
pub type Bilinear = LoDiffEq<2, 1>;
pub type Biquad = LoDiffEq<3, 2>;
impl Biquad {
#[must_use]
pub const fn new_normalized(a1: f64, a2: f64, b0: f64, b1: f64, b2: f64) -> Self {
Self::new_raw(DenseStc::new([b0, b1, b2]), DenseStc::new([a1, a2]))
}
#[must_use]
pub fn new(a0: f64, a1: f64, a2: f64, b0: f64, b1: f64, b2: f64) -> Self {
Self::new_normalized(a1 / a0, a2 / a0, b0 / a0, b1 / a0, b2 / a0)
}
#[must_use]
pub fn low_pass(freq: unt::Freq, q: unt::QFactor) -> Self {
let (ws, wc) = freq.angular().sin_cos();
let a = ws / (2.0 * q.0);
let b1 = 1.0 - wc;
let b0 = b1 / 2.0;
Self::new(1.0 + a, -2.0 * wc, 1.0 - a, b0, b1, b0)
}
#[must_use]
pub fn hi_pass(freq: unt::Freq, q: unt::QFactor) -> Self {
let (ws, wc) = freq.angular().sin_cos();
let a = ws / (2.0 * q.0);
let b1_neg = 1.0 + wc;
let b0 = b1_neg / 2.0;
Self::new(1.0 + a, -2.0 * wc, 1.0 - a, b0, -b1_neg, b0)
}
#[must_use]
pub fn band_pass(freq: unt::Freq, q: unt::QFactor) -> Self {
let (ws, wc) = freq.angular().sin_cos();
let a = ws / (2.0 * q.0);
Self::new(1.0 + a, -2.0 * wc, 1.0 - a, a, 0.0, -a)
}
#[must_use]
pub fn notch(freq: unt::Freq, q: unt::QFactor) -> Self {
let (ws, wc) = freq.angular().sin_cos();
let a = ws / (2.0 * q.0);
let a1 = -2.0 * wc;
Self::new(1.0 + a, a1, 1.0 - a, 1.0, a1, 1.0)
}
#[must_use]
pub fn all_pass(freq: unt::Freq, q: unt::QFactor) -> Self {
let (ws, wc) = freq.angular().sin_cos();
let a = ws / (2.0 * q.0);
let a0 = 1.0 + a;
let a1 = -2.0 * wc;
let a2 = 1.0 - a;
Self::new(a0, a1, a2, a2, a1, a0)
}
#[must_use]
pub fn peaking(freq: unt::Freq, vol: unt::Vol, q: unt::QFactor) -> Self {
assert!(vol.gain > 0.0);
let (ws, wc) = freq.angular().sin_cos();
let a1 = -2.0 * wc;
let amp = vol.gain.sqrt();
let a = ws / (2.0 * q.0);
let mul = a * amp;
let div = a / amp;
Self::new(1.0 + div, a1, 1.0 - div, 1.0 + mul, a1, 1.0 - mul)
}
#[must_use]
pub fn low_shelf(freq: unt::Freq, vol: unt::Vol, q: unt::QFactor) -> Self {
let (ws, wc) = freq.angular().sin_cos();
let amp = vol.gain.sqrt();
let amp_sqrt = amp.sqrt();
let mul = amp_sqrt * ws / q.0;
let nxt = amp + 1.0;
let prv = amp - 1.0;
let nxt_mul = nxt * wc;
let prv_mul = prv * wc;
let add = nxt + prv_mul;
let sub = nxt - prv_mul;
Self::new(
add + mul,
-2.0 * (prv + nxt_mul),
add - mul,
amp * (sub + mul),
2.0 * amp * (prv - nxt_mul),
amp * (sub - mul),
)
}
#[must_use]
pub fn hi_shelf(freq: unt::Freq, vol: unt::Vol, q: unt::QFactor) -> Self {
let (ws, wc) = freq.angular().sin_cos();
let amp = vol.gain.sqrt();
let amp_sqrt = amp.sqrt();
let mul = amp_sqrt * ws / q.0;
let nxt = amp + 1.0;
let prv = amp - 1.0;
let nxt_mul = nxt * wc;
let prv_mul = prv * wc;
let add = nxt + prv_mul;
let sub = nxt - prv_mul;
Self::new(
sub + mul,
2.0 * (prv - nxt_mul),
sub - mul,
amp * (add + mul),
-2.0 * amp * (prv + nxt_mul),
amp * (add - mul),
)
}
}