#![doc = include_str!("../README.md")]
#![cfg_attr(all(not(feature = "test-utils"), not(test)), no_std)]
mod traits;
pub use traits::{Adapter, AdapterMut};
pub mod stats;
mod iterators;
pub use iterators::AdapterIterators;
#[cfg(feature = "audio")]
pub mod audio;
#[cfg(any(test, feature = "test-utils"))]
pub mod tests {
use crate::{Adapter, AdapterMut};
use num_traits::Float;
pub struct MinimalAdapter<U> {
buf: Vec<U>,
frames: usize,
channels: usize,
}
impl<T> MinimalAdapter<T>
where
T: Clone,
{
pub fn new_from_vec(buf: Vec<T>, channels: usize, frames: usize) -> Self {
Self {
buf,
frames,
channels,
}
}
}
impl<'a, T> Adapter<'a, T> for MinimalAdapter<T>
where
T: Clone + 'a,
{
unsafe fn read_sample_unchecked(&self, channel: usize, frame: usize) -> T {
let index = frame * self.channels + channel;
self.buf.get_unchecked(index).clone()
}
fn channels(&self) -> usize {
self.channels
}
fn frames(&self) -> usize {
self.frames
}
}
impl<'a, T> AdapterMut<'a, T> for MinimalAdapter<T>
where
T: Clone + 'a,
{
unsafe fn write_sample_unchecked(
&mut self,
channel: usize,
frame: usize,
value: &T,
) -> bool {
let index = frame * self.channels + channel;
*self.buf.get_unchecked_mut(index) = value.clone();
false
}
}
pub fn test_adapter_mut_methods<'a, T>(buffer: &mut dyn AdapterMut<'a, T>)
where
T: Default + Clone + PartialEq + std::fmt::Debug + From<usize> + Into<usize> + 'a,
{
assert!(
buffer.channels() >= 2,
"Buffer must have at least 2 channels for this test"
);
assert!(
buffer.frames() >= 4,
"Buffer must have at least 4 frames for this test"
);
buffer.fill_with(&T::from(42));
assert_eq!(buffer.read_sample(0, 0), Some(T::from(42)));
assert_eq!(buffer.read_sample(1, 1), Some(T::from(42)));
assert_eq!(buffer.read_sample(buffer.channels(), 0), None);
assert_eq!(buffer.read_sample(0, buffer.frames()), None);
assert_eq!(buffer.write_sample(0, 0, &T::from(100)), Some(false));
assert_eq!(buffer.read_sample(0, 0), Some(T::from(100)));
assert_eq!(
buffer.write_sample(buffer.channels(), 0, &T::from(101)),
None
);
assert_eq!(buffer.write_sample(0, buffer.frames(), &T::from(102)), None);
buffer.fill_channel_with(1, &T::from(99)).unwrap();
assert_eq!(buffer.read_sample(1, 0), Some(T::from(99)));
assert_eq!(buffer.read_sample(1, 1), Some(T::from(99)));
assert_eq!(buffer.read_sample(0, 0), Some(T::from(100)));
buffer.fill_frame_with(2, &T::from(88)).unwrap();
assert_eq!(buffer.read_sample(0, 2), Some(T::from(88)));
assert_eq!(buffer.read_sample(1, 2), Some(T::from(88)));
assert_eq!(buffer.read_sample(1, 1), Some(T::from(99)));
buffer.fill_frames_with(0, 2, &T::from(77)).unwrap();
assert_eq!(buffer.read_sample(0, 0), Some(T::from(77)));
assert_eq!(buffer.read_sample(1, 1), Some(T::from(77)));
assert_eq!(buffer.read_sample(0, 2), Some(T::from(88)));
for c in 0..buffer.channels() {
for f in 0..buffer.frames() {
buffer.write_sample(c, f, &T::from(c * 10 + f));
}
}
let mut slice_ch = vec![T::default(); 2];
let copied = buffer.copy_from_channel_to_slice(1, 1, &mut slice_ch);
assert_eq!(copied, 2);
assert_eq!(slice_ch, vec![T::from(11), T::from(12)]);
let mut slice_fr = vec![T::default(); 2];
let copied = buffer.copy_from_frame_to_slice(2, 0, &mut slice_fr);
assert_eq!(copied, 2);
assert_eq!(slice_fr, vec![T::from(2), T::from(12)]);
let slice_to_ch = vec![T::from(101), T::from(102)];
let (copied, clipped) = buffer.copy_from_slice_to_channel(0, 2, &slice_to_ch);
assert_eq!(copied, 2);
assert_eq!(clipped, 0);
assert_eq!(buffer.read_sample(0, 2), Some(T::from(101)));
assert_eq!(buffer.read_sample(0, 3), Some(T::from(102)));
let slice_to_fr = vec![T::from(201)];
let (copied, clipped) = buffer.copy_from_slice_to_frame(3, 1, &slice_to_fr);
assert_eq!(copied, 1);
assert_eq!(clipped, 0);
assert_eq!(buffer.read_sample(1, 3), Some(T::from(201)));
assert!(buffer.copy_sample_within(0, 0, 1, 1));
assert_eq!(buffer.read_sample(1, 1), Some(T::from(0)));
assert!(buffer.swap_samples(0, 1, 1, 0));
assert_eq!(buffer.read_sample(0, 1), Some(T::from(10)));
assert_eq!(buffer.read_sample(1, 0), Some(T::from(1)));
buffer.copy_frames_within(0, 1, 2).unwrap();
assert_eq!(buffer.read_sample(0, 1), Some(T::from(0)));
assert_eq!(buffer.read_sample(1, 1), Some(T::from(1)));
assert_eq!(buffer.read_sample(0, 2), Some(T::from(10)));
assert_eq!(buffer.read_sample(1, 2), Some(T::from(0)));
}
pub fn test_float_adapter_mut_methods<'a, T>(buffer: &mut dyn AdapterMut<'a, T>)
where
T: Float + Default + Clone + PartialEq + std::fmt::Debug + 'a,
{
let assert_approx_eq = |a: T, b: T, message: &str| {
let epsilon = T::from(1e-6).unwrap();
assert!(
(a - b).abs() < epsilon,
"{} (left: {:?}, right: {:?})",
message,
a,
b
);
};
let assert_slice_approx_eq = |a: &[T], b: &[T], message: &str| {
assert_eq!(a.len(), b.len(), "{} (slice lengths differ)", message);
for (i, (val_a, val_b)) in a.iter().zip(b.iter()).enumerate() {
let msg = format!("{} (element {})", message, i);
assert_approx_eq(*val_a, *val_b, &msg);
}
};
assert!(
buffer.channels() >= 2,
"Buffer must have at least 2 channels for this test"
);
assert!(
buffer.frames() >= 4,
"Buffer must have at least 4 frames for this test"
);
buffer.fill_with(&T::from(0.42).unwrap());
assert_approx_eq(
buffer.read_sample(0, 0).unwrap(),
T::from(0.42).unwrap(),
"fill_with value mismatch",
);
assert_approx_eq(
buffer.read_sample(1, 1).unwrap(),
T::from(0.42).unwrap(),
"fill_with value mismatch",
);
assert_eq!(buffer.read_sample(buffer.channels(), 0), None);
assert_eq!(buffer.read_sample(0, buffer.frames()), None);
assert_eq!(
buffer.write_sample(0, 0, &T::from(0.1).unwrap()),
Some(false)
);
assert_approx_eq(
buffer.read_sample(0, 0).unwrap(),
T::from(0.1).unwrap(),
"write_sample value mismatch",
);
assert_eq!(
buffer.write_sample(buffer.channels(), 0, &T::from(0.101).unwrap()),
None
);
assert_eq!(
buffer.write_sample(0, buffer.frames(), &T::from(0.102).unwrap()),
None
);
buffer
.fill_channel_with(1, &T::from(0.99).unwrap())
.unwrap();
assert_approx_eq(
buffer.read_sample(1, 0).unwrap(),
T::from(0.99).unwrap(),
"fill_channel_with value mismatch",
);
assert_approx_eq(
buffer.read_sample(1, 1).unwrap(),
T::from(0.99).unwrap(),
"fill_channel_with value mismatch",
);
assert_approx_eq(
buffer.read_sample(0, 0).unwrap(),
T::from(0.1).unwrap(),
"Other channel should be unaffected",
);
buffer.fill_frame_with(2, &T::from(0.88).unwrap()).unwrap();
assert_approx_eq(
buffer.read_sample(0, 2).unwrap(),
T::from(0.88).unwrap(),
"fill_frame_with value mismatch",
);
assert_approx_eq(
buffer.read_sample(1, 2).unwrap(),
T::from(0.88).unwrap(),
"fill_frame_with value mismatch",
);
assert_approx_eq(
buffer.read_sample(1, 1).unwrap(),
T::from(0.99).unwrap(),
"Other frame should be unaffected",
);
buffer
.fill_frames_with(0, 2, &T::from(0.77).unwrap())
.unwrap();
assert_approx_eq(
buffer.read_sample(0, 0).unwrap(),
T::from(0.77).unwrap(),
"fill_frames_with value mismatch",
);
assert_approx_eq(
buffer.read_sample(1, 1).unwrap(),
T::from(0.77).unwrap(),
"fill_frames_with value mismatch",
);
assert_approx_eq(
buffer.read_sample(0, 2).unwrap(),
T::from(0.88).unwrap(),
"Unaffected frame should be unaffected",
);
for c in 0..buffer.channels() {
for f in 0..buffer.frames() {
buffer.write_sample(c, f, &T::from((c * 10 + f) as f32 / 100.0).unwrap());
}
}
let mut slice_ch = vec![T::default(); 2];
let copied = buffer.copy_from_channel_to_slice(1, 1, &mut slice_ch);
assert_eq!(copied, 2);
assert_slice_approx_eq(
&slice_ch,
&vec![T::from(0.11).unwrap(), T::from(0.12).unwrap()],
"copy_from_channel_to_slice mismatch",
);
let mut slice_fr = vec![T::default(); 2];
let copied = buffer.copy_from_frame_to_slice(2, 0, &mut slice_fr);
assert_eq!(copied, 2);
assert_slice_approx_eq(
&slice_fr,
&vec![T::from(0.02).unwrap(), T::from(0.12).unwrap()],
"copy_from_frame_to_slice mismatch",
);
assert!(buffer.copy_sample_within(0, 0, 1, 1));
assert_approx_eq(
buffer.read_sample(1, 1).unwrap(),
T::from(0.0).unwrap(),
"copy_sample_within value mismatch",
);
assert!(buffer.swap_samples(0, 1, 1, 0));
assert_approx_eq(
buffer.read_sample(0, 1).unwrap(),
T::from(0.10).unwrap(),
"swap_samples value mismatch on sample A",
);
assert_approx_eq(
buffer.read_sample(1, 0).unwrap(),
T::from(0.01).unwrap(),
"swap_samples value mismatch on sample B",
);
}
#[test]
fn test_vec_adapter() {
let mut buffer = MinimalAdapter::new_from_vec(vec![0; 8], 2, 4);
test_adapter_mut_methods(&mut buffer);
}
}