Define the CoreAudio default name only when needed
[openal-soft.git] / al / effects / autowah.cpp
blob51f8fff67e769168236acf86b5c55f5c70f43b8c
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 // [[nodiscard]]
143 bool dispatch(
144 const EaxEaxCall& eax_call) 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 // [[nodiscard]]
168 bool get(
169 const EaxEaxCall& eax_call);
172 void validate_attack_time(
173 float flAttackTime);
175 void validate_release_time(
176 float flReleaseTime);
178 void validate_resonance(
179 long lResonance);
181 void validate_peak_level(
182 long lPeakLevel);
184 void validate_all(
185 const EAXAUTOWAHPROPERTIES& eax_all);
188 void defer_attack_time(
189 float flAttackTime);
191 void defer_release_time(
192 float flReleaseTime);
194 void defer_resonance(
195 long lResonance);
197 void defer_peak_level(
198 long lPeakLevel);
200 void defer_all(
201 const EAXAUTOWAHPROPERTIES& eax_all);
204 void defer_attack_time(
205 const EaxEaxCall& eax_call);
207 void defer_release_time(
208 const EaxEaxCall& eax_call);
210 void defer_resonance(
211 const EaxEaxCall& eax_call);
213 void defer_peak_level(
214 const EaxEaxCall& eax_call);
216 void defer_all(
217 const EaxEaxCall& eax_call);
219 // [[nodiscard]]
220 bool apply_deferred();
222 // [[nodiscard]]
223 bool set(
224 const EaxEaxCall& eax_call);
225 }; // EaxAutoWahEffect
228 class EaxAutoWahEffectException :
229 public EaxException
231 public:
232 explicit EaxAutoWahEffectException(
233 const char* message)
235 EaxException{"EAX_AUTO_WAH_EFFECT", message}
238 }; // EaxAutoWahEffectException
241 EaxAutoWahEffect::EaxAutoWahEffect()
242 : EaxEffect{AL_EFFECT_AUTOWAH}
244 set_eax_defaults();
245 set_efx_defaults();
248 // [[nodiscard]]
249 bool EaxAutoWahEffect::dispatch(
250 const EaxEaxCall& eax_call)
252 return eax_call.is_get() ? get(eax_call) : set(eax_call);
255 void EaxAutoWahEffect::set_eax_defaults()
257 eax_.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
258 eax_.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
259 eax_.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
260 eax_.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
262 eax_d_ = eax_;
265 void EaxAutoWahEffect::set_efx_attack_time()
267 const auto attack_time = clamp(
268 eax_.flAttackTime,
269 AL_AUTOWAH_MIN_ATTACK_TIME,
270 AL_AUTOWAH_MAX_ATTACK_TIME);
272 al_effect_props_.Autowah.AttackTime = attack_time;
275 void EaxAutoWahEffect::set_efx_release_time()
277 const auto release_time = clamp(
278 eax_.flReleaseTime,
279 AL_AUTOWAH_MIN_RELEASE_TIME,
280 AL_AUTOWAH_MAX_RELEASE_TIME);
282 al_effect_props_.Autowah.ReleaseTime = release_time;
285 void EaxAutoWahEffect::set_efx_resonance()
287 const auto resonance = clamp(
288 level_mb_to_gain(static_cast<float>(eax_.lResonance)),
289 AL_AUTOWAH_MIN_RESONANCE,
290 AL_AUTOWAH_MAX_RESONANCE);
292 al_effect_props_.Autowah.Resonance = resonance;
295 void EaxAutoWahEffect::set_efx_peak_gain()
297 const auto peak_gain = clamp(
298 level_mb_to_gain(static_cast<float>(eax_.lPeakLevel)),
299 AL_AUTOWAH_MIN_PEAK_GAIN,
300 AL_AUTOWAH_MAX_PEAK_GAIN);
302 al_effect_props_.Autowah.PeakGain = peak_gain;
305 void EaxAutoWahEffect::set_efx_defaults()
307 set_efx_attack_time();
308 set_efx_release_time();
309 set_efx_resonance();
310 set_efx_peak_gain();
313 bool EaxAutoWahEffect::get(
314 const EaxEaxCall& eax_call)
316 switch (eax_call.get_property_id())
318 case EAXAUTOWAH_NONE:
319 break;
321 case EAXAUTOWAH_ALLPARAMETERS:
322 eax_call.set_value<EaxAutoWahEffectException>(eax_);
323 break;
325 case EAXAUTOWAH_ATTACKTIME:
326 eax_call.set_value<EaxAutoWahEffectException>(eax_.flAttackTime);
327 break;
329 case EAXAUTOWAH_RELEASETIME:
330 eax_call.set_value<EaxAutoWahEffectException>(eax_.flReleaseTime);
331 break;
333 case EAXAUTOWAH_RESONANCE:
334 eax_call.set_value<EaxAutoWahEffectException>(eax_.lResonance);
335 break;
337 case EAXAUTOWAH_PEAKLEVEL:
338 eax_call.set_value<EaxAutoWahEffectException>(eax_.lPeakLevel);
339 break;
341 default:
342 throw EaxAutoWahEffectException{"Unsupported property id."};
345 return false;
348 void EaxAutoWahEffect::validate_attack_time(
349 float flAttackTime)
351 eax_validate_range<EaxAutoWahEffectException>(
352 "Attack Time",
353 flAttackTime,
354 EAXAUTOWAH_MINATTACKTIME,
355 EAXAUTOWAH_MAXATTACKTIME);
358 void EaxAutoWahEffect::validate_release_time(
359 float flReleaseTime)
361 eax_validate_range<EaxAutoWahEffectException>(
362 "Release Time",
363 flReleaseTime,
364 EAXAUTOWAH_MINRELEASETIME,
365 EAXAUTOWAH_MAXRELEASETIME);
368 void EaxAutoWahEffect::validate_resonance(
369 long lResonance)
371 eax_validate_range<EaxAutoWahEffectException>(
372 "Resonance",
373 lResonance,
374 EAXAUTOWAH_MINRESONANCE,
375 EAXAUTOWAH_MAXRESONANCE);
378 void EaxAutoWahEffect::validate_peak_level(
379 long lPeakLevel)
381 eax_validate_range<EaxAutoWahEffectException>(
382 "Peak Level",
383 lPeakLevel,
384 EAXAUTOWAH_MINPEAKLEVEL,
385 EAXAUTOWAH_MAXPEAKLEVEL);
388 void EaxAutoWahEffect::validate_all(
389 const EAXAUTOWAHPROPERTIES& eax_all)
391 validate_attack_time(eax_all.flAttackTime);
392 validate_release_time(eax_all.flReleaseTime);
393 validate_resonance(eax_all.lResonance);
394 validate_peak_level(eax_all.lPeakLevel);
397 void EaxAutoWahEffect::defer_attack_time(
398 float flAttackTime)
400 eax_d_.flAttackTime = flAttackTime;
401 eax_dirty_flags_.flAttackTime = (eax_.flAttackTime != eax_d_.flAttackTime);
404 void EaxAutoWahEffect::defer_release_time(
405 float flReleaseTime)
407 eax_d_.flReleaseTime = flReleaseTime;
408 eax_dirty_flags_.flReleaseTime = (eax_.flReleaseTime != eax_d_.flReleaseTime);
411 void EaxAutoWahEffect::defer_resonance(
412 long lResonance)
414 eax_d_.lResonance = lResonance;
415 eax_dirty_flags_.lResonance = (eax_.lResonance != eax_d_.lResonance);
418 void EaxAutoWahEffect::defer_peak_level(
419 long lPeakLevel)
421 eax_d_.lPeakLevel = lPeakLevel;
422 eax_dirty_flags_.lPeakLevel = (eax_.lPeakLevel != eax_d_.lPeakLevel);
425 void EaxAutoWahEffect::defer_all(
426 const EAXAUTOWAHPROPERTIES& eax_all)
428 validate_all(eax_all);
430 defer_attack_time(eax_all.flAttackTime);
431 defer_release_time(eax_all.flReleaseTime);
432 defer_resonance(eax_all.lResonance);
433 defer_peak_level(eax_all.lPeakLevel);
436 void EaxAutoWahEffect::defer_attack_time(
437 const EaxEaxCall& eax_call)
439 const auto& attack_time =
440 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flAttackTime)>();
442 validate_attack_time(attack_time);
443 defer_attack_time(attack_time);
446 void EaxAutoWahEffect::defer_release_time(
447 const EaxEaxCall& eax_call)
449 const auto& release_time =
450 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flReleaseTime)>();
452 validate_release_time(release_time);
453 defer_release_time(release_time);
456 void EaxAutoWahEffect::defer_resonance(
457 const EaxEaxCall& eax_call)
459 const auto& resonance =
460 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lResonance)>();
462 validate_resonance(resonance);
463 defer_resonance(resonance);
466 void EaxAutoWahEffect::defer_peak_level(
467 const EaxEaxCall& eax_call)
469 const auto& peak_level =
470 eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lPeakLevel)>();
472 validate_peak_level(peak_level);
473 defer_peak_level(peak_level);
476 void EaxAutoWahEffect::defer_all(
477 const EaxEaxCall& eax_call)
479 const auto& all =
480 eax_call.get_value<EaxAutoWahEffectException, const EAXAUTOWAHPROPERTIES>();
482 validate_all(all);
483 defer_all(all);
486 // [[nodiscard]]
487 bool EaxAutoWahEffect::apply_deferred()
489 if (eax_dirty_flags_ == EaxAutoWahEffectDirtyFlags{})
491 return false;
494 eax_ = eax_d_;
496 if (eax_dirty_flags_.flAttackTime)
498 set_efx_attack_time();
501 if (eax_dirty_flags_.flReleaseTime)
503 set_efx_release_time();
506 if (eax_dirty_flags_.lResonance)
508 set_efx_resonance();
511 if (eax_dirty_flags_.lPeakLevel)
513 set_efx_peak_gain();
516 eax_dirty_flags_ = EaxAutoWahEffectDirtyFlags{};
518 return true;
521 // [[nodiscard]]
522 bool EaxAutoWahEffect::set(
523 const EaxEaxCall& eax_call)
525 switch (eax_call.get_property_id())
527 case EAXAUTOWAH_NONE:
528 break;
530 case EAXAUTOWAH_ALLPARAMETERS:
531 defer_all(eax_call);
532 break;
534 case EAXAUTOWAH_ATTACKTIME:
535 defer_attack_time(eax_call);
536 break;
538 case EAXAUTOWAH_RELEASETIME:
539 defer_release_time(eax_call);
540 break;
542 case EAXAUTOWAH_RESONANCE:
543 defer_resonance(eax_call);
544 break;
546 case EAXAUTOWAH_PEAKLEVEL:
547 defer_peak_level(eax_call);
548 break;
550 default:
551 throw EaxAutoWahEffectException{"Unsupported property id."};
554 if (!eax_call.is_deferred())
556 return apply_deferred();
559 return false;
562 } // namespace
564 EaxEffectUPtr eax_create_eax_auto_wah_effect()
566 return std::make_unique<::EaxAutoWahEffect>();
569 #endif // ALSOFT_EAX