#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SampleFormat {
U8,
I16,
I24,
I32,
F32,
F64,
}
impl SampleFormat {
pub fn bit_depth(self) -> u8 {
match self {
SampleFormat::U8 => 8,
SampleFormat::I16 => 16,
SampleFormat::I24 => 24,
SampleFormat::I32 => 32,
SampleFormat::F32 => 32,
SampleFormat::F64 => 64,
}
}
pub fn byte_size(self) -> usize {
match self {
SampleFormat::U8 => 1,
SampleFormat::I16 => 2,
SampleFormat::I24 => 4,
SampleFormat::I32 => 4,
SampleFormat::F32 => 4,
SampleFormat::F64 => 8,
}
}
pub fn is_float(self) -> bool {
matches!(self, SampleFormat::F32 | SampleFormat::F64)
}
pub fn is_integer(self) -> bool {
!self.is_float()
}
}
#[derive(Debug, Clone)]
pub struct SampleBuffer {
data: Vec<f32>,
channels: usize,
frames: usize,
planar: bool,
}
impl SampleBuffer {
pub fn new_interleaved(channels: usize, frames: usize) -> Self {
Self {
data: vec![0.0_f32; channels * frames],
channels,
frames,
planar: false,
}
}
pub fn new_planar(channels: usize, frames: usize) -> Self {
Self {
data: vec![0.0_f32; channels * frames],
channels,
frames,
planar: true,
}
}
pub fn channel_count(&self) -> usize {
self.channels
}
pub fn frame_count(&self) -> usize {
self.frames
}
pub fn is_interleaved(&self) -> bool {
!self.planar
}
pub fn interleaved(&self) -> Vec<f32> {
if !self.planar {
return self.data.clone();
}
let mut out = vec![0.0_f32; self.channels * self.frames];
for ch in 0..self.channels {
for fr in 0..self.frames {
out[fr * self.channels + ch] = self.data[ch * self.frames + fr];
}
}
out
}
pub fn deinterleaved(&self) -> Vec<Vec<f32>> {
let mut planes: Vec<Vec<f32>> = (0..self.channels)
.map(|_| vec![0.0_f32; self.frames])
.collect();
if self.planar {
for ch in 0..self.channels {
planes[ch].copy_from_slice(&self.data[ch * self.frames..(ch + 1) * self.frames]);
}
} else {
for fr in 0..self.frames {
for ch in 0..self.channels {
planes[ch][fr] = self.data[fr * self.channels + ch];
}
}
}
planes
}
pub fn as_slice(&self) -> &[f32] {
&self.data
}
pub fn as_mut_slice(&mut self) -> &mut [f32] {
&mut self.data
}
}
#[derive(Debug, Default)]
pub struct SampleBufferPool {
free: Vec<SampleBuffer>,
}
impl SampleBufferPool {
pub fn new() -> Self {
Self { free: Vec::new() }
}
pub fn acquire(&mut self, channels: usize, frames: usize, planar: bool) -> SampleBuffer {
let expected_len = channels * frames;
if let Some(pos) = self
.free
.iter()
.position(|b| b.data.len() == expected_len && b.planar == planar)
{
let mut buf = self.free.swap_remove(pos);
buf.channels = channels;
buf.frames = frames;
for s in buf.data.iter_mut() {
*s = 0.0;
}
return buf;
}
if planar {
SampleBuffer::new_planar(channels, frames)
} else {
SampleBuffer::new_interleaved(channels, frames)
}
}
pub fn release(&mut self, buf: SampleBuffer) {
self.free.push(buf);
}
pub fn free_count(&self) -> usize {
self.free.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sample_format_bit_depth() {
assert_eq!(SampleFormat::U8.bit_depth(), 8);
assert_eq!(SampleFormat::I16.bit_depth(), 16);
assert_eq!(SampleFormat::I24.bit_depth(), 24);
assert_eq!(SampleFormat::I32.bit_depth(), 32);
assert_eq!(SampleFormat::F32.bit_depth(), 32);
assert_eq!(SampleFormat::F64.bit_depth(), 64);
}
#[test]
fn test_sample_format_byte_size() {
assert_eq!(SampleFormat::U8.byte_size(), 1);
assert_eq!(SampleFormat::I16.byte_size(), 2);
assert_eq!(SampleFormat::I24.byte_size(), 4);
assert_eq!(SampleFormat::F32.byte_size(), 4);
assert_eq!(SampleFormat::F64.byte_size(), 8);
}
#[test]
fn test_sample_format_is_float() {
assert!(SampleFormat::F32.is_float());
assert!(SampleFormat::F64.is_float());
assert!(!SampleFormat::I16.is_float());
}
#[test]
fn test_sample_format_is_integer() {
assert!(SampleFormat::U8.is_integer());
assert!(SampleFormat::I32.is_integer());
assert!(!SampleFormat::F32.is_integer());
}
#[test]
fn test_interleaved_buffer_channel_count() {
let buf = SampleBuffer::new_interleaved(2, 64);
assert_eq!(buf.channel_count(), 2);
}
#[test]
fn test_interleaved_buffer_frame_count() {
let buf = SampleBuffer::new_interleaved(2, 64);
assert_eq!(buf.frame_count(), 64);
}
#[test]
fn test_interleaved_roundtrip() {
let mut buf = SampleBuffer::new_interleaved(2, 4);
let slice = buf.as_mut_slice();
for (i, s) in slice.iter_mut().enumerate() {
*s = i as f32;
}
let interleaved = buf.interleaved();
assert_eq!(interleaved.len(), 8);
assert!((interleaved[0] - 0.0).abs() < 1e-6);
assert!((interleaved[1] - 1.0).abs() < 1e-6);
}
#[test]
fn test_deinterleaved_from_interleaved() {
let mut buf = SampleBuffer::new_interleaved(2, 3);
let data = [1.0_f32, 2.0, 3.0, 4.0, 5.0, 6.0];
buf.as_mut_slice().copy_from_slice(&data);
let planes = buf.deinterleaved();
assert_eq!(planes.len(), 2);
assert_eq!(planes[0], vec![1.0, 3.0, 5.0]);
assert_eq!(planes[1], vec![2.0, 4.0, 6.0]);
}
#[test]
fn test_planar_buffer_interleaved_conversion() {
let mut buf = SampleBuffer::new_planar(2, 3);
let data = [1.0_f32, 3.0, 5.0, 2.0, 4.0, 6.0];
buf.as_mut_slice().copy_from_slice(&data);
let interleaved = buf.interleaved();
assert_eq!(interleaved, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
}
#[test]
fn test_pool_acquire_new() {
let mut pool = SampleBufferPool::new();
let buf = pool.acquire(2, 128, false);
assert_eq!(buf.channel_count(), 2);
assert_eq!(buf.frame_count(), 128);
assert_eq!(pool.free_count(), 0);
}
#[test]
fn test_pool_release_and_reacquire() {
let mut pool = SampleBufferPool::new();
let buf = pool.acquire(2, 128, false);
pool.release(buf);
assert_eq!(pool.free_count(), 1);
let buf2 = pool.acquire(2, 128, false);
assert_eq!(pool.free_count(), 0);
assert_eq!(buf2.channel_count(), 2);
}
#[test]
fn test_pool_zeroes_recycled_buffer() {
let mut pool = SampleBufferPool::new();
let mut buf = pool.acquire(1, 4, false);
buf.as_mut_slice().iter_mut().for_each(|s| *s = 99.0);
pool.release(buf);
let buf2 = pool.acquire(1, 4, false);
for s in buf2.as_slice() {
assert!((*s).abs() < 1e-6, "Expected zero, got {s}");
}
}
#[test]
fn test_pool_different_size_no_reuse() {
let mut pool = SampleBufferPool::new();
let buf = pool.acquire(2, 64, false);
pool.release(buf);
let _buf2 = pool.acquire(2, 128, false);
assert_eq!(pool.free_count(), 1);
}
}