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}