use std::f32::consts::PI; #[derive(Clone, Copy)] struct AllpassDelay { a1: f32, zm1: f32, } impl AllpassDelay { fn new() -> Self { AllpassDelay { a1: 0.0, zm1: 0.0 } } fn delay(&mut self, delay: f32) { self.a1 = (1.0 - delay) / (1.0 + delay); } fn update(&mut self, in_samp: f32) -> f32 { let y = in_samp * -self.a1 + self.zm1; self.zm1 = y * self.a1 + in_samp; y } } #[derive(Clone, Copy)] pub struct StereoPhaser { alps: [AllpassDelay; 6], dmin: f32, dmax: f32, fb: f32, lfo_phase: f32, lfo_inc: f32, depth: f32, zm1: f32, sample_rate: f32, } impl StereoPhaser { pub fn new() -> Self { let mut phaser = StereoPhaser { alps: [AllpassDelay::new(); 6], dmin: 0.0, dmax: 0.0, fb: 0.7, lfo_phase: 0.0, lfo_inc: 0.0, depth: 1.0, zm1: 0.0, sample_rate: 44100.0, }; phaser.range(440.0, 1600.0); phaser.set_rate(0.5); phaser } pub fn range(&mut self, f_min: f32, f_max: f32) { self.dmin = f_min / (self.sample_rate / 2.0); self.dmax = f_max / (self.sample_rate / 2.0); } pub fn set_sample_rate(&mut self, sample_rate: f32) { self.sample_rate = sample_rate; } pub fn set_rate(&mut self, rate: f32) { self.lfo_inc = 2.0 * PI * (rate / self.sample_rate); } pub fn set_feedback(&mut self, fb: f32) { self.fb = fb; } pub fn set_depth(&mut self, depth: f32) { self.depth = depth; } pub fn process(&mut self, left_in: f32, right_in: f32, amount: f32) -> (f32, f32) { let d = self.dmin + (self.dmax - self.dmin) * ((self.lfo_phase.sin() + 1.0) / 2.0); self.lfo_phase += self.lfo_inc; self.lfo_phase %= PI * 2.0; for alp in &mut self.alps { alp.delay(d); } let left_out = self .alps .iter_mut() .fold(left_in + self.zm1 * self.fb, |acc, alp| alp.update(acc)); let right_out = self .alps .iter_mut() .fold(right_in + self.zm1 * self.fb, |acc, alp| alp.update(acc)); self.zm1 = left_out; let output_l = left_out + left_in * self.depth; let output_r = right_out + right_in * self.depth; ( output_l * amount + left_in * (1.0 - amount), output_r * amount + right_in * (1.0 - amount), ) } }