use std::cmp::min;
use std::ops::Range;
use crate::units::{Channels, Samples};
#[derive(Clone, Debug)]
pub struct Buffer<T> {
data: Vec<T>,
num_channels: Channels,
num_samples: Samples,
}
impl<T> Buffer<T>
where
T: Copy + Default + PartialEq,
{
pub fn is_default_filled(&self) -> bool {
self.data.iter().all(|s| *s == T::default())
}
}
impl<T> Buffer<T>
where
T: Copy + Default,
{
pub fn allocate(num_channels: Channels, num_samples: Samples) -> Self {
let total_num_samples = num_samples.as_usize() * num_channels.as_usize();
let mut data = Vec::with_capacity(total_num_samples);
data.resize(total_num_samples, T::default());
Self {
data,
num_channels,
num_samples,
}
}
pub fn clone_resized(&self, num_channels: Channels, num_samples: Samples) -> Self {
let mut target = Self::allocate(num_channels, num_samples);
for channel in 0..min(self.num_channels(), num_channels).as_usize() {
for sample in 0..min(self.num_samples(), num_samples).as_usize() {
target.chan_mut(channel)[sample] = self.chan(channel)[sample];
}
}
target
}
pub fn data(&self) -> &[T] {
&self.data
}
pub fn data_mut(&mut self) -> &mut [T] {
&mut self.data
}
pub fn fill_default(&mut self) {
self.data.fill(T::default());
}
pub fn channel_indices(&self) -> Range<usize> {
0..self.num_channels.as_usize()
}
pub fn sample_indices(&self) -> Range<usize> {
0..self.num_samples.as_usize()
}
pub fn num_channels(&self) -> Channels {
self.num_channels
}
pub fn num_samples(&self) -> Samples {
self.num_samples
}
pub fn chan(&self, index: usize) -> &[T] {
if index >= self.num_channels.as_usize() {
panic!();
}
let start = index * self.num_samples.as_usize();
let end = start + self.num_samples.as_usize();
&self.data[start..end]
}
pub fn chan_mut(&mut self, index: usize) -> &mut [T] {
if index >= self.num_channels().as_usize() {
panic!();
}
let start = index * self.num_samples.as_usize();
let end = start + self.num_samples.as_usize();
&mut self.data[start..end]
}
pub fn iter_chans(&self) -> ChannelIterator<T> {
ChannelIterator {
buffer: self,
current_channel: 0,
}
}
pub fn iter_chans_mut(&mut self) -> MutChannelIterator<T> {
MutChannelIterator {
buffer: self,
current_channel: 0,
}
}
pub fn copy_into(&self, dest: &mut Self) {
assert_eq!(self.num_channels(), dest.num_channels());
assert_eq!(self.num_samples(), dest.num_samples());
for channel in self.channel_indices() {
for sample in self.sample_indices() {
dest.chan_mut(channel)[sample] = self.chan(channel)[sample];
}
}
}
pub fn map_samples(&mut self, mut func: impl FnMut(T) -> T) {
self.data
.iter_mut()
.for_each(|sample| *sample = func(*sample));
}
pub fn iter_interleaved(&self) -> InterleavedIterator<T> {
InterleavedIterator {
buffer: self,
index: 0,
}
}
}
pub struct InterleavedIterator<'a, T>
where
T: Copy + Default,
{
buffer: &'a Buffer<T>,
index: usize,
}
impl<'a, T> Iterator for InterleavedIterator<'a, T>
where
T: Copy + Default,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let num_channels = self.buffer.num_channels().as_usize();
let num_samples = self.buffer.num_samples().as_usize();
let total_num_samples = num_samples * num_channels;
if self.index >= total_num_samples {
None
} else {
let sample_index = self.index / num_channels;
let channel_index = self.index - (sample_index * num_channels);
self.index += 1;
Some(self.buffer.chan(channel_index)[sample_index])
}
}
}
pub struct MutChannelIterator<'a, T>
where
T: Copy,
{
buffer: &'a mut Buffer<T>,
current_channel: usize,
}
impl<'a, T> Iterator for MutChannelIterator<'a, T>
where
T: Copy + Default,
{
type Item = &'a mut [T];
fn next(&mut self) -> Option<Self::Item> {
if self.current_channel >= self.buffer.num_channels().as_usize() {
return None;
}
let channel = self.buffer.chan_mut(self.current_channel);
let channel_len = channel.len();
let channel_ptr = channel.as_mut_ptr();
self.current_channel += 1;
Some(unsafe { std::slice::from_raw_parts_mut(channel_ptr, channel_len) })
}
}
pub struct ChannelIterator<'a, T>
where
T: Copy + Default,
{
buffer: &'a Buffer<T>,
current_channel: usize,
}
impl<'a, T> Iterator for ChannelIterator<'a, T>
where
T: Copy + Default,
{
type Item = &'a [T];
fn next(&mut self) -> Option<Self::Item> {
if self.current_channel >= self.buffer.num_channels.as_usize() {
return None;
}
let channel = self.buffer.chan(self.current_channel);
self.current_channel += 1;
Some(channel)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn interleaved_iterator() {
let mut buffer = Buffer::allocate(Channels::from(2), Samples::from(3));
buffer.chan_mut(0)[0] = 1.0;
buffer.chan_mut(0)[1] = 1.0;
buffer.chan_mut(0)[2] = 1.0;
let mut result = Vec::new();
for sample in buffer.iter_interleaved() {
result.push(sample);
}
assert_eq!(result, &[1.0, 0.0, 1.0, 0.0, 1.0, 0.0]);
}
#[test]
fn correct_num_samples_and_channels() {
let buffer = Buffer::<f32>::allocate(Channels::from(2), Samples::from(10));
assert_eq!(buffer.num_samples(), Samples::from(10));
assert_eq!(buffer.num_channels(), Channels::from(2));
}
#[test]
fn index_into_channels() {
let buffer = Buffer::<f32>::allocate(Channels::from(2), Samples::from(10));
assert_eq!(buffer.chan(0).len(), buffer.num_samples().as_usize());
}
#[test]
fn iterate_channels() {
let buffer = Buffer::<f32>::allocate(Channels::from(2), Samples::from(10));
let mut num = 0;
for _chan in buffer.iter_chans() {
num += 1;
}
assert_eq!(Channels::from(num), buffer.num_channels());
}
#[test]
fn map_samples() {
let mut buffer = Buffer::<f32>::allocate(Channels::from(2), Samples::from(3));
buffer.map_samples(|_| 0.5);
assert_eq!(buffer.chan(1)[2], 0.5);
}
#[test]
fn clone_with_new_bigger_size() {
let mut buffer = Buffer::<f32>::allocate(Channels::from(2), Samples::from(3));
for chan in buffer.channel_indices() {
for samp in buffer.sample_indices() {
buffer.chan_mut(chan)[samp] = samp as f32;
}
}
let resized = buffer.clone_resized(Channels::from(3), Samples::from(4));
assert_eq!(resized.chan(0)[1], 1.0);
assert_eq!(resized.chan(0)[3], 0.0);
assert_eq!(resized.chan(1)[1], 1.0);
assert_eq!(resized.chan(1)[3], 0.0);
assert_eq!(resized.chan(2)[1], 0.0);
}
#[test]
fn clone_with_new_smaller_size() {
let mut buffer = Buffer::<f32>::allocate(Channels::from(2), Samples::from(3));
for chan in buffer.channel_indices() {
for samp in buffer.sample_indices() {
buffer.chan_mut(chan)[samp] = samp as f32;
}
}
let resized = buffer.clone_resized(Channels::from(1), Samples::from(2));
assert_eq!(resized.chan(0)[1], 1.0);
assert_eq!(resized.chan(0)[0], 0.0);
}
}