Skip to main content

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