dsp_process/
basic.rs

1use crate::{Inplace, Process};
2
3//////////// ELEMENTARY PROCESSORS ////////////
4
5/// Summation
6///
7/// Fan in.
8#[derive(Debug, Copy, Clone, Default)]
9pub struct Add;
10impl<X: Copy, Y: core::iter::Sum<X>, const N: usize> Process<[X; N], Y> for &Add {
11    fn process(&mut self, x: [X; N]) -> Y {
12        x.into_iter().sum()
13    }
14}
15impl<X0: Copy + core::ops::Add<X1, Output = Y>, X1: Copy, Y> Process<(X0, X1), Y> for &Add {
16    fn process(&mut self, x: (X0, X1)) -> Y {
17        x.0 + x.1
18    }
19}
20impl<X: Copy> Inplace<X> for &Add where Self: Process<X> {}
21
22/// Product
23///
24/// Fan in.
25#[derive(Debug, Copy, Clone, Default)]
26pub struct Mul;
27impl<X: Copy, Y: core::iter::Product<X>, const N: usize> Process<[X; N], Y> for &Mul {
28    fn process(&mut self, x: [X; N]) -> Y {
29        x.into_iter().product()
30    }
31}
32impl<X0: Copy + core::ops::Mul<X1, Output = Y>, X1: Copy, Y> Process<(X0, X1), Y> for &Mul {
33    fn process(&mut self, x: (X0, X1)) -> Y {
34        x.0 * x.1
35    }
36}
37impl<X: Copy> Inplace<X> for &Mul where Self: Process<X> {}
38
39/// Difference
40///
41/// Fan in.
42#[derive(Debug, Copy, Clone, Default)]
43pub struct Sub;
44impl<X: Copy + core::ops::Sub<Output = Y>, Y> Process<[X; 2], Y> for &Sub {
45    fn process(&mut self, x: [X; 2]) -> Y {
46        x[0] - x[1]
47    }
48}
49impl<X0: Copy + core::ops::Sub<X1, Output = Y>, X1: Copy, Y> Process<(X0, X1), Y> for &Sub {
50    fn process(&mut self, x: (X0, X1)) -> Y {
51        x.0 - x.1
52    }
53}
54impl<X: Copy> Inplace<X> for &Sub where Self: Process<X> {}
55
56/// Sum and difference
57#[derive(Debug, Copy, Clone, Default)]
58pub struct Butterfly;
59impl<X: Copy + core::ops::Add<Output = Y> + core::ops::Sub<Output = Y>, Y> Process<[X; 2], [Y; 2]>
60    for &Butterfly
61{
62    fn process(&mut self, x: [X; 2]) -> [Y; 2] {
63        [x[0] + x[1], x[0] - x[1]]
64    }
65}
66
67impl<X: Copy> Inplace<X> for &Butterfly where Self: Process<X> {}
68
69/// Identity using [`Copy`]
70#[derive(Debug, Copy, Clone, Default)]
71pub struct Identity;
72impl<T: Copy> Process<T> for &Identity {
73    fn process(&mut self, x: T) -> T {
74        x
75    }
76
77    fn block(&mut self, x: &[T], y: &mut [T]) {
78        y.copy_from_slice(x);
79    }
80}
81
82/// NOP
83impl<T: Copy> Inplace<T> for &Identity {
84    fn inplace(&mut self, _xy: &mut [T]) {}
85}
86
87/// Fan out
88impl<X: Copy> Process<X, (X, X)> for &Identity {
89    fn process(&mut self, x: X) -> (X, X) {
90        (x, x)
91    }
92}
93
94/// Fan out
95impl<X: Copy, const N: usize> Process<X, [X; N]> for &Identity {
96    fn process(&mut self, x: X) -> [X; N] {
97        core::array::repeat(x)
98    }
99}
100
101/// Flatten
102impl<X: Copy> Process<[X; 1], X> for &Identity {
103    fn process(&mut self, x: [X; 1]) -> X {
104        x[0]
105    }
106}
107
108/// Inversion using `Neg`.
109#[derive(Debug, Copy, Clone, Default)]
110pub struct Neg;
111impl<T: Copy + core::ops::Neg<Output = T>> Process<T> for &Neg {
112    fn process(&mut self, x: T) -> T {
113        x.neg()
114    }
115}
116
117impl<T: Copy> Inplace<T> for &Neg where Self: Process<T> {}
118
119/// Addition of a constant
120#[derive(Debug, Clone, Copy, Default)]
121#[repr(transparent)]
122pub struct Offset<T>(pub T);
123
124/// Offset using `Add`
125impl<X: Copy + core::ops::Add<T, Output = Y>, Y, T: Copy> Process<X, Y> for &Offset<T> {
126    fn process(&mut self, x: X) -> Y {
127        x + self.0
128    }
129}
130
131impl<X: Copy, T> Inplace<X> for &Offset<T> where Self: Process<X> {}
132
133/// Multiply by constant
134#[derive(Debug, Clone, Copy, Default)]
135#[repr(transparent)]
136pub struct Gain<T>(pub T);
137
138/// Gain using `Mul`
139impl<X: Copy + core::ops::Mul<T, Output = Y>, Y, T: Copy> Process<X, Y> for &Gain<T> {
140    fn process(&mut self, x: X) -> Y {
141        x * self.0
142    }
143}
144
145impl<X: Copy, T> Inplace<X> for &Gain<T> where Self: Process<X> {}
146
147/// Clamp between min and max using `Ord`
148#[derive(Debug, Copy, Clone, Default)]
149pub struct Clamp<T> {
150    /// Lowest output value
151    pub min: T,
152    /// Highest output value
153    pub max: T,
154}
155
156impl<T: Copy + Ord> Process<T> for &Clamp<T> {
157    fn process(&mut self, x: T) -> T {
158        x.clamp(self.min, self.max)
159    }
160}
161
162impl<T: Copy> Inplace<T> for &Clamp<T> where Self: Process<T> {}
163
164/// Decimate or zero stuff
165#[derive(Debug, Copy, Clone, Default)]
166pub struct Rate;
167impl<X: Copy, const N: usize> Process<[X; N], X> for &Rate {
168    fn process(&mut self, x: [X; N]) -> X {
169        x[N - 1]
170    }
171}
172
173impl<X: Copy + Default, const N: usize> Process<X, [X; N]> for &Rate {
174    fn process(&mut self, x: X) -> [X; N] {
175        let mut y = [X::default(); N];
176        y[0] = x;
177        y
178    }
179}
180impl<X: Copy> Inplace<X> for &Rate where Self: Process<X> {}
181
182/// Buffer input or output, or fixed delay line
183#[derive(Debug, Copy, Clone, Default)]
184pub struct Buffer<B> {
185    buffer: B,
186    idx: usize,
187}
188
189impl<X, const N: usize> Buffer<[X; N]> {
190    /// The buffer is empty
191    pub fn is_empty(&self) -> bool {
192        self.idx == 0
193    }
194}
195
196/// Delay line
197impl<X: Copy, const N: usize> Process<X> for Buffer<[X; N]> {
198    fn process(&mut self, x: X) -> X {
199        let y = core::mem::replace(&mut self.buffer[self.idx], x);
200        self.idx = (self.idx + 1) % N;
201        y
202    }
203
204    // TODO: block(), inplace(), Process<[X; M]>
205}
206
207impl<X: Copy, const N: usize> Inplace<X> for Buffer<[X; N]> where Self: Process<X> {}
208
209/// Buffer into chunks
210impl<X: Copy, const N: usize> Process<X, Option<[X; N]>> for Buffer<[X; N]> {
211    fn process(&mut self, x: X) -> Option<[X; N]> {
212        self.buffer[self.idx] = x;
213        self.idx += 1;
214        (self.idx == N).then(|| {
215            self.idx = 0;
216            self.buffer
217        })
218    }
219
220    // TODO: block()
221}
222
223/// Buffer out of chunks
224///
225/// Panics on underflow
226impl<X: Copy, const N: usize> Process<Option<[X; N]>, X> for Buffer<[X; N]> {
227    fn process(&mut self, x: Option<[X; N]>) -> X {
228        if let Some(x) = x {
229            self.buffer = x;
230            self.idx = 0;
231        } else {
232            self.idx += 1;
233        }
234        self.buffer[self.idx]
235    }
236
237    // TODO: block()
238}
239
240/// Nyquist zero with gain 2
241///
242/// This is inefficient for large differential delays
243#[derive(Debug, Copy, Clone, Default)]
244pub struct Nyquist<X>(
245    /// Previous input
246    pub X,
247);
248impl<X: Copy + core::ops::Add<X, Output = Y>, Y, const N: usize> Process<X, Y> for Nyquist<[X; N]> {
249    fn process(&mut self, x: X) -> Y {
250        const { assert!(N > 0) }
251        let y = x + self.0[N - 1];
252        self.0.copy_within(..N - 1, 1);
253        self.0[0] = x;
254        y
255    }
256
257    // TODO: block, inplace
258}
259impl<X: Copy> Inplace<X> for Nyquist<X> where Self: Process<X> {}
260
261/// Integrator
262#[derive(Debug, Copy, Clone, Default)]
263pub struct Integrator<Y>(
264    /// Current integrator value
265    pub Y,
266);
267impl<X: Copy, Y: core::ops::AddAssign<X> + Copy> Process<X, Y> for Integrator<Y> {
268    fn process(&mut self, x: X) -> Y {
269        self.0 += x;
270        self.0
271    }
272}
273impl<X: Copy> Inplace<X> for Integrator<X> where Self: Process<X> {}
274
275/// Comb (derivative)
276///
277/// Bad for large delays
278#[derive(Debug, Copy, Clone, Default)]
279pub struct Comb<X>(
280    /// Delay line
281    pub X,
282);
283impl<X: Copy + core::ops::Sub<X, Output = Y>, Y, const N: usize> Process<X, Y> for Comb<[X; N]> {
284    fn process(&mut self, x: X) -> Y {
285        const { assert!(N > 0) }
286        let y = x - self.0[N - 1];
287        self.0.copy_within(..N - 1, 1);
288        self.0[0] = x;
289        y
290    }
291
292    // TODO: block, inplace
293}
294impl<X: Copy> Inplace<X> for Comb<X> where Self: Process<X> {}