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 EqProcessor, 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 "eq",
99 EffectAvailability::Both,
100 Box::new(EqProcessor::default()),
101 );
102 registry.register_effect(
103 "equalizer",
104 EffectAvailability::Both,
105 Box::new(EqProcessor::default()),
106 );
107 registry.register_effect(
108 "bitcrush",
109 EffectAvailability::Both,
110 Box::new(BitcrushProcessor::default()),
111 );
112 registry.register_effect(
113 "lowpass",
114 EffectAvailability::Both,
115 Box::new(LowpassProcessor::default()),
116 );
117 registry.register_effect(
118 "highpass",
119 EffectAvailability::Both,
120 Box::new(HighpassProcessor::default()),
121 );
122 registry.register_effect(
123 "bandpass",
124 EffectAvailability::Both,
125 Box::new(BandpassProcessor::default()),
126 );
127 registry.register_effect(
128 "tremolo",
129 EffectAvailability::Both,
130 Box::new(TremoloProcessor::default()),
131 );
132 registry.register_effect(
133 "vibrato",
134 EffectAvailability::Both,
135 Box::new(VibratoProcessor::default()),
136 );
137 registry.register_effect(
138 "mono",
139 EffectAvailability::Both,
140 Box::new(MonoizerProcessor::default()),
141 );
142 registry.register_effect(
143 "monoizer",
144 EffectAvailability::Both,
145 Box::new(MonoizerProcessor::default()),
146 );
147 registry.register_effect(
148 "stereo",
149 EffectAvailability::Both,
150 Box::new(StereoProcessor::default()),
151 );
152 registry.register_effect(
153 "freeze",
154 EffectAvailability::Both,
155 Box::new(FreezeProcessor::default()),
156 );
157 registry.register_effect(
158 "distortion",
159 EffectAvailability::Both,
160 Box::new(DistortionProcessor::default()),
161 );
162 registry.register_effect(
163 "dist",
164 EffectAvailability::Both,
165 Box::new(DistortionProcessor::default()),
166 );
167 registry.register_effect(
168 "lfo",
169 EffectAvailability::Both,
170 Box::new(LfoProcessor::default()),
171 );
172
173 registry.register_effect(
175 "reverse",
176 EffectAvailability::TriggerOnly,
177 Box::new(ReverseProcessor::default()),
178 );
179 registry.register_effect(
180 "speed",
181 EffectAvailability::TriggerOnly,
182 Box::new(SpeedProcessor::default()),
183 );
184 registry.register_effect(
185 "slice",
186 EffectAvailability::TriggerOnly,
187 Box::new(SliceProcessor::default()),
188 );
189 registry.register_effect(
190 "stretch",
191 EffectAvailability::TriggerOnly,
192 Box::new(StretchProcessor::default()),
193 );
194 registry.register_effect(
195 "roll",
196 EffectAvailability::TriggerOnly,
197 Box::new(RollProcessor::default()),
198 );
199
200 registry.register_effect(
202 "dist",
203 EffectAvailability::Both,
204 Box::new(DistortionProcessor::default()),
205 );
206 registry.register_effect(
207 "comp",
208 EffectAvailability::Both,
209 Box::new(CompressorProcessor::default()),
210 );
211 registry.register_effect(
212 "lpf",
213 EffectAvailability::Both,
214 Box::new(LowpassProcessor::default()),
215 );
216 registry.register_effect(
217 "hpf",
218 EffectAvailability::Both,
219 Box::new(HighpassProcessor::default()),
220 );
221 registry.register_effect(
222 "bpf",
223 EffectAvailability::Both,
224 Box::new(BandpassProcessor::default()),
225 );
226
227 registry
230 }
231
232 pub fn register_effect(
234 &mut self,
235 name: &'static str,
236 availability: EffectAvailability,
237 processor: Box<dyn CloneableEffect>,
238 ) {
239 self.effects.insert(name, (availability, processor));
240 }
241
242 pub fn get_effect(&self, name: &str, synth_context: bool) -> Option<Box<dyn CloneableEffect>> {
244 self.effects
245 .get(name)
246 .and_then(|(availability, processor)| {
247 match (availability, synth_context) {
248 (EffectAvailability::SynthOnly, true) | (EffectAvailability::Both, true) => {
250 Some(processor.clone_box())
251 }
252 (EffectAvailability::TriggerOnly, false)
254 | (EffectAvailability::Both, false) => Some(processor.clone_box()),
255 _ => None, }
257 })
258 }
259
260 pub fn is_effect_available(&self, name: &str, synth_context: bool) -> bool {
262 self.effects.get(name).map_or(false, |(availability, _)| {
263 match (availability, synth_context) {
264 (EffectAvailability::SynthOnly, true)
265 | (EffectAvailability::Both, true)
266 | (EffectAvailability::TriggerOnly, false)
267 | (EffectAvailability::Both, false) => true,
268 _ => false,
269 }
270 })
271 }
272
273 pub fn list_available_effects(&self, synth_context: bool) -> Vec<&'static str> {
275 self.effects
276 .iter()
277 .filter_map(
278 |(&name, (availability, _))| match (availability, synth_context) {
279 (EffectAvailability::SynthOnly, true)
280 | (EffectAvailability::Both, true)
281 | (EffectAvailability::TriggerOnly, false)
282 | (EffectAvailability::Both, false) => Some(name),
283 _ => None,
284 },
285 )
286 .collect()
287 }
288}
289
290pub trait CloneableEffect: EffectProcessor {
294 fn clone_box(&self) -> Box<dyn CloneableEffect>;
295}
296
297impl<T> CloneableEffect for T
298where
299 T: EffectProcessor + Clone + 'static,
300{
301 fn clone_box(&self) -> Box<dyn CloneableEffect> {
302 Box::new(self.clone())
303 }
304}
305
306impl dyn EffectProcessor {
307 pub fn get_parameters_description(&self) -> HashMap<&'static str, String> {
309 let mut params = HashMap::new();
310 match self.name() {
311 "Chorus" => {
312 params.insert("depth", "Modulation depth (0.0 to 1.0)".to_string());
313 params.insert("rate", "Modulation rate (0.1 to 10.0 Hz)".to_string());
314 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
315 }
316 "Flanger" => {
317 params.insert("depth", "Modulation depth (0.0 to 1.0)".to_string());
318 params.insert("rate", "Modulation rate (0.1 to 10.0 Hz)".to_string());
319 params.insert("feedback", "Feedback amount (0.0 to 0.95)".to_string());
320 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
321 }
322 "Phaser" => {
323 params.insert("stages", "Number of allpass stages (2 to 12)".to_string());
324 params.insert("rate", "Modulation rate (0.1 to 10.0 Hz)".to_string());
325 params.insert("depth", "Modulation depth (0.0 to 1.0)".to_string());
326 params.insert("feedback", "Feedback amount (0.0 to 0.95)".to_string());
327 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
328 }
329 "Compressor" => {
330 params.insert(
331 "threshold",
332 "Threshold level in dB (-60.0 to 0.0)".to_string(),
333 );
334 params.insert("ratio", "Compression ratio (1.0 to 20.0)".to_string());
335 params.insert(
336 "attack",
337 "Attack time in seconds (0.001 to 1.0)".to_string(),
338 );
339 params.insert(
340 "release",
341 "Release time in seconds (0.001 to 2.0)".to_string(),
342 );
343 }
344 "Drive" => {
345 params.insert("amount", "Drive amount (0.0 to 1.0)".to_string());
346 params.insert("tone", "Tone control (0.0 to 1.0)".to_string());
347 params.insert(
348 "color",
349 "Color/timbre control (0.0 bright to 1.0 dark)".to_string(),
350 );
351 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
352 }
353 "Distortion" => {
354 params.insert("amount", "Distortion amount (0.0 to 1.0)".to_string());
355 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
356 }
357 "Bitcrush" => {
358 params.insert("depth", "Bit depth (1..16)".to_string());
359 params.insert(
360 "sample_rate",
361 "Target sample rate for downsampling (Hz)".to_string(),
362 );
363 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
364 }
365 "Lowpass" => {
366 params.insert("cutoff", "Cutoff frequency (20.0 to 20000.0)".to_string());
367 params.insert("resonance", "Resonance/Q (0.0 to 1.0)".to_string());
368 }
369 "Highpass" => {
370 params.insert("cutoff", "Cutoff frequency (20.0 to 20000.0)".to_string());
371 params.insert("resonance", "Resonance/Q (0.0 to 1.0)".to_string());
372 }
373 "Bandpass" => {
374 params.insert("cutoff", "Center frequency (20.0 to 20000.0)".to_string());
375 params.insert("resonance", "Bandwidth/Resonance (0.0 to 1.0)".to_string());
376 }
377 "Tremolo" => {
378 params.insert("rate", "LFO rate (0.1 to 20.0 Hz)".to_string());
379 params.insert("depth", "Depth (0.0 to 1.0)".to_string());
380 params.insert("sync", "Sync to tempo (true/false)".to_string());
381 }
382 "Vibrato" => {
383 params.insert("rate", "LFO rate (0.1 to 10.0 Hz)".to_string());
384 params.insert(
385 "depth",
386 "Delay depth in seconds (small, e.g. 0.003)".to_string(),
387 );
388 params.insert("sync", "Sync to tempo (true/false)".to_string());
389 }
390 "Monoizer" => {
391 params.insert("enabled", "Enable monoizer (true/false)".to_string());
392 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
393 }
394 "Stereo" => {
395 params.insert("width", "Stereo width (0.0 to 2.0)".to_string());
396 }
397 "Freeze" => {
398 params.insert("enabled", "Enable freeze (true/false)".to_string());
399 params.insert(
400 "fade",
401 "Fade-in amount when freezing (0.0 to 1.0)".to_string(),
402 );
403 params.insert("hold", "Hold time in seconds (0.05 to 5.0)".to_string());
404 }
405 "Slice" => {
406 params.insert("segments", "Number of segments (1 to 16)".to_string());
407 params.insert("mode", "Mode: sequential | random".to_string());
408 params.insert(
409 "crossfade",
410 "Crossfade between slices (0.0 to 1.0)".to_string(),
411 );
412 }
413 "Stretch" => {
414 params.insert("factor", "Time stretch factor (0.25 to 4.0)".to_string());
415 params.insert(
416 "pitch",
417 "Pitch shift in semitones (-48.0 to 48.0)".to_string(),
418 );
419 params.insert("formant", "Preserve formants (true/false)".to_string());
420 }
421 "Roll" => {
422 params.insert("duration_ms", "Roll segment duration in ms".to_string());
423 params.insert("sync", "Sync to tempo (true/false)".to_string());
424 params.insert("repeats", "Number of repeats (1 to 16)".to_string());
425 params.insert("fade", "Crossfade between repeats (0.0 to 1.0)".to_string());
426 }
427 "Reverb" => {
428 params.insert("size", "Room size (0.0 to 1.0)".to_string());
429 params.insert(
430 "decay",
431 "Decay/time multiplier (0.0 short to 2.0 long)".to_string(),
432 );
433 params.insert("damping", "High frequency damping (0.0 to 1.0)".to_string());
434 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
435 }
436 "Delay" => {
437 params.insert(
438 "time",
439 "Delay time in milliseconds (1.0 to 2000.0)".to_string(),
440 );
441 params.insert("feedback", "Feedback amount (0.0 to 0.95)".to_string());
442 params.insert("mix", "Wet/dry mix (0.0 to 1.0)".to_string());
443 }
444 "Reverse" => {
445 params.insert(
446 "enabled",
447 "Enable/disable reverse effect (true/false)".to_string(),
448 );
449 }
450 "Speed" => {
451 params.insert(
452 "speed",
453 "Playback speed multiplier (0.1 to 4.0)".to_string(),
454 );
455 }
456 _ => {}
457 }
458 params
459 }
460}
461
462#[cfg(test)]
465#[path = "test_registry.rs"]
466mod tests;