pub struct CollectedAudio {
samples: Vec<f32>,
sample_rate: u32,
channels: u16,
channel_layout: String,
}
impl CollectedAudio {
pub(crate) fn new(
samples: Vec<f32>,
sample_rate: u32,
channels: u16,
channel_layout: String,
) -> Self {
#[allow(clippy::manual_is_multiple_of)]
{
debug_assert!(
if channels == 0 {
samples.is_empty()
} else {
samples.len() % channels as usize == 0
},
"CollectedAudio buffer must hold whole interleaved frames"
);
}
Self {
samples,
sample_rate,
channels,
channel_layout,
}
}
pub fn sample_rate(&self) -> u32 {
self.sample_rate
}
pub fn channels(&self) -> u16 {
self.channels
}
pub fn channel_layout(&self) -> &str {
&self.channel_layout
}
pub fn as_slice(&self) -> &[f32] {
&self.samples
}
pub fn into_vec(self) -> Vec<f32> {
self.samples
}
}
impl std::fmt::Debug for CollectedAudio {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CollectedAudio")
.field("sample_rate", &self.sample_rate)
.field("channels", &self.channels)
.field("channel_layout", &self.channel_layout)
.field("samples", &self.samples.len())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accessors_round_trip_the_shape() {
let a = CollectedAudio::new(vec![0.25; 12], 48_000, 6, "5.1".to_string());
assert_eq!(a.sample_rate(), 48_000);
assert_eq!(a.channels(), 6);
assert_eq!(a.channel_layout(), "5.1");
assert_eq!(a.as_slice().len(), 12);
assert_eq!(a.into_vec(), vec![0.25; 12]);
}
#[test]
fn empty_run_is_fully_zeroed() {
let a = CollectedAudio::new(Vec::new(), 0, 0, String::new());
assert!(a.as_slice().is_empty());
assert_eq!(a.sample_rate(), 0);
assert_eq!(a.channels(), 0);
assert_eq!(a.channel_layout(), "");
}
}