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