conformal_component/audio.rs
1//! Types and utilities for Audio Buffers.
2//!
3//! In Conformal, components process audio in buffers. Buffers are groups of samples
4//! arranged into channels. In Conformal, each channel is represented by a `&[f32]`.
5
6/// Defines the layout of the channels in a buffer.
7#[derive(Debug, Copy, Clone, PartialEq, Eq)]
8pub enum ChannelLayout {
9 /// A single channel buffer.
10 Mono,
11
12 /// A two channel buffer.
13 ///
14 /// Channel 0 is the left channel, and channel 1 is the right channel.
15 Stereo,
16}
17
18mod compare;
19pub use compare::*;
20
21mod slice;
22pub use slice::*;
23
24impl ChannelLayout {
25 /// The number of channels in the layout.
26 ///
27 /// # Examples
28 ///
29 /// ```
30 /// # use conformal_component::audio::ChannelLayout;
31 /// assert_eq!(ChannelLayout::Mono.num_channels(), 1);
32 /// assert_eq!(ChannelLayout::Stereo.num_channels(), 2);
33 /// ```
34 #[must_use]
35 pub fn num_channels(self) -> usize {
36 match self {
37 ChannelLayout::Mono => 1,
38 ChannelLayout::Stereo => 2,
39 }
40 }
41}
42
43/// Represents a (potentially multi-channel) buffer of audio samples
44///
45/// A [Buffer] doesn't specify the exact storage format of the samples, but
46/// each channel must be a contiguous slice of samples. All channels must have
47/// the same number of samples, that is, [`Buffer::num_frames`].
48pub trait Buffer {
49 /// The layout of the channels in the buffer.
50 fn channel_layout(&self) -> ChannelLayout;
51
52 /// The number of channels in the buffer.
53 fn num_channels(&self) -> usize {
54 self.channel_layout().num_channels()
55 }
56
57 /// The number of frames in the buffer.
58 ///
59 /// Each channel will contain this many samples.
60 fn num_frames(&self) -> usize;
61
62 /// Get a channel from the buffer.
63 ///
64 /// This returns a slice that contains all samples of the channel.
65 /// The every channel will have [`Self::num_frames`] elements.
66 ///
67 /// # Panics
68 ///
69 /// Panics if `channel` is greater than or equal to [`Self::num_channels`].
70 fn channel(&self, channel: usize) -> &[f32];
71}
72
73/// Returns an iterator for the channels of a buffer.
74///
75/// The items of this iterator will be slices of the samples of each channel.
76/// Each slice will be exactly [`Buffer::num_frames`] elements long.
77///
78/// # Examples
79/// ```
80/// # use conformal_component::audio::{BufferData, Buffer, channels};
81/// let buffer = BufferData::new_stereo([1.0, 2.0], [3.0, 4.0]);
82/// assert!(channels(&buffer).eq([[1.0, 2.0], [3.0, 4.0]]));
83/// ```
84pub fn channels<B: Buffer>(buffer: &B) -> impl Iterator<Item = &[f32]> {
85 (0..buffer.num_channels()).map(move |channel| buffer.channel(channel))
86}
87
88/// A mutable (potentially multi-channel) buffer of audio samples.
89///
90/// This is a mutable version of [`Buffer`].
91pub trait BufferMut: Buffer {
92 /// Get a channel from the buffer as a mutable slice
93 fn channel_mut(&mut self, channel: usize) -> &mut [f32];
94}
95
96/// Returns an iterator for the channels of a mutable buffer.
97///
98/// The items of this iterator will be mutable slices of the samples of each channel.
99///
100/// # Examples
101///
102/// ```
103/// # use conformal_component::audio::{BufferData, Buffer, BufferMut, channels_mut};
104/// let mut buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0]);
105/// for channel in channels_mut(&mut buffer) {
106/// for sample in channel {
107/// *sample *= 2.0;
108/// }
109/// }
110/// assert_eq!(buffer.channel(0), [2.0, 4.0, 6.0]);
111/// ```
112pub fn channels_mut<B: BufferMut>(buffer: &mut B) -> impl Iterator<Item = &mut [f32]> {
113 (0..buffer.num_channels()).map(move |channel| unsafe {
114 std::slice::from_raw_parts_mut(
115 buffer.channel_mut(channel).as_mut_ptr(),
116 buffer.num_frames(),
117 )
118 })
119}
120
121/// A buffer of audio samples that owns its data.
122///
123/// This is a simple implementation of [`Buffer`] that owns its data on the heap.
124/// It is useful for testing and as a simple way to create buffers.
125///
126/// # Examples
127///
128/// ```
129/// # use conformal_component::audio::{BufferData, Buffer};
130/// let buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0]);
131/// assert_eq!(buffer.channel(0), [1.0, 2.0, 3.0]);
132/// ```
133#[derive(Debug, Clone)]
134pub struct BufferData {
135 channel_layout: ChannelLayout,
136 num_frames: usize,
137 data: Vec<f32>,
138}
139
140impl BufferData {
141 /// Create a new buffer with the given channel layout and number of frames.
142 ///
143 /// The buffer will be filled with zeros.
144 ///
145 /// # Examples
146 ///
147 /// ```
148 /// # use conformal_component::audio::{Buffer, BufferData, ChannelLayout};
149 /// let buffer = BufferData::new(ChannelLayout::Mono, 3);
150 /// assert_eq!(buffer.channel_layout(), ChannelLayout::Mono);
151 /// assert_eq!(buffer.channel(0), [0.0, 0.0, 0.0]);
152 /// ```
153 #[must_use]
154 pub fn new(channel_layout: ChannelLayout, num_frames: usize) -> Self {
155 Self {
156 channel_layout,
157 num_frames,
158 data: vec![0f32; channel_layout.num_channels() * num_frames],
159 }
160 }
161
162 /// Create a new mono buffer with the given data.
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// # use conformal_component::audio::{Buffer, BufferData, ChannelLayout};
168 /// let buffer = BufferData::new_mono(vec![1.0, 2.0, 3.0]);
169 /// assert_eq!(buffer.channel_layout(), ChannelLayout::Mono);
170 /// assert_eq!(buffer.channel(0), [1.0, 2.0, 3.0]);
171 /// ```
172 #[must_use]
173 pub fn new_mono(data: Vec<f32>) -> BufferData {
174 Self {
175 channel_layout: ChannelLayout::Mono,
176 num_frames: data.len(),
177 data,
178 }
179 }
180
181 /// Create a new stereo buffer with the given data.
182 ///
183 /// # Examples
184 ///
185 /// ```
186 /// # use conformal_component::audio::{Buffer, BufferData, ChannelLayout, channels};
187 /// let buffer = BufferData::new_stereo([1.0, 2.0], [3.0, 4.0]);
188 /// assert_eq!(buffer.channel_layout(), ChannelLayout::Stereo);
189 /// assert!(channels(&buffer).eq([[1.0, 2.0], [3.0, 4.0]]));
190 /// ```
191 ///
192 /// # Panics
193 ///
194 /// Panics if the length of `left` and `right` are not equal.
195 ///
196 /// ```should_panic
197 /// # use conformal_component::audio::BufferData;
198 /// let buffer = BufferData::new_stereo([1.0, 2.0], [3.0]);
199 /// ```
200 #[must_use]
201 pub fn new_stereo<L: IntoIterator<Item = f32>, R: IntoIterator<Item = f32>>(
202 left: L,
203 right: R,
204 ) -> BufferData {
205 let mut data: Vec<_> = left.into_iter().collect();
206 let left_len = data.len();
207 data.extend(right);
208 assert_eq!(left_len * 2, data.len());
209 Self {
210 channel_layout: ChannelLayout::Stereo,
211 num_frames: left_len,
212 data,
213 }
214 }
215}
216
217impl Buffer for BufferData {
218 fn channel_layout(&self) -> ChannelLayout {
219 self.channel_layout
220 }
221
222 fn num_frames(&self) -> usize {
223 self.num_frames
224 }
225
226 fn channel(&self, channel: usize) -> &[f32] {
227 &self.data[channel * self.num_frames..(channel + 1) * self.num_frames]
228 }
229}
230
231impl BufferMut for BufferData {
232 fn channel_mut(&mut self, channel: usize) -> &mut [f32] {
233 &mut self.data[channel * self.num_frames..(channel + 1) * self.num_frames]
234 }
235}