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}