Skip to main content

dsp_process/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3
4mod process;
5pub use process::*;
6mod view;
7pub use view::*;
8mod basic;
9pub use basic::*;
10mod adapters;
11pub use adapters::*;
12mod split;
13pub use split::*;
14mod compose;
15pub use compose::*;
16
17/// Parallel filter pair
18///
19/// This can be viewed as digital lattice filter or butterfly filter or complementary allpass pair
20/// or polyphase interpolator.
21/// Candidates for the branches are allpasses like Wdf or Ldi, polyphase banks for resampling or Hilbert filters.
22///
23/// Potentially required scaling with 0.5 gain is to be performed ahead of the filter, within each branch, or (with headroom) afterwards.
24///
25/// This uses the default configuration-minor/sample-major implementation
26/// and may lead to suboptimal cashing and register thrashing for large branches.
27/// To avoid this, use `block()` and `inplace()` on a scratch buffer ([`Major`] input or output).
28///
29/// The corresponding state for this is `((Unsplit<Identity>, (S0, S1)), Unsplit<Add>)`.
30///
31/// # Examples
32///
33/// ```rust
34/// use dsp_process::{Add, Gain, Identity, Offset, Pair, Parallel, Process, Split, Unsplit};
35///
36/// let mut pair = Split::new(
37///     Pair::<_, _, i32>::new((((), Parallel::new((Offset(3), Gain(4)))), ())),
38///     ((Unsplit(Identity), Default::default()), Unsplit(Add)),
39/// );
40/// let y: i32 = pair.process(5);
41/// assert_eq!(y, 28);
42/// ```
43pub type Pair<C0, C1, X, I = (), J = ()> = Minor<((I, Parallel<(C0, C1)>), J), [X; 2]>;
44
45#[cfg(test)]
46mod test {
47    use super::*;
48    use dsp_fixedpoint::Q32;
49
50    #[test]
51    fn basic() {
52        assert_eq!(3, Identity.process(3));
53        assert_eq!([7, 1], Butterfly.process([4, 3]));
54        assert_eq!(
55            Split::stateless(Gain(Q32::<3>::from_bits(32))).process(9),
56            9 * 4
57        );
58        assert_eq!(Split::stateless(Offset(7)).process(9), 7 + 9);
59    }
60
61    #[test]
62    fn stateless() {
63        assert_eq!(Neg.process(9), -9);
64        assert_eq!(Split::stateful(Neg).process(9), -9);
65
66        let mut p = (Split::stateless(Offset(7)) * Split::stateless(Offset(1))).minor();
67        p.assert_process::<i8, _>();
68        assert_eq!(p.process(9), 7 + 1 + 9);
69    }
70
71    #[test]
72    fn stateful() {
73        let mut xy = [3, 0, 0];
74        let mut dly = Buffer::<[_; 2]>::default();
75        dly.inplace(&mut xy);
76        assert_eq!(xy, [0, 0, 3]);
77        let y: i32 = Split::stateful(dly).process(4);
78        assert_eq!(y, 0);
79    }
80
81    #[test]
82    fn pair() {
83        let g = Gain(Q32::<1>::from_bits(4));
84        let mut f = Split::new(
85            Pair::<_, _, _>::new((((), Parallel::new((Offset(3), g))), ())),
86            ((Unsplit(Identity), Default::default()), Unsplit(Add)),
87        );
88        let y: i32 = f.process(5);
89        assert_eq!(y, (5 + 3) + ((5 * 4) >> 1));
90
91        let y: [i32; 5] = f.lanes().process([5; _]);
92        assert_eq!(y, [(5 + 3) + ((5 * 4) >> 1); 5]);
93    }
94
95    #[test]
96    fn chunk_in_out() {
97        let mut p = Split::stateless(ChunkInOut(FnSplitProcess(
98            |_: &mut (), [x0, x1]: [i32; 2]| [x0 + x1],
99        )));
100        let y = p.process([1, 2, 3, 4]);
101        assert_eq!(y, [3, 7]);
102    }
103
104    #[cfg(feature = "bytemuck")]
105    #[test]
106    fn chunk_out_pod() {
107        let mut p = Split::stateless(ChunkOutPod(FnSplitProcess(|_: &mut (), x: i32| [x, -x])));
108        let y = p.process([2, 3]);
109        assert_eq!(y, [2, -2, 3, -3]);
110    }
111
112    #[test]
113    fn frame_major_view_fallback() {
114        let mut p = Split::stateless(Offset(3));
115        let x = View::from_frames(&[[1, 2], [3, 4]]);
116        let mut y = [[0; 2]; 2];
117        let yb = ViewMut::from_frames(&mut y);
118        p.process_view(x, yb);
119        assert_eq!(y, [[4, 5], [6, 7]]);
120    }
121
122    #[test]
123    fn lane_major_lanes() {
124        let mut p = Split::stateless(Offset(3)).lanes::<2>();
125        let x = View::from_flat(&[1, 2, 3, 10, 20, 30], 3);
126        let mut y = [0; 6];
127        let yb = ViewMut::from_flat(&mut y, 3);
128        p.process_view(x, yb);
129        assert_eq!(y, [4, 5, 6, 13, 23, 33]);
130    }
131
132    #[test]
133    fn lane_major_by_lane() {
134        let mut p = Split::new(ByLane::new([Offset(1), Offset(10)]), [(), ()]);
135        let x = View::from_flat(&[1, 2, 3, 10, 20, 30], 3);
136        let mut y = [0; 6];
137        let yb = ViewMut::from_flat(&mut y, 3);
138        p.process_view(x, yb);
139        assert_eq!(y, [2, 3, 4, 20, 30, 40]);
140    }
141
142    #[test]
143    fn framewise_chunk_bridge() {
144        let mut p = Split::stateless(ChunkInOut::<_, 2, 1>(FnSplitProcess(
145            |_: &mut (), [x0, x1]: [i32; 2]| [x0 + x1],
146        )))
147        .per_frame();
148        let x = View::from_frames(&[[1, 2], [3, 4]]);
149        let mut y = [[0; 1]; 2];
150        let yb = ViewMut::from_frames(&mut y);
151        p.process_frames(x, yb);
152        assert_eq!(y, [[3], [7]]);
153    }
154
155    #[test]
156    fn buffer_blocks() {
157        let mut dly = Buffer::<[_; 2]>::default();
158        let mut y = [0; 5];
159        dly.block(&[1, 2, 3, 4, 5], &mut y);
160        assert_eq!(y, [0, 0, 1, 2, 3]);
161        assert_eq!(dly.process([6, 7, 8]), [4, 5, 6]);
162
163        let mut chunk = Buffer::<[i32; 2]>::default();
164        let mut y = [None; 5];
165        chunk.block(&[1, 2, 3, 4, 5], &mut y);
166        assert_eq!(y, [None, Some([1, 2]), None, Some([3, 4]), None]);
167
168        let mut stream = Buffer::<[i32; 2]>::default();
169        let mut y = [0; 5];
170        stream.block(
171            &[Some([1, 2]), None, Some([3, 4]), None, Some([5, 6])],
172            &mut y,
173        );
174        assert_eq!(y, [1, 2, 3, 4, 5]);
175    }
176
177    #[test]
178    fn diffsum_block() {
179        let mut nyq = Nyquist([10, 20]);
180        let mut y = [0; 4];
181        nyq.block(&[1, 2, 3, 4], &mut y);
182        assert_eq!(y, [21, 12, 4, 6]);
183        let mut xy = [5, 6, 7];
184        nyq.inplace(&mut xy);
185        assert_eq!(xy, [8, 10, 12]);
186
187        let mut comb = Comb([10, 20]);
188        let mut y = [0; 4];
189        comb.block(&[1, 2, 3, 4], &mut y);
190        assert_eq!(y, [-19, -8, 2, 2]);
191        let mut xy = [5, 6, 7];
192        comb.inplace(&mut xy);
193        assert_eq!(xy, [2, 2, 2]);
194    }
195}