Skip to main content

sample_resource/
helpers.rs

1//! Helper methods to create a [`SampleResource`](crate::SampleResource)
2
3use audioadapter_sample::sample::{BytesSample, RawSample};
4use core::ops::Range;
5
6/// A helper for
7/// [`SampleResource::fill_buffers_f32()`](crate::SampleResource::fill_buffers_f32)
8/// to fill buffers from a resource of interleaved samples.
9///
10/// Returns the number of frames (samples in a single channel of audio) that
11/// were successfully written to the buffer. This may be less than the requested
12/// number of frames if `output_buffer_range` falls outside the range of the sample
13/// resource.
14///
15/// # Panics
16/// Panics if:
17/// * `output_buffer_range` is out-of-bounds for any channel slice in `output_buffer`
18/// * `resource_samples.len() < resource_channels * resource_frames`
19pub fn fill_buffers_interleaved<T: RawSample>(
20    output_buffer: &mut [&mut [f32]],
21    output_buffer_range: Range<usize>,
22    start_frame_in_resource: u64,
23    resource_channels: usize,
24    resource_frames: usize,
25    resource_samples: &[T],
26) -> usize {
27    if output_buffer.is_empty() {
28        return 0;
29    }
30
31    let Some(frames) = valid_frames(
32        output_buffer_range.clone(),
33        start_frame_in_resource,
34        resource_frames,
35    ) else {
36        return 0;
37    };
38
39    let start_frame_in_resource = start_frame_in_resource as usize;
40
41    // Provide an optimized loop for mono.
42    if resource_channels == 1 {
43        // Mono, no need to deinterleave.
44        for (buf_s, src_s) in output_buffer[0][output_buffer_range.clone()]
45            .iter_mut()
46            .zip(&resource_samples[start_frame_in_resource..start_frame_in_resource + frames])
47        {
48            *buf_s = src_s.to_scaled_float();
49        }
50        return frames;
51    }
52
53    // Provide an optimized loop for stereo.
54    if resource_channels == 2 && output_buffer.len() >= 2 {
55        let (buf0, buf1) = output_buffer.split_first_mut().unwrap();
56        let buf0 = &mut buf0[output_buffer_range.clone()];
57        let buf1 = &mut buf1[0][output_buffer_range.clone()];
58
59        let src_slice =
60            &resource_samples[start_frame_in_resource * 2..(start_frame_in_resource + frames) * 2];
61
62        for (src_chunk, (buf0_s, buf1_s)) in src_slice
63            .chunks_exact(2)
64            .zip(buf0.iter_mut().zip(buf1.iter_mut()))
65        {
66            *buf0_s = src_chunk[0].to_scaled_float();
67            *buf1_s = src_chunk[1].to_scaled_float();
68        }
69
70        return frames;
71    }
72
73    let src_slice = &resource_samples[start_frame_in_resource * resource_channels
74        ..(start_frame_in_resource + frames) * resource_channels];
75    for (ch_i, buf_ch) in (0..resource_channels).zip(output_buffer.iter_mut()) {
76        for (src_chunk, buf_s) in src_slice
77            .chunks_exact(resource_channels)
78            .zip(buf_ch[output_buffer_range.clone()].iter_mut())
79        {
80            *buf_s = src_chunk[ch_i].to_scaled_float();
81        }
82    }
83
84    frames
85}
86
87/// A helper for
88/// [`SampleResource::fill_buffers_f32()`](crate::SampleResource::fill_buffers_f32)
89/// to fill buffers from a resource of interleaved samples stored as raw bytes.
90///
91/// Returns the number of frames (samples in a single channel of audio) that
92/// were successfully written to the buffer. This may be less than the requested
93/// number of frames if `output_buffer_range` falls outside the range of the sample
94/// resource.
95///
96/// # Panics
97/// Panics if:
98/// * `output_buffer_range` is out-of-bounds for any channel slice in `output_buffer`
99/// * `resource_samples.len() < resource_channels * resource_frames`
100pub fn fill_buffers_interleaved_bytes<T: BytesSample>(
101    output_buffer: &mut [&mut [f32]],
102    output_buffer_range: Range<usize>,
103    start_frame_in_resource: u64,
104    resource_channels: usize,
105    resource_frames: usize,
106    resource_data: &[u8],
107) -> usize
108where
109    T::NumericType: RawSample,
110{
111    if output_buffer.is_empty() {
112        return 0;
113    }
114
115    let Some(frames) = valid_frames(
116        output_buffer_range.clone(),
117        start_frame_in_resource,
118        resource_frames,
119    ) else {
120        return 0;
121    };
122
123    let start_frame_in_resource = start_frame_in_resource as usize;
124
125    // Provide an optimized loop for mono.
126    if resource_channels == 1 {
127        for (buf_s, src_s) in output_buffer[0][output_buffer_range.clone()]
128            .iter_mut()
129            .zip(
130                resource_data[start_frame_in_resource * T::BYTES_PER_SAMPLE
131                    ..(start_frame_in_resource + frames) * T::BYTES_PER_SAMPLE]
132                    .chunks_exact(T::BYTES_PER_SAMPLE),
133            )
134        {
135            *buf_s = T::from_slice(src_s).to_number().to_scaled_float();
136        }
137        return frames;
138    }
139
140    // Provide an optimized loop for stereo.
141    if resource_channels == 2 && output_buffer.len() >= 2 {
142        let (buf0, buf1) = output_buffer.split_first_mut().unwrap();
143        let buf0 = &mut buf0[output_buffer_range.clone()];
144        let buf1 = &mut buf1[0][output_buffer_range.clone()];
145
146        let src_slice = &resource_data[start_frame_in_resource * 2 * T::BYTES_PER_SAMPLE
147            ..(start_frame_in_resource + frames) * 2 * T::BYTES_PER_SAMPLE];
148
149        for (src_chunk, (buf0_s, buf1_s)) in src_slice
150            .chunks_exact(2 * T::BYTES_PER_SAMPLE)
151            .zip(buf0.iter_mut().zip(buf1.iter_mut()))
152        {
153            *buf0_s = T::from_slice(&src_chunk[0..T::BYTES_PER_SAMPLE])
154                .to_number()
155                .to_scaled_float();
156            *buf1_s = T::from_slice(&src_chunk[T::BYTES_PER_SAMPLE..2 * T::BYTES_PER_SAMPLE])
157                .to_number()
158                .to_scaled_float();
159        }
160
161        return frames;
162    }
163
164    let src_slice = &resource_data[start_frame_in_resource * resource_channels * T::BYTES_PER_SAMPLE
165        ..(start_frame_in_resource + frames) * resource_channels * T::BYTES_PER_SAMPLE];
166    for (ch_i, buf_ch) in (0..resource_channels).zip(output_buffer.iter_mut()) {
167        for (src_chunk, buf_s) in src_slice
168            .chunks_exact(resource_channels * T::BYTES_PER_SAMPLE)
169            .zip(buf_ch[output_buffer_range.clone()].iter_mut())
170        {
171            *buf_s = T::from_slice(
172                &src_chunk[ch_i * T::BYTES_PER_SAMPLE..(ch_i + 1) * T::BYTES_PER_SAMPLE],
173            )
174            .to_number()
175            .to_scaled_float();
176        }
177    }
178
179    frames
180}
181
182/// A helper for
183/// [`SampleResource::fill_buffers_f32()`](crate::SampleResource::fill_buffers_f32)
184/// to fill buffers from a resource of de-interleaved samples.
185///
186/// Returns the number of frames (samples in a single channel of audio) that
187/// were successfully written to the buffer. This may be less than the requested
188/// number of frames if `output_buffer_range` falls outside the range of the sample
189/// resource.
190///
191/// # Panics
192/// Panics if:
193/// * `output_buffer_range` is out-of-bounds for any channel slice in `output_buffer`
194/// * The length of a channel slice in `resource_channels` is less than `resource_frames`
195pub fn fill_buffers_deinterleaved<T: RawSample, V: AsRef<[T]>>(
196    output_buffer: &mut [&mut [f32]],
197    output_buffer_range: Range<usize>,
198    start_frame_in_resource: u64,
199    resource_frames: usize,
200    resource_channels: &[V],
201) -> usize {
202    if output_buffer.is_empty() {
203        return 0;
204    }
205
206    let Some(frames) = valid_frames(
207        output_buffer_range.clone(),
208        start_frame_in_resource,
209        resource_frames,
210    ) else {
211        return 0;
212    };
213
214    let start_frame_in_resource = start_frame_in_resource as usize;
215
216    for (buf, ch) in output_buffer.iter_mut().zip(resource_channels.iter()) {
217        for (buf_s, ch_s) in buf[output_buffer_range.clone()]
218            .iter_mut()
219            .zip(ch.as_ref()[start_frame_in_resource..start_frame_in_resource + frames].iter())
220        {
221            *buf_s = ch_s.to_scaled_float();
222        }
223    }
224
225    frames
226}
227
228/// A helper for
229/// [`SampleResource::fill_buffers_f32()`](crate::SampleResource::fill_buffers_f32)
230/// to fill buffers from a resource of de-interleaved samples stored as raw bytes.
231///
232/// Returns the number of frames (samples in a single channel of audio) that
233/// were successfully written to the buffer. This may be less than the requested
234/// number of frames if `output_buffer_range` falls outside the range of the sample
235/// resource.
236///
237/// # Panics
238/// Panics if:
239/// * `output_buffer_range` is out-of-bounds for any channel slice in `output_buffer`
240/// * The length of a channel slice in `resource_channels` is less than `resource_frames`
241pub fn fill_buffers_deinterleaved_bytes<T: BytesSample, V: AsRef<[u8]>>(
242    output_buffer: &mut [&mut [f32]],
243    output_buffer_range: Range<usize>,
244    start_frame_in_resource: u64,
245    resource_frames: usize,
246    resource_channels: &[V],
247) -> usize
248where
249    T::NumericType: RawSample,
250{
251    if output_buffer.is_empty() {
252        return 0;
253    }
254
255    let Some(frames) = valid_frames(
256        output_buffer_range.clone(),
257        start_frame_in_resource,
258        resource_frames,
259    ) else {
260        return 0;
261    };
262
263    let start_frame_in_resource = start_frame_in_resource as usize;
264
265    for (buf, ch) in output_buffer.iter_mut().zip(resource_channels.iter()) {
266        for (buf_s, ch_s) in buf[output_buffer_range.clone()].iter_mut().zip(
267            ch.as_ref()[start_frame_in_resource * T::BYTES_PER_SAMPLE
268                ..(start_frame_in_resource + frames) * T::BYTES_PER_SAMPLE]
269                .chunks_exact(T::BYTES_PER_SAMPLE),
270        ) {
271            *buf_s = T::from_slice(ch_s).to_number().to_scaled_float();
272        }
273    }
274
275    frames
276}
277
278/// A helper for
279/// [`SampleResource::fill_buffers_f32()`](crate::SampleResource::fill_buffers_f32)
280/// to fill buffers from a resource of de-interleaved samples in `f32`
281/// format.
282///
283/// Returns the number of frames (samples in a single channel of audio) that
284/// were successfully written to the buffer. This may be less than the requested
285/// number of frames if `output_buffer_range` falls outside the range of the sample
286/// resource.
287///
288/// # Panics
289/// Panics if:
290/// * `output_buffer_range` is out-of-bounds for any channel slice in `output_buffer`
291/// * The length of a channel slice in `resource_channels` is less than `resource_frames`
292pub fn fill_buffers_deinterleaved_f32<V: AsRef<[f32]>>(
293    output_buffer: &mut [&mut [f32]],
294    output_buffer_range: Range<usize>,
295    start_frame_in_resource: u64,
296    resource_frames: usize,
297    resource_channels: &[V],
298) -> usize {
299    if output_buffer.is_empty() {
300        return 0;
301    }
302
303    let Some(frames) = valid_frames(
304        output_buffer_range.clone(),
305        start_frame_in_resource,
306        resource_frames,
307    ) else {
308        return 0;
309    };
310
311    let start_frame_in_resource = start_frame_in_resource as usize;
312
313    for (buf, ch) in output_buffer.iter_mut().zip(resource_channels.iter()) {
314        buf[output_buffer_range.clone()].copy_from_slice(
315            &ch.as_ref()[start_frame_in_resource..start_frame_in_resource + frames],
316        );
317    }
318
319    frames
320}
321
322fn valid_frames(
323    output_buffer_range: Range<usize>,
324    start_frame_in_resource: u64,
325    resource_frames: usize,
326) -> Option<usize> {
327    let frames = ((output_buffer_range.end - output_buffer_range.start) as u64)
328        .min((resource_frames as u64).saturating_sub(start_frame_in_resource))
329        as usize;
330
331    if frames == 0 { None } else { Some(frames) }
332}