audio_processor_time/reverb/
free_verb.rs1use audio_garbage_collector::{make_shared, Shared};
24use audio_processor_traits::parameters::{
25 make_handle_ref, AudioProcessorHandle, AudioProcessorHandleProvider, AudioProcessorHandleRef,
26 FloatType, ParameterSpec, ParameterType, ParameterValue,
27};
28use audio_processor_traits::{AtomicF32, AudioBuffer, AudioContext, AudioProcessor};
29
30use crate::reverb::all_pass::AllPass;
31use crate::reverb::lowpass_feedback_comb_filter::LowpassFeedbackCombFilter;
32use crate::reverb::tuning::*;
33
34struct FreeverbProcessorHandle {
35 width: AtomicF32,
36 gain: AtomicF32,
37 dry: AtomicF32,
38 wet: AtomicF32,
39 damp: AtomicF32,
40 room_size: AtomicF32,
41}
42
43impl FreeverbProcessorHandle {
44 pub fn set_dry(&self, value: f32) {
45 self.dry.set(value * SCALE_DRY);
46 }
47
48 pub fn set_room_size(&self, value: f32) {
49 self.room_size.set(value * SCALE_ROOM + OFFSET_ROOM);
50 }
51
52 pub fn set_damp(&self, value: f32) {
53 self.damp.set(value * SCALE_DAMP);
54 }
55
56 pub fn set_wet(&self, value: f32) {
57 self.wet.set(value * SCALE_WET);
58 }
59}
60
61struct GenericHandle(Shared<FreeverbProcessorHandle>);
62
63impl AudioProcessorHandle for GenericHandle {
64 fn name(&self) -> String {
65 "Reverb".to_string()
66 }
67
68 fn parameter_count(&self) -> usize {
69 4
70 }
71
72 fn get_parameter_spec(&self, index: usize) -> ParameterSpec {
73 let specs: [ParameterSpec; 4] = [
74 ParameterSpec::new(
75 "Dry".into(),
76 ParameterType::Float(FloatType {
77 range: (0.0, 1.0),
78 step: None,
79 }),
80 ),
81 ParameterSpec::new(
82 "Room size".into(),
83 ParameterType::Float(FloatType {
84 range: (0.0, 1.0),
85 step: None,
86 }),
87 ),
88 ParameterSpec::new(
89 "Damp".into(),
90 ParameterType::Float(FloatType {
91 range: (0.0, 1.0),
92 step: None,
93 }),
94 ),
95 ParameterSpec::new(
96 "Wet".into(),
97 ParameterType::Float(FloatType {
98 range: (0.0, 1.0),
99 step: None,
100 }),
101 ),
102 ];
103 specs[index].clone()
104 }
105
106 fn get_parameter(&self, index: usize) -> Option<ParameterValue> {
107 match index {
108 0 => Some(self.0.dry.get().into()),
109 1 => Some(self.0.room_size.get().into()),
110 2 => Some(self.0.damp.get().into()),
111 3 => Some(self.0.wet.get().into()),
112 _ => None,
113 }
114 }
115
116 fn set_parameter(&self, index: usize, request: ParameterValue) {
117 if let Ok(value) = request.try_into() {
118 match index {
119 0 => self.0.set_dry(value),
120 1 => self.0.set_room_size(value),
121 2 => self.0.set_damp(value),
122 3 => self.0.set_wet(value),
123 _ => {}
124 }
125 }
126 }
127}
128
129pub struct MonoFreeverbProcessor {
130 comb_filters: [LowpassFeedbackCombFilter; 8],
131 all_pass: [AllPass; 4],
132}
133
134impl MonoFreeverbProcessor {
135 fn new(comb_filters: [LowpassFeedbackCombFilter; 8], all_pass: [AllPass; 4]) -> Self {
136 Self {
137 comb_filters,
138 all_pass,
139 }
140 }
141
142 fn prepare(&mut self) {
143 for all_pass in &mut self.all_pass {
144 all_pass.set_feedback(0.5)
145 }
146 }
147
148 fn update(&mut self, room_size: f32, damp: f32) {
149 for comb in self.comb_filters.iter_mut() {
150 comb.set_feedback(room_size);
151 comb.set_damp(damp);
152 }
153 }
154
155 fn process(&mut self, channel: &mut [f32], wet: f32, gain: f32) {
156 for input in channel {
157 let mut output = 0.0;
158 for comb in self.comb_filters.iter_mut() {
159 output += comb.process(*input * gain);
160 }
161
162 for allpass in self.all_pass.iter_mut() {
163 output = allpass.process(output);
164 }
165
166 *input = output * wet;
167 }
168 }
169}
170
171pub struct FreeverbProcessor {
172 processors: [MonoFreeverbProcessor; 2],
173 handle: Shared<FreeverbProcessorHandle>,
174
175 wet1: f32,
176 wet2: f32,
177 damp1: f32,
178 roomsize1: f32,
179}
180
181impl AudioProcessorHandleProvider for FreeverbProcessor {
182 fn generic_handle(&self) -> AudioProcessorHandleRef {
183 make_handle_ref(GenericHandle(self.handle.clone()))
184 }
185}
186
187impl Default for FreeverbProcessor {
188 fn default() -> Self {
189 Self {
190 processors: [
191 MonoFreeverbProcessor::new(
192 [
193 LowpassFeedbackCombFilter::new(COMBTUNING_L1),
194 LowpassFeedbackCombFilter::new(COMBTUNING_L2),
195 LowpassFeedbackCombFilter::new(COMBTUNING_L3),
196 LowpassFeedbackCombFilter::new(COMBTUNING_L4),
197 LowpassFeedbackCombFilter::new(COMBTUNING_L5),
198 LowpassFeedbackCombFilter::new(COMBTUNING_L6),
199 LowpassFeedbackCombFilter::new(COMBTUNING_L7),
200 LowpassFeedbackCombFilter::new(COMBTUNING_L8),
201 ],
202 [
203 AllPass::new(ALL_PASS_TUNING),
204 AllPass::new(ALLPASSTUNING_L2),
205 AllPass::new(ALLPASSTUNING_L3),
206 AllPass::new(ALLPASSTUNING_L4),
207 ],
208 ),
209 MonoFreeverbProcessor::new(
210 [
211 LowpassFeedbackCombFilter::new(COMBTUNING_R1),
212 LowpassFeedbackCombFilter::new(COMBTUNING_R2),
213 LowpassFeedbackCombFilter::new(COMBTUNING_R3),
214 LowpassFeedbackCombFilter::new(COMBTUNING_R4),
215 LowpassFeedbackCombFilter::new(COMBTUNING_R5),
216 LowpassFeedbackCombFilter::new(COMBTUNING_R6),
217 LowpassFeedbackCombFilter::new(COMBTUNING_R7),
218 LowpassFeedbackCombFilter::new(COMBTUNING_R8),
219 ],
220 [
221 AllPass::new(ALLPASSTUNING_R1),
222 AllPass::new(ALLPASSTUNING_R2),
223 AllPass::new(ALLPASSTUNING_R3),
224 AllPass::new(ALLPASSTUNING_R4),
225 ],
226 ),
227 ],
228 handle: make_shared(FreeverbProcessorHandle {
229 width: INITIAL_WIDTH.into(),
230 gain: FIXED_GAIN.into(),
231 dry: INITIAL_DRY.into(),
232 wet: INITIAL_WET.into(),
233 damp: INITIAL_DAMP.into(),
234 room_size: 0.0.into(),
235 }),
236
237 wet1: 0.0,
238 wet2: 0.0,
239 damp1: 0.0,
240 roomsize1: 0.0,
241 }
242 }
243}
244
245impl FreeverbProcessor {
246 fn update(&mut self) {
247 self.wet1 = self.handle.wet.get() * (self.handle.width.get() / 2.0 + 0.5);
248 self.wet2 = self.handle.wet.get() * ((1.0 - self.handle.width.get()) / 2.0);
249
250 self.roomsize1 = self.handle.room_size.get();
251 self.damp1 = self.handle.damp.get();
252
253 for processor in self.processors.iter_mut() {
254 processor.update(self.roomsize1, self.damp1);
255 }
256 }
257}
258
259impl AudioProcessor for FreeverbProcessor {
260 type SampleType = f32;
261
262 fn prepare(&mut self, _context: &mut AudioContext) {
263 for processor in self.processors.iter_mut() {
264 processor.prepare();
265 }
266
267 self.handle.set_wet(INITIAL_WET);
268 self.handle.set_damp(INITIAL_DAMP);
269 self.handle.set_room_size(INITIAL_ROOM);
270 }
271
272 fn process(&mut self, _context: &mut AudioContext, buffer: &mut AudioBuffer<Self::SampleType>) {
274 self.update();
276
277 for (channel_num, (channel, processor)) in buffer
278 .channels_mut()
279 .iter_mut()
280 .zip(&mut self.processors)
281 .enumerate()
282 {
283 let wet = if channel_num == 1 {
284 self.wet1
285 } else {
286 self.wet2
287 };
288 processor.process(channel, wet, self.handle.gain.get());
289 }
290
291 }
316}