use std::collections::VecDeque;
use crate::{Float, Sample};
pub trait Clamp {
#[must_use]
fn clamp(&self, mi: Self, mx: Self) -> Self;
}
impl Clamp for Float {
fn clamp(&self, mi: Float, mx: Float) -> Self {
Float::clamp(*self as Float, mi, mx)
}
}
pub trait Filter<T: Sample>: Send {
fn filter(&mut self, input: T) -> T;
fn fill(&mut self, s: T);
}
pub trait ClampedFilter<T: Sample + Clamp>: Filter<T> {
fn filter_clamped(&mut self, input: T, mi: T, mx: T) -> T;
}
pub struct IirFilter<T: Sample> {
taps: Vec<T>,
buf: VecDeque<T>,
}
impl<T> IirFilter<T>
where
T: Sample + std::ops::Mul<T, Output = T> + std::ops::Add<T, Output = T>,
{
pub fn new(taps: &[T]) -> Self {
Self {
taps: taps.to_vec(),
buf: VecDeque::new(),
}
}
}
impl<T> Filter<T> for IirFilter<T>
where
T: Sample
+ std::ops::Mul<T, Output = T>
+ std::ops::Add<T, Output = T>
+ Send
+ std::fmt::Debug,
{
fn filter(&mut self, sample: T) -> T {
let mut ret = self.taps[0] * sample;
for (i, s) in self.buf.iter().rev().enumerate() {
ret = ret + *s * self.taps[i + 1];
}
self.buf.push_back(ret);
if self.buf.len() == self.taps.len() {
self.buf.pop_front();
}
ret
}
fn fill(&mut self, s: T) {
for _ in 0..(self.taps.len() - 1) {
self.buf.push_back(s);
}
}
}
impl<T> ClampedFilter<T> for IirFilter<T>
where
T: Sample
+ std::ops::Mul<T, Output = T>
+ std::ops::Add<T, Output = T>
+ Clamp
+ Send
+ std::fmt::Debug,
{
fn filter_clamped(&mut self, sample: T, mi: T, mx: T) -> T {
let mut ret = self.taps[0] * sample;
for (i, s) in self.buf.iter().rev().enumerate() {
ret = ret + *s * self.taps[i + 1];
}
ret = ret.clamp(mi, mx);
self.buf.push_back(ret);
if self.buf.len() == self.taps.len() {
self.buf.pop_front();
}
ret
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
use crate::Result;
#[test]
fn zero_pole() -> Result<()> {
let mut f = IirFilter::new(&[1.0]);
assert_eq!(f.filter(123.0), 123.0);
assert_eq!(f.filter(123.0), 123.0);
let mut f = IirFilter::new(&[-0.5]);
assert_eq!(f.filter(402.0), -201.0);
assert_eq!(f.filter(402.0), -201.0);
Ok(())
}
#[test]
fn single_pole() -> Result<()> {
let mut f = IirFilter::new(&[1.0, 0.0]);
assert_eq!(f.filter(10.0), 10.0);
assert_eq!(f.filter(10.0), 10.0);
assert_eq!(f.filter(10.0), 10.0);
let mut f = IirFilter::new(&[0.9f32, 0.1]);
assert_eq!(f.filter(100.0), 90.0);
assert_eq!(f.filter(100.0), 99.0);
assert_eq!(f.filter(100.0), 99.9);
assert!((f.filter(100.0) - 99.99).abs() < 0.00001);
Ok(())
}
#[test]
fn single_pole_clamped() -> Result<()> {
let mut f = IirFilter::new(&[1.0, 0.0]);
assert_eq!(f.filter_clamped(10.0, 0.0, 1.0), 1.0);
assert_eq!(f.filter_clamped(10.0, 0.0, 1.0), 1.0);
assert_eq!(f.filter_clamped(10.0, 0.0, 1.0), 1.0);
Ok(())
}
#[test]
fn multi_pole() -> Result<()> {
let mut f = IirFilter::new(&[1.0, 0.0, 0.0]);
assert_eq!(f.filter(10.0), 10.0);
assert_eq!(f.filter(10.0), 10.0);
assert_eq!(f.filter(10.0), 10.0);
assert_eq!(f.filter(10.0), 10.0);
let mut f = IirFilter::new(&[1.0f32, 0.9, 0.1]);
assert_eq!(f.filter(100.0), 100.0);
assert_eq!(f.filter(100.0), 190.0);
assert_eq!(f.filter(100.0), 281.0);
assert_eq!(f.filter(100.0), 371.9);
Ok(())
}
#[test]
fn filled() -> Result<()> {
let mut f = IirFilter::new(&[1.0f32, 0.9, 0.1]);
f.fill(100.0);
assert_eq!(f.filter(100.0), 200.0);
assert_eq!(f.filter(100.0), 290.0);
assert_eq!(f.filter(200.0), 481.0);
Ok(())
}
}