audio_blocks/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(all(not(test), not(feature = "std")), no_std)] // enable std library when feature std is provided
3
4#[cfg(all(feature = "alloc", not(feature = "std")))]
5extern crate alloc;
6
7#[cfg(not(feature = "std"))]
8extern crate core as std;
9
10#[cfg(feature = "std")]
11extern crate std;
12
13pub use num::Zero;
14pub use ops::AudioBlockOps;
15
16#[cfg(any(feature = "std", feature = "alloc"))]
17pub use interleaved::AudioBlockInterleaved;
18pub use interleaved::AudioBlockInterleavedView;
19pub use interleaved::AudioBlockInterleavedViewMut;
20
21#[cfg(any(feature = "std", feature = "alloc"))]
22pub use sequential::AudioBlockSequential;
23pub use sequential::AudioBlockSequentialView;
24pub use sequential::AudioBlockSequentialViewMut;
25
26#[cfg(any(feature = "std", feature = "alloc"))]
27pub use planar::AudioBlockPlanar;
28pub use planar::AudioBlockPlanarView;
29pub use planar::AudioBlockPlanarViewMut;
30pub use planar::PlanarPtrAdapter;
31pub use planar::PlanarPtrAdapterMut;
32
33pub mod interleaved;
34mod iter;
35pub mod ops;
36pub mod planar;
37pub mod sequential;
38
39/// Represents the memory layout of audio data returned by [`AudioBlock::layout`].
40///
41/// This enum allows consumers to determine the underlying data layout, which is essential for:
42/// - Direct raw data access
43/// - Performance optimizations
44/// - Efficient interfacing with external audio APIs
45///
46/// # Examples of layouts
47///
48/// Each variant represents a common pattern used in audio processing.
49#[derive(PartialEq, Debug)]
50pub enum BlockLayout {
51    /// Samples from different channels alternate in sequence.
52    ///
53    /// Format: `[ch0, ch1, ..., ch0, ch1, ..., ch0, ch1, ...]`
54    ///
55    /// This layout is common in consumer audio formats and some APIs.
56    Interleaved,
57
58    /// Channels are separated into discrete chunks of memory.
59    ///
60    /// Format: `[[ch0, ch0, ch0, ...], [ch1, ch1, ch1, ...]]`
61    ///
62    /// Useful for operations that work on one channel at a time.
63    Planar,
64
65    /// All samples from one channel appear consecutively before the next channel.
66    ///
67    /// Format: `[ch0, ch0, ch0, ..., ch1, ch1, ch1, ...]`
68    ///
69    /// Also known as "planar" format in some audio libraries.
70    Sequential,
71}
72
73/// Represents a sample type that can be stored and processed in audio blocks.
74///
75/// This trait is automatically implemented for any type that meets the following requirements:
76/// - `Copy`: The type can be copied by value efficiently
77/// - `Zero`: The type has a zero value
78/// - `'static`: The type doesn't contain any non-static references
79///
80/// All numeric types (f32, f64, i16, i32, etc.) automatically implement this trait,
81/// as well as any custom types that satisfy these bounds.
82pub trait Sample: Copy + Zero + 'static {}
83impl<T> Sample for T where T: Copy + Zero + 'static {}
84
85/// Core trait for audio data access operations across various memory layouts.
86///
87/// [`AudioBlock`] provides a unified interface for interacting with audio data regardless of its
88/// underlying memory representation ([`BlockLayout::Interleaved`], [`BlockLayout::Sequential`], or [`BlockLayout::Planar`]). It supports operations
89/// on both owned audio blocks and temporary views.
90///
91/// # Usage
92///
93/// This trait gives you multiple ways to access audio data:
94/// - Direct sample access via indices
95/// - Channel and frame iterators for processing data streams
96/// - Raw data access for optimized operations
97/// - Layout information for specialized handling
98///
99/// # Example
100///
101/// ```
102/// use audio_blocks::AudioBlock;
103///
104/// fn example(audio: &impl AudioBlock<f32>) {
105///     // Get number of channels and frames
106///     let channels = audio.num_channels();
107///     let frames = audio.num_frames();
108///
109///     // Access individual samples
110///     let first_sample = audio.sample(0, 0);
111///
112///     // Process one channel
113///     for sample in audio.channel_iter(0) {
114///         // work with each sample
115///     }
116///
117///     // Process all channels
118///     for channel in audio.channels_iter() {
119///         for sample in channel {
120///             // work with each sample
121///         }
122///     }
123/// }
124/// ```
125pub trait AudioBlock<S: Sample> {
126    type PlanarView: AsRef<[S]>;
127
128    /// Returns the number of active audio channels.
129    fn num_channels(&self) -> u16;
130
131    /// Returns the number of audio frames (samples per channel).
132    fn num_frames(&self) -> usize;
133
134    /// Returns the total number of channels allocated in memory.
135    ///
136    /// This may be greater than `num_channels()` if the buffer has reserved capacity.
137    fn num_channels_allocated(&self) -> u16;
138
139    /// Returns the total number of frames allocated in memory.
140    ///
141    /// This may be greater than `num_frames()` if the buffer has reserved capacity.
142    fn num_frames_allocated(&self) -> usize;
143
144    /// Returns the memory layout of this audio block (interleaved, sequential, or planar).
145    fn layout(&self) -> BlockLayout;
146
147    /// Returns the sample value at the specified channel and frame position.
148    ///
149    /// # Panics
150    ///
151    /// Panics if channel or frame indices are out of bounds.
152    fn sample(&self, channel: u16, frame: usize) -> S;
153
154    /// Returns an iterator over all samples in the specified channel.
155    ///
156    /// # Panics
157    ///
158    /// Panics if channel index is out of bounds.
159    fn channel_iter(&self, channel: u16) -> impl Iterator<Item = &S>;
160
161    /// Returns an iterator that yields an iterator for each channel.
162    fn channels_iter(&self) -> impl Iterator<Item = impl Iterator<Item = &S> + '_> + '_;
163
164    /// Returns an iterator over all samples in the specified frame (across all channels).
165    ///
166    /// # Panics
167    ///
168    /// Panics if frame index is out of bounds.
169    fn frame_iter(&self, frame: usize) -> impl Iterator<Item = &S>;
170
171    /// Returns an iterator that yields an iterator for each frame.
172    fn frame_iters(&self) -> impl Iterator<Item = impl Iterator<Item = &S> + '_> + '_;
173
174    /// Creates a non-owning view of this audio block.
175    ///
176    /// This operation is real-time safe, as it returns a lightweight
177    /// wrapper around the original data.
178    fn as_view(&self) -> impl AudioBlock<S>;
179
180    /// Attempts to downcast this generic audio block to a concrete interleaved view.
181    /// This enables access to frame slices and the underlying raw data.
182    ///
183    /// Returns `Some` if the underlying data is stored in interleaved format,
184    /// otherwise returns `None`.
185    fn as_interleaved_view(&self) -> Option<AudioBlockInterleavedView<'_, S>> {
186        None
187    }
188
189    /// Attempts to downcast this generic audio block to a concrete planar view.
190    /// This enables access to frame slices and the underlying raw data.
191    ///
192    /// Returns `Some` if the underlying data is stored in planar format,
193    /// otherwise returns `None`.
194    fn as_planar_view(&self) -> Option<AudioBlockPlanarView<'_, S, Self::PlanarView>> {
195        None
196    }
197
198    /// Attempts to downcast this generic audio block to a concrete sequential view.
199    /// This enables access to frame slices and the underlying raw data.
200    ///
201    /// Returns `Some` if the underlying data is stored in sequential format,
202    /// otherwise returns `None`.
203    fn as_sequential_view(&self) -> Option<AudioBlockSequentialView<'_, S>> {
204        None
205    }
206}
207
208/// Extends the [`AudioBlock`] trait with mutable access operations.
209///
210/// [`AudioBlockMut`] provides methods for modifying audio data across different memory layouts.
211/// It enables in-place processing, buffer resizing, and direct mutable access to the underlying data.
212///
213/// # Usage
214///
215/// This trait gives you multiple ways to modify audio data:
216/// - Change individual samples at specific positions
217/// - Iterate through and modify channels or frames
218/// - Resize the buffer to accommodate different audio requirements
219/// - Access raw data for optimized processing
220///
221/// # Example
222///
223/// ```
224/// use audio_blocks::{AudioBlock, AudioBlockMut};
225///
226/// fn process_audio(audio: &mut impl AudioBlockMut<f32>) {
227///     // Resize to 2 channels, 1024 frames
228///     audio.set_active_size(2, 1024);
229///
230///     // Modify individual samples
231///     *audio.sample_mut(0, 0) = 0.5;
232///
233///     // Process one channel with mutable access
234///     for sample in audio.channel_iter_mut(0) {
235///         *sample *= 0.8; // Apply gain reduction
236///     }
237///
238///     // Process all channels
239///     for mut channel in audio.channels_iter_mut() {
240///         for sample in channel {
241///             // Apply processing to each sample
242///         }
243///     }
244/// }
245/// ```
246pub trait AudioBlockMut<S: Sample>: AudioBlock<S> {
247    type PlanarViewMut: AsRef<[S]> + AsMut<[S]>;
248
249    /// Sets the active size of the audio block to the specified number of channels and frames.
250    ///
251    /// # Panics
252    ///
253    /// When `num_channels` exceeds [`AudioBlock::num_channels_allocated`] or `num_frames` exceeds [`AudioBlock::num_frames_allocated`].
254    fn set_active_size(&mut self, num_channels: u16, num_frames: usize) {
255        self.set_active_num_channels(num_channels);
256        self.set_active_num_frames(num_frames);
257    }
258
259    /// Sets the active size of the audio block to the specified number of channels.
260    ///
261    /// This operation is real-time safe but only works up to [`AudioBlock::num_channels_allocated`].
262    ///
263    /// # Panics
264    ///
265    /// When `num_channels` exceeds [`AudioBlock::num_channels_allocated`].
266    fn set_active_num_channels(&mut self, num_channels: u16);
267
268    /// Sets the active size of the audio block to the specified number of frames.
269    ///
270    /// # Panics
271    ///
272    ///  When `num_frames` exceeds [`AudioBlock::num_frames_allocated`].
273    fn set_active_num_frames(&mut self, num_frames: usize);
274
275    /// Returns a mutable reference to the sample at the specified channel and frame position.
276    ///
277    /// # Panics
278    ///
279    /// Panics if channel or frame indices are out of bounds.
280    fn sample_mut(&mut self, channel: u16, frame: usize) -> &mut S;
281
282    /// Returns a mutable iterator over all samples in the specified channel.
283    ///
284    /// # Panics
285    ///
286    /// Panics if channel index is out of bounds.
287    fn channel_iter_mut(&mut self, channel: u16) -> impl Iterator<Item = &mut S>;
288
289    /// Returns a mutable iterator that yields mutable iterators for each channel.
290    fn channels_iter_mut(&mut self)
291    -> impl Iterator<Item = impl Iterator<Item = &mut S> + '_> + '_;
292
293    /// Returns a mutable iterator over all samples in the specified frame (across all channels).
294    ///
295    /// # Panics
296    ///
297    /// Panics if frame index is out of bounds.
298    fn frame_iter_mut(&mut self, frame: usize) -> impl Iterator<Item = &mut S>;
299
300    /// Returns a mutable iterator that yields mutable iterators for each frame.
301    fn frames_iter_mut(&mut self) -> impl Iterator<Item = impl Iterator<Item = &mut S> + '_> + '_;
302
303    /// Creates a non-owning mutable view of this audio block.
304    ///
305    /// This operation is real-time safe, as it returns a lightweight
306    /// wrapper around the original data.
307    fn as_view_mut(&mut self) -> impl AudioBlockMut<S>;
308
309    /// Attempts to downcast this generic audio block to a concrete interleaved view.
310    /// This enables access to frame slices and the underlying raw data.
311    ///
312    /// Returns `Some` if the underlying data is stored in interleaved format,
313    /// otherwise returns `None`.
314    fn as_interleaved_view_mut(&mut self) -> Option<AudioBlockInterleavedViewMut<'_, S>> {
315        None
316    }
317
318    /// Attempts to downcast this generic audio block to a concrete planar view.
319    /// This enables access to frame slices and the underlying raw data.
320    ///
321    /// Returns `Some` if the underlying data is stored in planar format,
322    /// otherwise returns `None`.
323    fn as_planar_view_mut(
324        &mut self,
325    ) -> Option<AudioBlockPlanarViewMut<'_, S, Self::PlanarViewMut>> {
326        None
327    }
328
329    /// Attempts to downcast this generic audio block to a concrete sequential view.
330    /// This enables access to frame slices and the underlying raw data.
331    ///
332    /// Returns `Some` if the underlying data is stored in sequential format,
333    /// otherwise returns `None`.
334    fn as_sequential_view_mut(&mut self) -> Option<AudioBlockSequentialViewMut<'_, S>> {
335        None
336    }
337}