Skip to main content

proteus_lib/effects/
reverb.rs

1use std::time::Instant;
2
3use log::debug;
4use rodio::{
5    buffer::SamplesBuffer,
6    dynamic_mixer::{self, DynamicMixer},
7    Source,
8};
9
10use crate::effects::convolution::Convolver;
11use crate::effects::spring_impulse_response::SPRING_IMPULSE_RESPONSE;
12
13const FFT_SIZE: usize = 24576;
14// const FFT_SIZE: usize = 4096;
15// const FFT_SIZE: usize = 1024;
16
17pub struct Reverb {
18    previous_tails: Vec<Vec<f32>>,
19    channels: usize,
20    dry_wet: f32,
21    convolvers: Vec<Convolver>,
22}
23
24impl Reverb {
25    pub fn new(channels: usize, dry_wet: f32) -> Self {
26        Self {
27            previous_tails: vec![vec![0.0; channels]],
28            channels,
29            dry_wet,
30            convolvers: vec![Convolver::new(SPRING_IMPULSE_RESPONSE, FFT_SIZE); channels],
31        }
32    }
33
34    pub fn process(&mut self, input_buffer: &[f32]) -> Vec<f32> {
35        let channels = self.split_channels(input_buffer);
36        let mut processed = Vec::with_capacity(self.channels);
37        for (i, channel) in channels.iter().enumerate() {
38            let processed_channel = self.process_channel(channel, i);
39            processed.push(processed_channel);
40        }
41        let mixed = self.mix_channels(&channels, &processed);
42        mixed
43    }
44
45    pub fn process_mixer(&mut self, mixer: DynamicMixer<f32>) -> SamplesBuffer<f32> {
46        let sample_rate = mixer.sample_rate();
47        let mixer_buffered = mixer.buffered();
48        let vector_samples = mixer_buffered.clone().into_iter().collect::<Vec<f32>>();
49        let processed = self.process(&vector_samples);
50        SamplesBuffer::new(mixer_buffered.channels(), sample_rate, processed)
51    }
52
53    fn process_channel(&mut self, channel: &[f32], index: usize) -> Vec<f32> {
54        let start = Instant::now();
55        let convolver = &mut self.convolvers[index];
56        // convolver.fft_size = channel.len();
57        // let mut convolver = Convolver::new(SPRING_IMPULSE_RESPONSE, FFT_SIZE);
58
59        debug!("Convolver fft size: {:?}", convolver.fft_size);
60        debug!("Channel length: {:?}", channel.len());
61
62        let time_to_create_convolver = Instant::now();
63        debug!(
64            "Time taken to create convolver #{}: {:?}",
65            index,
66            time_to_create_convolver.duration_since(start)
67        );
68        // println!("Channel length: {:?}", channel.len());
69        // println!("Previous tail length: {:?}", self.previous_tails.len());
70        // convolver.previous_tail = if self.previous_tails.len() > index {
71        //     self.previous_tails[index].clone()
72        // } else {
73        //     self.previous_tails.push(vec![0.0; channel.len()]);
74        //     self.previous_tails[index].clone()
75        // };
76        let processed = convolver.process(channel);
77        // self.previous_tails[index] = convolver.previous_tail;
78        let end = Instant::now();
79        debug!(
80            "Time taken to process channel #{}: {:?}",
81            index,
82            end.duration_since(start)
83        );
84        processed
85    }
86
87    fn split_channels(&self, input_buffer: &[f32]) -> Vec<Vec<f32>> {
88        let mut unzipped = Vec::with_capacity(self.channels);
89        for i in 0..self.channels {
90            unzipped.push(
91                input_buffer
92                    .iter()
93                    .skip(i)
94                    .step_by(self.channels)
95                    .cloned()
96                    .collect::<Vec<f32>>(),
97            );
98        }
99        unzipped
100    }
101
102    fn mix_channels(&self, dry: &Vec<Vec<f32>>, wet: &Vec<Vec<f32>>) -> Vec<f32> {
103        let mut mixed = Vec::with_capacity(dry[0].len() * self.channels);
104        let dry_amount = 1.0 - self.dry_wet;
105        let wet_amount = self.dry_wet;
106
107        // For each sample position
108        for i in 0..dry[0].len() {
109            // For each channel
110            for ch in 0..self.channels {
111                let mixed_sample = (dry[ch][i] * dry_amount) + (wet[ch][i] * wet_amount);
112                mixed.push(mixed_sample);
113            }
114        }
115
116        mixed
117    }
118
119    pub fn clear_tail(&mut self) {
120        for tail in &mut self.previous_tails {
121            tail.fill(0.0);
122        }
123    }
124}
125
126// pub fn apply_reverb(samples: Vec<f32>, dry_wet: f32) -> Vec<f32> {
127//     // Clamp dry_wet between 0 and 1
128//     let dry_wet = dry_wet.clamp(0.0, 1.0);
129//     let dry_amount = 1.0 - dry_wet;
130//     let wet_amount = dry_wet;
131
132//     println!("Samples length: {:?}", samples.len());
133//     let left_samples = samples.iter().step_by(2).cloned().collect::<Vec<f32>>();
134//     let right_samples = samples
135//         .iter()
136//         .skip(1)
137//         .step_by(2)
138//         .cloned()
139//         .collect::<Vec<f32>>();
140
141//     let mut convolver_left = Convolver::new(SPRING_IMPULSE_RESPONSE, left_samples.len());
142//     let mut convolver_right = Convolver::new(SPRING_IMPULSE_RESPONSE, right_samples.len());
143
144//     let processed_left = convolver_left.process(&left_samples);
145//     let processed_right = convolver_right.process(&right_samples);
146
147//     let previous_tail_left = convolver_left.previous_tail;
148//     let previous_tail_right = convolver_right.previous_tail;
149
150//     println!("Previous tail left: {:?}", previous_tail_left.len());
151//     println!("Previous tail right: {:?}", previous_tail_right.len());
152
153//     // Mix dry and wet signals
154//     let mut processed = Vec::with_capacity(processed_left.len() * 2);
155//     for ((dry_l, dry_r), (wet_l, wet_r)) in left_samples.iter().zip(right_samples.iter())
156//         .zip(processed_left.iter().zip(processed_right.iter()))
157//     {
158//         // Mix left channel
159//         let mixed_l = (dry_l * dry_amount) + (wet_l * wet_amount);
160//         // Mix right channel
161//         let mixed_r = (dry_r * dry_amount) + (wet_r * wet_amount);
162
163//         processed.push(mixed_l);
164//         processed.push(mixed_r);
165//     }
166
167//     println!("Processed length: {:?}", processed.len());
168//     processed
169// }