use crate::cubic_interpolate;
use crate::{f, Flt};
const DEFAULT_DELAY_BUFFER_SAMPLES: usize = 8 * 48000 * 5;
#[derive(Debug, Clone, Default)]
pub struct DelayBuffer<F: Flt> {
data: Vec<F>,
wr: usize,
srate: F,
}
impl<F: Flt> DelayBuffer<F> {
pub fn new() -> Self {
Self { data: vec![f(0.0); DEFAULT_DELAY_BUFFER_SAMPLES], wr: 0, srate: f(44100.0) }
}
pub fn new_with_size(size: usize) -> Self {
Self { data: vec![f(0.0); size], wr: 0, srate: f(44100.0) }
}
pub fn set_sample_rate(&mut self, srate: F) {
self.srate = srate;
}
pub fn reset(&mut self) {
self.data.fill(f(0.0));
self.wr = 0;
}
#[inline]
pub fn feed(&mut self, input: F) {
self.data[self.wr] = input;
self.wr = (self.wr + 1) % self.data.len();
}
#[inline]
pub fn next_cubic(&mut self, delay_time_ms: F, input: F) -> F {
let res = self.cubic_interpolate_at(delay_time_ms);
self.feed(input);
res
}
#[inline]
pub fn next_linear(&mut self, delay_time_ms: F, input: F) -> F {
let res = self.linear_interpolate_at(delay_time_ms);
self.feed(input);
res
}
#[inline]
pub fn next_nearest(&mut self, delay_time_ms: F, input: F) -> F {
let res = self.nearest_at(delay_time_ms);
self.feed(input);
res
}
#[inline]
pub fn tap_c(&self, delay_time_ms: F) -> F {
self.cubic_interpolate_at(delay_time_ms)
}
#[inline]
pub fn tap_n(&self, delay_time_ms: F) -> F {
self.nearest_at(delay_time_ms)
}
#[inline]
pub fn tap_l(&self, delay_time_ms: F) -> F {
self.linear_interpolate_at(delay_time_ms)
}
#[inline]
pub fn linear_interpolate_at(&self, delay_time_ms: F) -> F {
self.linear_interpolate_at_s((delay_time_ms * self.srate) / f(1000.0))
}
#[inline]
pub fn linear_interpolate_at_s(&self, s_offs: F) -> F {
let data = &self.data[..];
let len = data.len();
let offs = s_offs.floor().to_usize().unwrap_or(0) % len;
let fract = s_offs.fract();
let i = (self.wr + len) - (offs + 1);
let x0 = data[i % len];
let x1 = data[(i - 1) % len];
let res = x0 + fract * (x1 - x0);
res
}
#[inline]
pub fn cubic_interpolate_at(&self, delay_time_ms: F) -> F {
self.cubic_interpolate_at_s((delay_time_ms * self.srate) / f(1000.0))
}
#[inline]
pub fn cubic_interpolate_at_s(&self, s_offs: F) -> F {
let data = &self.data[..];
let len = data.len();
let offs = s_offs.floor().to_usize().unwrap_or(0) % len;
let fract = s_offs.fract();
let i = (self.wr + len) - (offs + 2);
let res = cubic_interpolate(data, len, i, f::<F>(1.0) - fract);
res
}
#[inline]
pub fn nearest_at(&self, delay_time_ms: F) -> F {
let len = self.data.len();
let offs = ((delay_time_ms * self.srate) / f(1000.0)).floor().to_usize().unwrap_or(0) % len;
let idx = ((self.wr + len) - (offs + 1)) % len;
self.data[idx]
}
#[inline]
pub fn at(&self, delay_sample_count: usize) -> F {
let len = self.data.len();
let idx = ((self.wr + len) - (delay_sample_count + 1)) % len;
self.data[idx]
}
}
const DEFAULT_ALLPASS_COMB_SAMPLES: usize = 8 * 48000;
#[derive(Debug, Clone, Default)]
pub struct AllPass<F: Flt> {
delay: DelayBuffer<F>,
}
impl<F: Flt> AllPass<F> {
pub fn new() -> Self {
Self { delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES) }
}
pub fn set_sample_rate(&mut self, srate: F) {
self.delay.set_sample_rate(srate);
}
pub fn reset(&mut self) {
self.delay.reset();
}
#[inline]
pub fn delay_tap_n(&self, time_ms: F) -> F {
self.delay.tap_n(time_ms)
}
#[inline]
pub fn next(&mut self, time_ms: F, g: F, v: F) -> F {
let s = self.delay.cubic_interpolate_at(time_ms);
let input = v + -g * s;
self.delay.feed(input);
input * g + s
}
#[inline]
pub fn next_linear(&mut self, time_ms: F, g: F, v: F) -> F {
let s = self.delay.linear_interpolate_at(time_ms);
let input = v + -g * s;
self.delay.feed(input);
input * g + s
}
}
#[derive(Debug, Clone)]
pub struct Comb {
delay: DelayBuffer<f32>,
}
impl Comb {
pub fn new() -> Self {
Self { delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES) }
}
pub fn set_sample_rate(&mut self, srate: f32) {
self.delay.set_sample_rate(srate);
}
pub fn reset(&mut self) {
self.delay.reset();
}
#[inline]
pub fn delay_tap_c(&self, time_ms: f32) -> f32 {
self.delay.tap_c(time_ms)
}
#[inline]
pub fn delay_tap_n(&self, time_ms: f32) -> f32 {
self.delay.tap_n(time_ms)
}
#[inline]
pub fn next_feedback(&mut self, time: f32, g: f32, v: f32) -> f32 {
let s = self.delay.cubic_interpolate_at(time);
let v = v + s * g;
self.delay.feed(v);
v
}
#[inline]
pub fn next_feedforward(&mut self, time: f32, g: f32, v: f32) -> f32 {
let s = self.delay.next_cubic(time, v);
v + s * g
}
}