idsp/iir/
svf.rs

1//! State variable filter
2
3use num_traits::{Float, FloatConst};
4
5use dsp_process::SplitProcess;
6
7/// Second order state variable filter state
8pub struct State<T> {
9    /// Lowpass output
10    pub lp: T,
11    /// Highpass output
12    pub hp: T,
13    /// Bandpass output
14    pub bp: T,
15}
16
17impl<T: Float> State<T> {
18    /// Bandreject (notch) output
19    pub fn br(&self) -> T {
20        self.hp + self.lp
21    }
22}
23
24/// State variable filter
25///
26/// <https://www.earlevel.com/main/2003/03/02/the-digital-state-variable-filter/>
27#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
28pub struct Svf<T> {
29    f: T,
30    q: T,
31}
32
33impl<T: Float + FloatConst> Svf<T> {
34    /// Set the critical frequency
35    ///
36    /// In units of the sample frequency.
37    pub fn set_frequency(&mut self, f0: T) {
38        self.f = (T::one() + T::one()) * (T::PI() * f0).sin();
39    }
40
41    /// Set the Q parameter
42    pub fn set_q(&mut self, q: T) {
43        self.q = T::one() / q;
44    }
45}
46
47impl<T> SplitProcess<T, (), State<T>> for Svf<T>
48where
49    T: Float + FloatConst + Copy,
50{
51    /// Update the filter
52    ///
53    /// Ingest an input sample and update state correspondingly.
54    /// Selected output(s) are available from [`State`].
55    fn process(&self, state: &mut State<T>, x: T) {
56        state.lp = state.bp * self.f + state.lp;
57        state.hp = x - state.lp - state.bp * self.q;
58        state.bp = state.hp * self.f + state.bp;
59    }
60}