audio_blocks/
lib.rs

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