use no_denormals::*;
pub struct Delay {
time: f32,
sample_rate: f32,
pub feedback: f32,
pub mix: f32,
ring: Vec<f32>,
read: usize,
write: usize,
mask: usize,
scratch: Vec<f32>,
}
impl Delay {
pub fn new(time: f32, sample_rate: f32) -> Self {
let capacity = Self::capacity_for(time, sample_rate);
Self {
time,
sample_rate,
feedback: 0.5,
mix: 0.5,
ring: vec![0.0; capacity],
read: 0,
write: 0,
mask: capacity - 1,
scratch: Vec::new(),
}
}
fn capacity_for(time: f32, sample_rate: f32) -> usize {
((time * 0.001 * sample_rate) as usize)
.max(1)
.next_power_of_two()
}
fn resize(&mut self, capacity: usize) {
self.ring = vec![0.0; capacity];
self.read = 0;
self.write = 0;
self.mask = capacity - 1;
}
pub fn get_time(&self) -> f32 {
self.time
}
pub fn set_time(&mut self, time: f32) {
self.time = time;
self.resize(Self::capacity_for(time, self.sample_rate));
}
pub fn set_sample_rate(&mut self, sample_rate: f32) {
self.sample_rate = sample_rate;
self.resize(Self::capacity_for(self.time, sample_rate));
}
#[inline]
fn step(&mut self, input: f32) -> f32 {
let delayed = self.ring[self.read];
self.read = (self.read + 1) & self.mask;
self.ring[self.write] = input + delayed * self.feedback;
self.write = (self.write + 1) & self.mask;
delayed
}
#[inline]
pub fn process(&mut self, input: f32) -> f32 {
let delayed = self.step(input);
input * (1.0 - self.mix) + delayed * self.mix
}
pub fn run(&mut self, input: &[f32], output: &mut [f32]) {
let len = input.len().min(output.len());
if self.scratch.len() < len {
self.scratch.resize(len, 0.0);
}
unsafe {
no_denormals(|| {
#[allow(clippy::needless_range_loop)]
for index in 0..len {
self.scratch[index] = self.step(input[index]);
}
crate::simd::mix_scalar(
&mut output[..len],
&input[..len],
&self.scratch[..len],
self.mix,
);
});
}
}
}