Skip to main content

audio_blocks/mono/
owned.rs

1use rtsan_standalone::{blocking, nonblocking};
2
3#[cfg(all(feature = "alloc", not(feature = "std")))]
4use alloc::{boxed::Box, vec, vec::Vec};
5#[cfg(all(feature = "std", not(feature = "alloc")))]
6use std::{boxed::Box, vec, vec::Vec};
7#[cfg(all(feature = "std", feature = "alloc"))]
8use std::{boxed::Box, vec, vec::Vec};
9
10use super::{view::AudioBlockMonoView, view_mut::AudioBlockMonoViewMut};
11use crate::{AudioBlock, AudioBlockMut, Sample};
12
13/// A mono (single-channel) audio block that owns its data.
14///
15/// This is a simplified version of the multi-channel audio blocks, optimized for
16/// mono audio processing with a streamlined API that doesn't require channel indexing.
17///
18/// * **Layout:** `[sample0, sample1, sample2, ...]`
19/// * **Interpretation:** A simple sequence of samples representing a single audio channel.
20/// * **Usage:** Ideal for mono audio processing, side-chain signals, or any single-channel audio data.
21///
22/// # Example
23///
24/// ```
25/// use audio_blocks::*;
26///
27/// let mut block = AudioBlockMono::new(512);
28///
29/// // Fill with a simple ramp
30/// for (i, sample) in block.samples_mut().iter_mut().enumerate() {
31///     *sample = i as f32;
32/// }
33///
34/// assert_eq!(block.sample(0), 0.0);
35/// assert_eq!(block.sample(511), 511.0);
36/// ```
37pub struct AudioBlockMono<S: Sample> {
38    data: Box<[S]>,
39    num_frames: usize,
40    num_frames_allocated: usize,
41}
42
43impl<S: Sample + Default> AudioBlockMono<S> {
44    /// Creates a new mono audio block with the specified number of frames.
45    ///
46    /// Allocates memory for a new mono audio block with exactly the specified
47    /// number of frames. The block is initialized with the default value (zero)
48    /// for the sample type.
49    ///
50    /// Do not use in real-time processes!
51    ///
52    /// # Arguments
53    ///
54    /// * `num_frames` - The number of frames (samples)
55    ///
56    /// # Example
57    ///
58    /// ```
59    /// use audio_blocks::{mono::AudioBlockMono, AudioBlock};
60    ///
61    /// let block = AudioBlockMono::<f32>::new(1024);
62    /// assert_eq!(block.num_frames(), 1024);
63    /// ```
64    #[blocking]
65    pub fn new(num_frames: usize) -> Self {
66        Self {
67            data: vec![S::default(); num_frames].into_boxed_slice(),
68            num_frames,
69            num_frames_allocated: num_frames,
70        }
71    }
72}
73
74impl<S: Sample> AudioBlockMono<S> {
75    /// Creates a new mono audio block from a slice of samples.
76    ///
77    /// Copies the provided slice into a new owned mono block.
78    ///
79    /// # Warning
80    ///
81    /// This function allocates memory and should not be used in real-time audio processing contexts.
82    ///
83    /// # Arguments
84    ///
85    /// * `samples` - The slice of samples to copy
86    #[blocking]
87    pub fn from_slice(samples: &[S]) -> Self {
88        Self {
89            data: samples.to_vec().into_boxed_slice(),
90            num_frames: samples.len(),
91            num_frames_allocated: samples.len(),
92        }
93    }
94
95    /// Creates a new mono audio block from a slice of samples.
96    ///
97    /// Copies the provided slice into a new owned mono block.
98    ///
99    /// # Warning
100    ///
101    /// This function allocates memory and should not be used in real-time audio processing contexts.
102    ///
103    /// # Arguments
104    ///
105    /// * `samples` - The slice of samples to copy
106    /// * `num_frames_visible` - Number of audio frames to expose
107    #[blocking]
108    pub fn from_slice_limited(samples: &[S], num_frames_visible: usize) -> Self {
109        assert!(num_frames_visible <= samples.len());
110        Self {
111            data: samples.to_vec().into_boxed_slice(),
112            num_frames: num_frames_visible,
113            num_frames_allocated: samples.len(),
114        }
115    }
116
117    /// Creates a new mono audio block by copying data from another [`AudioBlock`].
118    ///
119    /// Extracts the first channel from any [`AudioBlock`] implementation.
120    /// If the source block has no channels, creates an empty mono block.
121    ///
122    /// # Warning
123    ///
124    /// This function allocates memory and should not be used in real-time audio processing contexts.
125    ///
126    /// # Arguments
127    ///
128    /// * `block` - The source audio block to copy data from (first channel will be used)
129    ///
130    /// # Panics
131    ///
132    /// Panics if the source block has zero channels.
133    #[blocking]
134    pub fn from_block(block: &impl AudioBlock<S>) -> Self {
135        assert!(
136            block.num_channels() > 0,
137            "Cannot create mono block from block with zero channels"
138        );
139
140        let mut data = Vec::with_capacity(block.num_frames());
141        block.channel_iter(0).for_each(|&v| data.push(v));
142
143        Self {
144            data: data.into_boxed_slice(),
145            num_frames: block.num_frames(),
146            num_frames_allocated: block.num_frames(),
147        }
148    }
149
150    /// Returns the sample at the specified frame index.
151    ///
152    /// # Panics
153    ///
154    /// Panics if frame index is out of bounds.
155    #[nonblocking]
156    pub fn sample(&self, frame: usize) -> S {
157        assert!(frame < self.num_frames);
158        unsafe { *self.data.get_unchecked(frame) }
159    }
160
161    /// Returns a mutable reference to the sample at the specified frame index.
162    ///
163    /// # Panics
164    ///
165    /// Panics if frame index is out of bounds.
166    #[nonblocking]
167    pub fn sample_mut(&mut self, frame: usize) -> &mut S {
168        assert!(frame < self.num_frames);
169        unsafe { self.data.get_unchecked_mut(frame) }
170    }
171
172    /// Provides direct access to the underlying samples as a slice.
173    ///
174    /// Returns only the visible samples (up to `num_frames`).
175    #[nonblocking]
176    pub fn samples(&self) -> &[S] {
177        &self.data[..self.num_frames]
178    }
179
180    /// Provides direct mutable access to the underlying samples as a slice.
181    ///
182    /// Returns only the visible samples (up to `num_frames`).
183    #[nonblocking]
184    pub fn samples_mut(&mut self) -> &mut [S] {
185        let num_frames = self.num_frames;
186        &mut self.data[..num_frames]
187    }
188
189    /// Provides direct access to all allocated memory, including reserved capacity.
190    ///
191    /// This gives access to the full allocated buffer, including any frames
192    /// beyond the visible range.
193    #[nonblocking]
194    pub fn raw_data(&self) -> &[S] {
195        &self.data
196    }
197
198    /// Provides direct mutable access to all allocated memory, including reserved capacity.
199    ///
200    /// This gives mutable access to the full allocated buffer, including any frames
201    /// beyond the visible range.
202    #[nonblocking]
203    pub fn raw_data_mut(&mut self) -> &mut [S] {
204        &mut self.data
205    }
206
207    /// Creates a view of this mono audio block.
208    #[nonblocking]
209    pub fn view(&self) -> AudioBlockMonoView<'_, S> {
210        AudioBlockMonoView::from_slice_limited(
211            self.raw_data(),
212            self.num_frames,
213            self.num_frames_allocated,
214        )
215    }
216
217    /// Creates a mutable view of this mono audio block.
218    #[nonblocking]
219    pub fn view_mut(&mut self) -> AudioBlockMonoViewMut<'_, S> {
220        let num_frames = self.num_frames;
221        let num_frames_allocated = self.num_frames_allocated;
222        AudioBlockMonoViewMut::from_slice_limited(
223            self.raw_data_mut(),
224            num_frames,
225            num_frames_allocated,
226        )
227    }
228}
229
230impl<S: Sample> AudioBlock<S> for AudioBlockMono<S> {
231    type PlanarView = [S; 0];
232
233    #[nonblocking]
234    fn num_channels(&self) -> u16 {
235        1
236    }
237
238    #[nonblocking]
239    fn num_frames(&self) -> usize {
240        self.num_frames
241    }
242
243    #[nonblocking]
244    fn num_channels_allocated(&self) -> u16 {
245        1
246    }
247
248    #[nonblocking]
249    fn num_frames_allocated(&self) -> usize {
250        self.num_frames_allocated
251    }
252
253    #[nonblocking]
254    fn layout(&self) -> crate::BlockLayout {
255        crate::BlockLayout::Sequential
256    }
257
258    #[nonblocking]
259    fn sample(&self, channel: u16, frame: usize) -> S {
260        assert_eq!(channel, 0, "AudioBlockMono only has channel 0");
261        self.sample(frame)
262    }
263
264    #[nonblocking]
265    fn channel_iter(&self, channel: u16) -> impl Iterator<Item = &S> {
266        assert_eq!(channel, 0, "AudioBlockMono only has channel 0");
267        self.samples().iter()
268    }
269
270    #[nonblocking]
271    fn channels_iter(&self) -> impl Iterator<Item = impl Iterator<Item = &S> + '_> + '_ {
272        core::iter::once(self.samples().iter())
273    }
274
275    #[nonblocking]
276    fn frame_iter(&self, frame: usize) -> impl Iterator<Item = &S> {
277        assert!(frame < self.num_frames);
278        core::iter::once(&self.data[frame])
279    }
280
281    #[nonblocking]
282    fn frames_iter(&self) -> impl Iterator<Item = impl Iterator<Item = &S> + '_> + '_ {
283        self.data.iter().take(self.num_frames).map(core::iter::once)
284    }
285
286    #[nonblocking]
287    fn as_view(&self) -> impl AudioBlock<S> {
288        AudioBlockMonoView::from_slice_limited(
289            self.raw_data(),
290            self.num_frames,
291            self.num_frames_allocated,
292        )
293    }
294}
295
296impl<S: Sample> AudioBlockMut<S> for AudioBlockMono<S> {
297    type PlanarViewMut = [S; 0];
298
299    #[nonblocking]
300    fn set_num_channels_visible(&mut self, num_channels: u16) {
301        assert_eq!(
302            num_channels, 1,
303            "AudioBlockMono can only have 1 channel, got {}",
304            num_channels
305        );
306    }
307
308    #[nonblocking]
309    fn set_num_frames_visible(&mut self, num_frames: usize) {
310        assert!(
311            num_frames <= self.num_frames_allocated,
312            "Cannot set visible frames ({}) beyond allocated frames ({})",
313            num_frames,
314            self.num_frames_allocated
315        );
316        self.num_frames = num_frames;
317    }
318
319    #[nonblocking]
320    fn sample_mut(&mut self, channel: u16, frame: usize) -> &mut S {
321        assert_eq!(channel, 0, "AudioBlockMono only has channel 0");
322        self.sample_mut(frame)
323    }
324
325    #[nonblocking]
326    fn channel_iter_mut(&mut self, channel: u16) -> impl Iterator<Item = &mut S> {
327        assert_eq!(channel, 0, "AudioBlockMono only has channel 0");
328        self.samples_mut().iter_mut()
329    }
330
331    #[nonblocking]
332    fn channels_iter_mut(
333        &mut self,
334    ) -> impl Iterator<Item = impl Iterator<Item = &mut S> + '_> + '_ {
335        core::iter::once(self.samples_mut().iter_mut())
336    }
337
338    #[nonblocking]
339    fn frame_iter_mut(&mut self, frame: usize) -> impl Iterator<Item = &mut S> {
340        assert!(frame < self.num_frames);
341        let ptr = &mut self.data[frame] as *mut S;
342        // Safety: We're creating a single-item iterator from a valid mutable reference
343        core::iter::once(unsafe { &mut *ptr })
344    }
345
346    #[nonblocking]
347    fn frames_iter_mut(&mut self) -> impl Iterator<Item = impl Iterator<Item = &mut S> + '_> + '_ {
348        let num_frames = self.num_frames;
349        self.data.iter_mut().take(num_frames).map(core::iter::once)
350    }
351
352    #[nonblocking]
353    fn as_view_mut(&mut self) -> impl AudioBlockMut<S> {
354        let num_frames = self.num_frames;
355        let num_frames_allocated = self.num_frames_allocated;
356        AudioBlockMonoViewMut::from_slice_limited(
357            self.raw_data_mut(),
358            num_frames,
359            num_frames_allocated,
360        )
361    }
362}
363
364impl<S: Sample + core::fmt::Debug> core::fmt::Debug for AudioBlockMono<S> {
365    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
366        writeln!(f, "AudioBlockMono {{")?;
367        writeln!(f, "  num_frames: {}", self.num_frames)?;
368        writeln!(f, "  num_frames_allocated: {}", self.num_frames_allocated)?;
369        writeln!(f, "  samples: {:?}", self.samples())?;
370        writeln!(f, "}}")?;
371        Ok(())
372    }
373}
374
375#[cfg(test)]
376mod tests {
377    use super::*;
378    use rtsan_standalone::no_sanitize_realtime;
379
380    #[test]
381    fn test_new() {
382        let block = AudioBlockMono::<f32>::new(1024);
383        assert_eq!(block.num_frames(), 1024);
384        assert_eq!(block.num_frames_allocated(), 1024);
385        assert!(block.samples().iter().all(|&s| s == 0.0));
386    }
387
388    #[test]
389    fn test_from_slice() {
390        let samples = [1.0, 2.0, 3.0, 4.0, 5.0];
391        let block = AudioBlockMono::from_slice(&samples);
392        assert_eq!(block.num_frames(), 5);
393        assert_eq!(block.samples(), &samples);
394    }
395
396    #[test]
397    fn test_sample_access() {
398        let mut block = AudioBlockMono::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
399        assert_eq!(block.sample(0), 1.0);
400        assert_eq!(block.sample(2), 3.0);
401        assert_eq!(block.sample(4), 5.0);
402
403        *block.sample_mut(2) = 10.0;
404        assert_eq!(block.sample(2), 10.0);
405    }
406
407    #[test]
408    fn test_iterators() {
409        let mut block = AudioBlockMono::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
410
411        let sum: f32 = block.samples().iter().sum();
412        assert_eq!(sum, 15.0);
413
414        for sample in block.samples_mut() {
415            *sample *= 2.0;
416        }
417
418        assert_eq!(block.samples(), &[2.0, 4.0, 6.0, 8.0, 10.0]);
419    }
420
421    #[test]
422    #[should_panic]
423    #[no_sanitize_realtime]
424    fn test_resize_beyond_allocated() {
425        let mut block = AudioBlockMono::<f32>::new(10);
426        block.set_num_frames_visible(11);
427    }
428
429    #[test]
430    fn test_audio_block_trait() {
431        let block = AudioBlockMono::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
432
433        assert_eq!(block.num_channels(), 1);
434        assert_eq!(block.num_frames(), 5);
435
436        // Test channel_iter
437        let channel: Vec<f32> = block.channel_iter(0).copied().collect();
438        assert_eq!(channel, vec![1.0, 2.0, 3.0, 4.0, 5.0]);
439
440        // Test frame_iter
441        let frame: Vec<f32> = block.frame_iter(2).copied().collect();
442        assert_eq!(frame, vec![3.0]);
443    }
444
445    #[test]
446    fn test_audio_block_mut_trait() {
447        let mut block = AudioBlockMono::<f32>::new(5);
448
449        for (i, sample) in block.channel_iter_mut(0).enumerate() {
450            *sample = i as f32;
451        }
452
453        assert_eq!(block.samples(), &[0.0, 1.0, 2.0, 3.0, 4.0]);
454    }
455
456    #[test]
457    #[should_panic]
458    #[no_sanitize_realtime]
459    fn test_wrong_channel() {
460        let block = AudioBlockMono::<f32>::new(10);
461        let _ = block.channel_iter(1);
462    }
463
464    #[test]
465    #[should_panic]
466    #[no_sanitize_realtime]
467    fn test_sample_out_of_bounds() {
468        let block = AudioBlockMono::<f32>::new(10);
469        let _ = block.sample(10);
470    }
471
472    #[test]
473    fn test_from_block() {
474        use crate::AudioBlockInterleaved;
475
476        let mut multi = AudioBlockInterleaved::<f32>::new(2, 5);
477        for (i, sample) in multi.channel_iter_mut(0).enumerate() {
478            *sample = i as f32;
479        }
480
481        let mono = AudioBlockMono::from_block(&multi);
482        assert_eq!(mono.samples(), &[0.0, 1.0, 2.0, 3.0, 4.0]);
483    }
484
485    #[test]
486    fn test_views() {
487        let mut block = AudioBlockMono::from_slice(&[1.0, 2.0, 3.0, 4.0, 5.0]);
488
489        // Test immutable view
490        {
491            let view = block.as_view();
492            assert_eq!(view.num_frames(), 5);
493            assert_eq!(view.sample(0, 2), 3.0);
494        }
495
496        // Test mutable view
497        {
498            let mut view_mut = block.as_view_mut();
499            *view_mut.sample_mut(0, 2) = 10.0;
500        }
501
502        assert_eq!(block.sample(2), 10.0);
503    }
504}