audio_blocks/
ops.rs

1use rtsan_standalone::nonblocking;
2
3use crate::{AudioBlock, AudioBlockMut, BlockLayout, Sample};
4
5pub trait Ops<S: Sample> {
6    /// Copy will panic if blocks don't have the exact same size
7    fn copy_from_block(&mut self, block: &impl AudioBlock<S>);
8    /// Destination block will take over the size from source block.
9    /// Panics if destination block has not enough memory allocated to grow.
10    fn copy_from_block_resize(&mut self, block: &impl AudioBlock<S>);
11    /// Gives access to all samples in the block.
12    fn for_each(&mut self, f: impl FnMut(&mut S));
13    /// Gives access to all samples in the block.
14    /// This is faster than `for_each` by not checking bounds of the block.
15    /// It can be used if your algorithm does not change if wrong samples are accessed.
16    /// For example this is the case for gain, clear, etc.
17    fn for_each_including_non_visible(&mut self, f: impl FnMut(&mut S));
18    /// Gives access to all samples in the block while supplying the information
19    /// about which channel and frame number the sample is stored in.
20    fn enumerate(&mut self, f: impl FnMut(u16, usize, &mut S));
21    /// Gives access to all samples in the block while supplying the information
22    /// about which channel and frame number the sample is stored in.
23    ///
24    /// This is faster than `enumerate` by not checking bounds of the block.
25    /// It can be used if your algorithm does not change if wrong samples are accessed.
26    /// For example this is the case for applying a gain, clear, etc.
27    fn enumerate_including_non_visible(&mut self, f: impl FnMut(u16, usize, &mut S));
28    /// Sets all samples in the block to the specified value
29    fn fill_with(&mut self, sample: S);
30    /// Sets all samples in the block to the default value
31    fn clear(&mut self);
32}
33
34impl<S: Sample, B: AudioBlockMut<S>> Ops<S> for B {
35    #[nonblocking]
36    fn copy_from_block(&mut self, block: &impl AudioBlock<S>) {
37        assert_eq!(block.num_channels(), self.num_channels());
38        assert_eq!(block.num_frames(), self.num_frames());
39        for ch in 0..self.num_channels() {
40            for (sample_mut, sample) in self.channel_mut(ch).zip(block.channel(ch)) {
41                *sample_mut = *sample;
42            }
43        }
44    }
45
46    #[nonblocking]
47    fn copy_from_block_resize(&mut self, block: &impl AudioBlock<S>) {
48        assert!(block.num_channels() <= self.num_channels_allocated());
49        assert!(block.num_frames() <= self.num_frames_allocated());
50        self.resize(block.num_channels(), block.num_frames());
51
52        for ch in 0..self.num_channels() {
53            for (sample_mut, sample) in self.channel_mut(ch).zip(block.channel(ch)) {
54                *sample_mut = *sample;
55            }
56        }
57    }
58
59    #[nonblocking]
60    fn for_each(&mut self, mut f: impl FnMut(&mut S)) {
61        // below 8 channels it is faster to always go per channel
62        if self.num_channels() < 8 {
63            for channel in self.channels_mut() {
64                channel.for_each(&mut f);
65            }
66        } else {
67            match self.layout() {
68                BlockLayout::Sequential | BlockLayout::Stacked => {
69                    for channel in self.channels_mut() {
70                        channel.for_each(&mut f);
71                    }
72                }
73                BlockLayout::Interleaved => {
74                    for frame in 0..self.num_frames() {
75                        self.frame_mut(frame).for_each(&mut f);
76                    }
77                }
78            }
79        }
80    }
81
82    #[nonblocking]
83    fn for_each_including_non_visible(&mut self, mut f: impl FnMut(&mut S)) {
84        match self.layout() {
85            BlockLayout::Sequential => {
86                self.raw_data_mut(None).iter_mut().for_each(&mut f);
87            }
88            BlockLayout::Interleaved => {
89                self.raw_data_mut(None).iter_mut().for_each(&mut f);
90            }
91            BlockLayout::Stacked => {
92                for ch in 0..self.num_channels() {
93                    self.raw_data_mut(Some(ch)).iter_mut().for_each(&mut f);
94                }
95            }
96        }
97    }
98
99    #[nonblocking]
100    fn enumerate(&mut self, mut f: impl FnMut(u16, usize, &mut S)) {
101        // below 8 channels it is faster to always go per channel
102        if self.num_channels() < 8 {
103            for ch in 0..self.num_channels() {
104                self.channel_mut(ch)
105                    .enumerate()
106                    .for_each(|(frame, sample)| f(ch, frame, sample));
107            }
108        } else {
109            match self.layout() {
110                BlockLayout::Sequential | BlockLayout::Stacked => {
111                    for ch in 0..self.num_channels() {
112                        self.channel_mut(ch)
113                            .enumerate()
114                            .for_each(|(frame, sample)| f(ch, frame, sample));
115                    }
116                }
117                BlockLayout::Interleaved => {
118                    for frame in 0..self.num_frames() {
119                        self.frame_mut(frame)
120                            .enumerate()
121                            .for_each(|(ch, sample)| f(ch as u16, frame, sample));
122                    }
123                }
124            }
125        }
126    }
127
128    #[nonblocking]
129    fn enumerate_including_non_visible(&mut self, mut f: impl FnMut(u16, usize, &mut S)) {
130        match self.layout() {
131            BlockLayout::Sequential => {
132                let num_frames = self.num_frames_allocated();
133                self.raw_data_mut(None)
134                    .iter_mut()
135                    .enumerate()
136                    .for_each(|(i, sample)| {
137                        let channel = i / num_frames;
138                        let frame = i % num_frames;
139                        f(channel as u16, frame, sample)
140                    });
141            }
142            BlockLayout::Interleaved => {
143                let num_frames = self.num_frames_allocated();
144                self.raw_data_mut(None)
145                    .iter_mut()
146                    .enumerate()
147                    .for_each(|(i, sample)| {
148                        let channel = i % num_frames;
149                        let frame = i / num_frames;
150                        f(channel as u16, frame, sample)
151                    });
152            }
153            BlockLayout::Stacked => {
154                for ch in 0..self.num_channels() {
155                    self.raw_data_mut(Some(ch))
156                        .iter_mut()
157                        .enumerate()
158                        .for_each(|(frame, sample)| f(ch, frame, sample));
159                }
160            }
161        }
162    }
163
164    #[nonblocking]
165    fn fill_with(&mut self, sample: S) {
166        self.for_each_including_non_visible(|v| *v = sample);
167    }
168
169    #[nonblocking]
170    fn clear(&mut self) {
171        self.fill_with(S::default());
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use rtsan_standalone::no_sanitize_realtime;
178
179    use crate::{
180        interleaved::InterleavedViewMut,
181        sequential::{SequentialView, SequentialViewMut},
182        stacked::StackedViewMut,
183    };
184
185    use super::*;
186
187    #[test]
188    fn test_copy_from() {
189        let mut data = [0.0; 15];
190        let mut block = InterleavedViewMut::from_slice(&mut data, 3, 5);
191        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
192        block.copy_from_block_resize(&view);
193
194        assert_eq!(block.num_channels(), 2);
195        assert_eq!(block.num_frames(), 4);
196        assert_eq!(block.num_channels_allocated(), 3);
197        assert_eq!(block.num_frames_allocated(), 5);
198
199        assert_eq!(
200            block.channel(0).copied().collect::<Vec<_>>(),
201            vec![0.0, 1.0, 2.0, 3.0]
202        );
203        assert_eq!(
204            block.channel(1).copied().collect::<Vec<_>>(),
205            vec![4.0, 5.0, 6.0, 7.0]
206        );
207    }
208
209    #[test]
210    fn test_copy_from_exact() {
211        let mut data = [0.0; 8];
212        let mut block = InterleavedViewMut::from_slice(&mut data, 2, 4);
213        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
214        block.copy_from_block(&view);
215
216        assert_eq!(block.num_channels(), 2);
217        assert_eq!(block.num_frames(), 4);
218        assert_eq!(block.num_channels_allocated(), 2);
219        assert_eq!(block.num_frames_allocated(), 4);
220
221        assert_eq!(
222            block.channel(0).copied().collect::<Vec<_>>(),
223            vec![0.0, 1.0, 2.0, 3.0]
224        );
225        assert_eq!(
226            block.channel(1).copied().collect::<Vec<_>>(),
227            vec![4.0, 5.0, 6.0, 7.0]
228        );
229    }
230
231    #[test]
232    #[should_panic]
233    #[no_sanitize_realtime]
234    fn test_copy_data_wrong_channels() {
235        let mut data = [0.0; 5];
236        let mut block = InterleavedViewMut::from_slice(&mut data, 1, 5);
237        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
238        block.copy_from_block_resize(&view);
239    }
240
241    #[test]
242    #[should_panic]
243    #[no_sanitize_realtime]
244    fn test_copy_data_wrong_frames() {
245        let mut data = [0.0; 9];
246        let mut block = InterleavedViewMut::from_slice(&mut data, 3, 3);
247        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
248        block.copy_from_block(&view);
249    }
250
251    #[test]
252    #[should_panic]
253    #[no_sanitize_realtime]
254    fn test_copy_data_exact_wrong_channels() {
255        let mut data = [0.0; 12];
256        let mut block = InterleavedViewMut::from_slice(&mut data, 3, 4);
257        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
258        block.copy_from_block(&view);
259    }
260
261    #[test]
262    #[should_panic]
263    #[no_sanitize_realtime]
264    fn test_copy_data_exact_wrong_frames() {
265        let mut data = [0.0; 10];
266        let mut block = InterleavedViewMut::from_slice(&mut data, 2, 5);
267        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
268        block.copy_from_block(&view);
269    }
270
271    #[test]
272    fn test_for_each() {
273        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
274        let mut block = SequentialViewMut::from_slice(&mut data, 2, 4);
275
276        let mut i = 0;
277        let mut c_exp = 0;
278        let mut f_exp = 0;
279        block.enumerate_including_non_visible(|c, f, v| {
280            assert_eq!(c, c_exp);
281            assert_eq!(f, f_exp);
282            assert_eq!(*v, i as f32);
283            if f_exp == 3 {
284                c_exp = (c_exp + 1) % 4;
285            }
286            f_exp = (f_exp + 1) % 4;
287            i += 1;
288        });
289
290        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
291        let mut block = InterleavedViewMut::from_slice(&mut data, 2, 4);
292
293        let mut i = 0;
294        let mut f_exp = 0;
295        let mut c_exp = 0;
296        block.enumerate_including_non_visible(|c, f, v| {
297            assert_eq!(c, c_exp);
298            assert_eq!(f, f_exp);
299            assert_eq!(*v, i as f32);
300            if c_exp == 3 {
301                f_exp = (f_exp + 1) % 4;
302            }
303            c_exp = (c_exp + 1) % 4;
304            i += 1;
305        });
306
307        let mut data = [[0.0, 1.0, 2.0, 3.0], [4.0, 5.0, 6.0, 7.0]];
308        let mut block = StackedViewMut::from_slice(&mut data);
309
310        let mut i = 0;
311        let mut c_exp = 0;
312        let mut f_exp = 0;
313        block.enumerate_including_non_visible(|c, f, v| {
314            assert_eq!(c, c_exp);
315            assert_eq!(f, f_exp);
316            assert_eq!(*v, i as f32);
317            if f_exp == 3 {
318                c_exp = (c_exp + 1) % 4;
319            }
320            f_exp = (f_exp + 1) % 4;
321            i += 1;
322        });
323    }
324
325    #[test]
326    fn test_clear() {
327        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
328        let mut block = SequentialViewMut::from_slice(&mut data, 2, 4);
329
330        block.fill_with(1.0);
331
332        assert_eq!(
333            block.channel(0).copied().collect::<Vec<_>>(),
334            vec![1.0, 1.0, 1.0, 1.0]
335        );
336        assert_eq!(
337            block.channel(1).copied().collect::<Vec<_>>(),
338            vec![1.0, 1.0, 1.0, 1.0]
339        );
340
341        block.clear();
342
343        assert_eq!(
344            block.channel(0).copied().collect::<Vec<_>>(),
345            vec![0.0, 0.0, 0.0, 0.0]
346        );
347        assert_eq!(
348            block.channel(1).copied().collect::<Vec<_>>(),
349            vec![0.0, 0.0, 0.0, 0.0]
350        );
351    }
352}