Skip to main content

audio_blocks/
ops.rs

1use rtsan_standalone::nonblocking;
2
3use crate::{
4    AudioBlock, AudioBlockMut, BlockLayout, Sample,
5    mono::{MonoView, MonoViewMut},
6};
7
8pub trait AudioBlockOps<S: Sample> {
9    /// Mix all channels to mono by averaging them.
10    /// Only processes `min(src_frames, dst_frames)` frames.
11    /// Returns `None` if all frames were processed (exact match),
12    /// or `Some(frames_processed)` if a partial mix occurred.
13    fn mix_to_mono(&self, dest: &mut MonoViewMut<S>) -> Option<usize>
14    where
15        S: std::ops::AddAssign + std::ops::Div<Output = S> + From<u16>;
16    /// Mix all channels to mono by averaging them.
17    /// Panics if source and destination don't have the same number of frames.
18    fn mix_to_mono_exact(&self, dest: &mut MonoViewMut<S>)
19    where
20        S: std::ops::AddAssign + std::ops::Div<Output = S> + From<u16>;
21    /// Copy a specific channel to a mono buffer.
22    /// Only copies `min(src_frames, dst_frames)` frames.
23    /// Returns `None` if all frames were copied (exact match),
24    /// or `Some(frames_copied)` if a partial copy occurred.
25    fn copy_channel_to_mono(&self, dest: &mut MonoViewMut<S>, channel: u16) -> Option<usize>;
26    /// Copy a specific channel to a mono buffer.
27    /// Panics if source and destination don't have the same number of frames.
28    fn copy_channel_to_mono_exact(&self, dest: &mut MonoViewMut<S>, channel: u16);
29}
30
31pub trait AudioBlockOpsMut<S: Sample> {
32    /// Copy samples from source block into destination.
33    /// Only copies `min(src, dst)` channels and frames.
34    /// Returns `None` if the entire block was copied (exact match),
35    /// or `Some((channels_copied, frames_copied))` if a partial copy occurred.
36    /// Never panics - safely handles mismatched block sizes.
37    fn copy_from_block(&mut self, block: &impl AudioBlock<S>) -> Option<(u16, usize)>;
38    /// Copy samples from source block, requiring exact size match.
39    /// Panics if source and destination don't have identical channels and frames.
40    fn copy_from_block_exact(&mut self, block: &impl AudioBlock<S>);
41    /// Copy a mono block to all channels of this block.
42    /// Only copies `min(src_frames, dst_frames)` frames.
43    /// Returns `None` if all frames were copied (exact match),
44    /// or `Some(frames_copied)` if a partial copy occurred.
45    fn copy_mono_to_all_channels(&mut self, mono: &MonoView<S>) -> Option<usize>;
46    /// Copy a mono block to all channels of this block.
47    /// Panics if blocks don't have the same number of frames.
48    fn copy_mono_to_all_channels_exact(&mut self, mono: &MonoView<S>);
49    /// Gives access to all samples in the block.
50    fn for_each(&mut self, f: impl FnMut(&mut S));
51    /// Gives access to all samples in the block while supplying the information
52    /// about which channel and frame number the sample is stored in.
53    fn enumerate(&mut self, f: impl FnMut(u16, usize, &mut S));
54    /// Iterate over all allocated samples using fast linear buffer iteration.
55    ///
56    /// This iterates over `num_frames_allocated()` samples, not just `num_frames()`.
57    /// It uses cache-friendly linear access over the underlying storage, which is
58    /// significantly faster than [`for_each`](AudioBlockOpsMut::for_each) for large buffers when the visible
59    /// window is close to the allocated size.
60    ///
61    /// # Performance Note
62    ///
63    /// Only use this when `num_frames()` is close to `num_frames_allocated()`.
64    /// If the buffer has been resized dramatically (e.g., `set_visible()` to half
65    /// the allocation), [`for_each`](AudioBlockOpsMut::for_each) will be faster as it respects the visible window.
66    fn for_each_allocated(&mut self, f: impl FnMut(&mut S));
67    /// Iterate over all allocated samples with indices using fast linear buffer iteration.
68    ///
69    /// Like [`for_each_allocated`](AudioBlockOpsMut::for_each_allocated), this iterates over the entire allocated buffer
70    /// for cache-friendly linear access. Only faster than [`enumerate`](AudioBlockOpsMut::enumerate) when the
71    /// visible window is close to the allocated size.
72    fn enumerate_allocated(&mut self, f: impl FnMut(u16, usize, &mut S));
73    /// Sets all samples in the block to the specified value.
74    /// Iterates over the entire allocated buffer for efficiency.
75    fn fill_with(&mut self, sample: S);
76    /// Sets all samples in the block to the default value (zero for numeric types).
77    /// Iterates over the entire allocated buffer for efficiency.
78    fn clear(&mut self)
79    where
80        S: Default;
81    /// Applies gain to all samples by multiplying each sample.
82    /// Iterates over the entire allocated buffer for efficiency.
83    fn gain(&mut self, gain: S)
84    where
85        S: std::ops::Mul<Output = S> + Copy;
86}
87
88impl<S: Sample, B: AudioBlock<S>> AudioBlockOps<S> for B {
89    #[nonblocking]
90    fn mix_to_mono(&self, dest: &mut MonoViewMut<S>) -> Option<usize>
91    where
92        S: std::ops::AddAssign + std::ops::Div<Output = S> + From<u16>,
93    {
94        let frames = self.num_frames().min(dest.num_frames());
95        let num_channels = S::from(self.num_channels());
96
97        for frame in 0..frames {
98            let mut sum = *self.frame_iter(frame).next().unwrap();
99            for sample in self.frame_iter(frame).skip(1) {
100                sum += *sample;
101            }
102            *dest.sample_mut(frame) = sum / num_channels;
103        }
104
105        if frames == self.num_frames() {
106            None
107        } else {
108            Some(frames)
109        }
110    }
111
112    #[nonblocking]
113    fn mix_to_mono_exact(&self, dest: &mut MonoViewMut<S>)
114    where
115        S: std::ops::AddAssign + std::ops::Div<Output = S> + From<u16>,
116    {
117        assert_eq!(self.num_frames(), dest.num_frames());
118
119        let num_channels = S::from(self.num_channels());
120
121        for frame in 0..self.num_frames() {
122            let mut sum = *self.frame_iter(frame).next().unwrap();
123            for sample in self.frame_iter(frame).skip(1) {
124                sum += *sample;
125            }
126            *dest.sample_mut(frame) = sum / num_channels;
127        }
128    }
129
130    #[nonblocking]
131    fn copy_channel_to_mono(&self, dest: &mut MonoViewMut<S>, channel: u16) -> Option<usize> {
132        let frames = self.num_frames().min(dest.num_frames());
133        for (o, i) in dest
134            .raw_data_mut()
135            .iter_mut()
136            .take(frames)
137            .zip(self.channel_iter(channel).take(frames))
138        {
139            *o = *i;
140        }
141
142        if frames == self.num_frames() {
143            None
144        } else {
145            Some(frames)
146        }
147    }
148
149    #[nonblocking]
150    fn copy_channel_to_mono_exact(&self, dest: &mut MonoViewMut<S>, channel: u16) {
151        assert_eq!(self.num_frames(), dest.num_frames());
152        for (o, i) in dest
153            .raw_data_mut()
154            .iter_mut()
155            .zip(self.channel_iter(channel))
156        {
157            *o = *i;
158        }
159    }
160}
161
162impl<S: Sample, B: AudioBlockMut<S>> AudioBlockOpsMut<S> for B {
163    #[nonblocking]
164    fn copy_from_block(&mut self, block: &impl AudioBlock<S>) -> Option<(u16, usize)> {
165        let channels = self.num_channels().min(block.num_channels());
166        let frames = self.num_frames().min(block.num_frames());
167
168        for (this_channel, other_channel) in self.channels_iter_mut().zip(block.channels_iter()) {
169            for (sample_mut, sample) in this_channel.zip(other_channel) {
170                *sample_mut = *sample;
171            }
172        }
173
174        if channels == block.num_channels() && frames == block.num_frames() {
175            None
176        } else {
177            Some((channels, frames))
178        }
179    }
180
181    #[nonblocking]
182    fn copy_from_block_exact(&mut self, block: &impl AudioBlock<S>) {
183        assert_eq!(block.num_channels(), self.num_channels());
184        assert_eq!(block.num_frames(), self.num_frames());
185        for ch in 0..self.num_channels() {
186            for (sample_mut, sample) in self.channel_iter_mut(ch).zip(block.channel_iter(ch)) {
187                *sample_mut = *sample;
188            }
189        }
190    }
191
192    #[nonblocking]
193    fn copy_mono_to_all_channels(&mut self, mono: &MonoView<S>) -> Option<usize> {
194        let frames = mono.num_frames().min(self.num_frames());
195        for channel in self.channels_iter_mut() {
196            for (sample_mut, sample) in channel.take(frames).zip(mono.samples().iter().take(frames))
197            {
198                *sample_mut = *sample;
199            }
200        }
201
202        if frames == mono.num_frames() {
203            None
204        } else {
205            Some(frames)
206        }
207    }
208
209    #[nonblocking]
210    fn copy_mono_to_all_channels_exact(&mut self, mono: &MonoView<S>) {
211        assert_eq!(mono.num_frames(), self.num_frames());
212        for channel in self.channels_iter_mut() {
213            for (sample_mut, sample) in channel.zip(mono.samples()) {
214                *sample_mut = *sample;
215            }
216        }
217    }
218
219    #[nonblocking]
220    fn for_each(&mut self, mut f: impl FnMut(&mut S)) {
221        // below 8 channels it is faster to always go per channel
222        if self.num_channels() < 8 {
223            for channel in self.channels_iter_mut() {
224                channel.for_each(&mut f);
225            }
226        } else {
227            match self.layout() {
228                BlockLayout::Sequential | BlockLayout::Planar => {
229                    for channel in self.channels_iter_mut() {
230                        channel.for_each(&mut f);
231                    }
232                }
233                BlockLayout::Interleaved => {
234                    for frame in 0..self.num_frames() {
235                        self.frame_iter_mut(frame).for_each(&mut f);
236                    }
237                }
238            }
239        }
240    }
241
242    #[nonblocking]
243    fn enumerate(&mut self, mut f: impl FnMut(u16, usize, &mut S)) {
244        // below 8 channels it is faster to always go per channel
245        if self.num_channels() < 8 {
246            for (ch, channel) in self.channels_iter_mut().enumerate() {
247                for (fr, sample) in channel.enumerate() {
248                    f(ch as u16, fr, sample)
249                }
250            }
251        } else {
252            match self.layout() {
253                BlockLayout::Interleaved => {
254                    for (fr, frame) in self.frames_iter_mut().enumerate() {
255                        for (ch, sample) in frame.enumerate() {
256                            f(ch as u16, fr, sample)
257                        }
258                    }
259                }
260                BlockLayout::Planar | BlockLayout::Sequential => {
261                    for (ch, channel) in self.channels_iter_mut().enumerate() {
262                        for (fr, sample) in channel.enumerate() {
263                            f(ch as u16, fr, sample)
264                        }
265                    }
266                }
267            }
268        }
269    }
270
271    #[nonblocking]
272    fn for_each_allocated(&mut self, mut f: impl FnMut(&mut S)) {
273        match self.layout() {
274            BlockLayout::Interleaved => self
275                .as_interleaved_view_mut()
276                .expect("Layout is interleaved")
277                .raw_data_mut()
278                .iter_mut()
279                .for_each(&mut f),
280            BlockLayout::Planar => self
281                .as_planar_view_mut()
282                .expect("Layout is planar")
283                .raw_data_mut()
284                .iter_mut()
285                .for_each(|c| c.as_mut().iter_mut().for_each(&mut f)),
286            BlockLayout::Sequential => self
287                .as_sequential_view_mut()
288                .expect("Layout is sequential")
289                .raw_data_mut()
290                .iter_mut()
291                .for_each(&mut f),
292        }
293    }
294
295    #[nonblocking]
296    fn enumerate_allocated(&mut self, mut f: impl FnMut(u16, usize, &mut S)) {
297        match self.layout() {
298            BlockLayout::Interleaved => {
299                let num_frames = self.num_frames_allocated();
300                self.as_interleaved_view_mut()
301                    .expect("Layout is interleaved")
302                    .raw_data_mut()
303                    .iter_mut()
304                    .enumerate()
305                    .for_each(|(i, sample)| {
306                        let channel = i % num_frames;
307                        let frame = i / num_frames;
308                        f(channel as u16, frame, sample)
309                    });
310            }
311            BlockLayout::Planar => self
312                .as_planar_view_mut()
313                .expect("Layout is planar")
314                .raw_data_mut()
315                .iter_mut()
316                .enumerate()
317                .for_each(|(ch, v)| {
318                    v.as_mut()
319                        .iter_mut()
320                        .enumerate()
321                        .for_each(|(frame, sample)| f(ch as u16, frame, sample))
322                }),
323            BlockLayout::Sequential => {
324                let num_frames = self.num_frames_allocated();
325                self.as_sequential_view_mut()
326                    .expect("Layout is sequential")
327                    .raw_data_mut()
328                    .iter_mut()
329                    .enumerate()
330                    .for_each(|(i, sample)| {
331                        let channel = i / num_frames;
332                        let frame = i % num_frames;
333                        f(channel as u16, frame, sample)
334                    });
335            }
336        }
337    }
338
339    #[nonblocking]
340    fn fill_with(&mut self, sample: S) {
341        self.for_each_allocated(|v| *v = sample);
342    }
343
344    #[nonblocking]
345    fn clear(&mut self)
346    where
347        S: Default,
348    {
349        self.fill_with(S::default());
350    }
351
352    #[nonblocking]
353    fn gain(&mut self, gain: S)
354    where
355        S: std::ops::Mul<Output = S> + Copy,
356    {
357        self.for_each_allocated(|v| *v = *v * gain);
358    }
359}
360
361#[cfg(test)]
362mod tests {
363    use rtsan_standalone::no_sanitize_realtime;
364
365    use crate::{
366        interleaved::InterleavedViewMut,
367        sequential::{SequentialView, SequentialViewMut},
368    };
369
370    use super::*;
371
372    #[test]
373    fn test_copy_from_block_dest_larger() {
374        // Destination is larger than source - source is fully copied
375        let mut data = [0.0; 15];
376        let mut block = InterleavedViewMut::from_slice(&mut data, 3);
377        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2);
378
379        // Source fits entirely, so returns None (exact match from source perspective)
380        let result = block.copy_from_block(&view);
381        assert_eq!(result, None);
382
383        // Buffer size should NOT change
384        assert_eq!(block.num_channels(), 3);
385        assert_eq!(block.num_frames(), 5);
386
387        // First 2 channels should have the data
388        // Only check first 4 frames that were copied
389        assert_eq!(
390            block.channel_iter(0).take(4).copied().collect::<Vec<_>>(),
391            vec![0.0, 1.0, 2.0, 3.0]
392        );
393        assert_eq!(
394            block.channel_iter(1).take(4).copied().collect::<Vec<_>>(),
395            vec![4.0, 5.0, 6.0, 7.0]
396        );
397    }
398
399    #[test]
400    fn test_copy_from_block_exact_match_returns_none() {
401        // Source and destination are the same size - should return None
402        let mut data = [0.0; 8];
403        let mut block = InterleavedViewMut::from_slice(&mut data, 2);
404        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2);
405
406        let result = block.copy_from_block(&view);
407        assert_eq!(result, None); // Exact match returns None
408    }
409
410    #[test]
411    fn test_copy_from_block_clamps_to_dest_size() {
412        // Source is larger than destination - partial copy
413        let mut data = [0.0; 4]; // 2 channels, 2 frames
414        let mut block = SequentialViewMut::from_slice(&mut data, 2);
415        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2);
416
417        let result = block.copy_from_block(&view);
418        assert_eq!(result, Some((2, 2))); // Only 2 frames copied
419        // Only first 2 frames copied from each channel
420        assert_eq!(
421            block.channel_iter(0).copied().collect::<Vec<_>>(),
422            vec![0.0, 1.0]
423        );
424        assert_eq!(
425            block.channel_iter(1).copied().collect::<Vec<_>>(),
426            vec![4.0, 5.0]
427        );
428    }
429
430    #[test]
431    fn test_copy_from_block_source_larger_channels() {
432        // Source has more channels than destination
433        let mut data = [0.0; 4]; // 1 channel, 4 frames
434        let mut block = SequentialViewMut::from_slice(&mut data, 1);
435        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2);
436
437        let result = block.copy_from_block(&view);
438        assert_eq!(result, Some((1, 4))); // Only 1 channel copied
439
440        assert_eq!(
441            block.channel_iter(0).copied().collect::<Vec<_>>(),
442            vec![0.0, 1.0, 2.0, 3.0]
443        );
444    }
445
446    #[test]
447    fn test_copy_from_block_exact() {
448        let mut data = [0.0; 8];
449        let mut block = InterleavedViewMut::from_slice(&mut data, 2);
450        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2);
451        block.copy_from_block_exact(&view);
452
453        assert_eq!(block.num_channels(), 2);
454        assert_eq!(block.num_frames(), 4);
455
456        // First 2 channels should have the data
457        assert_eq!(
458            block.channel_iter(0).take(4).copied().collect::<Vec<_>>(),
459            vec![0.0, 1.0, 2.0, 3.0]
460        );
461        assert_eq!(
462            block.channel_iter(1).take(4).copied().collect::<Vec<_>>(),
463            vec![4.0, 5.0, 6.0, 7.0]
464        );
465        // Third channel should still be zeros (only visible frames matter for iterator)
466        // Note: channel_iter respects num_visible, so we check allocated directly
467    }
468
469    #[test]
470    #[should_panic]
471    #[no_sanitize_realtime]
472    fn test_copy_from_block_exact_wrong_channels() {
473        let mut data = [0.0; 12];
474        let mut block = InterleavedViewMut::from_slice(&mut data, 3);
475        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2);
476        block.copy_from_block_exact(&view);
477    }
478
479    #[test]
480    #[should_panic]
481    #[no_sanitize_realtime]
482    fn test_copy_from_block_exact_wrong_frames() {
483        let mut data = [0.0; 10];
484        let mut block = InterleavedViewMut::from_slice(&mut data, 2);
485        let view = SequentialView::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], 2);
486        block.copy_from_block_exact(&view);
487    }
488
489    #[test]
490    fn test_for_each() {
491        // Test that for_each processes all visible samples
492        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
493        let mut block = SequentialViewMut::from_slice(&mut data, 2);
494
495        let mut count = 0;
496        block.for_each(|v| {
497            *v *= 2.0;
498            count += 1;
499        });
500        assert_eq!(count, 8); // All 8 samples processed
501        assert_eq!(data, [0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0]);
502
503        // Test enumerate provides valid channel/frame indices
504        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
505        let mut block = InterleavedViewMut::from_slice(&mut data, 2);
506
507        let mut seen = Vec::with_capacity(8);
508        block.enumerate(|c, f, v| {
509            seen.push((c, f, *v));
510        });
511
512        // Should have seen all 8 samples
513        assert_eq!(seen.len(), 8);
514
515        // Verify each sample appears exactly once with valid indices
516        let mut values: Vec<f32> = seen.iter().map(|(_, _, v)| *v).collect();
517        values.sort_by(|a, b| a.partial_cmp(b).unwrap());
518        assert_eq!(values, vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]);
519
520        // Verify channel indices are valid (0 or 1 for 2-channel block)
521        for (c, _, _) in &seen {
522            assert!(*c == 0 || *c == 1);
523        }
524
525        // Verify frame indices are valid (0-3 for 4-frame block)
526        for (_, f, _) in &seen {
527            assert!(*f < 4);
528        }
529    }
530
531    #[test]
532    fn test_for_each_allocated() {
533        // Test that for_each_allocated iterates over the entire allocated buffer
534        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
535        let mut block = SequentialViewMut::from_slice(&mut data, 2);
536
537        // Resize to half, but for_each_allocated should still process all
538        block.set_visible(2, 2);
539
540        let mut count = 0;
541        block.for_each_allocated(|v| {
542            *v *= 2.0;
543            count += 1;
544        });
545
546        // Should have processed all 8 samples (4 frames * 2 channels), not just 4
547        assert_eq!(count, 8);
548        // All values should be doubled
549        assert_eq!(data, [0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0]);
550    }
551
552    #[test]
553    fn test_enumerate_allocated() {
554        // Test that enumerate_allocated provides correct indices for entire buffer
555        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
556        let mut block = SequentialViewMut::from_slice(&mut data, 2);
557
558        // Resize to half
559        block.set_visible(2, 2);
560
561        let mut seen = Vec::with_capacity(8);
562        block.enumerate_allocated(|c, f, v| {
563            seen.push((c, f, *v));
564            *v = 0.0;
565        });
566
567        // Should have seen all 8 samples with correct (channel, frame) indices
568        assert_eq!(seen.len(), 8);
569        assert_eq!(seen[0], (0, 0, 0.0));
570        assert_eq!(seen[1], (0, 1, 1.0));
571        assert_eq!(seen[2], (0, 2, 2.0));
572        assert_eq!(seen[3], (0, 3, 3.0));
573        assert_eq!(seen[4], (1, 0, 4.0));
574        assert_eq!(seen[5], (1, 1, 5.0));
575        assert_eq!(seen[6], (1, 2, 6.0));
576        assert_eq!(seen[7], (1, 3, 7.0));
577
578        // All values should be zeroed
579        assert_eq!(data, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
580    }
581
582    #[test]
583    fn test_clear() {
584        let mut data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0];
585        let mut block = SequentialViewMut::from_slice(&mut data, 2);
586
587        block.fill_with(1.0);
588
589        assert_eq!(
590            block.channel_iter(0).copied().collect::<Vec<_>>(),
591            vec![1.0, 1.0, 1.0, 1.0]
592        );
593        assert_eq!(
594            block.channel_iter(1).copied().collect::<Vec<_>>(),
595            vec![1.0, 1.0, 1.0, 1.0]
596        );
597
598        block.clear();
599
600        assert_eq!(
601            block.channel_iter(0).copied().collect::<Vec<_>>(),
602            vec![0.0, 0.0, 0.0, 0.0]
603        );
604        assert_eq!(
605            block.channel_iter(1).copied().collect::<Vec<_>>(),
606            vec![0.0, 0.0, 0.0, 0.0]
607        );
608    }
609
610    #[test]
611    fn test_mix_to_mono() {
612        use crate::mono::MonoViewMut;
613
614        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
615        let block = SequentialView::from_slice(&data, 2);
616
617        let mut mono_data = [0.0; 4];
618        let mut mono = MonoViewMut::from_slice(&mut mono_data);
619
620        block.mix_to_mono(&mut mono);
621
622        assert_eq!(mono.num_frames(), 4);
623        assert_eq!(
624            mono.samples().iter().copied().collect::<Vec<_>>(),
625            vec![3.0, 4.0, 5.0, 6.0] // (1+5)/2, (2+6)/2, (3+7)/2, (4+8)/2
626        );
627    }
628
629    #[test]
630    fn test_copy_mono_to_all_channels() {
631        use crate::mono::MonoView;
632
633        let mono_data = [1.0, 2.0, 3.0, 4.0];
634        let mono = MonoView::from_slice(&mono_data);
635
636        let mut data = [0.0; 12];
637        let mut block = SequentialViewMut::from_slice(&mut data, 3);
638
639        block.copy_mono_to_all_channels(&mono);
640
641        assert_eq!(
642            block.channel_iter(0).copied().collect::<Vec<_>>(),
643            vec![1.0, 2.0, 3.0, 4.0]
644        );
645        assert_eq!(
646            block.channel_iter(1).copied().collect::<Vec<_>>(),
647            vec![1.0, 2.0, 3.0, 4.0]
648        );
649        assert_eq!(
650            block.channel_iter(2).copied().collect::<Vec<_>>(),
651            vec![1.0, 2.0, 3.0, 4.0]
652        );
653    }
654
655    #[test]
656    fn test_mix_to_mono_flexible_dest_smaller() {
657        use crate::mono::MonoViewMut;
658
659        // Source has 4 frames, destination has 2 frames
660        // Should only process 2 frames, returns Some(frames_processed)
661        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
662        let block = SequentialView::from_slice(&data, 2);
663
664        let mut mono_data = [0.0; 2];
665        let mut mono = MonoViewMut::from_slice(&mut mono_data);
666
667        let result = block.mix_to_mono(&mut mono);
668        assert_eq!(result, Some(2)); // Partial mix
669
670        assert_eq!(mono.num_frames(), 2);
671        assert_eq!(
672            mono.samples().iter().copied().collect::<Vec<_>>(),
673            vec![3.0, 4.0] // (1+5)/2, (2+6)/2 - only first 2 frames
674        );
675    }
676
677    #[test]
678    fn test_mix_to_mono_flexible_self_smaller() {
679        use crate::mono::MonoViewMut;
680
681        // Source has 2 frames, destination has 4 frames
682        // Should only process 2 frames, returns None (exact match for source)
683        let data = [1.0, 2.0, 3.0, 4.0];
684        let block = SequentialView::from_slice(&data, 2);
685
686        let mut mono_data = [99.0; 4];
687        let mut mono = MonoViewMut::from_slice(&mut mono_data);
688
689        let result = block.mix_to_mono(&mut mono);
690        assert_eq!(result, None); // Source was fully processed
691
692        assert_eq!(mono.num_frames(), 4);
693        // Only first 2 frames should be mixed
694        assert_eq!(
695            mono.samples().iter().copied().collect::<Vec<_>>(),
696            vec![2.0, 3.0, 99.0, 99.0] // (1+3)/2, (2+4)/2, then unchanged
697        );
698    }
699
700    #[test]
701    fn test_mix_to_mono_exact() {
702        use crate::mono::MonoViewMut;
703
704        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
705        let block = SequentialView::from_slice(&data, 2);
706
707        let mut mono_data = [0.0; 4];
708        let mut mono = MonoViewMut::from_slice(&mut mono_data);
709
710        block.mix_to_mono_exact(&mut mono);
711
712        assert_eq!(mono.num_frames(), 4);
713        assert_eq!(
714            mono.samples().iter().copied().collect::<Vec<_>>(),
715            vec![3.0, 4.0, 5.0, 6.0] // (1+5)/2, (2+6)/2, (3+7)/2, (4+8)/2
716        );
717    }
718
719    #[test]
720    #[should_panic]
721    #[no_sanitize_realtime]
722    fn test_mix_to_mono_exact_wrong_frames() {
723        use crate::mono::MonoViewMut;
724
725        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
726        let block = SequentialView::from_slice(&data, 2);
727
728        let mut mono_data = [0.0; 2]; // Wrong size - only 2 frames instead of 4
729        let mut mono = MonoViewMut::from_slice(&mut mono_data);
730
731        block.mix_to_mono_exact(&mut mono);
732    }
733
734    #[test]
735    fn test_copy_channel_to_mono_flexible_dest_smaller() {
736        use crate::mono::MonoViewMut;
737
738        // Source has 4 frames, destination has 2 frames
739        // Should only copy 2 frames, returns Some(frames_copied)
740        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
741        let block = SequentialView::from_slice(&data, 2);
742
743        let mut mono_data = [0.0; 2];
744        let mut mono = MonoViewMut::from_slice(&mut mono_data);
745
746        let result = block.copy_channel_to_mono(&mut mono, 0);
747        assert_eq!(result, Some(2)); // Partial copy
748
749        assert_eq!(mono.num_frames(), 2);
750        assert_eq!(
751            mono.samples().iter().copied().collect::<Vec<_>>(),
752            vec![1.0, 2.0] // Only first 2 frames from channel 0
753        );
754    }
755
756    #[test]
757    fn test_copy_channel_to_mono_flexible_self_smaller() {
758        use crate::mono::MonoViewMut;
759
760        // Source has 2 frames, destination has 4 frames allocated
761        // Should only copy 2 frames, returns None (source fully copied)
762        let data = [1.0, 2.0, 3.0, 4.0];
763        let block = SequentialView::from_slice(&data, 2);
764
765        let mut mono_data = [0.0; 4];
766        let mut mono = MonoViewMut::from_slice(&mut mono_data);
767
768        let result = block.copy_channel_to_mono(&mut mono, 1);
769        assert_eq!(result, None); // Source fully copied
770
771        assert_eq!(mono.num_frames(), 4);
772        // Only first 2 frames should be copied from channel 1
773        assert_eq!(
774            mono.samples().iter().copied().collect::<Vec<_>>(),
775            vec![3.0, 4.0, 0.0, 0.0]
776        );
777    }
778
779    #[test]
780    fn test_copy_channel_to_mono_exact_match_returns_none() {
781        use crate::mono::MonoViewMut;
782
783        // Source and destination have the same size
784        // Should copy all frames and return None
785        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
786        let block = SequentialView::from_slice(&data, 2);
787
788        let mut mono_data = [0.0; 4];
789        let mut mono = MonoViewMut::from_slice(&mut mono_data);
790
791        let result = block.copy_channel_to_mono(&mut mono, 0);
792        assert_eq!(result, None); // Exact match
793
794        assert_eq!(
795            mono.samples().iter().copied().collect::<Vec<_>>(),
796            vec![1.0, 2.0, 3.0, 4.0]
797        );
798    }
799
800    #[test]
801    fn test_copy_channel_to_mono_exact() {
802        use crate::mono::MonoViewMut;
803
804        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
805        let block = SequentialView::from_slice(&data, 2);
806
807        let mut mono_data = [0.0; 4];
808        let mut mono = MonoViewMut::from_slice(&mut mono_data);
809
810        block.copy_channel_to_mono_exact(&mut mono, 1);
811
812        assert_eq!(
813            mono.samples().iter().copied().collect::<Vec<_>>(),
814            vec![5.0, 6.0, 7.0, 8.0]
815        );
816    }
817
818    #[test]
819    #[should_panic]
820    #[no_sanitize_realtime]
821    fn test_copy_channel_to_mono_exact_wrong_frames() {
822        use crate::mono::MonoViewMut;
823
824        let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
825        let block = SequentialView::from_slice(&data, 2);
826
827        let mut mono_data = [0.0; 2]; // Wrong size
828        let mut mono = MonoViewMut::from_slice(&mut mono_data);
829
830        block.copy_channel_to_mono_exact(&mut mono, 0);
831    }
832
833    #[test]
834    fn test_copy_mono_to_all_channels_flexible_dest_smaller() {
835        use crate::mono::MonoView;
836
837        // Mono has 4 frames, destination has only 2 frames
838        // Should only copy 2 frames, returns Some(frames_copied)
839        let mono_data = [1.0, 2.0, 3.0, 4.0];
840        let mono = MonoView::from_slice(&mono_data);
841
842        let mut data = [0.0; 2]; // 1 channel, 2 frames
843        let mut block = SequentialViewMut::from_slice(&mut data, 1);
844
845        let result = block.copy_mono_to_all_channels(&mono);
846        assert_eq!(result, Some(2)); // Partial copy
847
848        assert_eq!(
849            block.channel_iter(0).copied().collect::<Vec<_>>(),
850            vec![1.0, 2.0] // Only first 2 frames copied
851        );
852    }
853
854    #[test]
855    fn test_copy_mono_to_all_channels_flexible_self_smaller() {
856        use crate::mono::MonoView;
857
858        // Mono has 2 frames, destination has 4 frames
859        // Should only copy 2 frames, returns None (mono fully copied)
860        let mono_data = [1.0, 2.0];
861        let mono = MonoView::from_slice(&mono_data);
862
863        let mut data = [0.0; 8]; // 2 channels, 4 frames
864        let mut block = SequentialViewMut::from_slice(&mut data, 2);
865
866        let result = block.copy_mono_to_all_channels(&mono);
867        assert_eq!(result, None); // Mono fully copied
868
869        assert_eq!(
870            block.channel_iter(0).copied().collect::<Vec<_>>(),
871            vec![1.0, 2.0, 0.0, 0.0] // Only first 2 frames copied
872        );
873        assert_eq!(
874            block.channel_iter(1).copied().collect::<Vec<_>>(),
875            vec![1.0, 2.0, 0.0, 0.0] // Only first 2 frames copied
876        );
877    }
878
879    #[test]
880    fn test_copy_mono_to_all_channels_exact_match_returns_none() {
881        use crate::mono::MonoView;
882
883        // Mono and destination have the same size
884        // Should copy all frames and return None
885        let mono_data = [1.0, 2.0, 3.0, 4.0];
886        let mono = MonoView::from_slice(&mono_data);
887
888        let mut data = [0.0; 12]; // 3 channels, 4 frames
889        let mut block = SequentialViewMut::from_slice(&mut data, 3);
890
891        let result = block.copy_mono_to_all_channels(&mono);
892        assert_eq!(result, None); // Exact match
893
894        assert_eq!(
895            block.channel_iter(0).copied().collect::<Vec<_>>(),
896            vec![1.0, 2.0, 3.0, 4.0]
897        );
898    }
899
900    #[test]
901    fn test_copy_mono_to_all_channels_exact() {
902        use crate::mono::MonoView;
903
904        let mono_data = [1.0, 2.0, 3.0, 4.0];
905        let mono = MonoView::from_slice(&mono_data);
906
907        let mut data = [0.0; 12];
908        let mut block = SequentialViewMut::from_slice(&mut data, 3);
909
910        block.copy_mono_to_all_channels_exact(&mono);
911
912        assert_eq!(
913            block.channel_iter(0).copied().collect::<Vec<_>>(),
914            vec![1.0, 2.0, 3.0, 4.0]
915        );
916        assert_eq!(
917            block.channel_iter(1).copied().collect::<Vec<_>>(),
918            vec![1.0, 2.0, 3.0, 4.0]
919        );
920        assert_eq!(
921            block.channel_iter(2).copied().collect::<Vec<_>>(),
922            vec![1.0, 2.0, 3.0, 4.0]
923        );
924    }
925
926    #[test]
927    #[should_panic]
928    #[no_sanitize_realtime]
929    fn test_copy_mono_to_all_channels_exact_wrong_frames() {
930        use crate::mono::MonoView;
931
932        let mono_data = [1.0, 2.0, 3.0, 4.0, 5.0]; // 5 frames
933        let mono = MonoView::from_slice(&mono_data);
934
935        let mut data = [0.0; 12]; // 3 channels, 4 frames - mismatch!
936        let mut block = SequentialViewMut::from_slice(&mut data, 3);
937
938        block.copy_mono_to_all_channels_exact(&mono);
939    }
940}