Skip to main content

zk_audio/
factory.rs

1use crate::contracts::{AudioProcessor, ProcessorBuildRequest, ProcessorFactory};
2use crate::core::AudioResult;
3use crate::profiles::build_processors;
4
5pub struct ProfileProcessorFactory;
6
7impl ProfileProcessorFactory {
8    pub fn new() -> Self {
9        Self
10    }
11}
12
13impl Default for ProfileProcessorFactory {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl ProcessorFactory for ProfileProcessorFactory {
20    fn build_processors(
21        &self,
22        request: ProcessorBuildRequest,
23    ) -> AudioResult<Vec<Box<dyn AudioProcessor>>> {
24        build_processors(
25            request.profile,
26            request.gain_db,
27            request.limiter_threshold,
28            request.high_pass_hz,
29            request.noise_suppression_amount,
30            request.noise_calibration_ms,
31            request.delay_effect,
32            &request.stage_overrides,
33        )
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use crate::core::{AudioProfile, DelayEffectConfig, DelayEffectPreset};
41    use std::collections::BTreeMap;
42
43    #[test]
44    fn factory_builds_expected_hvac_chain() {
45        let factory = ProfileProcessorFactory::new();
46        let processors = factory
47            .build_processors(ProcessorBuildRequest {
48                profile: AudioProfile::VoiceHvac,
49                gain_db: 2.0,
50                limiter_threshold: 0.92,
51                high_pass_hz: 100.0,
52                noise_suppression_amount: 0.5,
53                noise_calibration_ms: 350,
54                delay_effect: None,
55                stage_overrides: BTreeMap::new(),
56            })
57            .unwrap();
58
59        let names = processors.iter().map(|p| p.name()).collect::<Vec<_>>();
60        assert_eq!(
61            names,
62            vec![
63                "high_pass",
64                "low_shelf_cut",
65                "low_pass",
66                "expander",
67                "noise_suppression",
68                "adaptive_gain",
69                "compressor",
70                "agc",
71                "adaptive_tone_shaper",
72                "mid_resonance_suppressor",
73                "high_band_cleanup",
74                "presence_boost",
75                "deesser",
76                "tail_suppression",
77                "air_band_reducer",
78                "voice_finisher",
79                "limiter"
80            ]
81        );
82    }
83
84    #[test]
85    fn factory_builds_raw_profile_without_processors() {
86        let factory = ProfileProcessorFactory::new();
87        let processors = factory
88            .build_processors(ProcessorBuildRequest {
89                profile: AudioProfile::Raw,
90                gain_db: 0.0,
91                limiter_threshold: 0.92,
92                high_pass_hz: 0.0,
93                noise_suppression_amount: 0.0,
94                noise_calibration_ms: 0,
95                delay_effect: None,
96                stage_overrides: BTreeMap::new(),
97            })
98            .unwrap();
99
100        assert!(processors.is_empty());
101    }
102
103    #[test]
104    fn factory_builds_delay_stage_before_limiter_when_enabled() {
105        let factory = ProfileProcessorFactory::new();
106        let processors = factory
107            .build_processors(ProcessorBuildRequest {
108                profile: AudioProfile::VoiceClean,
109                gain_db: 2.0,
110                limiter_threshold: 0.92,
111                high_pass_hz: 100.0,
112                noise_suppression_amount: 0.5,
113                noise_calibration_ms: 350,
114                delay_effect: Some(DelayEffectConfig {
115                    preset: DelayEffectPreset::Slapback,
116                }),
117                stage_overrides: BTreeMap::new(),
118            })
119            .unwrap();
120
121        let names = processors.iter().map(|p| p.name()).collect::<Vec<_>>();
122        assert_eq!(names[names.len() - 3], "doubling_delay");
123        assert_eq!(names[names.len() - 2], "voice_finisher");
124        assert_eq!(names[names.len() - 1], "limiter");
125    }
126}