use super::simd_allocator::SimdAlignedBuffer;
use std::marker::PhantomData;
pub struct AudioFrameView<'a, T> {
data: &'a [T],
sample_rate: u32,
channels: usize,
}
impl<'a, T> AudioFrameView<'a, T> {
pub fn new(data: &'a [T], sample_rate: u32, channels: usize) -> Self {
Self {
data,
sample_rate,
channels,
}
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
pub fn num_frames(&self) -> usize {
self.data.len() / self.channels
}
#[inline]
pub fn sample_rate(&self) -> u32 {
self.sample_rate
}
#[inline]
pub fn channels(&self) -> usize {
self.channels
}
#[inline]
pub fn as_slice(&self) -> &[T] {
self.data
}
#[inline]
pub fn iter(&self) -> std::slice::Iter<'_, T> {
self.data.iter()
}
pub fn channel(&self, ch: usize) -> impl Iterator<Item = &T> {
assert!(ch < self.channels, "Channel index out of bounds");
self.data.iter().skip(ch).step_by(self.channels)
}
}
pub struct AudioFrameViewMut<'a, T> {
data: &'a mut [T],
sample_rate: u32,
channels: usize,
}
impl<'a, T> AudioFrameViewMut<'a, T> {
pub fn new(data: &'a mut [T], sample_rate: u32, channels: usize) -> Self {
Self {
data,
sample_rate,
channels,
}
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
pub fn num_frames(&self) -> usize {
self.data.len() / self.channels
}
#[inline]
pub fn sample_rate(&self) -> u32 {
self.sample_rate
}
#[inline]
pub fn channels(&self) -> usize {
self.channels
}
#[inline]
pub fn as_slice(&self) -> &[T] {
self.data
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.data
}
#[inline]
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
self.data.iter_mut()
}
pub fn channel_mut(&mut self, ch: usize) -> impl Iterator<Item = &mut T> {
assert!(ch < self.channels, "Channel index out of bounds");
let channels = self.channels;
self.data.iter_mut().skip(ch).step_by(channels)
}
pub fn as_view(&self) -> AudioFrameView<'_, T> {
AudioFrameView::new(self.data, self.sample_rate, self.channels)
}
}
type ProcessingStage<T> = Box<dyn FnMut(&mut [T]) + Send>;
pub struct ZeroCopyProcessor<T> {
stages: Vec<ProcessingStage<T>>,
sample_rate: u32,
channels: usize,
}
impl<T: Copy> ZeroCopyProcessor<T> {
pub fn new(sample_rate: u32, channels: usize) -> Self {
Self {
stages: Vec::new(),
sample_rate,
channels,
}
}
pub fn add_stage<F>(&mut self, stage: F) -> &mut Self
where
F: FnMut(&mut [T]) + Send + 'static,
{
self.stages.push(Box::new(stage));
self
}
pub fn process(&mut self, data: &mut [T]) {
for stage in &mut self.stages {
stage(data);
}
}
pub fn process_view(&mut self, view: &mut AudioFrameViewMut<T>) {
self.process(view.as_mut_slice())
}
pub fn num_stages(&self) -> usize {
self.stages.len()
}
pub fn clear(&mut self) {
self.stages.clear();
}
}
pub struct AudioFrameAllocator<T> {
pool: Vec<SimdAlignedBuffer<T>>,
max_pool_size: usize,
buffer_size: usize,
}
impl<T: Copy + Default> AudioFrameAllocator<T> {
pub fn new(buffer_size: usize, max_pool_size: usize) -> Self {
Self {
pool: Vec::with_capacity(max_pool_size),
max_pool_size,
buffer_size,
}
}
pub fn allocate(&mut self) -> SimdAlignedBuffer<T> {
self.pool
.pop()
.unwrap_or_else(|| SimdAlignedBuffer::zeroed(self.buffer_size))
}
pub fn deallocate(&mut self, buffer: SimdAlignedBuffer<T>) {
if self.pool.len() < self.max_pool_size {
self.pool.push(buffer);
}
}
pub fn utilization(&self) -> f32 {
self.pool.len() as f32 / self.max_pool_size as f32
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frame_view() {
let data = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0];
let view = AudioFrameView::new(&data, 48000, 2);
assert_eq!(view.len(), 6);
assert_eq!(view.num_frames(), 3);
assert_eq!(view.channels(), 2);
assert_eq!(view.sample_rate(), 48000);
}
#[test]
fn test_frame_view_mut() {
let mut data = vec![1.0f32, 2.0, 3.0, 4.0];
let mut view = AudioFrameViewMut::new(&mut data, 48000, 2);
for sample in view.iter_mut() {
*sample *= 2.0;
}
assert_eq!(data, vec![2.0, 4.0, 6.0, 8.0]);
}
#[test]
fn test_channel_iteration() {
let data = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0]; let view = AudioFrameView::new(&data, 48000, 2);
let left: Vec<f32> = view.channel(0).copied().collect();
let right: Vec<f32> = view.channel(1).copied().collect();
assert_eq!(left, vec![1.0, 3.0, 5.0]);
assert_eq!(right, vec![2.0, 4.0, 6.0]);
}
#[test]
fn test_zero_copy_processor() {
let mut processor = ZeroCopyProcessor::new(48000, 1);
processor.add_stage(|data| {
for sample in data.iter_mut() {
*sample *= 0.5;
}
});
processor.add_stage(|data| {
for sample in data.iter_mut() {
*sample += 1.0;
}
});
let mut data = vec![2.0f32, 4.0, 6.0, 8.0];
processor.process(&mut data);
assert_eq!(data, vec![2.0, 3.0, 4.0, 5.0]);
}
#[test]
fn test_frame_allocator() {
let mut allocator = AudioFrameAllocator::<f32>::new(512, 4);
let buf1 = allocator.allocate();
assert_eq!(buf1.len(), 512);
allocator.deallocate(buf1);
assert!(allocator.utilization() > 0.0);
let _buf2 = allocator.allocate();
assert_eq!(allocator.pool.len(), 0); }
}