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}