conformal_component/audio/
slice.rs

1//! Utilities for slicing audio buffers.
2
3// this is a private module
4#![allow(clippy::module_name_repetitions)]
5
6use super::{Buffer, BufferMut, ChannelLayout};
7
8struct SlicedBuffer<'a, B, I> {
9    buffer: &'a B,
10    index: I,
11}
12
13/// A trait for index types that can be used in `slice_buffer` and `slice_buffer_mut`.
14pub trait BufferIndex {
15    #[doc(hidden)]
16    fn num_frames(&self, parent: usize) -> usize;
17    #[doc(hidden)]
18    fn index<'a>(&self, buffer: &'a [f32]) -> &'a [f32];
19    #[doc(hidden)]
20    fn index_mut<'a>(&self, buffer: &'a mut [f32]) -> &'a mut [f32];
21}
22
23impl BufferIndex for std::ops::Range<usize> {
24    fn num_frames(&self, _parent: usize) -> usize {
25        self.len()
26    }
27
28    fn index<'a>(&self, buffer: &'a [f32]) -> &'a [f32] {
29        &buffer[self.clone()]
30    }
31
32    fn index_mut<'a>(&self, buffer: &'a mut [f32]) -> &'a mut [f32] {
33        &mut buffer[self.clone()]
34    }
35}
36
37impl BufferIndex for std::ops::RangeInclusive<usize> {
38    fn num_frames(&self, _parent: usize) -> usize {
39        self.end() - self.start() + 1
40    }
41
42    fn index<'a>(&self, buffer: &'a [f32]) -> &'a [f32] {
43        &buffer[self.clone()]
44    }
45
46    fn index_mut<'a>(&self, buffer: &'a mut [f32]) -> &'a mut [f32] {
47        &mut buffer[self.clone()]
48    }
49}
50
51impl BufferIndex for std::ops::RangeFrom<usize> {
52    fn num_frames(&self, parent: usize) -> usize {
53        parent - self.start
54    }
55
56    fn index<'a>(&self, buffer: &'a [f32]) -> &'a [f32] {
57        &buffer[self.clone()]
58    }
59
60    fn index_mut<'a>(&self, buffer: &'a mut [f32]) -> &'a mut [f32] {
61        &mut buffer[self.clone()]
62    }
63}
64
65impl BufferIndex for std::ops::RangeTo<usize> {
66    fn num_frames(&self, _parent: usize) -> usize {
67        self.end
68    }
69
70    fn index<'a>(&self, buffer: &'a [f32]) -> &'a [f32] {
71        &buffer[*self]
72    }
73
74    fn index_mut<'a>(&self, buffer: &'a mut [f32]) -> &'a mut [f32] {
75        &mut buffer[*self]
76    }
77}
78
79impl BufferIndex for std::ops::RangeFull {
80    fn num_frames(&self, parent: usize) -> usize {
81        parent
82    }
83
84    fn index<'a>(&self, buffer: &'a [f32]) -> &'a [f32] {
85        buffer
86    }
87
88    fn index_mut<'a>(&self, buffer: &'a mut [f32]) -> &'a mut [f32] {
89        buffer
90    }
91}
92
93impl BufferIndex for std::ops::RangeToInclusive<usize> {
94    fn num_frames(&self, _parent: usize) -> usize {
95        self.end + 1
96    }
97
98    fn index<'a>(&self, buffer: &'a [f32]) -> &'a [f32] {
99        &buffer[*self]
100    }
101
102    fn index_mut<'a>(&self, buffer: &'a mut [f32]) -> &'a mut [f32] {
103        &mut buffer[*self]
104    }
105}
106
107impl<B: Buffer, I: BufferIndex> Buffer for SlicedBuffer<'_, B, I> {
108    fn channel_layout(&self) -> ChannelLayout {
109        self.buffer.channel_layout()
110    }
111
112    fn num_frames(&self) -> usize {
113        self.index.num_frames(self.buffer.num_frames())
114    }
115
116    fn channel(&self, channel: usize) -> &[f32] {
117        self.index.index(self.buffer.channel(channel))
118    }
119}
120
121/// Create a sub-buffer from a buffer using an index range.
122///
123/// # Examples
124///
125/// ```
126/// # use conformal_component::audio::{Buffer, BufferData};
127/// # use conformal_component::audio::slice_buffer;
128/// let buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0]);
129/// assert_eq!(slice_buffer(&buffer, 1..).channel(0), [2.0, 3.0]);
130/// assert_eq!(slice_buffer(&buffer, 1..2).channel(0), [2.0]);
131/// assert_eq!(slice_buffer(&buffer, ..=1).channel(0), [1.0, 2.0]);
132/// ```
133///
134/// # Panics
135///
136/// Will panic if the index range isn't within the bounds of the buffer:
137///
138/// ```should_panic
139/// # use conformal_component::audio::{BufferData};
140/// # use conformal_component::audio::slice_buffer;;
141/// let buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0]);
142/// slice_buffer(&buffer, 4..);
143/// ```
144pub fn slice_buffer<'a, B: Buffer, I: BufferIndex + 'a>(buffer: &'a B, index: I) -> impl Buffer {
145    let ret = SlicedBuffer { buffer, index };
146    // Grab the first channel and throw it away - this will
147    // cause us to panic early in the case of an invalid range
148    ret.channel(0);
149    ret
150}
151
152struct SlicedMutBuffer<'a, B, I> {
153    buffer: &'a mut B,
154    index: I,
155}
156
157impl<B: Buffer, I: BufferIndex> Buffer for SlicedMutBuffer<'_, B, I> {
158    fn channel_layout(&self) -> ChannelLayout {
159        self.buffer.channel_layout()
160    }
161
162    fn num_frames(&self) -> usize {
163        self.index.num_frames(self.buffer.num_frames())
164    }
165
166    fn channel(&self, channel: usize) -> &[f32] {
167        self.index.index(self.buffer.channel(channel))
168    }
169}
170
171impl<B: BufferMut, I: BufferIndex> BufferMut for SlicedMutBuffer<'_, B, I> {
172    fn channel_mut(&mut self, channel: usize) -> &mut [f32] {
173        self.index.index_mut(self.buffer.channel_mut(channel))
174    }
175}
176
177/// Create a sub-buffer of a mutable buffer using an index range.
178///
179/// # Examples
180///
181/// ```
182/// # use conformal_component::audio::{Buffer, BufferMut, BufferData};
183/// # use conformal_component::audio::slice_buffer_mut;
184/// let mut buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0]);
185/// slice_buffer_mut(&mut buffer, 1..).channel_mut(0).copy_from_slice(&[4.0, 5.0]);
186/// assert_eq!(buffer.channel(0), [1.0, 4.0, 5.0]);
187/// ```
188///
189/// # Panics
190///
191/// Will panic if the index range isn't within the bounds of the buffer:
192///
193/// ```should_panic
194/// # use conformal_component::audio::{BufferData};
195/// # use conformal_component::audio::slice_buffer_mut;
196/// let mut buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0]);
197/// slice_buffer_mut(&mut buffer, 4..);
198/// ```
199pub fn slice_buffer_mut<'a>(
200    buffer: &'a mut impl BufferMut,
201    index: impl BufferIndex + 'a,
202) -> impl BufferMut {
203    let ret = SlicedMutBuffer { buffer, index };
204    // Grab the first channel and throw it away - this will
205    // cause us to panic early in the case of an invalid range
206    ret.channel(0);
207    ret
208}
209
210#[cfg(test)]
211mod tests {
212    use crate::audio::BufferData;
213
214    use super::*;
215
216    #[test]
217    fn test_slice_buffer_mono() {
218        let buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0, 4.0]);
219        let sliced = slice_buffer(&buffer, 1..3);
220        assert_eq!(sliced.channel_layout(), ChannelLayout::Mono);
221        assert_eq!(sliced.num_channels(), 1);
222        assert_eq!(sliced.num_frames(), 2);
223        assert_eq!(sliced.channel(0), &[2.0, 3.0]);
224    }
225
226    #[test]
227    fn test_slice_buffer_indexing_modes() {
228        let buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0, 4.0]);
229        assert_eq!(slice_buffer(&buffer, 1..3).num_frames(), 2);
230        assert_eq!(slice_buffer(&buffer, 1..3).channel(0), [2.0, 3.0]);
231        assert_eq!(slice_buffer(&buffer, 1..).num_frames(), 3);
232        assert_eq!(slice_buffer(&buffer, 1..).channel(0), [2.0, 3.0, 4.0]);
233        assert_eq!(slice_buffer(&buffer, 1..=2).num_frames(), 2);
234        assert_eq!(slice_buffer(&buffer, 1..=2).channel(0), [2.0, 3.0]);
235        assert_eq!(slice_buffer(&buffer, ..2).num_frames(), 2);
236        assert_eq!(slice_buffer(&buffer, ..2).channel(0), [1.0, 2.0]);
237        assert_eq!(slice_buffer(&buffer, ..=2).num_frames(), 3);
238        assert_eq!(slice_buffer(&buffer, ..=2).channel(0), [1.0, 2.0, 3.0]);
239        assert_eq!(slice_buffer(&buffer, ..).num_frames(), 4);
240        assert_eq!(slice_buffer(&buffer, ..).channel(0), [1.0, 2.0, 3.0, 4.0]);
241    }
242
243    #[test]
244    fn test_slice_buffer_mut_mono() {
245        let mut buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0, 4.0]);
246        {
247            let mut sliced = slice_buffer_mut(&mut buffer, 1..3);
248            assert_eq!(sliced.channel_layout(), ChannelLayout::Mono);
249            assert_eq!(sliced.num_frames(), 2);
250            assert_eq!(sliced.channel(0), &[2.0, 3.0]);
251            sliced.channel_mut(0)[0] = 5.0;
252        }
253        assert_eq!(buffer.channel(0), [1.0, 5.0, 3.0, 4.0]);
254    }
255
256    #[test]
257    fn test_slice_buffer_stereo() {
258        let buffer = BufferData::new_stereo([1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]);
259        let sliced = slice_buffer(&buffer, 1..3);
260        assert_eq!(sliced.channel_layout(), ChannelLayout::Stereo);
261        assert_eq!(sliced.num_channels(), 2);
262        assert_eq!(sliced.num_frames(), 2);
263        assert_eq!(sliced.channel(0), &[2.0, 3.0]);
264        assert_eq!(sliced.channel(1), &[6.0, 7.0]);
265    }
266
267    #[test]
268    fn test_slice_buffer_mut_stereo() {
269        let mut buffer = BufferData::new_stereo([1.0, 2.0, 3.0, 4.0], [5.0, 6.0, 7.0, 8.0]);
270        {
271            let mut sliced = slice_buffer_mut(&mut buffer, 1..3);
272            assert_eq!(sliced.channel_layout(), ChannelLayout::Stereo);
273            sliced.channel_mut(0)[0] = 9.0;
274            sliced.channel_mut(1)[1] = 10.0;
275        }
276        assert_eq!(buffer.channel(0), [1.0, 9.0, 3.0, 4.0]);
277        assert_eq!(buffer.channel(1), [5.0, 6.0, 10.0, 8.0]);
278    }
279
280    #[test]
281    fn test_slice_buffer_mut_indexing_modes() {
282        let mut buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0, 4.0]);
283        {
284            slice_buffer_mut(&mut buffer, 1..3)
285                .channel_mut(0)
286                .copy_from_slice(&[20.0, 30.0]);
287        }
288        assert_eq!(buffer.channel(0), [1.0, 20.0, 30.0, 4.0]);
289        {
290            slice_buffer_mut(&mut buffer, 2..)
291                .channel_mut(0)
292                .copy_from_slice(&[300.0, 400.0]);
293        }
294        assert_eq!(buffer.channel(0), [1.0, 20.0, 300.0, 400.0]);
295        {
296            slice_buffer_mut(&mut buffer, 1..=2)
297                .channel_mut(0)
298                .copy_from_slice(&[2000.0, 3000.0]);
299        }
300        assert_eq!(buffer.channel(0), [1.0, 2000.0, 3000.0, 400.0]);
301        {
302            slice_buffer_mut(&mut buffer, ..2)
303                .channel_mut(0)
304                .copy_from_slice(&[10000.0, 20000.0]);
305        }
306        assert_eq!(buffer.channel(0), [10000.0, 20000.0, 3000.0, 400.0]);
307        {
308            slice_buffer_mut(&mut buffer, ..=2)
309                .channel_mut(0)
310                .copy_from_slice(&[100000.0, 200000.0, 300000.0]);
311        }
312        assert_eq!(buffer.channel(0), [100000.0, 200000.0, 300000.0, 400.0]);
313        {
314            slice_buffer_mut(&mut buffer, ..)
315                .channel_mut(0)
316                .copy_from_slice(&[1000000.0, 2000000.0, 3000000.0, 4000000.0]);
317        }
318        assert_eq!(
319            buffer.channel(0),
320            [1000000.0, 2000000.0, 3000000.0, 4000000.0]
321        );
322    }
323}