dsp_process/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![doc = include_str!("../README.md")]
3
4mod process;
5pub use process::*;
6mod basic;
7pub use basic::*;
8mod adapters;
9pub use adapters::*;
10mod split;
11pub use split::*;
12mod compose;
13pub use compose::*;
14
15/// Parallel filter pair
16///
17/// This can be viewed as digital lattice filter or butterfly filter or complementary allpass pair
18/// or polyphase interpolator.
19/// Candidates for the branches are allpasses like Wdf or Ldi, polyphase banks for resampling or Hilbert filters.
20///
21/// Potentially required scaling with 0.5 gain is to be performed ahead of the filter, within each branch, or (with headroom) afterwards.
22///
23/// This uses the default configuration-minor/sample-major implementation
24/// and may lead to suboptimal cashing and register thrashing for large branches.
25/// To avoid this, use `block()` and `inplace()` on a scratch buffer ([`Major`] input or output).
26///
27/// The corresponding state for this is `(((), (S0, S1)), ())`.
28pub type Pair<C0, C1, X, I = Unsplit<&'static Identity>, J = Unsplit<&'static Add>> =
29    Minor<((I, Parallel<(C0, C1)>), J), [X; 2]>;
30
31#[cfg(test)]
32mod test {
33    use super::*;
34    use dsp_fixedpoint::Q32;
35
36    #[test]
37    fn basic() {
38        assert_eq!(3, (&Identity).process(3));
39        assert_eq!((&Gain(Q32::<3>::new(32))).process(9), 9 * 4);
40        assert_eq!((&Offset(7)).process(9), 7 + 9);
41    }
42
43    #[test]
44    fn stateless() {
45        assert_eq!(Unsplit(&Neg).process(&mut (), 9), -9);
46        assert_eq!(Split::stateless(&Neg).as_mut().process(9), -9);
47
48        let mut p = (Split::stateless(&Offset(7)) * Split::stateless(&Offset(1))).minor();
49        p.as_mut().assert_process::<i8, _>();
50        assert_eq!(p.as_mut().process(9), 7 + 1 + 9);
51    }
52
53    #[test]
54    fn stateful() {
55        let mut xy = [3, 0, 0];
56        let mut dly = Buffer::<[_; 2]>::default();
57        dly.inplace(&mut xy);
58        assert_eq!(xy, [0, 0, 3]);
59        let y: i32 = Split::stateful(dly).as_mut().process(4);
60        assert_eq!(y, 0);
61    }
62
63    #[test]
64    fn pair() {
65        let g = Gain(Q32::<1>::new(4));
66        let mut f = Split::new(
67            Pair::<_, _, _>::new((
68                (
69                    Unsplit(&Identity),
70                    Parallel((Unsplit(&Offset(3)), Unsplit(&g))),
71                ),
72                Unsplit(&Add),
73            )),
74            Default::default(),
75        );
76        let y: i32 = f.as_mut().process(5);
77        assert_eq!(y, (5 + 3) + ((5 * 4) >> 1));
78
79        let y: [i32; 5] = f.channels().as_mut().process([5; _]);
80        assert_eq!(y, [(5 + 3) + ((5 * 4) >> 1); 5]);
81    }
82}