Check for a minimum PipeWire version
[openal-soft.git] / al / effects / autowah.cpp
blob273ec7ae76e53991c6ce02d81469e2dca5fee478
2 #include "config.h"
4 #include <cmath>
5 #include <cstdlib>
7 #include <algorithm>
9 #include "AL/efx.h"
11 #include "alc/effects/base.h"
12 #include "effects.h"
14 #ifdef ALSOFT_EAX
15 #include "alnumeric.h"
17 #include "al/eax_exception.h"
18 #include "al/eax_utils.h"
19 #endif // ALSOFT_EAX
22 namespace {
24 void Autowah_setParamf(EffectProps *props, ALenum param, float val)
26 switch(param)
28 case AL_AUTOWAH_ATTACK_TIME:
29 if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME))
30 throw effect_exception{AL_INVALID_VALUE, "Autowah attack time out of range"};
31 props->Autowah.AttackTime = val;
32 break;
34 case AL_AUTOWAH_RELEASE_TIME:
35 if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME))
36 throw effect_exception{AL_INVALID_VALUE, "Autowah release time out of range"};
37 props->Autowah.ReleaseTime = val;
38 break;
40 case AL_AUTOWAH_RESONANCE:
41 if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE))
42 throw effect_exception{AL_INVALID_VALUE, "Autowah resonance out of range"};
43 props->Autowah.Resonance = val;
44 break;
46 case AL_AUTOWAH_PEAK_GAIN:
47 if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN))
48 throw effect_exception{AL_INVALID_VALUE, "Autowah peak gain out of range"};
49 props->Autowah.PeakGain = val;
50 break;
52 default:
53 throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
56 void Autowah_setParamfv(EffectProps *props, ALenum param, const float *vals)
57 { Autowah_setParamf(props, param, vals[0]); }
59 void Autowah_setParami(EffectProps*, ALenum param, int)
60 { throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
61 void Autowah_setParamiv(EffectProps*, ALenum param, const int*)
63 throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
64 param};
67 void Autowah_getParamf(const EffectProps *props, ALenum param, float *val)
69 switch(param)
71 case AL_AUTOWAH_ATTACK_TIME:
72 *val = props->Autowah.AttackTime;
73 break;
75 case AL_AUTOWAH_RELEASE_TIME:
76 *val = props->Autowah.ReleaseTime;
77 break;
79 case AL_AUTOWAH_RESONANCE:
80 *val = props->Autowah.Resonance;
81 break;
83 case AL_AUTOWAH_PEAK_GAIN:
84 *val = props->Autowah.PeakGain;
85 break;
87 default:
88 throw effect_exception{AL_INVALID_ENUM, "Invalid autowah float property 0x%04x", param};
92 void Autowah_getParamfv(const EffectProps *props, ALenum param, float *vals)
93 { Autowah_getParamf(props, param, vals); }
95 void Autowah_getParami(const EffectProps*, ALenum param, int*)
96 { throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer property 0x%04x", param}; }
97 void Autowah_getParamiv(const EffectProps*, ALenum param, int*)
99 throw effect_exception{AL_INVALID_ENUM, "Invalid autowah integer vector property 0x%04x",
100 param};
103 EffectProps genDefaultProps() noexcept
105 EffectProps props{};
106 props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
107 props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
108 props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
109 props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
110 return props;
113 } // namespace
115 DEFINE_ALEFFECT_VTABLE(Autowah);
117 const EffectProps AutowahEffectProps{genDefaultProps()};
119 #ifdef ALSOFT_EAX
120 namespace {
122 using EaxAutoWahEffectDirtyFlagsValue = std::uint_least8_t;
124 struct EaxAutoWahEffectDirtyFlags
126 using EaxIsBitFieldStruct = bool;
128 EaxAutoWahEffectDirtyFlagsValue flAttackTime : 1;
129 EaxAutoWahEffectDirtyFlagsValue flReleaseTime : 1;
130 EaxAutoWahEffectDirtyFlagsValue lResonance : 1;
131 EaxAutoWahEffectDirtyFlagsValue lPeakLevel : 1;
132 }; // EaxAutoWahEffectDirtyFlags
135 class EaxAutoWahEffect final :
136 public EaxEffect
138 public:
139 EaxAutoWahEffect();
142 void dispatch(const EaxEaxCall& eax_call) override;
144 // [[nodiscard]]
145 bool apply_deferred() override;
147 private:
148 EAXAUTOWAHPROPERTIES eax_{};
149 EAXAUTOWAHPROPERTIES eax_d_{};
150 EaxAutoWahEffectDirtyFlags eax_dirty_flags_{};
153 void set_eax_defaults();
156 void set_efx_attack_time();
158 void set_efx_release_time();
160 void set_efx_resonance();
162 void set_efx_peak_gain();
164 void set_efx_defaults();
167 void get(const EaxEaxCall& eax_call);
170 void validate_attack_time(
171 float flAttackTime);
173 void validate_release_time(
174 float flReleaseTime);
176 void validate_resonance(
177 long lResonance);
179 void validate_peak_level(
180 long lPeakLevel);
182 void validate_all(
183 const EAXAUTOWAHPROPERTIES& eax_all);
186 void defer_attack_time(
187 float flAttackTime);
189 void defer_release_time(
190 float flReleaseTime);
192 void defer_resonance(
193 long lResonance);
195 void defer_peak_level(
196 long lPeakLevel);
198 void defer_all(
199 const EAXAUTOWAHPROPERTIES& eax_all);
202 void defer_attack_time(
203 const EaxEaxCall& eax_call);
205 void defer_release_time(
206 const EaxEaxCall& eax_call);
208 void defer_resonance(
209 const EaxEaxCall& eax_call);
211 void defer_peak_level(
212 const EaxEaxCall& eax_call);
214 void defer_all(
215 const EaxEaxCall& eax_call);
217 void set(const EaxEaxCall& eax_call);
218 }; // EaxAutoWahEffect
221 class EaxAutoWahEffectException :
222 public EaxException
224 public:
225 explicit EaxAutoWahEffectException(
226 const char* message)
228 EaxException{"EAX_AUTO_WAH_EFFECT", message}
231 }; // EaxAutoWahEffectException
234 EaxAutoWahEffect::EaxAutoWahEffect()
235 : EaxEffect{AL_EFFECT_AUTOWAH}
237 set_eax_defaults();
238 set_efx_defaults();
241 void EaxAutoWahEffect::dispatch(const EaxEaxCall& eax_call)
243 eax_call.is_get() ? get(eax_call) : set(eax_call);
246 void EaxAutoWahEffect::set_eax_defaults()
248 eax_.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
249 eax_.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
250 eax_.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
251 eax_.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
253 eax_d_ = eax_;
256 void EaxAutoWahEffect::set_efx_attack_time()
258 const auto attack_time = clamp(
259 eax_.flAttackTime,
260 AL_AUTOWAH_MIN_ATTACK_TIME,
261 AL_AUTOWAH_MAX_ATTACK_TIME);
263 al_effect_props_.Autowah.AttackTime = attack_time;
266 void EaxAutoWahEffect::set_efx_release_time()
268 const auto release_time = clamp(
269 eax_.flReleaseTime,
270 AL_AUTOWAH_MIN_RELEASE_TIME,
271 AL_AUTOWAH_MAX_RELEASE_TIME);
273 al_effect_props_.Autowah.ReleaseTime = release_time;
276 void EaxAutoWahEffect::set_efx_resonance()
278 const auto resonance = clamp(
279 level_mb_to_gain(static_cast<float>(eax_.lResonance)),
280 AL_AUTOWAH_MIN_RESONANCE,
281 AL_AUTOWAH_MAX_RESONANCE);
283 al_effect_props_.Autowah.Resonance = resonance;
286 void EaxAutoWahEffect::set_efx_peak_gain()
288 const auto peak_gain = clamp(
289 level_mb_to_gain(static_cast<float>(eax_.lPeakLevel)),
290 AL_AUTOWAH_MIN_PEAK_GAIN,
291 AL_AUTOWAH_MAX_PEAK_GAIN);
293 al_effect_props_.Autowah.PeakGain = peak_gain;
296 void EaxAutoWahEffect::set_efx_defaults()
298 set_efx_attack_time();
299 set_efx_release_time();
300 set_efx_resonance();
301 set_efx_peak_gain();
304 void EaxAutoWahEffect::get(const EaxEaxCall& eax_call)
306 switch (eax_call.get_property_id())
308 case EAXAUTOWAH_NONE:
309 break;
311 case EAXAUTOWAH_ALLPARAMETERS:
312 eax_call.set_value<EaxAutoWahEffectException>(eax_);
313 break;
315 case EAXAUTOWAH_ATTACKTIME:
316 eax_call.set_value<EaxAutoWahEffectException>(eax_.flAttackTime);
317 break;
319 case EAXAUTOWAH_RELEASETIME:
320 eax_call.set_value<EaxAutoWahEffectException>(eax_.flReleaseTime);
321 break;
323 case EAXAUTOWAH_RESONANCE:
324 eax_call.set_value<EaxAutoWahEffectException>(eax_.lResonance);
325 break;
327 case EAXAUTOWAH_PEAKLEVEL:
328 eax_call.set_value<EaxAutoWahEffectException>(eax_.lPeakLevel);
329 break;
331 default:
332 throw EaxAutoWahEffectException{"Unsupported property id."};
336 void EaxAutoWahEffect::validate_attack_time(
337 float flAttackTime)
339 eax_validate_range<EaxAutoWahEffectException>(
340 "Attack Time",
341 flAttackTime,
342 EAXAUTOWAH_MINATTACKTIME,
343 EAXAUTOWAH_MAXATTACKTIME);
346 void EaxAutoWahEffect::validate_release_time(
347 float flReleaseTime)
349 eax_validate_range<EaxAutoWahEffectException>(
350 "Release Time",
351 flReleaseTime,
352 EAXAUTOWAH_MINRELEASETIME,
353 EAXAUTOWAH_MAXRELEASETIME);
356 void EaxAutoWahEffect::validate_resonance(
357 long lResonance)
359 eax_validate_range<EaxAutoWahEffectException>(
360 "Resonance",
361 lResonance,
362 EAXAUTOWAH_MINRESONANCE,
363 EAXAUTOWAH_MAXRESONANCE);
366 void EaxAutoWahEffect::validate_peak_level(
367 long lPeakLevel)
369 eax_validate_range<EaxAutoWahEffectException>(
370 "Peak Level",
371 lPeakLevel,
372 EAXAUTOWAH_MINPEAKLEVEL,
373 EAXAUTOWAH_MAXPEAKLEVEL);
376 void EaxAutoWahEffect::validate_all(
377 const EAXAUTOWAHPROPERTIES& eax_all)
379 validate_attack_time(eax_all.flAttackTime);
380 validate_release_time(eax_all.flReleaseTime);
381 validate_resonance(eax_all.lResonance);
382 validate_peak_level(eax_all.lPeakLevel);
385 void EaxAutoWahEffect::defer_attack_time(
386 float flAttackTime)
388 eax_d_.flAttackTime = flAttackTime;
389 eax_dirty_flags_.flAttackTime = (eax_.flAttackTime != eax_d_.flAttackTime);
392 void EaxAutoWahEffect::defer_release_time(
393 float flReleaseTime)
395 eax_d_.flReleaseTime = flReleaseTime;
396 eax_dirty_flags_.flReleaseTime = (eax_.flReleaseTime != eax_d_.flReleaseTime);
399 void EaxAutoWahEffect::defer_resonance(
400 long lResonance)
402 eax_d_.lResonance = lResonance;
403 eax_dirty_flags_.lResonance = (eax_.lResonance != eax_d_.lResonance);
406 void EaxAutoWahEffect::defer_peak_level(
407 long lPeakLevel)
409 eax_d_.lPeakLevel = lPeakLevel;
410 eax_dirty_flags_.lPeakLevel = (eax_.lPeakLevel != eax_d_.lPeakLevel);
413 void EaxAutoWahEffect::defer_all(
414 const EAXAUTOWAHPROPERTIES& eax_all)
416 validate_all(eax_all);
418 defer_attack_time(eax_all.flAttackTime);
419 defer_release_time(eax_all.flReleaseTime);
420 defer_resonance(eax_all.lResonance);
421 defer_peak_level(eax_all.lPeakLevel);
424 void EaxAutoWahEffect::defer_attack_time(
425 const EaxEaxCall& eax_call)
427 const auto& attack_time =
428 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flAttackTime)>();
430 validate_attack_time(attack_time);
431 defer_attack_time(attack_time);
434 void EaxAutoWahEffect::defer_release_time(
435 const EaxEaxCall& eax_call)
437 const auto& release_time =
438 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flReleaseTime)>();
440 validate_release_time(release_time);
441 defer_release_time(release_time);
444 void EaxAutoWahEffect::defer_resonance(
445 const EaxEaxCall& eax_call)
447 const auto& resonance =
448 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lResonance)>();
450 validate_resonance(resonance);
451 defer_resonance(resonance);
454 void EaxAutoWahEffect::defer_peak_level(
455 const EaxEaxCall& eax_call)
457 const auto& peak_level =
458 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lPeakLevel)>();
460 validate_peak_level(peak_level);
461 defer_peak_level(peak_level);
464 void EaxAutoWahEffect::defer_all(
465 const EaxEaxCall& eax_call)
467 const auto& all =
468 eax_call.get_value<EaxAutoWahEffectException, const EAXAUTOWAHPROPERTIES>();
470 validate_all(all);
471 defer_all(all);
474 // [[nodiscard]]
475 bool EaxAutoWahEffect::apply_deferred()
477 if (eax_dirty_flags_ == EaxAutoWahEffectDirtyFlags{})
479 return false;
482 eax_ = eax_d_;
484 if (eax_dirty_flags_.flAttackTime)
486 set_efx_attack_time();
489 if (eax_dirty_flags_.flReleaseTime)
491 set_efx_release_time();
494 if (eax_dirty_flags_.lResonance)
496 set_efx_resonance();
499 if (eax_dirty_flags_.lPeakLevel)
501 set_efx_peak_gain();
504 eax_dirty_flags_ = EaxAutoWahEffectDirtyFlags{};
506 return true;
509 void EaxAutoWahEffect::set(const EaxEaxCall& eax_call)
511 switch (eax_call.get_property_id())
513 case EAXAUTOWAH_NONE:
514 break;
516 case EAXAUTOWAH_ALLPARAMETERS:
517 defer_all(eax_call);
518 break;
520 case EAXAUTOWAH_ATTACKTIME:
521 defer_attack_time(eax_call);
522 break;
524 case EAXAUTOWAH_RELEASETIME:
525 defer_release_time(eax_call);
526 break;
528 case EAXAUTOWAH_RESONANCE:
529 defer_resonance(eax_call);
530 break;
532 case EAXAUTOWAH_PEAKLEVEL:
533 defer_peak_level(eax_call);
534 break;
536 default:
537 throw EaxAutoWahEffectException{"Unsupported property id."};
541 } // namespace
543 EaxEffectUPtr eax_create_eax_auto_wah_effect()
545 return std::make_unique<::EaxAutoWahEffect>();
548 #endif // ALSOFT_EAX