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 zero
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.set_active_size(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 => self.raw_data_mut(None).iter_mut().for_each(&mut f),
86            BlockLayout::Interleaved => self.raw_data_mut(None).iter_mut().for_each(&mut f),
87            BlockLayout::Stacked => {
88                for ch in 0..self.num_channels() {
89                    self.raw_data_mut(Some(ch)).iter_mut().for_each(&mut f);
90                }
91            }
92        }
93    }
94
95    #[nonblocking]
96    fn enumerate(&mut self, mut f: impl FnMut(u16, usize, &mut S)) {
97        // below 8 channels it is faster to always go per channel
98        if self.num_channels() < 8 {
99            for ch in 0..self.num_channels() {
100                self.channel_mut(ch)
101                    .enumerate()
102                    .for_each(|(frame, sample)| f(ch, frame, sample));
103            }
104        } else {
105            match self.layout() {
106                BlockLayout::Sequential | BlockLayout::Stacked => {
107                    for ch in 0..self.num_channels() {
108                        self.channel_mut(ch)
109                            .enumerate()
110                            .for_each(|(frame, sample)| f(ch, frame, sample));
111                    }
112                }
113                BlockLayout::Interleaved => {
114                    for frame in 0..self.num_frames() {
115                        self.frame_mut(frame)
116                            .enumerate()
117                            .for_each(|(ch, sample)| f(ch as u16, frame, sample));
118                    }
119                }
120            }
121        }
122    }
123
124    #[nonblocking]
125    fn enumerate_including_non_visible(&mut self, mut f: impl FnMut(u16, usize, &mut S)) {
126        match self.layout() {
127            BlockLayout::Sequential => {
128                let num_frames = self.num_frames_allocated();
129                self.raw_data_mut(None)
130                    .iter_mut()
131                    .enumerate()
132                    .for_each(|(i, sample)| {
133                        let channel = i / num_frames;
134                        let frame = i % num_frames;
135                        f(channel as u16, frame, sample)
136                    });
137            }
138            BlockLayout::Interleaved => {
139                let num_frames = self.num_frames_allocated();
140                self.raw_data_mut(None)
141                    .iter_mut()
142                    .enumerate()
143                    .for_each(|(i, sample)| {
144                        let channel = i % num_frames;
145                        let frame = i / num_frames;
146                        f(channel as u16, frame, sample)
147                    });
148            }
149            BlockLayout::Stacked => {
150                for ch in 0..self.num_channels() {
151                    self.raw_data_mut(Some(ch))
152                        .iter_mut()
153                        .enumerate()
154                        .for_each(|(frame, sample)| f(ch, frame, sample));
155                }
156            }
157        }
158    }
159
160    #[nonblocking]
161    fn fill_with(&mut self, sample: S) {
162        self.for_each_including_non_visible(|v| *v = sample);
163    }
164
165    #[nonblocking]
166    fn clear(&mut self) {
167        self.fill_with(S::zero());
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use rtsan_standalone::no_sanitize_realtime;
174
175    use crate::{
176        interleaved::InterleavedViewMut,
177        sequential::{SequentialView, SequentialViewMut},
178        stacked::StackedViewMut,
179    };
180
181    use super::*;
182
183    #[test]
184    fn test_copy_from() {
185        let mut data = [0.0; 15];
186        let mut block = InterleavedViewMut::from_slice(&mut data, 3, 5);
187        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
188        block.copy_from_block_resize(&view);
189
190        assert_eq!(block.num_channels(), 2);
191        assert_eq!(block.num_frames(), 4);
192        assert_eq!(block.num_channels_allocated(), 3);
193        assert_eq!(block.num_frames_allocated(), 5);
194
195        assert_eq!(
196            block.channel(0).copied().collect::<Vec<_>>(),
197            vec![0.0, 1.0, 2.0, 3.0]
198        );
199        assert_eq!(
200            block.channel(1).copied().collect::<Vec<_>>(),
201            vec![4.0, 5.0, 6.0, 7.0]
202        );
203    }
204
205    #[test]
206    fn test_copy_from_exact() {
207        let mut data = [0.0; 8];
208        let mut block = InterleavedViewMut::from_slice(&mut data, 2, 4);
209        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
210        block.copy_from_block(&view);
211
212        assert_eq!(block.num_channels(), 2);
213        assert_eq!(block.num_frames(), 4);
214        assert_eq!(block.num_channels_allocated(), 2);
215        assert_eq!(block.num_frames_allocated(), 4);
216
217        assert_eq!(
218            block.channel(0).copied().collect::<Vec<_>>(),
219            vec![0.0, 1.0, 2.0, 3.0]
220        );
221        assert_eq!(
222            block.channel(1).copied().collect::<Vec<_>>(),
223            vec![4.0, 5.0, 6.0, 7.0]
224        );
225    }
226
227    #[test]
228    #[should_panic]
229    #[no_sanitize_realtime]
230    fn test_copy_data_wrong_channels() {
231        let mut data = [0.0; 5];
232        let mut block = InterleavedViewMut::from_slice(&mut data, 1, 5);
233        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
234        block.copy_from_block_resize(&view);
235    }
236
237    #[test]
238    #[should_panic]
239    #[no_sanitize_realtime]
240    fn test_copy_data_wrong_frames() {
241        let mut data = [0.0; 9];
242        let mut block = InterleavedViewMut::from_slice(&mut data, 3, 3);
243        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
244        block.copy_from_block(&view);
245    }
246
247    #[test]
248    #[should_panic]
249    #[no_sanitize_realtime]
250    fn test_copy_data_exact_wrong_channels() {
251        let mut data = [0.0; 12];
252        let mut block = InterleavedViewMut::from_slice(&mut data, 3, 4);
253        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
254        block.copy_from_block(&view);
255    }
256
257    #[test]
258    #[should_panic]
259    #[no_sanitize_realtime]
260    fn test_copy_data_exact_wrong_frames() {
261        let mut data = [0.0; 10];
262        let mut block = InterleavedViewMut::from_slice(&mut data, 2, 5);
263        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2, 4);
264        block.copy_from_block(&view);
265    }
266
267    #[test]
268    fn test_for_each() {
269        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
270        let mut block = SequentialViewMut::from_slice(&mut data, 2, 4);
271
272        let mut i = 0;
273        let mut c_exp = 0;
274        let mut f_exp = 0;
275        block.enumerate_including_non_visible(|c, f, v| {
276            assert_eq!(c, c_exp);
277            assert_eq!(f, f_exp);
278            assert_eq!(*v, i as f32);
279            if f_exp == 3 {
280                c_exp = (c_exp + 1) % 4;
281            }
282            f_exp = (f_exp + 1) % 4;
283            i += 1;
284        });
285
286        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
287        let mut block = InterleavedViewMut::from_slice(&mut data, 2, 4);
288
289        let mut i = 0;
290        let mut f_exp = 0;
291        let mut c_exp = 0;
292        block.enumerate_including_non_visible(|c, f, v| {
293            assert_eq!(c, c_exp);
294            assert_eq!(f, f_exp);
295            assert_eq!(*v, i as f32);
296            if c_exp == 3 {
297                f_exp = (f_exp + 1) % 4;
298            }
299            c_exp = (c_exp + 1) % 4;
300            i += 1;
301        });
302
303        let mut data = [[0.0, 1.0, 2.0, 3.0], [4.0, 5.0, 6.0, 7.0]];
304        let mut block = StackedViewMut::from_slice(&mut data);
305
306        let mut i = 0;
307        let mut c_exp = 0;
308        let mut f_exp = 0;
309        block.enumerate_including_non_visible(|c, f, v| {
310            assert_eq!(c, c_exp);
311            assert_eq!(f, f_exp);
312            assert_eq!(*v, i as f32);
313            if f_exp == 3 {
314                c_exp = (c_exp + 1) % 4;
315            }
316            f_exp = (f_exp + 1) % 4;
317            i += 1;
318        });
319    }
320
321    #[test]
322    fn test_clear() {
323        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
324        let mut block = SequentialViewMut::from_slice(&mut data, 2, 4);
325
326        block.fill_with(1.0);
327
328        assert_eq!(
329            block.channel(0).copied().collect::<Vec<_>>(),
330            vec![1.0, 1.0, 1.0, 1.0]
331        );
332        assert_eq!(
333            block.channel(1).copied().collect::<Vec<_>>(),
334            vec![1.0, 1.0, 1.0, 1.0]
335        );
336
337        block.clear();
338
339        assert_eq!(
340            block.channel(0).copied().collect::<Vec<_>>(),
341            vec![0.0, 0.0, 0.0, 0.0]
342        );
343        assert_eq!(
344            block.channel(1).copied().collect::<Vec<_>>(),
345            vec![0.0, 0.0, 0.0, 0.0]
346        );
347    }
348}