use std::sync::Arc;
use crate::render::AudioRenderQuantum;
use crate::{
assert_valid_channel_number, assert_valid_number_of_channels, assert_valid_sample_rate,
};
#[derive(Clone, Debug)]
pub struct AudioBufferOptions {
pub number_of_channels: usize,
pub length: usize,
pub sample_rate: f32,
}
#[derive(Clone, Debug)]
pub struct AudioBuffer {
channels: Vec<ChannelData>,
sample_rate: f32,
}
impl AudioBuffer {
pub fn new(options: AudioBufferOptions) -> Self {
assert_valid_sample_rate(options.sample_rate);
assert_valid_number_of_channels(options.number_of_channels);
let silence = ChannelData::new(options.length);
Self {
channels: vec![silence; options.number_of_channels],
sample_rate: options.sample_rate,
}
}
pub fn from(samples: Vec<Vec<f32>>, sample_rate: f32) -> Self {
assert_valid_sample_rate(sample_rate);
assert_valid_number_of_channels(samples.len());
let channels: Vec<_> = samples.into_iter().map(ChannelData::from).collect();
if !channels.iter().all(|c| c.len() == channels[0].len()) {
panic!("Trying to create AudioBuffer from channel data with unequal length");
}
Self {
channels,
sample_rate,
}
}
pub fn number_of_channels(&self) -> usize {
self.channels.len()
}
pub fn length(&self) -> usize {
self.channels.get(0).map(ChannelData::len).unwrap_or(0)
}
pub fn sample_rate(&self) -> f32 {
self.sample_rate
}
pub fn duration(&self) -> f64 {
self.length() as f64 / self.sample_rate as f64
}
pub fn copy_from_channel(&self, destination: &mut [f32], channel_number: usize) {
assert_valid_channel_number(channel_number, self.number_of_channels());
self.copy_from_channel_with_offset(destination, channel_number, 0);
}
pub fn copy_from_channel_with_offset(
&self,
destination: &mut [f32],
channel_number: usize,
offset: usize,
) {
assert_valid_channel_number(channel_number, self.number_of_channels());
let offset = offset.min(self.length());
let dest_length = destination.len();
let max_frame = (self.length() - offset).clamp(0, dest_length);
let channel = self.channel_data(channel_number).as_slice();
destination[..max_frame].copy_from_slice(&channel[offset..(max_frame + offset)]);
}
pub fn copy_to_channel(&mut self, source: &[f32], channel_number: usize) {
assert_valid_channel_number(channel_number, self.number_of_channels());
self.copy_to_channel_with_offset(source, channel_number, 0);
}
pub fn copy_to_channel_with_offset(
&mut self,
source: &[f32],
channel_number: usize,
offset: usize,
) {
assert_valid_channel_number(channel_number, self.number_of_channels());
let offset = offset.min(self.length());
let src_len = source.len();
let max_frame = (self.length() - offset).clamp(0, src_len);
let channel = self.channel_data_mut(channel_number).as_mut_slice();
channel[offset..(max_frame + offset)].copy_from_slice(&source[..max_frame]);
}
pub fn get_channel_data(&self, channel_number: usize) -> &[f32] {
assert_valid_channel_number(channel_number, self.number_of_channels());
self.channel_data(channel_number).as_slice()
}
pub fn get_channel_data_mut(&mut self, channel_number: usize) -> &mut [f32] {
assert_valid_channel_number(channel_number, self.number_of_channels());
self.channel_data_mut(channel_number).as_mut_slice()
}
pub(crate) fn from_channels(channels: Vec<ChannelData>, sample_rate: f32) -> Self {
Self {
channels,
sample_rate,
}
}
pub(crate) fn channels(&self) -> &[ChannelData] {
&self.channels
}
pub(crate) fn channels_mut(&mut self) -> &mut [ChannelData] {
&mut self.channels
}
pub(crate) fn channel_data(&self, index: usize) -> &ChannelData {
&self.channels[index]
}
pub(crate) fn channel_data_mut(&mut self, index: usize) -> &mut ChannelData {
&mut self.channels[index]
}
pub(crate) fn extend(&mut self, other: &Self) {
assert_eq!(self.sample_rate, other.sample_rate);
assert_eq!(self.number_of_channels(), other.number_of_channels());
let data = self.channels_mut();
data.iter_mut()
.zip(other.channels.iter())
.for_each(|(channel, other_channel)| {
let cur_channel_data = Arc::make_mut(&mut channel.data);
cur_channel_data.extend(other_channel.as_slice());
})
}
pub(crate) fn extend_alloc(&mut self, other: &AudioRenderQuantum) {
assert_eq!(self.number_of_channels(), other.number_of_channels());
self.channels_mut()
.iter_mut()
.zip(other.channels())
.for_each(|(channel, other_channel)| {
let cur_channel_data = Arc::make_mut(&mut channel.data);
cur_channel_data.extend_from_slice(&other_channel[..]);
})
}
pub(crate) fn split_off(&mut self, index: usize) -> Self {
let channels: Vec<_> = self
.channels_mut()
.iter_mut()
.map(|channel_data| Arc::make_mut(&mut channel_data.data).split_off(index))
.map(ChannelData::from)
.collect();
AudioBuffer::from_channels(channels, self.sample_rate)
}
pub(crate) fn resample(&mut self, sample_rate: f32) {
assert_valid_sample_rate(sample_rate);
if float_eq::float_eq!(self.sample_rate, sample_rate, abs <= 0.1) {
self.sample_rate = sample_rate;
return;
}
if self.length() == 0 {
self.sample_rate = sample_rate;
return;
}
let source_sr = self.sample_rate as f64;
let target_sr = sample_rate as f64;
let ratio = target_sr / source_sr;
let source_length = self.length();
let target_length = (self.length() as f64 * ratio).ceil() as usize;
let num_channels = self.number_of_channels();
let mut resampled = Vec::<Vec<f32>>::with_capacity(num_channels);
resampled.resize_with(num_channels, || Vec::<f32>::with_capacity(target_length));
for i in 0..target_length {
let position = i as f64 / (target_length - 1) as f64; let playhead = position * (source_length - 1) as f64;
let playhead_floored = playhead.floor();
let prev_index = playhead_floored as usize;
let next_index = (prev_index + 1).min(source_length - 1);
let k = (playhead - playhead_floored) as f32;
let k_inv = 1. - k;
for (channel, resampled_data) in resampled.iter_mut().enumerate() {
let prev_sample = self.channels[channel].data[prev_index];
let next_sample = self.channels[channel].data[next_index];
let value = k_inv * prev_sample + k * next_sample;
resampled_data.push(value);
}
}
self.channels
.iter_mut()
.zip(resampled)
.for_each(|(channel_data, resampled_data)| {
channel_data.data = Arc::new(resampled_data);
});
self.sample_rate = sample_rate;
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct ChannelData {
data: Arc<Vec<f32>>,
}
impl ChannelData {
pub fn new(length: usize) -> Self {
let buffer = vec![0.; length];
let data = Arc::new(buffer);
Self { data }
}
pub fn from(data: Vec<f32>) -> Self {
Self {
data: Arc::new(data),
}
}
pub fn len(&self) -> usize {
self.data.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn as_slice(&self) -> &[f32] {
&self.data[..]
}
pub fn as_mut_slice(&mut self) -> &mut [f32] {
&mut Arc::make_mut(&mut self.data)[..]
}
}
#[cfg(test)]
mod tests {
use float_eq::assert_float_eq;
use std::f32::consts::PI;
use super::*;
#[test]
fn test_constructor() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 96000,
sample_rate: 48000.,
};
let audio_buffer = AudioBuffer::new(options);
assert_eq!(audio_buffer.number_of_channels(), 1);
assert_eq!(audio_buffer.length(), 96000);
assert_float_eq!(audio_buffer.sample_rate(), 48000., abs <= 0.);
assert_float_eq!(audio_buffer.duration(), 2., abs <= 0.);
}
#[test]
#[should_panic]
fn test_zero_channels() {
let options = AudioBufferOptions {
number_of_channels: 0,
length: 10,
sample_rate: 48000.,
};
AudioBuffer::new(options); }
#[test]
#[should_panic]
fn test_zero_channels_from() {
let samples = vec![];
let sample_rate = 48000.;
AudioBuffer::from(samples, sample_rate); }
#[test]
#[should_panic]
fn test_invalid_sample_rate() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 10,
sample_rate: 0.,
};
AudioBuffer::new(options); }
#[test]
#[should_panic]
fn test_invalid_sample_rate_from() {
let samples = vec![vec![0.]];
let sample_rate = 0.;
AudioBuffer::from(samples, sample_rate); }
#[test]
fn test_channel_data_get_set() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 10,
sample_rate: 48000.,
};
let mut audio_buffer = AudioBuffer::new(options);
audio_buffer.channel_data_mut(0).as_mut_slice().fill(1.);
assert_float_eq!(
audio_buffer.channel_data(0).as_slice()[..],
[1.; 10][..],
abs_all <= 0.
);
}
#[test]
#[should_panic]
fn test_invalid_copy_from_channel() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 10,
sample_rate: 48000.,
};
let audio_buffer = AudioBuffer::new(options);
let mut dest = vec![1.; 10];
audio_buffer.copy_from_channel(&mut dest, 1);
}
#[test]
fn test_copy_from_channel() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 10,
sample_rate: 48000.,
};
let audio_buffer = AudioBuffer::new(options);
let mut dest = vec![1.; 10];
audio_buffer.copy_from_channel(&mut dest, 0);
assert_float_eq!(dest[..], vec![0.; 10][..], abs_all <= 0.);
let mut dest = vec![1.; 5];
audio_buffer.copy_from_channel(&mut dest, 0);
assert_float_eq!(dest[..], [0., 0., 0., 0., 0.][..], abs_all <= 0.);
let mut dest = vec![1.; 11];
audio_buffer.copy_from_channel(&mut dest, 0);
assert_float_eq!(
dest[..],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.][..],
abs_all <= 0.
);
let mut dest = vec![1.; 10];
audio_buffer.copy_from_channel_with_offset(&mut dest, 0, 5);
assert_float_eq!(
dest[..],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.][..],
abs_all <= 0.
);
let mut dest = vec![1.; 10];
audio_buffer.copy_from_channel_with_offset(&mut dest, 0, usize::MAX);
assert_float_eq!(dest[..], vec![1.; 10][..], abs_all <= 0.);
}
#[test]
#[should_panic]
fn test_invalid_copy_to_channel() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 10,
sample_rate: 48000.,
};
let mut audio_buffer = AudioBuffer::new(options);
let src = vec![1.; 10];
audio_buffer.copy_to_channel(&src, 1);
}
#[test]
fn test_copy_to_channel() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 10,
sample_rate: 48000.,
};
{
let mut audio_buffer = AudioBuffer::new(options.clone());
let src = vec![1.; 10];
audio_buffer.copy_to_channel(&src, 0);
assert_float_eq!(
audio_buffer.channel_data(0).as_slice()[..],
[1.; 10][..],
abs_all <= 0.
);
}
{
let mut audio_buffer = AudioBuffer::new(options.clone());
let src = vec![1.; 5];
audio_buffer.copy_to_channel(&src, 0);
assert_float_eq!(
audio_buffer.channel_data(0).as_slice()[..],
[1., 1., 1., 1., 1., 0., 0., 0., 0., 0.][..],
abs_all <= 0.
);
}
{
let mut audio_buffer = AudioBuffer::new(options.clone());
let src = vec![1.; 12];
audio_buffer.copy_to_channel(&src, 0);
assert_float_eq!(
audio_buffer.channel_data(0).as_slice()[..],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.][..],
abs_all <= 0.
);
}
{
let mut audio_buffer = AudioBuffer::new(options.clone());
let src = vec![1.; 10];
audio_buffer.copy_to_channel_with_offset(&src, 0, 5);
assert_float_eq!(
audio_buffer.channel_data(0).as_slice()[..],
[0., 0., 0., 0., 0., 1., 1., 1., 1., 1.][..],
abs_all <= 0.
);
}
{
let mut audio_buffer = AudioBuffer::new(options);
let src = vec![1.; 10];
audio_buffer.copy_to_channel_with_offset(&src, 0, usize::MAX);
assert_float_eq!(
audio_buffer.channel_data(0).as_slice()[..],
[0.; 10][..],
abs_all <= 0.
);
}
}
#[test]
#[should_panic]
fn test_invalid_get_channel_data() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 10,
sample_rate: 48000.,
};
let audio_buffer = AudioBuffer::new(options);
audio_buffer.get_channel_data(1);
}
#[test]
fn test_silent() {
let options = AudioBufferOptions {
number_of_channels: 2,
length: 10,
sample_rate: 44100.,
};
let b = AudioBuffer::new(options);
assert_eq!(b.length(), 10);
assert_eq!(b.number_of_channels(), 2);
assert_float_eq!(b.sample_rate(), 44100., abs_all <= 0.);
assert_float_eq!(b.channel_data(0).as_slice(), &[0.; 10][..], abs_all <= 0.);
assert_float_eq!(b.channel_data(1).as_slice(), &[0.; 10][..], abs_all <= 0.);
assert_eq!(b.channels().get(2), None);
}
#[test]
fn test_concat() {
let options = AudioBufferOptions {
number_of_channels: 2,
length: 5,
sample_rate: 44100.,
};
let mut b1 = AudioBuffer::new(options.clone());
let b2 = AudioBuffer::new(options);
b1.extend(&b2);
assert_eq!(b1.length(), 10);
assert_eq!(b1.number_of_channels(), 2);
assert_float_eq!(b1.sample_rate(), 44100., abs_all <= 0.);
let channel_data = ChannelData::from(vec![1.; 5]);
let b3 = AudioBuffer::from_channels(vec![channel_data; 2], 44100.);
b1.extend(&b3);
assert_eq!(b1.length(), 15);
assert_eq!(b1.number_of_channels(), 2);
assert_float_eq!(b1.sample_rate(), 44100., abs_all <= 0.);
assert_float_eq!(
b1.channel_data(0).as_slice(),
&[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1.][..],
abs_all <= 0.
);
}
#[test]
#[should_panic]
fn test_resample_to_zero_hertz() {
let channel = ChannelData::from(vec![1., 2., 3., 4., 5.]);
let mut buffer = AudioBuffer::from_channels(vec![channel], 48000.);
buffer.resample(0.);
}
#[test]
fn test_resample_from_empty() {
let options = AudioBufferOptions {
number_of_channels: 1,
length: 0,
sample_rate: 48000.,
};
let mut buffer = AudioBuffer::new(options);
buffer.resample(48000.);
assert_eq!(buffer.length(), 0);
assert_float_eq!(buffer.sample_rate, 48000., abs_all <= 0.);
}
#[test]
fn test_upsample() {
let channel = ChannelData::from(vec![1., 2., 3., 4., 5.]);
let mut buffer = AudioBuffer::from_channels(vec![channel], 48000.);
buffer.resample(96000.);
let mut expected = [0.; 10];
let incr = 4. / 9.;
for (i, value) in expected.iter_mut().enumerate() {
*value = 1. + incr * i as f32;
}
assert_float_eq!(
buffer.channel_data(0).as_slice(),
&expected[..],
abs_all <= 1e-6
);
assert_float_eq!(buffer.sample_rate, 96000., abs_all <= 0.);
}
#[test]
fn test_downsample() {
let channel = ChannelData::from(vec![1., 2., 3., 4., 5.]);
let mut buffer = AudioBuffer::from_channels(vec![channel], 96000.);
buffer.resample(48000.);
assert_float_eq!(
buffer.channel_data(0).as_slice(),
&[1., 3., 5.][..],
abs_all <= 0.
);
assert_float_eq!(buffer.sample_rate, 48000., abs_all <= 0.);
}
#[test]
fn test_resample_stereo() {
[22500, 38000, 48000, 96000].iter().for_each(|sr| {
let source_sr = *sr;
let target_sr = 44_100;
let mut left = Vec::<f32>::with_capacity(source_sr);
let mut right = Vec::<f32>::with_capacity(source_sr);
for i in 0..source_sr {
let phase = i as f32 / source_sr as f32 * 2. * PI;
left.push(phase.sin());
right.push(phase.cos());
}
let left_chan = ChannelData::from(left);
let right_chan = ChannelData::from(right);
let mut buffer =
AudioBuffer::from_channels(vec![left_chan, right_chan], source_sr as f32);
buffer.resample(target_sr as f32);
let mut expected_left = vec![];
let mut expected_right = vec![];
for i in 0..target_sr {
let phase = i as f32 / target_sr as f32 * 2. * PI;
expected_left.push(phase.sin());
expected_right.push(phase.cos());
}
assert_float_eq!(
buffer.get_channel_data(0)[..],
&expected_left[..],
abs_all <= 1e-3
);
assert_float_eq!(
buffer.get_channel_data(1)[..],
&expected_right[..],
abs_all <= 1e-3
);
assert_float_eq!(buffer.sample_rate, target_sr as f32, abs_all <= 0.);
});
}
}