1use std::convert::TryFrom;
2use std::fmt::{Display, Formatter};
3
4use strum::IntoEnumIterator;
5use strum_macros::EnumIter;
6use uom::si::f64::Ratio;
7
8use crate::Envelope;
9
10#[derive(Debug)]
11pub struct Chorus {
12 pub enabled: bool,
13 pub depth: f64,
14 pub pre_delay: f64,
15 pub ratio: f64,
16 pub mix: f64,
17}
18
19impl Effect for Chorus {
20 fn is_enabled(&self) -> bool {
21 self.enabled
22 }
23}
24
25#[derive(Copy, Clone, Debug, EnumIter, Eq, PartialEq)]
31#[repr(u32)]
32pub enum DelayFilterMode {
33 Off = 0,
34 LowPass5000 = 42,
35 LowPass3800 = 83,
36 LowPass2500 = 125,
37 LowPass1600 = 167,
38 LowPass1000 = 208,
39 LowPass750 = 25,
40 LowPass400 = 292,
41 LowPass200 = 333,
42 HighPass4000 = 375,
43 HighPass2000 = 417,
44 HighPass1200 = 458,
45 HighPass800 = 500,
46 HighPass600 = 542,
47 HighPass400 = 583,
48 HighPass250 = 625,
49 HighPass100 = 667,
50 BandPass3000 = 708,
51 BandPass1800 = 750,
52 BandPass1300 = 792,
53 BandPass1000 = 833,
54 BandPass700 = 875,
55 BandPass500 = 917,
56 BandPass300 = 958,
57 BandPass150 = 1000,
58}
59
60impl DelayFilterMode {
61 pub(crate) fn from_or(mode_id: u32, default: Self) -> Self {
62 Self::iter()
63 .find(|id| *id as u32 == mode_id)
64 .unwrap_or(default)
65 }
66}
67
68impl Display for DelayFilterMode {
69 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70 use DelayFilterMode::*;
71 let msg = match self {
72 Off => "Filter: Off",
73 LowPass5000 => "LP: 5000 Hz",
74 LowPass3800 => "LP: 3800 Hz",
75 LowPass2500 => "LP: 2500 Hz",
76 LowPass1600 => "LP: 1600 Hz",
77 LowPass1000 => "LP: 1000 Hz",
78 LowPass750 => "LP: 750 Hz",
79 LowPass400 => "LP: 400 Hz",
80 LowPass200 => "LP: 200 Hz",
81 HighPass4000 => "HP: 4000 Hz",
82 HighPass2000 => "HP: 2000 Hz",
83 HighPass1200 => "HP: 1200 Hz",
84 HighPass800 => "HP: 800 Hz",
85 HighPass600 => "HP: 600 Hz",
86 HighPass400 => "HP: 400 Hz",
87 HighPass250 => "HP: 250 Hz",
88 HighPass100 => "HP: 100 Hz",
89 BandPass3000 => "BP: 3000 Hz",
90 BandPass1800 => "BP: 1800 Hz",
91 BandPass1300 => "BP: 1300 Hz",
92 BandPass1000 => "BP: 1000 Hz",
93 BandPass700 => "BP: 700 Hz",
94 BandPass500 => "BP: 500 Hz",
95 BandPass300 => "BP: 300 Hz",
96 BandPass150 => "BP: 150 Hz",
97 };
98 f.write_str(msg)
99 }
100}
101
102#[derive(Debug)]
103pub struct Delay {
104 pub enabled: bool,
105 pub ping_pong: bool,
106 pub feedback: f64,
107 pub filter_mode: DelayFilterMode,
108 pub sync: bool,
109 pub time: f64,
110 pub mix: f64,
111}
112
113impl Effect for Delay {
114 fn is_enabled(&self) -> bool {
115 self.enabled
116 }
117}
118
119#[derive(Debug)]
120pub struct Distortion {
121 pub enabled: bool,
122
123 pub gain: f64,
125}
126
127impl Effect for Distortion {
128 fn is_enabled(&self) -> bool {
129 self.enabled
130 }
131}
132
133pub trait Effect {
134 fn is_enabled(&self) -> bool {
135 false
136 }
137}
138
139#[derive(Debug)]
140pub struct Equalizer {
141 pub enabled: bool,
142 pub high_gain: Ratio,
143 pub low_gain: Ratio,
144 pub mid_gain: Ratio,
145}
146
147impl Effect for Equalizer {
148 fn is_enabled(&self) -> bool {
149 self.enabled
150 }
151}
152
153#[derive(Copy, Clone, Debug, EnumIter, Eq, PartialEq)]
158#[repr(u32)]
159pub enum EffectType {
160 Distortion,
161 LoFi,
162 Filter,
163 Chorus,
164 Equalizer,
165 Delay,
166 Reverb,
167}
168
169impl TryFrom<u32> for EffectType {
170 type Error = String;
171
172 fn try_from(effect_type_id: u32) -> Result<Self, Self::Error> {
173 Self::iter()
174 .find(|id| *id as u32 == effect_type_id)
175 .ok_or(format!("Unknown effect type ID {}", effect_type_id))
176 }
177}
178
179#[derive(Copy, Clone, Debug, EnumIter, Eq, PartialEq)]
181#[repr(u32)]
182pub enum FilterMode {
183 LowPass,
184 BandPass,
185 HighPass,
186 Notch,
187 Peak,
188}
189
190impl FilterMode {
191 pub(crate) fn from_or(mode_id: u32, default: Self) -> Self {
192 Self::iter()
193 .find(|id| *id as u32 == mode_id)
194 .unwrap_or(default)
195 }
196}
197
198#[derive(Copy, Clone, Debug, EnumIter, Eq, PartialEq)]
200#[repr(u32)]
201pub enum FilterEffectMode {
202 Off,
203 Saturation,
204 Overdrive,
205 Distortion,
206 BitRateReduction,
207 SampleRateReduction,
208}
209
210impl FilterEffectMode {
211 pub(crate) fn from_or(mode_id: u32, default: FilterEffectMode) -> FilterEffectMode {
212 FilterEffectMode::iter()
213 .find(|id| *id as u32 == mode_id)
214 .unwrap_or(default)
215 }
216}
217
218#[derive(Debug)]
219pub struct Filter {
220 pub enabled: bool,
221 pub mode: FilterMode,
222 pub resonance: f64,
223 pub cutoff_frequency: f64,
224 pub key_tracking: f64,
225 pub envelope: Envelope,
226
227 pub envelope_amount: f64,
229
230 pub effect_mode: FilterEffectMode,
232 pub effect_enabled: bool,
233 pub effect_amount: f64,
234}
235
236impl Effect for Filter {
237 fn is_enabled(&self) -> bool {
238 self.enabled
239 }
240}
241
242#[derive(Debug)]
243pub struct LoFi {
244 pub enabled: bool,
245 pub bitrate: f64,
246
247 pub sample_rate: f64,
249
250 pub mix: f64,
252}
253
254impl Effect for LoFi {
255 fn is_enabled(&self) -> bool {
256 self.enabled
257 }
258}
259
260#[derive(Debug)]
261pub struct Reverb {
262 pub enabled: bool,
263 pub dampen: f64,
264 pub filter: f64,
265 pub room: f64,
266 pub width: f64,
267 pub mix: f64,
268}
269
270impl Effect for Reverb {
271 fn is_enabled(&self) -> bool {
272 self.enabled
273 }
274}
275
276#[cfg(test)]
277mod test {
278 use std::io::Result;
279 use std::path::Path;
280
281 use approx::assert_relative_eq;
282 use strum::IntoEnumIterator;
283 use uom::si::ratio::percent;
284
285 use crate::{DelayFilterMode, EffectType, FilterMode, Preset};
286
287 fn read_preset(filename: &str) -> Result<Preset> {
288 let path = &Path::new("tests").join("effects").join(&filename);
289 Preset::read_file(path)
290 }
291
292 #[test]
293 fn delay() {
294 let preset = read_preset("delay-ping_pong_off-1.0.2.bab").unwrap();
295 assert!(!preset.delay.ping_pong);
296
297 let preset = read_preset("delay-ping_pong_on-1.0.2.bab").unwrap();
298 assert!(preset.delay.ping_pong);
299
300 let preset = read_preset("delay-time1t-hp100-ping_pong-1.0.3.bab").unwrap();
301 assert!(preset.delay.ping_pong);
302 assert!(preset.delay.sync);
303 assert_eq!(preset.delay.time, 1.0);
304 assert_eq!(preset.delay.filter_mode, DelayFilterMode::HighPass100);
305
306 let preset = read_preset("delay-time504-syncoff-1.0.3.bab").unwrap();
307 assert!(!preset.delay.sync);
308 assert_relative_eq!(preset.delay.time, 0.504, epsilon = 0.00001);
309
310 let preset = read_preset("delay-timehalf-lp200-1.0.3.bab").unwrap();
311 assert_relative_eq!(preset.delay.time, 0.257, epsilon = 0.00001);
312 assert_eq!(preset.delay.filter_mode, DelayFilterMode::LowPass200);
313
314 let preset = read_preset("delay-timesixteenth-bp3000-1.0.3.bab").unwrap();
315 assert_relative_eq!(preset.delay.time, 0.410, epsilon = 0.00001);
316 assert_eq!(preset.delay.filter_mode, DelayFilterMode::BandPass3000);
317 }
318
319 #[test]
320 fn delay_filter_mode() {
321 let preset = read_preset("delay-band_pass_150-1.0.4.bab").unwrap();
322 assert!(preset.delay.enabled);
323 assert_eq!(preset.delay.filter_mode, DelayFilterMode::BandPass150);
324
325 let preset = read_preset("delay-band_pass_1000-1.0.4.bab").unwrap();
326 assert!(preset.delay.enabled);
327 assert_eq!(preset.delay.filter_mode, DelayFilterMode::BandPass1000);
328
329 let preset = read_preset("delay-high_pass_250-1.0.4.bab").unwrap();
330 assert!(preset.delay.enabled);
331 assert_eq!(preset.delay.filter_mode, DelayFilterMode::HighPass250);
332
333 let preset = read_preset("delay-low_pass_200-1.0.4.bab").unwrap();
334 assert!(preset.delay.enabled);
335 assert_eq!(preset.delay.filter_mode, DelayFilterMode::LowPass200);
336 }
337
338 #[test]
339 fn distortion() {
340 let preset = read_preset("distortion-gain5-1.0.3.bab").unwrap();
341 assert!(preset.distortion.enabled);
342 assert_eq!(preset.distortion.gain, 0.5);
343 }
344
345 #[test]
346 fn effect_order() {
347 let preset = read_preset("effect-order-reversed-1.0.2.bab").unwrap();
348 let expected_effect_order: Vec<EffectType> = EffectType::iter().rev().collect();
349 assert_eq!(&preset.effect_order, &expected_effect_order);
350 assert_eq!(preset.effect_position(EffectType::Equalizer).unwrap(), 2);
351 }
352
353 #[test]
354 fn equalizer() {
355 let preset = read_preset("equalizer-l-10-m5-h-10-1.0.3.bab").unwrap();
356 assert!(preset.equalizer.enabled);
357 assert_eq!(preset.equalizer.low_gain.get::<percent>(), 0.5);
358 assert_eq!(preset.equalizer.mid_gain.get::<percent>(), 0.5);
359 assert_eq!(preset.equalizer.high_gain.get::<percent>(), 0.5);
360 }
361
362 #[test]
363 fn filter() {
364 let preset = read_preset("filter-bandpass-1.0.2.bab").unwrap();
365 assert_eq!(preset.filter.mode, FilterMode::BandPass);
366 assert_eq!(preset.filter.cutoff_frequency, 100.0);
367
368 let preset = read_preset("filter-highpass-1.0.2.bab").unwrap();
369 assert_eq!(preset.filter.mode, FilterMode::HighPass);
370
371 let preset = read_preset("filter-notch-1.0.2.bab").unwrap();
372 assert_eq!(preset.filter.mode, FilterMode::Notch);
373
374 let preset = read_preset("filter-peak-1.0.2.bab").unwrap();
375 assert_eq!(preset.filter.mode, FilterMode::Peak);
376 }
377
378 #[test]
379 fn reverb() {
380 let preset = read_preset("reverb-r100-w0-d50-m34-hp400-1.0.3.bab").unwrap();
381 assert!(preset.reverb.enabled);
382 assert_relative_eq!(preset.reverb.room, 1.0, epsilon = 0.0001);
383 assert_relative_eq!(preset.reverb.width, 0.0, epsilon = 0.0001);
384 assert_relative_eq!(preset.reverb.dampen, 0.50, epsilon = 0.0001);
385 assert_relative_eq!(preset.reverb.mix, 0.34, epsilon = 0.0001);
386 assert_relative_eq!(preset.reverb.filter, 0.583, epsilon = 0.0001);
387 }
388}