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}