use std::f32::consts::PI; #[derive(Clone)] pub struct StereoFlanger { sample_rate: f32, depth: f32, lfo_rate: f32, delay_range: f32, feedback: f32, delay_line: Vec<(f32, f32)>, index: usize, lfo_phase: f32, } impl StereoFlanger { pub fn new( sample_rate: f32, depth: f32, lfo_rate: f32, delay_range: f32, feedback: f32, max_delay_samples: usize, ) -> Self { Self { sample_rate, depth, lfo_rate, delay_range, feedback, delay_line: vec![(0.0, 0.0); max_delay_samples], index: 0, lfo_phase: 0.0, } } pub fn update(&mut self, sample_rate: f32, depth: f32, lfo_rate: f32, feedback: f32) { self.sample_rate = sample_rate; self.depth = depth; self.lfo_rate = lfo_rate; self.feedback = feedback; } pub fn process(&mut self, left_in: f32, right_in: f32, amount: f32) -> (f32, f32) { // Update LFO phase self.lfo_phase += 2.0 * PI * self.lfo_rate / self.sample_rate; if self.lfo_phase > 2.0 * PI { self.lfo_phase -= 2.0 * PI; } // Calculate modulation depth let modulator = self.depth * (0.5 * self.lfo_phase.sin() + 0.5); // Calculate delay in samples let delay_samples = (self.delay_range * modulator) as usize; // Retrieve delayed samples from the delay line let delayed_left = self.delay_line[(self.index + delay_samples) % self.delay_line.len()].0; let delayed_right = self.delay_line[(self.index + delay_samples) % self.delay_line.len()].1; // Apply flanger effect let mut left_out = left_in + self.feedback * delayed_left; let mut right_out = right_in + self.feedback * delayed_right; // Update delay line self.delay_line[self.index] = (left_in, right_in); // Increment index and wrap around self.index = (self.index + 1) % self.delay_line.len(); // Mix dry and wet signals based on the amount parameter left_out = left_in * (1.0 - amount) + left_out * amount; right_out = right_in * (1.0 - amount) + right_out * amount; (left_out, right_out) } }