#[cfg(not(feature = "std"))]
#[allow(unused_imports)]
use num_traits::float::FloatCore as _;
use dsp_fixedpoint::Q32;
use dsp_process::{SplitInplace, SplitProcess};
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum Tpa {
Z = 0x0,
A = 0xA,
B = 0xB,
B1 = 0xE,
X = 0x1,
C = 0xC,
C1 = 0xF,
D = 0xD,
}
impl From<u8> for Tpa {
#[inline]
fn from(value: u8) -> Self {
match value {
0xa => Tpa::A,
0xb => Tpa::B,
0xe => Tpa::B1,
0x1 => Tpa::X,
0xc => Tpa::C,
0xf => Tpa::C1,
0xd => Tpa::D,
_ => Tpa::Z,
}
}
}
impl Tpa {
fn quantize(self, g: f64) -> Option<Q32<32>> {
let a = match self {
Self::Z => 0.0,
Self::A => g - 1.0,
Self::B | Self::B1 => -g,
Self::X => 0.0,
Self::C | Self::C1 => g,
Self::D => -1.0 - g,
};
(-0.5..=0.0).contains(&a).then_some(Q32::from_f64(a))
}
#[inline]
fn adapt(&self, x: [i32; 2], a: Q32<32>) -> [i32; 2] {
match self {
Tpa::A => {
let c = x[1] - x[0];
let y = (c * a).wrapping_add(x[1]);
[y.wrapping_add(c), y]
}
Tpa::B => {
let c = x[0] - x[1];
let y = (c * a).wrapping_add(x[1]);
[y, y.wrapping_add(c)]
}
Tpa::B1 => {
let c = x[0] - x[1];
let y = c * a;
[y.wrapping_add(x[1]), y.wrapping_add(x[0])]
}
Tpa::X => [x[1], x[0]],
Tpa::C => {
let c = x[1] - x[0];
let y = (c * a).wrapping_sub(x[1]);
[y, y.wrapping_add(c)]
}
Tpa::C1 => {
let c = x[1] - x[0];
let y = c * a;
[y.wrapping_sub(x[1]), y.wrapping_sub(x[0])]
}
Tpa::D => {
let c = x[0] - x[1];
let y = (c * a).wrapping_sub(x[1]);
[y.wrapping_add(c), y]
}
Tpa::Z => x,
}
}
}
#[derive(Debug, Clone)]
pub struct Wdf<const N: usize, const M: u32> {
pub a: [Q32<32>; N],
}
impl<const N: usize, const M: u32> Default for Wdf<N, M> {
fn default() -> Self {
Self {
a: [Default::default(); N],
}
}
}
impl<const N: usize, const M: u32> Wdf<N, M> {
pub fn quantize(g: &[f64; N]) -> Option<Self> {
let mut a = [Default::default(); N];
let mut m = M;
for (a, g) in a.iter_mut().zip(g) {
*a = Tpa::from((m & 0xf) as u8).quantize(*g)?;
m >>= 4;
}
debug_assert_eq!(m, 0);
Some(Self { a })
}
}
#[derive(Clone, Debug)]
pub struct WdfState<const N: usize> {
pub z: [i32; N],
}
impl<const N: usize> Default for WdfState<N> {
fn default() -> Self {
Self { z: [0; N] }
}
}
impl<const N: usize, const M: u32> SplitProcess<i32, i32, WdfState<N>> for Wdf<N, M> {
#[inline]
fn process(&self, state: &mut WdfState<N>, x: i32) -> i32 {
let mut y = 0;
let (m, x, z) =
self.a
.iter()
.zip(state.z.iter_mut())
.fold((M, x, &mut y), |(m, mut x, y), (a, z)| {
[*y, x] = Tpa::from((m & 0xf) as u8).adapt([x, *z], *a);
(m >> 4, x, z)
});
debug_assert_eq!(m, 0);
*z = x;
y
}
}
impl<const N: usize, const M: u32> SplitInplace<i32, WdfState<N>> for Wdf<N, M> {}