dsp_process/
process.rs

1//! Sample processing, filtering, combination of filters.
2
3/// Processing block
4///
5/// Single input, single output
6pub trait Process<X: Copy, Y = X> {
7    /// Update the state with a new input and obtain an output
8    fn process(&mut self, x: X) -> Y;
9
10    /// Process a block of inputs into a block of outputs
11    ///
12    /// Input and output must be of the same size.
13    fn block(&mut self, x: &[X], y: &mut [Y]) {
14        debug_assert_eq!(x.len(), y.len());
15        for (x, y) in x.iter().zip(y) {
16            *y = self.process(*x);
17        }
18    }
19}
20
21/// Inplace processing
22pub trait Inplace<X: Copy>: Process<X> {
23    /// Process an input block into the same data as output
24    fn inplace(&mut self, xy: &mut [X]) {
25        for xy in xy.iter_mut() {
26            *xy = self.process(*xy);
27        }
28    }
29}
30
31/// Processing with split state
32///
33/// Splitting configuration (the part of the filter that is unaffected
34/// by processing inputs, e.g. "coefficients"), from state (the part
35/// that is modified by processing) allows:
36///
37/// * Separating mutable from immutable state guarantees consistency
38///   (configuration can not change state and processing can
39///   not change configuration)
40/// * Reduces memory traffic when swapping configuration
41/// * Allows the same filter to be applied to multiple states
42///   (e.g. IQ data, multiple channels) guaranteeing consistency,
43///   reducing memory usage, and improving caching.
44pub trait SplitProcess<X: Copy, Y = X, S: ?Sized = ()> {
45    /// Process an input into an output
46    ///
47    /// See also [`Process::process`]
48    fn process(&self, state: &mut S, x: X) -> Y;
49
50    /// Process a block of inputs
51    ///
52    /// See also [`Process::block`]
53    fn block(&self, state: &mut S, x: &[X], y: &mut [Y]) {
54        debug_assert_eq!(x.len(), y.len());
55        for (x, y) in x.iter().zip(y) {
56            *y = self.process(state, *x);
57        }
58    }
59}
60
61/// Inplace processing with a split state
62pub trait SplitInplace<X: Copy, S: ?Sized = ()>: SplitProcess<X, X, S> {
63    /// See also [`Inplace::inplace`]
64    fn inplace(&self, state: &mut S, xy: &mut [X]) {
65        for xy in xy.iter_mut() {
66            *xy = self.process(state, *xy);
67        }
68    }
69}
70
71//////////// BLANKET ////////////
72
73impl<X: Copy, Y, T: Process<X, Y>> Process<X, Y> for &mut T {
74    fn process(&mut self, x: X) -> Y {
75        T::process(self, x)
76    }
77
78    fn block(&mut self, x: &[X], y: &mut [Y]) {
79        T::block(self, x, y)
80    }
81}
82
83impl<X: Copy, T: Inplace<X>> Inplace<X> for &mut T {
84    fn inplace(&mut self, xy: &mut [X]) {
85        T::inplace(self, xy)
86    }
87}
88
89impl<X: Copy, Y, S: ?Sized, T: SplitProcess<X, Y, S>> SplitProcess<X, Y, S> for &T {
90    fn process(&self, state: &mut S, x: X) -> Y {
91        T::process(self, state, x)
92    }
93
94    fn block(&self, state: &mut S, x: &[X], y: &mut [Y]) {
95        T::block(self, state, x, y)
96    }
97}
98
99impl<X: Copy, S: ?Sized, T: SplitInplace<X, S>> SplitInplace<X, S> for &T {
100    fn inplace(&self, state: &mut S, xy: &mut [X]) {
101        T::inplace(self, state, xy)
102    }
103}
104
105impl<X: Copy, Y, S: ?Sized, T: SplitProcess<X, Y, S>> SplitProcess<X, Y, S> for &mut T {
106    fn process(&self, state: &mut S, x: X) -> Y {
107        T::process(self, state, x)
108    }
109
110    fn block(&self, state: &mut S, x: &[X], y: &mut [Y]) {
111        T::block(self, state, x, y)
112    }
113}
114
115impl<X: Copy, S: ?Sized, T: SplitInplace<X, S>> SplitInplace<X, S> for &mut T {
116    fn inplace(&self, state: &mut S, xy: &mut [X]) {
117        T::inplace(self, state, xy)
118    }
119}