use alloc::vec::Vec;
use super::{Pole, PoleKind, StreamInfo};
const TAU: f64 = core::f64::consts::TAU;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct OnePole {
kind: PoleKind,
a: f32,
prev_in: f32,
prev_out: f32,
}
impl OnePole {
#[must_use]
pub fn new(pole: Pole, rate_num: u64, rate_den: u64) -> OnePole {
let rate = if rate_den == 0 {
0.0
} else {
rate_num as f64 / rate_den as f64
};
let corner = f64::from(pole.corner_hz);
let a = if rate <= 0.0 || corner <= 0.0 || corner * 2.0 >= rate {
1.0
} else {
let ratio = 1.0 / (1.0 + TAU * corner / rate);
match pole.kind {
PoleKind::LOW_PASS => 1.0 - ratio,
_ => ratio,
}
};
OnePole {
kind: pole.kind,
a: a as f32,
prev_in: 0.0,
prev_out: 0.0,
}
}
#[inline]
#[must_use]
pub fn step(&mut self, x: f32) -> f32 {
match self.kind {
PoleKind::LOW_PASS => {
self.prev_out += self.a * (x - self.prev_out);
self.prev_out
}
_ => {
let y = self.a * (self.prev_out + x - self.prev_in);
self.prev_in = x;
self.prev_out = y;
y
}
}
}
pub const fn reset(&mut self) {
self.prev_in = 0.0;
self.prev_out = 0.0;
}
#[inline]
#[must_use]
pub const fn coefficient(&self) -> f32 {
self.a
}
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Chain {
sections: Vec<OnePole>,
}
impl Chain {
#[must_use]
pub fn for_stream(info: StreamInfo) -> Chain {
Chain {
sections: info
.output_stage
.iter()
.map(|pole| OnePole::new(*pole, info.rate_num, info.rate_den))
.collect(),
}
}
#[must_use]
pub const fn passthrough() -> Chain {
Chain {
sections: Vec::new(),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.sections.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.sections.is_empty()
}
#[inline]
#[must_use]
pub fn step(&mut self, x: f32) -> f32 {
let mut y = x;
for section in &mut self.sections {
y = section.step(y);
}
y
}
pub fn reset(&mut self) {
for section in &mut self.sections {
section.reset();
}
}
}