1use super::{Plugin, PluginError, PluginResult, PluginType};
2use crate::audio::effects::{AudioEffect, EffectConfig};
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::sync::{Arc, Mutex};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct EffectPluginConfig {
9 pub parameters: HashMap<String, f32>,
10 pub enabled: bool,
11 pub bypass: bool,
12 pub wet_mix: f32,
13 pub dry_mix: f32,
14}
15
16impl Default for EffectPluginConfig {
17 fn default() -> Self {
18 Self {
19 parameters: HashMap::new(),
20 enabled: true,
21 bypass: false,
22 wet_mix: 1.0,
23 dry_mix: 0.0,
24 }
25 }
26}
27
28pub trait EffectPlugin: Plugin {
29 fn process_audio(
30 &self,
31 input: &[f32],
32 output: &mut [f32],
33 config: &EffectPluginConfig,
34 ) -> PluginResult<()>;
35 fn get_parameter_info(&self) -> Vec<ParameterInfo>;
36 fn set_parameter(&mut self, name: &str, value: f32) -> PluginResult<()>;
37 fn get_parameter(&self, name: &str) -> PluginResult<f32>;
38 fn reset(&mut self) -> PluginResult<()>;
39 fn get_latency(&self) -> u32;
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ParameterInfo {
44 pub name: String,
45 pub display_name: String,
46 pub min_value: f32,
47 pub max_value: f32,
48 pub default_value: f32,
49 pub step_size: f32,
50 pub unit: String,
51 pub description: String,
52 pub parameter_type: ParameterType,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub enum ParameterType {
57 Float,
58 Integer,
59 Boolean,
60 Choice(Vec<String>),
61}
62
63pub struct EffectPluginManager {
64 effects: HashMap<String, Arc<dyn EffectPlugin>>,
65 presets: HashMap<String, EffectPluginConfig>,
66}
67
68impl EffectPluginManager {
69 pub fn new() -> Self {
70 Self {
71 effects: HashMap::new(),
72 presets: HashMap::new(),
73 }
74 }
75
76 pub fn register_effect(&mut self, name: String, effect: Arc<dyn EffectPlugin>) {
77 self.effects.insert(name, effect);
78 }
79
80 pub fn unregister_effect(&mut self, name: &str) -> bool {
81 self.effects.remove(name).is_some()
82 }
83
84 pub fn list_effects(&self) -> Vec<String> {
85 self.effects.keys().cloned().collect()
86 }
87
88 pub fn get_effect(&self, name: &str) -> Option<Arc<dyn EffectPlugin>> {
89 self.effects.get(name).cloned()
90 }
91
92 pub fn process_with_effect(
93 &self,
94 effect_name: &str,
95 input: &[f32],
96 output: &mut [f32],
97 config: &EffectPluginConfig,
98 ) -> PluginResult<()> {
99 let effect = self
100 .effects
101 .get(effect_name)
102 .ok_or_else(|| PluginError::NotFound(effect_name.to_string()))?;
103
104 if !config.enabled || config.bypass {
105 output.copy_from_slice(input);
106 return Ok(());
107 }
108
109 effect.process_audio(input, output, config)
110 }
111
112 pub fn create_effect_chain(&self, effect_names: &[String]) -> EffectChain {
113 let mut effects = Vec::new();
114 for name in effect_names {
115 if let Some(effect) = self.effects.get(name) {
116 effects.push((name.clone(), effect.clone()));
117 }
118 }
119 EffectChain::new(effects)
120 }
121
122 pub fn save_preset(&mut self, name: String, config: EffectPluginConfig) {
123 self.presets.insert(name, config);
124 }
125
126 pub fn load_preset(&self, name: &str) -> Option<&EffectPluginConfig> {
127 self.presets.get(name)
128 }
129
130 pub fn delete_preset(&mut self, name: &str) -> bool {
131 self.presets.remove(name).is_some()
132 }
133
134 pub fn list_presets(&self) -> Vec<String> {
135 self.presets.keys().cloned().collect()
136 }
137}
138
139impl Default for EffectPluginManager {
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145pub struct EffectChain {
146 effects: Vec<(String, Arc<dyn EffectPlugin>)>,
147 buffer: Vec<f32>,
148}
149
150impl EffectChain {
151 pub fn new(effects: Vec<(String, Arc<dyn EffectPlugin>)>) -> Self {
152 Self {
153 effects,
154 buffer: Vec::new(),
155 }
156 }
157
158 pub fn process(
159 &mut self,
160 input: &[f32],
161 output: &mut [f32],
162 configs: &HashMap<String, EffectPluginConfig>,
163 ) -> PluginResult<()> {
164 if self.effects.is_empty() {
165 output.copy_from_slice(input);
166 return Ok(());
167 }
168
169 if self.buffer.len() < input.len() {
171 self.buffer.resize(input.len(), 0.0);
172 }
173
174 let default_config = EffectPluginConfig::default();
175
176 if let Some((name, effect)) = self.effects.first() {
178 let config = configs.get(name).unwrap_or(&default_config);
179 effect.process_audio(input, &mut self.buffer[..input.len()], config)?;
180 }
181
182 for i in 1..self.effects.len() {
184 let (name, effect) = &self.effects[i];
185 let config = configs.get(name).unwrap_or(&default_config);
186
187 if i == self.effects.len() - 1 {
188 effect.process_audio(&self.buffer[..input.len()], output, config)?;
190 } else {
191 let mut temp_buffer = vec![0.0; input.len()];
193 effect.process_audio(&self.buffer[..input.len()], &mut temp_buffer, config)?;
194 self.buffer[..input.len()].copy_from_slice(&temp_buffer);
195 }
196 }
197
198 Ok(())
199 }
200
201 pub fn get_total_latency(&self) -> u32 {
202 self.effects
203 .iter()
204 .map(|(_, effect)| effect.get_latency())
205 .sum()
206 }
207
208 pub fn reset_all(&mut self) -> PluginResult<()> {
209 for (_, effect) in &self.effects {
210 }
213 Ok(())
214 }
215}
216
217struct CombFilter {
220 buffer: Vec<f32>,
221 buffer_index: usize,
222 feedback: f32,
223 filter_state: f32,
224 damping: f32,
225}
226
227impl CombFilter {
228 fn new(size: usize) -> Self {
229 Self {
230 buffer: vec![0.0; size],
231 buffer_index: 0,
232 feedback: 0.0,
233 filter_state: 0.0,
234 damping: 0.0,
235 }
236 }
237
238 fn process(&mut self, input: f32) -> f32 {
239 let output = self.buffer[self.buffer_index];
240
241 self.filter_state = output * (1.0 - self.damping) + self.filter_state * self.damping;
243
244 self.buffer[self.buffer_index] = input + self.filter_state * self.feedback;
245 self.buffer_index = (self.buffer_index + 1) % self.buffer.len();
246
247 output
248 }
249
250 fn set_damping(&mut self, damping: f32) {
251 self.damping = damping;
252 }
253
254 fn set_feedback(&mut self, feedback: f32) {
255 self.feedback = feedback;
256 }
257
258 fn clear(&mut self) {
259 self.buffer.fill(0.0);
260 self.filter_state = 0.0;
261 self.buffer_index = 0;
262 }
263}
264
265struct AllpassFilter {
267 buffer: Vec<f32>,
268 buffer_index: usize,
269}
270
271impl AllpassFilter {
272 fn new(size: usize) -> Self {
273 Self {
274 buffer: vec![0.0; size],
275 buffer_index: 0,
276 }
277 }
278
279 fn process(&mut self, input: f32) -> f32 {
280 let buffered = self.buffer[self.buffer_index];
281 let output = -input + buffered;
282
283 self.buffer[self.buffer_index] = input + buffered * 0.5;
284 self.buffer_index = (self.buffer_index + 1) % self.buffer.len();
285
286 output
287 }
288
289 fn clear(&mut self) {
290 self.buffer.fill(0.0);
291 self.buffer_index = 0;
292 }
293}
294
295pub struct ReverbEffectPlugin {
296 name: String,
297 version: String,
298 room_size: f32,
299 damping: f32,
300 wet_level: f32,
301 dry_level: f32,
302 comb_filters: Mutex<Vec<CombFilter>>,
304 allpass_filters: Mutex<Vec<AllpassFilter>>,
305}
306
307impl Default for ReverbEffectPlugin {
308 fn default() -> Self {
309 Self::new()
310 }
311}
312
313impl ReverbEffectPlugin {
314 pub fn new() -> Self {
315 const COMB_DELAYS: [usize; 8] = [1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617];
317 const ALLPASS_DELAYS: [usize; 4] = [556, 441, 341, 225];
319
320 let comb_filters: Vec<CombFilter> = COMB_DELAYS
321 .iter()
322 .map(|&size| CombFilter::new(size))
323 .collect();
324
325 let allpass_filters: Vec<AllpassFilter> = ALLPASS_DELAYS
326 .iter()
327 .map(|&size| AllpassFilter::new(size))
328 .collect();
329
330 Self {
331 name: "builtin-reverb".to_string(),
332 version: "1.0.0".to_string(),
333 room_size: 0.5,
334 damping: 0.5,
335 wet_level: 0.3,
336 dry_level: 0.7,
337 comb_filters: Mutex::new(comb_filters),
338 allpass_filters: Mutex::new(allpass_filters),
339 }
340 }
341
342 fn update_filters(&self) {
343 let feedback = 0.28 + self.room_size * 0.7;
345
346 let mut comb_filters = self
347 .comb_filters
348 .lock()
349 .expect("Reverb comb_filters mutex poisoned - unrecoverable error");
350 for comb in comb_filters.iter_mut() {
351 comb.set_feedback(feedback);
352 comb.set_damping(self.damping);
353 }
354 }
355}
356
357impl Plugin for ReverbEffectPlugin {
358 fn name(&self) -> &str {
359 &self.name
360 }
361
362 fn version(&self) -> &str {
363 &self.version
364 }
365
366 fn description(&self) -> &str {
367 "Built-in reverb effect plugin"
368 }
369
370 fn plugin_type(&self) -> PluginType {
371 PluginType::Effect
372 }
373
374 fn initialize(&mut self, config: &serde_json::Value) -> PluginResult<()> {
375 if let Some(room_size) = config.get("room_size").and_then(|v| v.as_f64()) {
376 self.room_size = room_size as f32;
377 }
378 if let Some(damping) = config.get("damping").and_then(|v| v.as_f64()) {
379 self.damping = damping as f32;
380 }
381 if let Some(wet_level) = config.get("wet_level").and_then(|v| v.as_f64()) {
382 self.wet_level = wet_level as f32;
383 }
384 if let Some(dry_level) = config.get("dry_level").and_then(|v| v.as_f64()) {
385 self.dry_level = dry_level as f32;
386 }
387 Ok(())
388 }
389
390 fn cleanup(&mut self) -> PluginResult<()> {
391 Ok(())
392 }
393
394 fn get_capabilities(&self) -> Vec<String> {
395 vec![
396 "process_audio".to_string(),
397 "set_parameter".to_string(),
398 "get_parameter".to_string(),
399 "reset".to_string(),
400 ]
401 }
402
403 fn execute(&self, command: &str, args: &serde_json::Value) -> PluginResult<serde_json::Value> {
404 match command {
405 "get_parameters" => Ok(serde_json::json!({
406 "room_size": self.room_size,
407 "damping": self.damping,
408 "wet_level": self.wet_level,
409 "dry_level": self.dry_level
410 })),
411 "set_parameter" => {
412 let param_name = args.get("name").and_then(|v| v.as_str()).ok_or_else(|| {
413 PluginError::ExecutionFailed("Missing parameter name".to_string())
414 })?;
415 let value = args.get("value").and_then(|v| v.as_f64()).ok_or_else(|| {
416 PluginError::ExecutionFailed("Missing parameter value".to_string())
417 })? as f32;
418
419 match param_name {
420 "room_size" => Ok(serde_json::json!({"old_value": self.room_size})),
421 "damping" => Ok(serde_json::json!({"old_value": self.damping})),
422 "wet_level" => Ok(serde_json::json!({"old_value": self.wet_level})),
423 "dry_level" => Ok(serde_json::json!({"old_value": self.dry_level})),
424 _ => Err(PluginError::ExecutionFailed(format!(
425 "Unknown parameter: {}",
426 param_name
427 ))),
428 }
429 }
430 _ => Err(PluginError::ExecutionFailed(format!(
431 "Unknown command: {}",
432 command
433 ))),
434 }
435 }
436}
437
438impl EffectPlugin for ReverbEffectPlugin {
439 fn process_audio(
440 &self,
441 input: &[f32],
442 output: &mut [f32],
443 config: &EffectPluginConfig,
444 ) -> PluginResult<()> {
445 self.update_filters();
447
448 let mut comb_filters = self
449 .comb_filters
450 .lock()
451 .expect("Reverb comb_filters mutex poisoned - unrecoverable error");
452 let mut allpass_filters = self
453 .allpass_filters
454 .lock()
455 .expect("Reverb allpass_filters mutex poisoned - unrecoverable error");
456
457 for (i, &input_sample) in input.iter().enumerate() {
458 let mut comb_out = 0.0;
460 for comb in comb_filters.iter_mut() {
461 comb_out += comb.process(input_sample);
462 }
463
464 let mut allpass_out = comb_out;
466 for allpass in allpass_filters.iter_mut() {
467 allpass_out = allpass.process(allpass_out);
468 }
469
470 let wet = allpass_out * self.wet_level * config.wet_mix;
472 let dry = input_sample * self.dry_level * config.dry_mix;
473 output[i] = wet + dry;
474 }
475
476 Ok(())
477 }
478
479 fn get_parameter_info(&self) -> Vec<ParameterInfo> {
480 vec![
481 ParameterInfo {
482 name: "room_size".to_string(),
483 display_name: "Room Size".to_string(),
484 min_value: 0.0,
485 max_value: 1.0,
486 default_value: 0.5,
487 step_size: 0.01,
488 unit: "".to_string(),
489 description: "Size of the reverb room".to_string(),
490 parameter_type: ParameterType::Float,
491 },
492 ParameterInfo {
493 name: "damping".to_string(),
494 display_name: "Damping".to_string(),
495 min_value: 0.0,
496 max_value: 1.0,
497 default_value: 0.5,
498 step_size: 0.01,
499 unit: "".to_string(),
500 description: "Damping factor for high frequencies".to_string(),
501 parameter_type: ParameterType::Float,
502 },
503 ParameterInfo {
504 name: "wet_level".to_string(),
505 display_name: "Wet Level".to_string(),
506 min_value: 0.0,
507 max_value: 1.0,
508 default_value: 0.3,
509 step_size: 0.01,
510 unit: "".to_string(),
511 description: "Level of processed signal".to_string(),
512 parameter_type: ParameterType::Float,
513 },
514 ParameterInfo {
515 name: "dry_level".to_string(),
516 display_name: "Dry Level".to_string(),
517 min_value: 0.0,
518 max_value: 1.0,
519 default_value: 0.7,
520 step_size: 0.01,
521 unit: "".to_string(),
522 description: "Level of original signal".to_string(),
523 parameter_type: ParameterType::Float,
524 },
525 ]
526 }
527
528 fn set_parameter(&mut self, name: &str, value: f32) -> PluginResult<()> {
529 match name {
530 "room_size" => self.room_size = value.clamp(0.0, 1.0),
531 "damping" => self.damping = value.clamp(0.0, 1.0),
532 "wet_level" => self.wet_level = value.clamp(0.0, 1.0),
533 "dry_level" => self.dry_level = value.clamp(0.0, 1.0),
534 _ => {
535 return Err(PluginError::ExecutionFailed(format!(
536 "Unknown parameter: {}",
537 name
538 )))
539 }
540 }
541 Ok(())
542 }
543
544 fn get_parameter(&self, name: &str) -> PluginResult<f32> {
545 match name {
546 "room_size" => Ok(self.room_size),
547 "damping" => Ok(self.damping),
548 "wet_level" => Ok(self.wet_level),
549 "dry_level" => Ok(self.dry_level),
550 _ => Err(PluginError::ExecutionFailed(format!(
551 "Unknown parameter: {}",
552 name
553 ))),
554 }
555 }
556
557 fn reset(&mut self) -> PluginResult<()> {
558 self.room_size = 0.5;
560 self.damping = 0.5;
561 self.wet_level = 0.3;
562 self.dry_level = 0.7;
563
564 let mut comb_filters = self
566 .comb_filters
567 .lock()
568 .expect("Reverb comb_filters mutex poisoned - unrecoverable error");
569 for comb in comb_filters.iter_mut() {
570 comb.clear();
571 }
572
573 let mut allpass_filters = self
574 .allpass_filters
575 .lock()
576 .expect("Reverb allpass_filters mutex poisoned - unrecoverable error");
577 for allpass in allpass_filters.iter_mut() {
578 allpass.clear();
579 }
580
581 Ok(())
582 }
583
584 fn get_latency(&self) -> u32 {
585 1617 }
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593
594 #[test]
595 fn test_effect_plugin_manager() {
596 let mut manager = EffectPluginManager::new();
597 let reverb = Arc::new(ReverbEffectPlugin::new());
598
599 manager.register_effect("reverb".to_string(), reverb);
600
601 let effects = manager.list_effects();
602 assert!(effects.contains(&"reverb".to_string()));
603
604 let effect = manager.get_effect("reverb");
605 assert!(effect.is_some());
606 }
607
608 #[test]
609 fn test_reverb_plugin() {
610 let mut reverb = ReverbEffectPlugin::new();
611 assert_eq!(reverb.name(), "builtin-reverb");
612 assert_eq!(reverb.version(), "1.0.0");
613
614 let config = EffectPluginConfig::default();
615 let input = vec![1.0, 0.5, -0.5, -1.0];
616 let mut output = vec![0.0; 4];
617
618 reverb
619 .process_audio(&input, &mut output, &config)
620 .expect("Failed to process audio with reverb");
621
622 assert_ne!(input, output);
624 }
625
626 #[test]
627 fn test_parameter_setting() {
628 let mut reverb = ReverbEffectPlugin::new();
629
630 reverb
631 .set_parameter("room_size", 0.8)
632 .expect("Failed to set room_size parameter");
633 assert_eq!(
634 reverb
635 .get_parameter("room_size")
636 .expect("Failed to get room_size parameter"),
637 0.8
638 );
639
640 reverb
642 .set_parameter("room_size", 1.5)
643 .expect("Failed to set room_size parameter");
644 assert_eq!(
645 reverb
646 .get_parameter("room_size")
647 .expect("Failed to get room_size parameter"),
648 1.0
649 );
650
651 assert!(reverb.set_parameter("invalid", 0.5).is_err());
653 }
654
655 #[test]
656 fn test_effect_chain() {
657 let reverb = Arc::new(ReverbEffectPlugin::new());
658 let effects = vec![("reverb".to_string(), reverb as Arc<dyn EffectPlugin>)];
659 let mut chain = EffectChain::new(effects);
660
661 let input = vec![1.0, 0.5, -0.5, -1.0];
662 let mut output = vec![0.0; 4];
663 let configs = HashMap::new();
664
665 chain
666 .process(&input, &mut output, &configs)
667 .expect("Failed to process audio with effect chain");
668
669 assert_eq!(output.len(), input.len());
671 }
672}