use crate as knyst;
use crate::gen::GenState;
use crate::BlockSize;
use crate::SampleRate;
use knyst_macro::impl_gen;
use crate::time::Seconds;
use crate::Sample;
pub struct SampleDelay {
buffer: Vec<Sample>,
write_position: usize,
max_delay_length: Seconds,
}
impl SampleDelay {}
#[impl_gen]
impl SampleDelay {
#[new]
pub fn new(max_delay_length: Seconds) -> Self {
Self {
buffer: vec![0.0; 0],
max_delay_length,
write_position: 0,
}
}
#[process]
fn process(
&mut self,
signal: &[Sample],
delay_time: &[Sample],
output: &mut [Sample],
sample_rate: SampleRate,
) -> GenState {
let sig_buf = signal;
let time_buf = delay_time;
let out_buf = output;
for ((&input, &time), o) in sig_buf.iter().zip(time_buf).zip(out_buf.iter_mut()) {
self.buffer[self.write_position] = input;
let delay_samples = (time * *sample_rate) as usize;
*o = self.buffer
[(self.write_position + self.buffer.len() - delay_samples) % self.buffer.len()];
self.write_position = (self.write_position + 1) % self.buffer.len();
}
GenState::Continue
}
#[init]
fn init(&mut self, sample_rate: SampleRate) {
self.buffer =
vec![0.0; (self.max_delay_length.to_seconds_f64() * sample_rate.to_f64()) as usize];
self.write_position = 0;
}
}
#[derive(Clone, Copy, Debug)]
pub struct AllpassInterpolator {
coeff: f64,
prev_input: f64,
prev_output: f64,
}
impl AllpassInterpolator {
pub fn new() -> Self {
Self {
coeff: 0.0,
prev_input: 0.0,
prev_output: 0.0,
}
}
pub fn clear(&mut self) {
self.prev_input = 0.0;
self.prev_output = 0.0;
}
pub fn set_delta(&mut self, delta: f64) {
self.coeff = (1.0 - delta) / (1.0 + delta);
}
pub fn process_sample(&mut self, input: f64) -> f64 {
let output = self.coeff * (input - self.prev_output) + self.prev_input;
self.prev_output = output;
self.prev_input = input;
output
}
}
#[derive(Clone, Debug)]
pub struct AllpassDelay {
buffer: Vec<f64>,
buffer_size: usize,
frame: usize,
num_frames: usize,
allpass: AllpassInterpolator,
}
impl AllpassDelay {
#[allow(missing_docs)]
#[must_use]
pub fn new(buffer_size: usize) -> Self {
let buffer = vec![0.0; buffer_size];
Self {
buffer,
buffer_size,
frame: 0,
num_frames: 1,
allpass: AllpassInterpolator::new(),
}
}
pub fn read(&mut self) -> f64 {
let index = self.frame % self.buffer.len();
self.allpass.process_sample(self.buffer[index])
}
pub fn set_delay_in_frames(&mut self, num_frames: f64) {
self.num_frames = num_frames.floor() as usize;
self.allpass.set_delta(num_frames - self.num_frames as f64);
}
pub fn clear(&mut self) {
for sample in &mut self.buffer {
*sample = 0.0;
}
self.allpass.clear();
}
pub fn set_delay_in_frames_and_clear(&mut self, num_frames: f64) {
for sample in &mut self.buffer {
*sample = 0.0;
}
self.set_delay_in_frames(num_frames);
}
pub fn write_and_advance(&mut self, input: f64) {
self.frame += 1;
let index = (self.frame + self.num_frames) % self.buffer_size;
self.buffer[index] = input;
}
}
#[derive(Clone, Debug)]
pub struct AllpassFeedbackDelay {
pub feedback: f64,
previous_delay_time: Sample,
allpass_delay: AllpassDelay,
}
#[impl_gen]
impl AllpassFeedbackDelay {
#[allow(missing_docs)]
#[must_use]
pub fn new(max_delay_samples: usize) -> Self {
let allpass_delay = AllpassDelay::new(max_delay_samples);
let s = Self {
feedback: 0.,
allpass_delay,
previous_delay_time: max_delay_samples as Sample,
};
s
}
pub fn set_delay_in_frames(&mut self, delay_length: f64) {
self.allpass_delay.set_delay_in_frames(delay_length);
}
pub fn clear(&mut self) {
self.allpass_delay.clear();
}
pub fn process_sample(&mut self, input: f64) -> f64 {
let delayed_sig = self.allpass_delay.read();
let delay_write = delayed_sig * self.feedback + input;
self.allpass_delay.write_and_advance(delay_write);
delayed_sig - self.feedback * delay_write
}
pub fn process(
&mut self,
input: &[Sample],
feedback: &[Sample],
delay_time: &[Sample],
output: &mut [Sample],
sample_rate: SampleRate,
) -> GenState {
for (((&input, &feedback), &delay_time), output) in input
.iter()
.zip(feedback)
.zip(delay_time)
.zip(output.iter_mut())
{
if delay_time != self.previous_delay_time {
self.set_delay_in_frames(delay_time as f64 * sample_rate.to_f64());
self.previous_delay_time = delay_time;
}
self.feedback = f64::from(feedback);
*output = self.process_sample(f64::from(input)) as Sample;
}
GenState::Continue
}
}
pub struct StaticSampleDelay {
buffer: Vec<Sample>,
pub position: usize,
delay_length: usize,
}
#[impl_gen]
impl StaticSampleDelay {
#[must_use]
pub fn new(delay_length_in_samples: usize) -> Self {
assert!(delay_length_in_samples != 0);
Self {
buffer: vec![0.0; delay_length_in_samples],
position: 0,
delay_length: delay_length_in_samples,
}
}
#[inline]
pub fn set_delay_length(&mut self, delay_length_in_samples: usize) {
self.delay_length = delay_length_in_samples.min(self.buffer.len());
}
pub fn set_delay_length_fraction(&mut self, fraction: Sample) {
self.delay_length = (self.buffer.len() as Sample * fraction) as usize;
}
#[inline]
pub fn read_block(&mut self, output: &mut [Sample]) {
let block_size = output.len();
assert!(self.buffer.len() >= block_size);
let read_end = self.position + block_size;
if read_end <= self.buffer.len() {
output.copy_from_slice(&self.buffer[self.position..read_end]);
} else {
let read_end = read_end % self.delay_length;
output[0..(block_size - read_end)].copy_from_slice(&self.buffer[self.position..]);
output[(block_size - read_end)..].copy_from_slice(&self.buffer[0..read_end]);
}
}
#[inline]
pub fn write_block_and_advance(&mut self, input: &[Sample]) {
let block_size = input.len();
assert!(self.buffer.len() >= block_size);
let write_end = self.position + block_size;
if write_end <= self.buffer.len() {
self.buffer[self.position..write_end].copy_from_slice(&input);
} else {
let write_end = write_end % self.delay_length;
self.buffer[self.position..].copy_from_slice(&input[0..block_size - write_end]);
self.buffer[0..write_end].copy_from_slice(&input[block_size - write_end..]);
}
self.position = (self.position + block_size) % self.buffer.len();
}
#[inline]
pub fn read(&mut self) -> Sample {
self.buffer[self.position]
}
pub fn read_at(&mut self, index: usize) -> Sample {
self.buffer[index]
}
pub fn read_at_lin(&mut self, index: Sample) -> Sample {
let mut low = index.floor() as usize;
let mut high = index.ceil() as usize;
while low >= self.buffer.len() {
low -= self.buffer.len();
high -= self.buffer.len();
}
if high >= self.buffer.len() {
high -= self.buffer.len();
}
let low_sample = self.buffer[low];
let high_sample = self.buffer[high];
low_sample + (high_sample - low_sample) * index.fract()
}
#[inline]
pub fn write_and_advance(&mut self, input: Sample) {
self.buffer[self.position] = input;
self.position = (self.position + 1) % self.delay_length;
}
#[inline]
pub fn process(
&mut self,
input: &[Sample],
output: &mut [Sample],
block_size: BlockSize,
) -> GenState {
if self.buffer.len() > *block_size {
self.read_block(output);
self.write_block_and_advance(input);
} else {
for (i, o) in input.iter().zip(output.iter_mut()) {
*o = self.read();
self.write_and_advance(*i);
}
}
GenState::Continue
}
}