1use serde::{Deserialize, Serialize};
4
5use crate::dsp::effects::convolution_reverb::ImpulseResponseSpec;
6
7pub mod convolution_reverb;
8pub mod basic_reverb;
9pub mod distortion;
10pub mod high_pass;
11pub mod low_pass;
12pub mod compressor;
13pub mod limiter;
14mod biquad;
15
16pub use basic_reverb::{BasicReverbEffect, BasicReverbSettings};
17pub use convolution_reverb::{ConvolutionReverbEffect, ConvolutionReverbSettings};
18pub use distortion::{DistortionEffect, DistortionSettings};
19pub use high_pass::{HighPassFilterEffect, HighPassFilterSettings};
20pub use low_pass::{LowPassFilterEffect, LowPassFilterSettings};
21pub use compressor::{CompressorEffect, CompressorSettings};
22pub use limiter::{LimiterEffect, LimiterSettings};
23
24#[derive(Debug, Clone)]
26pub struct EffectContext {
27 pub sample_rate: u32,
28 pub channels: usize,
29 pub container_path: Option<String>,
30 pub impulse_response_spec: Option<ImpulseResponseSpec>,
31 pub impulse_response_tail_db: f32,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub enum AudioEffect {
37 #[serde(rename = "BasicReverbSettings")]
38 BasicReverb(BasicReverbEffect),
39 #[serde(rename = "ConvolutionReverbSettings")]
40 ConvolutionReverb(ConvolutionReverbEffect),
41 #[serde(rename = "LowPassFilterSettings")]
42 LowPassFilter(LowPassFilterEffect),
43 #[serde(rename = "HighPassFilterSettings")]
44 HighPassFilter(HighPassFilterEffect),
45 #[serde(rename = "DistortionSettings")]
46 Distortion(DistortionEffect),
47 #[serde(rename = "CompressorSettings")]
48 Compressor(CompressorEffect),
49 #[serde(rename = "LimiterSettings")]
50 Limiter(LimiterEffect),
51}
52
53impl AudioEffect {
54 pub fn process(
64 &mut self,
65 samples: &[f32],
66 context: &EffectContext,
67 drain: bool,
68 ) -> Vec<f32> {
69 match self {
70 AudioEffect::BasicReverb(effect) => effect.process(samples, context, drain),
71 AudioEffect::ConvolutionReverb(effect) => effect.process(samples, context, drain),
72 AudioEffect::LowPassFilter(effect) => effect.process(samples, context, drain),
73 AudioEffect::HighPassFilter(effect) => effect.process(samples, context, drain),
74 AudioEffect::Distortion(effect) => effect.process(samples, context, drain),
75 AudioEffect::Compressor(effect) => effect.process(samples, context, drain),
76 AudioEffect::Limiter(effect) => effect.process(samples, context, drain),
77 }
78 }
79
80 pub fn reset_state(&mut self) {
82 match self {
83 AudioEffect::BasicReverb(effect) => effect.reset_state(),
84 AudioEffect::ConvolutionReverb(effect) => effect.reset_state(),
85 AudioEffect::LowPassFilter(effect) => effect.reset_state(),
86 AudioEffect::HighPassFilter(effect) => effect.reset_state(),
87 AudioEffect::Distortion(effect) => effect.reset_state(),
88 AudioEffect::Compressor(effect) => effect.reset_state(),
89 AudioEffect::Limiter(effect) => effect.reset_state(),
90 }
91 }
92
93 pub fn as_convolution_reverb_mut(&mut self) -> Option<&mut ConvolutionReverbEffect> {
95 match self {
96 AudioEffect::ConvolutionReverb(effect) => Some(effect),
97 _ => None,
98 }
99 }
100
101 pub fn as_convolution_reverb(&self) -> Option<&ConvolutionReverbEffect> {
103 match self {
104 AudioEffect::ConvolutionReverb(effect) => Some(effect),
105 _ => None,
106 }
107 }
108
109 pub fn as_basic_reverb_mut(&mut self) -> Option<&mut BasicReverbEffect> {
111 match self {
112 AudioEffect::BasicReverb(effect) => Some(effect),
113 _ => None,
114 }
115 }
116
117 pub fn as_basic_reverb(&self) -> Option<&BasicReverbEffect> {
119 match self {
120 AudioEffect::BasicReverb(effect) => Some(effect),
121 _ => None,
122 }
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn audio_effect_serde_roundtrip_variants() {
132 let effects = vec![
133 AudioEffect::BasicReverb(BasicReverbEffect::default()),
134 AudioEffect::ConvolutionReverb(ConvolutionReverbEffect::default()),
135 AudioEffect::LowPassFilter(LowPassFilterEffect::default()),
136 AudioEffect::HighPassFilter(HighPassFilterEffect::default()),
137 AudioEffect::Distortion(DistortionEffect::default()),
138 AudioEffect::Compressor(CompressorEffect::default()),
139 AudioEffect::Limiter(LimiterEffect::default()),
140 ];
141
142 let json = serde_json::to_string(&effects).expect("serialize effects");
143 let decoded: Vec<AudioEffect> =
144 serde_json::from_str(&json).expect("deserialize effects");
145 assert_eq!(decoded.len(), effects.len());
146 }
147
148 #[test]
149 fn audio_effect_serde_accepts_aliases() {
150 let json = r#"
151 [
152 {"ConvolutionReverbSettings":{"enabled":true,"wet_dry":0.25}},
153 {"BasicReverbSettings":{"enabled":true,"dry_wet":0.5}},
154 {"LowPassFilterSettings":{"enabled":true,"freq":800,"bandwidth":0.7}},
155 {"HighPassFilterSettings":{"enabled":true,"frequency_hz":1200,"q":0.9}},
156 {"DistortionSettings":{"enabled":true,"gain":2.0,"threshold":0.4}},
157 {"CompressorSettings":{"enabled":true,"threshold":-12.0,"ratio":2.0,
158 "attack":5.0,"release":50.0,"makeup_db":3.0}},
159 {"LimiterSettings":{"enabled":true,"threshold_db":-3.0,"knee_width":2.0,
160 "attack_ms":3.0,"release_ms":30.0}}
161 ]
162 "#;
163
164 let decoded: Vec<AudioEffect> =
165 serde_json::from_str(json).expect("deserialize effects");
166 assert_eq!(decoded.len(), 7);
167 }
168}