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}