use core::any::Any;
use miniconf::Tree;
use num_traits::{AsPrimitive, Float, FloatConst};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use crate::{
Build,
iir::{
BiquadClamp,
coefficients::Shape,
pid::{Pid, Units},
},
};
#[derive(Debug, Clone, Tree)]
#[tree(meta(doc, typename))]
pub struct Ba<T> {
#[tree(with=miniconf::leaf, bounds(serialize="T: Serialize", deserialize="T: DeserializeOwned", any="T: Any"))]
pub ba: [[T; 3]; 2],
pub u: T,
pub min: T,
pub max: T,
}
impl<T: Float> Default for Ba<T> {
fn default() -> Self {
Self {
ba: [[T::zero(); 3], [T::one(), T::zero(), T::zero()]],
u: T::zero(),
min: T::neg_infinity(),
max: T::infinity(),
}
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Default, PartialEq, PartialOrd)]
pub enum Typ {
#[default]
Lowpass,
Highpass,
Bandpass,
Allpass,
Notch,
Peaking,
Lowshelf,
Highshelf,
IHo,
}
#[derive(Clone, Debug, Tree)]
#[tree(meta(doc, typename))]
pub struct FilterRepr<T> {
#[tree(with=miniconf::leaf)]
pub typ: Typ,
pub frequency: T,
pub gain: T,
pub shelf: T,
#[tree(with=miniconf::leaf, bounds(serialize="T: Serialize", deserialize="T: DeserializeOwned", any="T: Any"))]
pub shape: Shape<T>,
pub offset: T,
pub min: T,
pub max: T,
}
impl<T: Float + FloatConst> Default for FilterRepr<T> {
fn default() -> Self {
Self {
typ: Typ::default(),
frequency: T::zero(),
gain: T::one(),
shelf: T::one(),
shape: Shape::default(),
offset: T::zero(),
min: T::neg_infinity(),
max: T::infinity(),
}
}
}
#[derive(
Debug,
Clone,
Tree,
strum::AsRefStr,
strum::EnumString,
strum::EnumDiscriminants,
strum::IntoStaticStr,
)]
#[strum_discriminants(derive(serde::Serialize, serde::Deserialize), allow(missing_docs))]
#[tree(meta(doc = "Representation of a biquad", typename))]
pub enum BiquadRepr<T, C = T, Y = T>
where
Ba<T>: Default,
Pid<T>: Default,
BiquadClamp<C, Y>: Default,
FilterRepr<T>: Default,
{
Ba(Ba<T>),
Raw(
#[tree(with=miniconf::leaf, bounds(
serialize="C: Serialize, Y: Serialize",
deserialize="C: DeserializeOwned, Y: DeserializeOwned",
any="C: Any, Y: Any"))]
BiquadClamp<C, Y>,
),
Pid(Pid<T>),
Filter(FilterRepr<T>),
}
impl<T, C, Y> Default for BiquadRepr<T, C, Y>
where
Ba<T>: Default,
Pid<T>: Default,
BiquadClamp<C, Y>: Default,
FilterRepr<T>: Default,
{
fn default() -> Self {
Self::Ba(Default::default())
}
}
impl<T, C, Y> BiquadRepr<T, C, Y>
where
BiquadClamp<C, Y>: Default + Clone,
Y: 'static + Copy,
T: 'static + Float + FloatConst + Default + AsPrimitive<Y>,
f32: AsPrimitive<T>,
Pid<T>: Build<BiquadClamp<C, Y>, Context = Units<T>>,
[[T; 3]; 2]: Into<BiquadClamp<C, Y>>,
{
pub fn build(&self, units: &Units<T>) -> BiquadClamp<C, Y> {
let yu = units.y.recip();
let yx = units.x * yu;
match self {
Self::Ba(ba) => {
let mut bba = ba.ba;
bba[0] = bba[0].map(|b| b * yx);
let mut b: BiquadClamp<C, Y> = bba.into();
b.u = (ba.u * yu).as_();
b.min = (ba.min * yu).as_();
b.max = (ba.max * yu).as_();
b
}
Self::Raw(raw) => raw.clone(),
Self::Pid(pid) => pid.build(units),
Self::Filter(filter) => {
let mut f = crate::iir::coefficients::Filter::default();
f.gain_db(filter.gain);
f.critical_frequency(filter.frequency * units.t);
f.shelf_db(filter.shelf);
f.set_shape(filter.shape);
let mut ba = match filter.typ {
Typ::Lowpass => f.lowpass(),
Typ::Highpass => f.highpass(),
Typ::Allpass => f.allpass(),
Typ::Bandpass => f.bandpass(),
Typ::Highshelf => f.highshelf(),
Typ::Lowshelf => f.lowshelf(),
Typ::IHo => f.iho(),
Typ::Notch => f.notch(),
Typ::Peaking => f.peaking(),
};
ba[0] = ba[0].map(|b| b * yx);
let mut b: BiquadClamp<C, Y> = ba.into();
b.u = (filter.offset * yu).as_();
b.min = (filter.min * yu).as_();
b.max = (filter.max * yu).as_();
b
}
}
}
}