#![allow(unused_imports)]
#[cfg(feature = "std")]
use std::{vec::Vec, marker::PhantomData};
#[cfg(not(feature = "std"))]
use core::marker::PhantomData;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;
use num_traits::Float;
pub struct Buffer<T: Float> {
buffer_index: usize,
buffer_mask: usize,
buffer: Vec<T>,
}
impl<T: Float> Buffer<T> {
pub fn new(min_capacity: usize) -> Self {
let mut result = Self {
buffer_index: 0,
buffer_mask: 0,
buffer: Vec::new(),
};
result.resize(min_capacity, T::zero());
result
}
pub fn resize(&mut self, min_capacity: usize, value: T) {
let mut buffer_length = 1;
while buffer_length < min_capacity {
buffer_length *= 2;
}
self.buffer = vec![value; buffer_length];
self.buffer_mask = buffer_length - 1;
self.buffer_index = 0;
}
pub fn reset(&mut self, value: T) {
for i in 0..self.buffer.len() {
self.buffer[i] = value;
}
}
pub fn get(&self, offset: isize) -> T {
let index = (self.buffer_index as isize + offset) as usize & self.buffer_mask;
self.buffer[index]
}
pub fn set(&mut self, offset: isize, value: T) {
let index = (self.buffer_index as isize + offset) as usize & self.buffer_mask;
self.buffer[index] = value;
}
pub fn advance(&mut self, amount: isize) -> &mut Self {
if amount >= 0 {
self.buffer_index = self.buffer_index.wrapping_add(amount as usize);
} else {
self.buffer_index = self.buffer_index.wrapping_sub((-amount) as usize);
}
self
}
pub fn write<D>(&mut self, data: &[D], length: usize)
where
D: Copy + Into<T>,
{
for i in 0..length {
self.set(i as isize, data[i].into());
}
}
pub fn read<D>(&self, length: usize, data: &mut [D])
where
T: Into<D>,
D: Copy,
{
for i in 0..length {
data[i] = self.get(i as isize).into();
}
}
pub fn view(&self) -> View<T> {
View {
buffer: self,
offset: 0,
}
}
pub fn view_at(&self, offset: isize) -> View<T> {
View {
buffer: self,
offset,
}
}
}
pub struct View<'a, T: Float> {
buffer: &'a Buffer<T>,
offset: isize,
}
impl<'a, T: Float> View<'a, T> {
pub fn get(&self, offset: isize) -> T {
self.buffer.get(self.offset + offset)
}
pub fn offset(&self, offset: isize) -> View<'a, T> {
View {
buffer: self.buffer,
offset: self.offset + offset,
}
}
}
pub struct MultiBuffer<T: Float> {
channels: usize,
stride: usize,
buffer: Buffer<T>,
}
impl<T: Float> MultiBuffer<T> {
pub fn new(channels: usize, capacity: usize) -> Self {
Self {
channels,
stride: capacity,
buffer: Buffer::new(channels * capacity),
}
}
pub fn resize(&mut self, channels: usize, capacity: usize, value: T) {
self.channels = channels;
self.stride = capacity;
self.buffer.resize(channels * capacity, value);
}
pub fn reset(&mut self, value: T) {
self.buffer.reset(value);
}
pub fn advance(&mut self, amount: isize) -> &mut Self {
self.buffer.advance(amount);
self
}
pub fn channel(&self, channel: usize) -> View<T> {
self.buffer.view_at((channel * self.stride) as isize)
}
pub fn get(&self, channel: usize, offset: isize) -> T {
self.buffer.get((channel * self.stride) as isize + offset)
}
pub fn set(&mut self, channel: usize, offset: isize, value: T) {
self.buffer.set((channel * self.stride) as isize + offset, value);
}
}
pub struct InterpolatorNearest<T: Float> {
_marker: PhantomData<T>,
}
impl<T: Float> InterpolatorNearest<T> {
pub fn new() -> Self {
Self { _marker: PhantomData }
}
pub const INPUT_LENGTH: usize = 1;
pub fn latency() -> T {
-T::from(0.5).unwrap()
}
pub fn fractional<D>(&self, data: &D, _fractional: T) -> T
where
D: core::ops::Index<usize, Output = T>,
{
data[0]
}
}
pub struct InterpolatorLinear<T: Float> {
_marker: PhantomData<T>,
}
impl<T: Float> InterpolatorLinear<T> {
pub fn new() -> Self {
Self { _marker: PhantomData }
}
pub const INPUT_LENGTH: usize = 2;
pub fn latency() -> T {
T::zero()
}
pub fn fractional<D>(&self, data: &D, fractional: T) -> T
where
D: core::ops::Index<usize, Output = T>,
{
let a = data[0];
let b = data[1];
a + fractional * (b - a)
}
}
pub struct InterpolatorCubic<T: Float> {
_marker: PhantomData<T>,
}
impl<T: Float> InterpolatorCubic<T> {
pub fn new() -> Self {
Self { _marker: PhantomData }
}
pub const INPUT_LENGTH: usize = 4;
pub fn latency() -> T {
T::one()
}
pub fn fractional<D>(&self, data: &D, fractional: T) -> T
where
D: core::ops::Index<usize, Output = T>,
{
let a = data[0];
let b = data[1];
let c = data[2];
let d = data[3];
let cb_diff = c - b;
let half = T::from(0.5).unwrap();
let k1 = (c - a) * half;
let two = T::one() + T::one();
let k3 = k1 + (d - b) * half - cb_diff * two;
let k2 = cb_diff - k3 - k1;
b + fractional * (k1 + fractional * (k2 + fractional * k3))
}
}
pub struct Reader<T: Float, I> {
interpolator: I,
_marker: PhantomData<T>,
}
impl<T: Float, I> Reader<T, I> {
pub fn new(interpolator: I) -> Self {
Self {
interpolator,
_marker: PhantomData,
}
}
pub fn read<B>(&self, buffer: &B, delay_samples: T) -> T
where
I: InterpolatorTrait<T>,
B: BufferTrait<T>,
{
let start_index = delay_samples.floor().to_usize().unwrap_or(0);
let remainder = delay_samples - T::from(start_index).unwrap();
struct Flipped<'a, T: Float, B: BufferTrait<T>> {
view: &'a B,
start_index: usize,
_marker: PhantomData<T>,
}
impl<'a, T: Float, B: BufferTrait<T>> core::ops::Index<usize> for Flipped<'a, T, B> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
let offset = -(index as isize) - (self.start_index as isize);
self.view.get_ref(offset)
}
}
let flipped = Flipped {
view: buffer,
start_index,
_marker: PhantomData,
};
self.interpolator.fractional(&flipped, remainder)
}
}
pub trait BufferTrait<T: Float> {
fn get_ref(&self, offset: isize) -> &T;
}
impl<T: Float> BufferTrait<T> for Buffer<T> {
fn get_ref(&self, offset: isize) -> &T {
let index = (self.buffer_index as isize + offset) as usize & self.buffer_mask;
&self.buffer[index]
}
}
impl<'a, T: Float> BufferTrait<T> for View<'a, T> {
fn get_ref(&self, offset: isize) -> &T {
let index = (self.buffer.buffer_index as isize + self.offset + offset) as usize
& self.buffer.buffer_mask;
&self.buffer.buffer[index]
}
}
pub trait InterpolatorTrait<T: Float> {
fn fractional<D>(&self, data: &D, fractional: T) -> T
where
D: core::ops::Index<usize, Output = T>;
}
impl<T: Float> InterpolatorTrait<T> for InterpolatorNearest<T> {
fn fractional<D>(&self, data: &D, fractional: T) -> T
where
D: core::ops::Index<usize, Output = T>,
{
self.fractional(data, fractional)
}
}
impl<T: Float> InterpolatorTrait<T> for InterpolatorLinear<T> {
fn fractional<D>(&self, data: &D, fractional: T) -> T
where
D: core::ops::Index<usize, Output = T>,
{
self.fractional(data, fractional)
}
}
impl<T: Float> InterpolatorTrait<T> for InterpolatorCubic<T> {
fn fractional<D>(&self, data: &D, fractional: T) -> T
where
D: core::ops::Index<usize, Output = T>,
{
self.fractional(data, fractional)
}
}
pub struct Delay<T: Float, I> {
reader: Reader<T, I>,
buffer: Buffer<T>,
}
impl<T: Float, I: InterpolatorTrait<T>> Delay<T, I> {
pub fn new(interpolator: I, capacity: usize) -> Self {
Self {
reader: Reader::new(interpolator),
buffer: Buffer::new(capacity),
}
}
pub fn reset(&mut self, value: T) {
self.buffer.reset(value);
}
pub fn resize(&mut self, min_capacity: usize, value: T) {
self.buffer.resize(min_capacity, value);
}
pub fn read(&self, delay_samples: T) -> T {
self.reader.read(&self.buffer, delay_samples)
}
pub fn write(&mut self, value: T) -> &mut Self {
self.buffer.advance(1);
self.buffer.set(0, value);
self
}
}
pub struct MultiDelay<T: Float, I> {
reader: Reader<T, I>,
channels: usize,
buffer: MultiBuffer<T>,
}
impl<T: Float, I: InterpolatorTrait<T>> MultiDelay<T, I> {
pub fn new(interpolator: I, channels: usize, capacity: usize) -> Self {
Self {
reader: Reader::new(interpolator),
channels,
buffer: MultiBuffer::new(channels, capacity),
}
}
pub fn reset(&mut self, value: T) {
self.buffer.reset(value);
}
pub fn resize(&mut self, channels: usize, capacity: usize, value: T) {
self.channels = channels;
self.buffer.resize(channels, capacity, value);
}
pub fn read_channel(&self, channel: usize, delay_samples: T) -> T {
self.reader.read(&self.buffer.channel(channel), delay_samples)
}
pub fn read(&self, delay_samples: T, output: &mut [T]) {
for c in 0..self.channels {
output[c] = self.read_channel(c, delay_samples);
}
}
pub fn read_multi(&self, delays: &[T], output: &mut [T]) {
for c in 0..self.channels {
output[c] = self.read_channel(c, delays[c]);
}
}
pub fn write(&mut self, data: &[T]) -> &mut Self {
self.buffer.advance(1);
for c in 0..self.channels {
self.buffer.set(c, 0, data[c]);
}
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buffer() {
let mut buffer = Buffer::<f32>::new(16);
buffer.set(0, 1.0);
buffer.set(1, 2.0);
buffer.set(2, 3.0);
assert_eq!(buffer.get(0), 1.0);
assert_eq!(buffer.get(1), 2.0);
assert_eq!(buffer.get(2), 3.0);
buffer.advance(1);
assert_eq!(buffer.get(-1), 1.0);
assert_eq!(buffer.get(0), 2.0);
assert_eq!(buffer.get(1), 3.0);
}
#[test]
fn test_multi_buffer() {
let mut buffer = MultiBuffer::<f32>::new(2, 16);
buffer.set(0, 0, 1.0);
buffer.set(0, 1, 2.0);
buffer.set(1, 0, 3.0);
buffer.set(1, 1, 4.0);
assert_eq!(buffer.get(0, 0), 1.0);
assert_eq!(buffer.get(0, 1), 2.0);
assert_eq!(buffer.get(1, 0), 3.0);
assert_eq!(buffer.get(1, 1), 4.0);
buffer.advance(1);
assert_eq!(buffer.get(0, -1), 1.0);
assert_eq!(buffer.get(0, 0), 2.0);
assert_eq!(buffer.get(1, -1), 3.0);
assert_eq!(buffer.get(1, 0), 4.0);
}
#[test]
fn test_interpolators() {
let data = [1.0, 2.0, 3.0, 4.0];
let nearest = InterpolatorNearest::<f32>::new();
assert_eq!(nearest.fractional(&data, 0.0), 1.0);
assert_eq!(nearest.fractional(&data, 0.4), 1.0);
assert_eq!(nearest.fractional(&data, 0.6), 1.0);
let linear = InterpolatorLinear::<f32>::new();
assert_eq!(linear.fractional(&data, 0.0), 1.0);
assert_eq!(linear.fractional(&data, 0.5), 1.5);
assert_eq!(linear.fractional(&data, 1.0), 2.0);
let cubic = InterpolatorCubic::<f32>::new();
assert_eq!(cubic.fractional(&data, 0.0), 2.0);
let cubic_result = cubic.fractional(&data, 0.5);
assert!(cubic_result > 2.0 && cubic_result < 3.0);
}
#[test]
fn test_delay() {
let interpolator = InterpolatorLinear::<f32>::new();
let mut delay = Delay::new(interpolator, 16);
delay.write(1.0).write(2.0).write(3.0);
assert_eq!(delay.read(0.0), 3.0);
assert_eq!(delay.read(1.0), 2.0);
assert_eq!(delay.read(2.0), 1.0);
assert_eq!(delay.read(0.5), 2.5); }
#[test]
fn test_multi_delay() {
let interpolator = InterpolatorLinear::<f32>::new();
let mut delay = MultiDelay::new(interpolator, 2, 16);
delay.write(&[1.0, 3.0]).write(&[2.0, 4.0]);
let mut output = [0.0, 0.0];
delay.read(0.0, &mut output);
assert_eq!(output, [2.0, 4.0]);
delay.read(1.0, &mut output);
assert_eq!(output, [1.0, 3.0]);
delay.read_multi(&[0.0, 1.0], &mut output);
assert_eq!(output, [2.0, 3.0]);
}
}