1use super::EffectAvailability;
2use crate::engine::audio::effects::processors::EffectProcessor;
3use crate::engine::audio::effects::processors::{
4 BandpassProcessor, BitcrushProcessor, FreezeProcessor, HighpassProcessor, LfoProcessor,
5 LowpassProcessor, MonoizerProcessor, ReverseProcessor, RollProcessor, SliceProcessor,
6 SpeedProcessor, StereoProcessor, StretchProcessor, TremoloProcessor, VibratoProcessor,
7};
8use crate::engine::audio::effects::processors::{
9 ChorusProcessor, CompressorProcessor, DelayProcessor, DistortionProcessor, DriveProcessor,
10 FlangerProcessor, GateProcessor, PhaserProcessor, ReverbProcessor,
11};
12use std::collections::HashMap;
13
14#[derive(Debug)]
16pub struct EffectRegistry {
17 effects: HashMap<&'static str, (EffectAvailability, Box<dyn CloneableEffect>)>,
18}
19
20impl EffectRegistry {
21 pub fn new() -> Self {
22 let mut registry = Self {
23 effects: HashMap::new(),
24 };
25
26 registry.register_effect(
28 "gain",
29 EffectAvailability::Both,
30 Box::new(DriveProcessor::default()),
31 );
32 registry.register_effect(
33 "volume",
34 EffectAvailability::Both,
35 Box::new(DriveProcessor::default()),
36 );
37 registry.register_effect(
38 "pan",
39 EffectAvailability::Both,
40 Box::new(DriveProcessor::default()),
41 );
42 registry.register_effect(
43 "fadeIn",
44 EffectAvailability::Both,
45 Box::new(DriveProcessor::default()),
46 );
47 registry.register_effect(
48 "fadeOut",
49 EffectAvailability::Both,
50 Box::new(DriveProcessor::default()),
51 );
52 registry.register_effect(
53 "pitch",
54 EffectAvailability::Both,
55 Box::new(DriveProcessor::default()),
56 );
57 registry.register_effect(
58 "chorus",
59 EffectAvailability::Both,
60 Box::new(ChorusProcessor::default()),
61 );
62 registry.register_effect(
63 "flanger",
64 EffectAvailability::Both,
65 Box::new(FlangerProcessor::default()),
66 );
67 registry.register_effect(
68 "phaser",
69 EffectAvailability::Both,
70 Box::new(PhaserProcessor::default()),
71 );
72 registry.register_effect(
73 "compressor",
74 EffectAvailability::Both,
75 Box::new(CompressorProcessor::default()),
76 );
77 registry.register_effect(
78 "gate",
79 EffectAvailability::Both,
80 Box::new(GateProcessor::default()),
81 );
82 registry.register_effect(
83 "drive",
84 EffectAvailability::Both,
85 Box::new(DriveProcessor::default()),
86 );
87 registry.register_effect(
88 "reverb",
89 EffectAvailability::Both,
90 Box::new(ReverbProcessor::default()),
91 );
92 registry.register_effect(
93 "delay",
94 EffectAvailability::Both,
95 Box::new(DelayProcessor::default()),
96 );
97 registry.register_effect(
98 "bitcrush",
99 EffectAvailability::Both,
100 Box::new(BitcrushProcessor::default()),
101 );
102 registry.register_effect(
103 "lowpass",
104 EffectAvailability::Both,
105 Box::new(LowpassProcessor::default()),
106 );
107 registry.register_effect(
108 "highpass",
109 EffectAvailability::Both,
110 Box::new(HighpassProcessor::default()),
111 );
112 registry.register_effect(
113 "bandpass",
114 EffectAvailability::Both,
115 Box::new(BandpassProcessor::default()),
116 );
117 registry.register_effect(
118 "tremolo",
119 EffectAvailability::Both,
120 Box::new(TremoloProcessor::default()),
121 );
122 registry.register_effect(
123 "vibrato",
124 EffectAvailability::Both,
125 Box::new(VibratoProcessor::default()),
126 );
127 registry.register_effect(
128 "mono",
129 EffectAvailability::Both,
130 Box::new(MonoizerProcessor::default()),
131 );
132 registry.register_effect(
133 "monoizer",
134 EffectAvailability::Both,
135 Box::new(MonoizerProcessor::default()),
136 );
137 registry.register_effect(
138 "stereo",
139 EffectAvailability::Both,
140 Box::new(StereoProcessor::default()),
141 );
142 registry.register_effect(
143 "freeze",
144 EffectAvailability::Both,
145 Box::new(FreezeProcessor::default()),
146 );
147 registry.register_effect(
148 "distortion",
149 EffectAvailability::Both,
150 Box::new(DistortionProcessor::default()),
151 );
152 registry.register_effect(
153 "dist",
154 EffectAvailability::Both,
155 Box::new(DistortionProcessor::default()),
156 );
157 registry.register_effect(
158 "lfo",
159 EffectAvailability::Both,
160 Box::new(LfoProcessor::default()),
161 );
162
163 registry.register_effect(
165 "reverse",
166 EffectAvailability::TriggerOnly,
167 Box::new(ReverseProcessor::default()),
168 );
169 registry.register_effect(
170 "speed",
171 EffectAvailability::TriggerOnly,
172 Box::new(SpeedProcessor::default()),
173 );
174 registry.register_effect(
175 "slice",
176 EffectAvailability::TriggerOnly,
177 Box::new(SliceProcessor::default()),
178 );
179 registry.register_effect(
180 "stretch",
181 EffectAvailability::TriggerOnly,
182 Box::new(StretchProcessor::default()),
183 );
184 registry.register_effect(
185 "roll",
186 EffectAvailability::TriggerOnly,
187 Box::new(RollProcessor::default()),
188 );
189
190 registry.register_effect(
192 "dist",
193 EffectAvailability::Both,
194 Box::new(DistortionProcessor::default()),
195 );
196 registry.register_effect(
197 "comp",
198 EffectAvailability::Both,
199 Box::new(CompressorProcessor::default()),
200 );
201 registry.register_effect(
202 "lpf",
203 EffectAvailability::Both,
204 Box::new(LowpassProcessor::default()),
205 );
206 registry.register_effect(
207 "hpf",
208 EffectAvailability::Both,
209 Box::new(HighpassProcessor::default()),
210 );
211 registry.register_effect(
212 "bpf",
213 EffectAvailability::Both,
214 Box::new(BandpassProcessor::default()),
215 );
216
217 registry
220 }
221
222 pub fn register_effect(
224 &mut self,
225 name: &'static str,
226 availability: EffectAvailability,
227 processor: Box<dyn CloneableEffect>,
228 ) {
229 self.effects.insert(name, (availability, processor));
230 }
231
232 pub fn get_effect(&self, name: &str, synth_context: bool) -> Option<Box<dyn CloneableEffect>> {
234 self.effects
235 .get(name)
236 .and_then(|(availability, processor)| {
237 match (availability, synth_context) {
238 (EffectAvailability::SynthOnly, true) | (EffectAvailability::Both, true) => {
240 Some(processor.clone_box())
241 }
242 (EffectAvailability::TriggerOnly, false)
244 | (EffectAvailability::Both, false) => Some(processor.clone_box()),
245 _ => None, }
247 })
248 }
249
250 pub fn is_effect_available(&self, name: &str, synth_context: bool) -> bool {
252 self.effects.get(name).map_or(false, |(availability, _)| {
253 match (availability, synth_context) {
254 (EffectAvailability::SynthOnly, true)
255 | (EffectAvailability::Both, true)
256 | (EffectAvailability::TriggerOnly, false)
257 | (EffectAvailability::Both, false) => true,
258 _ => false,
259 }
260 })
261 }
262
263 pub fn list_available_effects(&self, synth_context: bool) -> Vec<&'static str> {
265 self.effects
266 .iter()
267 .filter_map(
268 |(&name, (availability, _))| match (availability, synth_context) {
269 (EffectAvailability::SynthOnly, true)
270 | (EffectAvailability::Both, true)
271 | (EffectAvailability::TriggerOnly, false)
272 | (EffectAvailability::Both, false) => Some(name),
273 _ => None,
274 },
275 )
276 .collect()
277 }
278}
279
280pub trait CloneableEffect: EffectProcessor {
284 fn clone_box(&self) -> Box<dyn CloneableEffect>;
285}
286
287impl<T> CloneableEffect for T
288where
289 T: EffectProcessor + Clone + 'static,
290{
291 fn clone_box(&self) -> Box<dyn CloneableEffect> {
292 Box::new(self.clone())
293 }
294}
295
296impl dyn EffectProcessor {
297 pub fn get_parameters_description(&self) -> HashMap<&'static str, String> {
299 let mut params = HashMap::new();
300 match self.name() {
301 "Chorus" => {
302 params.insert("depth", "Modulation depth (0.0 to 1.0)".to_string());
303 params.insert("rate", "Modulation rate (0.1 to 10.0 Hz)".to_string());
304 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
305 }
306 "Flanger" => {
307 params.insert("depth", "Modulation depth (0.0 to 1.0)".to_string());
308 params.insert("rate", "Modulation rate (0.1 to 10.0 Hz)".to_string());
309 params.insert("feedback", "Feedback amount (0.0 to 0.95)".to_string());
310 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
311 }
312 "Phaser" => {
313 params.insert("stages", "Number of allpass stages (2 to 12)".to_string());
314 params.insert("rate", "Modulation rate (0.1 to 10.0 Hz)".to_string());
315 params.insert("depth", "Modulation depth (0.0 to 1.0)".to_string());
316 params.insert("feedback", "Feedback amount (0.0 to 0.95)".to_string());
317 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
318 }
319 "Compressor" => {
320 params.insert(
321 "threshold",
322 "Threshold level in dB (-60.0 to 0.0)".to_string(),
323 );
324 params.insert("ratio", "Compression ratio (1.0 to 20.0)".to_string());
325 params.insert(
326 "attack",
327 "Attack time in seconds (0.001 to 1.0)".to_string(),
328 );
329 params.insert(
330 "release",
331 "Release time in seconds (0.001 to 2.0)".to_string(),
332 );
333 }
334 "Drive" => {
335 params.insert("amount", "Drive amount (0.0 to 1.0)".to_string());
336 params.insert("tone", "Tone control (0.0 to 1.0)".to_string());
337 params.insert(
338 "color",
339 "Color/timbre control (0.0 bright to 1.0 dark)".to_string(),
340 );
341 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
342 }
343 "Distortion" => {
344 params.insert("amount", "Distortion amount (0.0 to 1.0)".to_string());
345 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
346 }
347 "Bitcrush" => {
348 params.insert("depth", "Bit depth (1..16)".to_string());
349 params.insert(
350 "sample_rate",
351 "Target sample rate for downsampling (Hz)".to_string(),
352 );
353 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
354 }
355 "Lowpass" => {
356 params.insert("cutoff", "Cutoff frequency (20.0 to 20000.0)".to_string());
357 params.insert("resonance", "Resonance/Q (0.0 to 1.0)".to_string());
358 }
359 "Highpass" => {
360 params.insert("cutoff", "Cutoff frequency (20.0 to 20000.0)".to_string());
361 params.insert("resonance", "Resonance/Q (0.0 to 1.0)".to_string());
362 }
363 "Bandpass" => {
364 params.insert("cutoff", "Center frequency (20.0 to 20000.0)".to_string());
365 params.insert("resonance", "Bandwidth/Resonance (0.0 to 1.0)".to_string());
366 }
367 "Tremolo" => {
368 params.insert("rate", "LFO rate (0.1 to 20.0 Hz)".to_string());
369 params.insert("depth", "Depth (0.0 to 1.0)".to_string());
370 params.insert("sync", "Sync to tempo (true/false)".to_string());
371 }
372 "Vibrato" => {
373 params.insert("rate", "LFO rate (0.1 to 10.0 Hz)".to_string());
374 params.insert(
375 "depth",
376 "Delay depth in seconds (small, e.g. 0.003)".to_string(),
377 );
378 params.insert("sync", "Sync to tempo (true/false)".to_string());
379 }
380 "Monoizer" => {
381 params.insert("enabled", "Enable monoizer (true/false)".to_string());
382 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
383 }
384 "Stereo" => {
385 params.insert("width", "Stereo width (0.0 to 2.0)".to_string());
386 }
387 "Freeze" => {
388 params.insert("enabled", "Enable freeze (true/false)".to_string());
389 params.insert(
390 "fade",
391 "Fade-in amount when freezing (0.0 to 1.0)".to_string(),
392 );
393 params.insert("hold", "Hold time in seconds (0.05 to 5.0)".to_string());
394 }
395 "Slice" => {
396 params.insert("segments", "Number of segments (1 to 16)".to_string());
397 params.insert("mode", "Mode: sequential | random".to_string());
398 params.insert(
399 "crossfade",
400 "Crossfade between slices (0.0 to 1.0)".to_string(),
401 );
402 }
403 "Stretch" => {
404 params.insert("factor", "Time stretch factor (0.25 to 4.0)".to_string());
405 params.insert(
406 "pitch",
407 "Pitch shift in semitones (-48.0 to 48.0)".to_string(),
408 );
409 params.insert("formant", "Preserve formants (true/false)".to_string());
410 }
411 "Roll" => {
412 params.insert("duration_ms", "Roll segment duration in ms".to_string());
413 params.insert("sync", "Sync to tempo (true/false)".to_string());
414 params.insert("repeats", "Number of repeats (1 to 16)".to_string());
415 params.insert("fade", "Crossfade between repeats (0.0 to 1.0)".to_string());
416 }
417 "Reverb" => {
418 params.insert("size", "Room size (0.0 to 1.0)".to_string());
419 params.insert(
420 "decay",
421 "Decay/time multiplier (0.0 short to 2.0 long)".to_string(),
422 );
423 params.insert("damping", "High frequency damping (0.0 to 1.0)".to_string());
424 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
425 }
426 "Delay" => {
427 params.insert(
428 "time",
429 "Delay time in milliseconds (1.0 to 2000.0)".to_string(),
430 );
431 params.insert("feedback", "Feedback amount (0.0 to 0.95)".to_string());
432 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
433 }
434 "Reverse" => {
435 params.insert(
436 "enabled",
437 "Enable/disable reverse effect (true/false)".to_string(),
438 );
439 }
440 "Speed" => {
441 params.insert(
442 "speed",
443 "Playback speed multiplier (0.1 to 4.0)".to_string(),
444 );
445 }
446 _ => {}
447 }
448 params
449 }
450}
451
452#[cfg(test)]
455#[path = "test_registry.rs"]
456mod tests;