Skip to main content

audioadapter/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3
4/// The traits for accessing samples in buffers.
5mod traits;
6pub use traits::{Adapter, AdapterMut};
7
8/// Calculate statistics for adapters with numerical sample types
9pub mod stats;
10
11/// Read-only iterators
12mod iterators;
13
14pub use iterators::AdapterIterators;
15
16#[cfg(any(test, feature = "test-utils"))]
17pub mod tests {
18    extern crate alloc;
19
20    use crate::{Adapter, AdapterMut};
21    use alloc::vec;
22    use alloc::vec::Vec;
23    use num_traits::{NumCast, float::FloatCore};
24
25    /// Minimal implementation of an Adapter based on a vec
26    /// intended for testing purposes.
27    pub struct MinimalAdapter<U> {
28        buf: Vec<U>,
29        frames: usize,
30        channels: usize,
31    }
32
33    impl<T> MinimalAdapter<T>
34    where
35        T: Clone,
36    {
37        pub fn new_from_vec(buf: Vec<T>, channels: usize, frames: usize) -> Self {
38            Self {
39                buf,
40                frames,
41                channels,
42            }
43        }
44    }
45
46    unsafe impl<T> Adapter<T> for MinimalAdapter<T>
47    where
48        T: Clone,
49    {
50        unsafe fn read_sample_unchecked(&self, channel: usize, frame: usize) -> T {
51            let index = frame * self.channels + channel;
52            unsafe { self.buf.get_unchecked(index).clone() }
53        }
54
55        fn channels(&self) -> usize {
56            self.channels
57        }
58
59        fn frames(&self) -> usize {
60            self.frames
61        }
62    }
63
64    unsafe impl<T> AdapterMut<T> for MinimalAdapter<T>
65    where
66        T: Clone,
67    {
68        unsafe fn write_sample_unchecked(
69            &mut self,
70            channel: usize,
71            frame: usize,
72            value: &T,
73        ) -> bool {
74            let index = frame * self.channels + channel;
75            unsafe {
76                *self.buf.get_unchecked_mut(index) = value.clone();
77            }
78            false
79        }
80    }
81
82    /// A generic test function to verify the implementation of `Adapter` and `AdapterMut` traits.
83    ///
84    /// It takes a mutable reference to an adapter and runs a series of tests.
85    /// The adapter is expected to have at least 2 channels and 4 frames.
86    /// The sample type `T` must support `Default`, `Clone`, `PartialEq`, `Debug`, and be convertible to and from `usize`.
87    pub fn test_adapter_mut_methods<T>(buffer: &mut dyn AdapterMut<T>)
88    where
89        T: Default + Clone + PartialEq + core::fmt::Debug + From<usize> + Into<usize>,
90    {
91        // Ensure buffer is large enough for tests
92        assert!(
93            buffer.channels() >= 2,
94            "Buffer must have at least 2 channels for this test"
95        );
96        assert!(
97            buffer.frames() >= 4,
98            "Buffer must have at least 4 frames for this test"
99        );
100
101        // --- Test `fill_with` and `read_sample` ---
102        buffer.fill_with(&T::from(42));
103        assert_eq!(buffer.read_sample(0, 0), Some(T::from(42)));
104        assert_eq!(buffer.read_sample(1, 1), Some(T::from(42)));
105        // Test OOB read
106        assert_eq!(buffer.read_sample(buffer.channels(), 0), None);
107        assert_eq!(buffer.read_sample(0, buffer.frames()), None);
108
109        // --- Test `write_sample` ---
110        assert_eq!(buffer.write_sample(0, 0, &T::from(100)), Some(false));
111        assert_eq!(buffer.read_sample(0, 0), Some(T::from(100)));
112        // Test OOB write
113        assert_eq!(
114            buffer.write_sample(buffer.channels(), 0, &T::from(101)),
115            None
116        );
117        assert_eq!(buffer.write_sample(0, buffer.frames(), &T::from(102)), None);
118
119        // --- Test `fill_channel_with` ---
120        buffer.fill_channel_with(1, &T::from(99)).unwrap();
121        assert_eq!(buffer.read_sample(1, 0), Some(T::from(99)));
122        assert_eq!(buffer.read_sample(1, 1), Some(T::from(99)));
123        assert_eq!(buffer.read_sample(0, 0), Some(T::from(100))); // Other channel unaffected
124
125        // --- Test `fill_frame_with` ---
126        buffer.fill_frame_with(2, &T::from(88)).unwrap();
127        assert_eq!(buffer.read_sample(0, 2), Some(T::from(88)));
128        assert_eq!(buffer.read_sample(1, 2), Some(T::from(88)));
129        assert_eq!(buffer.read_sample(1, 1), Some(T::from(99))); // Other frame unaffected
130
131        // --- Test `fill_frames_with` ---
132        buffer.fill_frames_with(0, 2, &T::from(77)).unwrap();
133        assert_eq!(buffer.read_sample(0, 0), Some(T::from(77)));
134        assert_eq!(buffer.read_sample(1, 1), Some(T::from(77)));
135        assert_eq!(buffer.read_sample(0, 2), Some(T::from(88))); // Unaffected frame
136
137        // Reset for next tests
138        for c in 0..buffer.channels() {
139            for f in 0..buffer.frames() {
140                buffer.write_sample(c, f, &T::from(c * 10 + f));
141            }
142        }
143        // Expected: ch0: [0, 1, 2, 3, ...], ch1: [10, 11, 12, 13, ...]
144
145        // --- Test `copy_from_channel_to_slice` ---
146        let mut slice_ch = vec![T::default(); 2];
147        let copied = buffer.copy_from_channel_to_slice(1, 1, &mut slice_ch);
148        assert_eq!(copied, 2);
149        assert_eq!(slice_ch, vec![T::from(11), T::from(12)]);
150
151        // --- Test `copy_from_frame_to_slice` ---
152        let mut slice_fr = vec![T::default(); 2];
153        let copied = buffer.copy_from_frame_to_slice(2, 0, &mut slice_fr);
154        assert_eq!(copied, 2);
155        assert_eq!(slice_fr, vec![T::from(2), T::from(12)]);
156
157        // --- Test `copy_from_slice_to_channel` ---
158        let slice_to_ch = vec![T::from(101), T::from(102)];
159        let (copied, clipped) = buffer.copy_from_slice_to_channel(0, 2, &slice_to_ch);
160        assert_eq!(copied, 2);
161        assert_eq!(clipped, 0);
162        assert_eq!(buffer.read_sample(0, 2), Some(T::from(101)));
163        assert_eq!(buffer.read_sample(0, 3), Some(T::from(102)));
164
165        // --- Test `copy_from_slice_to_frame` ---
166        let slice_to_fr = vec![T::from(201)];
167        let (copied, clipped) = buffer.copy_from_slice_to_frame(3, 1, &slice_to_fr);
168        assert_eq!(copied, 1);
169        assert_eq!(clipped, 0);
170        assert_eq!(buffer.read_sample(1, 3), Some(T::from(201)));
171
172        // --- Test `copy_sample_within` ---
173        // Before: (0,0) is 0, (1,1) is 11
174        assert!(buffer.copy_sample_within(0, 0, 1, 1));
175        // After: (0,0) is 0, (1,1) is 0
176        assert_eq!(buffer.read_sample(1, 1), Some(T::from(0)));
177
178        // --- Test `swap_samples` ---
179        // Before: (0,1) is 1, (1,0) is 10
180        assert!(buffer.swap_samples(0, 1, 1, 0));
181        // After: (0,1) is 10, (1,0) is 1
182        assert_eq!(buffer.read_sample(0, 1), Some(T::from(10)));
183        assert_eq!(buffer.read_sample(1, 0), Some(T::from(1)));
184
185        // --- Test `copy_frames_within` ---
186        // Before: F0:[0, 1], F1:[10, 0], F2:[101, 12]
187        buffer.copy_frames_within(0, 1, 2).unwrap();
188        // After: F0:[0, 1], F1:[0, 1], F2:[10, 0]
189        assert_eq!(buffer.read_sample(0, 1), Some(T::from(0)));
190        assert_eq!(buffer.read_sample(1, 1), Some(T::from(1)));
191        assert_eq!(buffer.read_sample(0, 2), Some(T::from(10)));
192        assert_eq!(buffer.read_sample(1, 2), Some(T::from(0)));
193    }
194
195    /// A generic test function to verify the implementation of `Adapter` and `AdapterMut` traits for float types.
196    ///
197    /// It takes a mutable reference to an adapter and runs a series of tests.
198    /// The adapter is expected to have at least 2 channels and 4 frames.
199    /// The sample type `T` must be a floating-point type implementing `FloatCore`, `NumCast`, `Default`, `Clone`, `PartialEq`, and `Debug`.
200    pub fn test_float_adapter_mut_methods<T>(buffer: &mut dyn AdapterMut<T>)
201    where
202        T: FloatCore + NumCast + Default + Clone + PartialEq + core::fmt::Debug,
203    {
204        // Helper for approximate float comparison
205        let assert_approx_eq = |a: T, b: T, message: &str| {
206            let epsilon = NumCast::from(1e-6f64).unwrap();
207            assert!(
208                (a - b).abs() < epsilon,
209                "{} (left: {:?}, right: {:?})",
210                message,
211                a,
212                b
213            );
214        };
215
216        let assert_slice_approx_eq = |a: &[T], b: &[T], message: &str| {
217            assert_eq!(a.len(), b.len(), "{} (slice lengths differ)", message);
218            for (i, (val_a, val_b)) in a.iter().zip(b.iter()).enumerate() {
219                let msg = alloc::format!("{} (element {})", message, i);
220                assert_approx_eq(*val_a, *val_b, &msg);
221            }
222        };
223
224        // Ensure buffer is large enough for tests
225        assert!(
226            buffer.channels() >= 2,
227            "Buffer must have at least 2 channels for this test"
228        );
229        assert!(
230            buffer.frames() >= 4,
231            "Buffer must have at least 4 frames for this test"
232        );
233
234        // --- Test `fill_with` and `read_sample` ---
235        buffer.fill_with(&NumCast::from(0.42f64).unwrap());
236        assert_approx_eq(
237            buffer.read_sample(0, 0).unwrap(),
238            NumCast::from(0.42f64).unwrap(),
239            "fill_with value mismatch",
240        );
241        assert_approx_eq(
242            buffer.read_sample(1, 1).unwrap(),
243            NumCast::from(0.42f64).unwrap(),
244            "fill_with value mismatch",
245        );
246        // Test OOB read
247        assert_eq!(buffer.read_sample(buffer.channels(), 0), None);
248        assert_eq!(buffer.read_sample(0, buffer.frames()), None);
249
250        // --- Test `write_sample` ---
251        assert_eq!(
252            buffer.write_sample(0, 0, &NumCast::from(0.1f64).unwrap()),
253            Some(false)
254        );
255        assert_approx_eq(
256            buffer.read_sample(0, 0).unwrap(),
257            NumCast::from(0.1f64).unwrap(),
258            "write_sample value mismatch",
259        );
260        // Test OOB write
261        assert_eq!(
262            buffer.write_sample(buffer.channels(), 0, &NumCast::from(0.101f64).unwrap()),
263            None
264        );
265        assert_eq!(
266            buffer.write_sample(0, buffer.frames(), &NumCast::from(0.102f64).unwrap()),
267            None
268        );
269
270        // --- Test `fill_channel_with` ---
271        buffer
272            .fill_channel_with(1, &NumCast::from(0.99f64).unwrap())
273            .unwrap();
274        assert_approx_eq(
275            buffer.read_sample(1, 0).unwrap(),
276            NumCast::from(0.99f64).unwrap(),
277            "fill_channel_with value mismatch",
278        );
279        assert_approx_eq(
280            buffer.read_sample(1, 1).unwrap(),
281            NumCast::from(0.99f64).unwrap(),
282            "fill_channel_with value mismatch",
283        );
284        assert_approx_eq(
285            buffer.read_sample(0, 0).unwrap(),
286            NumCast::from(0.1f64).unwrap(),
287            "Other channel should be unaffected",
288        ); // Other channel unaffected
289
290        // --- Test `fill_frame_with` ---
291        buffer
292            .fill_frame_with(2, &NumCast::from(0.88f64).unwrap())
293            .unwrap();
294        assert_approx_eq(
295            buffer.read_sample(0, 2).unwrap(),
296            NumCast::from(0.88f64).unwrap(),
297            "fill_frame_with value mismatch",
298        );
299        assert_approx_eq(
300            buffer.read_sample(1, 2).unwrap(),
301            NumCast::from(0.88f64).unwrap(),
302            "fill_frame_with value mismatch",
303        );
304        assert_approx_eq(
305            buffer.read_sample(1, 1).unwrap(),
306            NumCast::from(0.99f64).unwrap(),
307            "Other frame should be unaffected",
308        ); // Other frame unaffected
309
310        // --- Test `fill_frames_with` ---
311        buffer
312            .fill_frames_with(0, 2, &NumCast::from(0.77f64).unwrap())
313            .unwrap();
314        assert_approx_eq(
315            buffer.read_sample(0, 0).unwrap(),
316            NumCast::from(0.77f64).unwrap(),
317            "fill_frames_with value mismatch",
318        );
319        assert_approx_eq(
320            buffer.read_sample(1, 1).unwrap(),
321            NumCast::from(0.77f64).unwrap(),
322            "fill_frames_with value mismatch",
323        );
324        assert_approx_eq(
325            buffer.read_sample(0, 2).unwrap(),
326            NumCast::from(0.88f64).unwrap(),
327            "Unaffected frame should be unaffected",
328        ); // Unaffected frame
329
330        // Reset for next tests
331        for c in 0..buffer.channels() {
332            for f in 0..buffer.frames() {
333                buffer.write_sample(c, f, &NumCast::from((c * 10 + f) as f64 / 100.0).unwrap());
334            }
335        }
336        // Expected: ch0: [0.00, 0.01, 0.02, 0.03, ...], ch1: [0.10, 0.11, 0.12, 0.13, ...]
337
338        // --- Test `copy_from_channel_to_slice` ---
339        let mut slice_ch = vec![T::default(); 2];
340        let copied = buffer.copy_from_channel_to_slice(1, 1, &mut slice_ch);
341        assert_eq!(copied, 2);
342        assert_slice_approx_eq(
343            &slice_ch,
344            &[
345                NumCast::from(0.11f64).unwrap(),
346                NumCast::from(0.12f64).unwrap(),
347            ],
348            "copy_from_channel_to_slice mismatch",
349        );
350
351        // --- Test `copy_from_frame_to_slice` ---
352        let mut slice_fr = vec![T::default(); 2];
353        let copied = buffer.copy_from_frame_to_slice(2, 0, &mut slice_fr);
354        assert_eq!(copied, 2);
355        assert_slice_approx_eq(
356            &slice_fr,
357            &[
358                NumCast::from(0.02f64).unwrap(),
359                NumCast::from(0.12f64).unwrap(),
360            ],
361            "copy_from_frame_to_slice mismatch",
362        );
363
364        // --- Test `copy_sample_within` ---
365        // Before: (0,0) is 0.0, (1,1) is 0.11
366        assert!(buffer.copy_sample_within(0, 0, 1, 1));
367        // After: (0,0) is 0.0, (1,1) is 0.0
368        assert_approx_eq(
369            buffer.read_sample(1, 1).unwrap(),
370            NumCast::from(0.0f64).unwrap(),
371            "copy_sample_within value mismatch",
372        );
373
374        // --- Test `swap_samples` ---
375        // Before: (0,1) is 0.01, (1,0) is 0.10
376        assert!(buffer.swap_samples(0, 1, 1, 0));
377        // After: (0,1) is 0.10, (1,0) is 0.01
378        assert_approx_eq(
379            buffer.read_sample(0, 1).unwrap(),
380            NumCast::from(0.10f64).unwrap(),
381            "swap_samples value mismatch on sample A",
382        );
383        assert_approx_eq(
384            buffer.read_sample(1, 0).unwrap(),
385            NumCast::from(0.01f64).unwrap(),
386            "swap_samples value mismatch on sample B",
387        );
388    }
389
390    #[test]
391    fn test_vec_adapter() {
392        let mut buffer = MinimalAdapter::new_from_vec(vec![0; 8], 2, 4);
393        test_adapter_mut_methods(&mut buffer);
394    }
395}