proteus_lib/playback/player/
effects.rs1use std::sync::atomic::Ordering;
7
8use crate::dsp::effects::convolution_reverb::{parse_impulse_response_string, ImpulseResponseSpec};
9use crate::{
10 dsp::effects::AudioEffect,
11 playback::engine::{DspChainMetrics, InlineEffectsUpdate},
12};
13
14use super::{Player, ReverbSettingsSnapshot};
15
16impl Player {
17 pub fn set_impulse_response_spec(&mut self, spec: ImpulseResponseSpec) {
23 self.impulse_response_override = Some(spec.clone());
24 let mut prot = self.prot.lock().unwrap();
25 prot.set_impulse_response_spec(spec);
26 self.request_effects_reset();
27 }
28
29 pub fn set_impulse_response_from_string(&mut self, value: &str) {
33 if let Some(spec) = parse_impulse_response_string(value) {
34 self.set_impulse_response_spec(spec);
35 }
36 }
37
38 pub fn set_impulse_response_tail_db(&mut self, tail_db: f32) {
44 self.impulse_response_tail_override = Some(tail_db);
45 let mut prot = self.prot.lock().unwrap();
46 prot.set_impulse_response_tail_db(tail_db);
47 self.request_effects_reset();
48 }
49
50 pub fn set_reverb_enabled(&self, enabled: bool) {
55 let mut effects = self.effects.lock().unwrap();
56 if let Some(effect) = effects
57 .iter_mut()
58 .find_map(|effect| effect.as_convolution_reverb_mut())
59 {
60 effect.enabled = enabled;
61 }
62 if let Some(effect) = effects
63 .iter_mut()
64 .find_map(|effect| effect.as_delay_reverb_mut())
65 {
66 effect.enabled = enabled;
67 }
68 }
69
70 pub fn set_reverb_mix(&self, dry_wet: f32) {
75 let mut effects = self.effects.lock().unwrap();
76 if let Some(effect) = effects
77 .iter_mut()
78 .find_map(|effect| effect.as_convolution_reverb_mut())
79 {
80 effect.dry_wet = dry_wet.clamp(0.0, 1.0);
81 }
82 if let Some(effect) = effects
83 .iter_mut()
84 .find_map(|effect| effect.as_delay_reverb_mut())
85 {
86 effect.mix = dry_wet.clamp(0.0, 1.0);
87 }
88 if let Some(effect) = effects
89 .iter_mut()
90 .find_map(|effect| effect.as_diffusion_reverb_mut())
91 {
92 effect.mix = dry_wet.clamp(0.0, 1.0);
93 }
94 }
95
96 pub fn get_reverb_settings(&self) -> ReverbSettingsSnapshot {
100 let effects = self.effects.lock().unwrap();
101 if let Some(effect) = effects
102 .iter()
103 .find_map(|effect| effect.as_convolution_reverb())
104 {
105 return ReverbSettingsSnapshot {
106 enabled: effect.enabled,
107 dry_wet: effect.dry_wet,
108 };
109 }
110 if let Some(effect) = effects
111 .iter()
112 .find_map(|effect| effect.as_diffusion_reverb())
113 {
114 return ReverbSettingsSnapshot {
115 enabled: effect.enabled,
116 dry_wet: effect.mix,
117 };
118 }
119 if let Some(effect) = effects.iter().find_map(|effect| effect.as_delay_reverb()) {
120 return ReverbSettingsSnapshot {
121 enabled: effect.enabled,
122 dry_wet: effect.mix,
123 };
124 }
125 ReverbSettingsSnapshot {
126 enabled: false,
127 dry_wet: 0.0,
128 }
129 }
130
131 #[allow(deprecated)]
135 pub fn get_effect_names(&self) -> Vec<String> {
136 let effects = self.effects.lock().unwrap();
137 effects
138 .iter()
139 .map(|effect| match effect {
140 AudioEffect::DelayReverb(_) => "DelayReverb".to_string(),
141 AudioEffect::BasicReverb(_) => "DelayReverb".to_string(),
142 AudioEffect::DiffusionReverb(_) => "DiffusionReverb".to_string(),
143 AudioEffect::ConvolutionReverb(_) => "ConvolutionReverb".to_string(),
144 AudioEffect::LowPassFilter(_) => "LowPassFilter".to_string(),
145 AudioEffect::HighPassFilter(_) => "HighPassFilter".to_string(),
146 AudioEffect::Distortion(_) => "Distortion".to_string(),
147 AudioEffect::Gain(_) => "Gain".to_string(),
148 AudioEffect::Compressor(_) => "Compressor".to_string(),
149 AudioEffect::Limiter(_) => "Limiter".to_string(),
150 AudioEffect::MultibandEq(_) => "MultibandEq".to_string(),
151 })
152 .collect()
153 }
154
155 pub fn set_effects(&mut self, effects: Vec<AudioEffect>) {
165 self.clear_inline_effects_update();
166 self.replace_effects_chain(effects);
167 self.request_effects_reset();
168
169 if !self.thread_finished() {
172 let ts = self.get_time();
173 self.seek(ts);
174 }
175 }
176
177 pub fn set_effects_inline(&self, effects: Vec<AudioEffect>) {
188 if self.thread_finished() {
189 self.replace_effects_chain(effects);
190 return;
191 }
192
193 let transition_ms = {
194 let settings = self.buffer_settings.lock().unwrap();
195 settings.inline_effects_transition_ms.max(0.0)
196 };
197 let mut pending = self.inline_effects_update.lock().unwrap();
198 *pending = Some(InlineEffectsUpdate::new(effects, transition_ms));
199 }
200
201 pub fn get_dsp_metrics(&self) -> DspChainMetrics {
207 *self.dsp_metrics.lock().unwrap()
208 }
209
210 pub fn get_levels(&self) -> Vec<f32> {
212 self.output_meter.lock().unwrap().levels()
213 }
214
215 pub fn get_levels_db(&self) -> Vec<f32> {
217 self.output_meter
218 .lock()
219 .unwrap()
220 .levels()
221 .into_iter()
222 .map(linear_to_dbfs)
223 .collect()
224 }
225
226 pub fn get_levels_avg(&self) -> Vec<f32> {
228 self.output_meter.lock().unwrap().averages()
229 }
230
231 pub fn set_output_meter_refresh_hz(&self, hz: f32) {
233 self.output_meter.lock().unwrap().set_refresh_hz(hz);
234 }
235
236 pub(super) fn request_effects_reset(&self) {
238 self.effects_reset.fetch_add(1, Ordering::SeqCst);
239 }
240
241 pub(super) fn clear_inline_effects_update(&self) {
243 let mut pending = self.inline_effects_update.lock().unwrap();
244 pending.take();
245 }
246
247 fn replace_effects_chain(&self, effects: Vec<AudioEffect>) {
249 let mut guard = self.effects.lock().unwrap();
250 log::info!("updated effects chain: {} effect(s)", effects.len());
251 *guard = effects;
252 }
253}
254
255fn linear_to_dbfs(value: f32) -> f32 {
256 if value <= 0.0 {
257 f32::NEG_INFINITY
258 } else {
259 20.0 * value.log10()
260 }
261}