Define the CoreAudio default name only when needed
[openal-soft.git] / al / effects / echo.cpp
blobf54e4f319901903afe82bb583b3d0fa3d2da408b
2 #include "config.h"
4 #include "AL/al.h"
5 #include "AL/efx.h"
7 #include "alc/effects/base.h"
8 #include "effects.h"
10 #ifdef ALSOFT_EAX
11 #include "alnumeric.h"
13 #include "al/eax_exception.h"
14 #include "al/eax_utils.h"
15 #endif // ALSOFT_EAX
18 namespace {
20 static_assert(EchoMaxDelay >= AL_ECHO_MAX_DELAY, "Echo max delay too short");
21 static_assert(EchoMaxLRDelay >= AL_ECHO_MAX_LRDELAY, "Echo max left-right delay too short");
23 void Echo_setParami(EffectProps*, ALenum param, int)
24 { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
25 void Echo_setParamiv(EffectProps*, ALenum param, const int*)
26 { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
27 void Echo_setParamf(EffectProps *props, ALenum param, float val)
29 switch(param)
31 case AL_ECHO_DELAY:
32 if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
33 throw effect_exception{AL_INVALID_VALUE, "Echo delay out of range"};
34 props->Echo.Delay = val;
35 break;
37 case AL_ECHO_LRDELAY:
38 if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
39 throw effect_exception{AL_INVALID_VALUE, "Echo LR delay out of range"};
40 props->Echo.LRDelay = val;
41 break;
43 case AL_ECHO_DAMPING:
44 if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
45 throw effect_exception{AL_INVALID_VALUE, "Echo damping out of range"};
46 props->Echo.Damping = val;
47 break;
49 case AL_ECHO_FEEDBACK:
50 if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
51 throw effect_exception{AL_INVALID_VALUE, "Echo feedback out of range"};
52 props->Echo.Feedback = val;
53 break;
55 case AL_ECHO_SPREAD:
56 if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
57 throw effect_exception{AL_INVALID_VALUE, "Echo spread out of range"};
58 props->Echo.Spread = val;
59 break;
61 default:
62 throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
65 void Echo_setParamfv(EffectProps *props, ALenum param, const float *vals)
66 { Echo_setParamf(props, param, vals[0]); }
68 void Echo_getParami(const EffectProps*, ALenum param, int*)
69 { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
70 void Echo_getParamiv(const EffectProps*, ALenum param, int*)
71 { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
72 void Echo_getParamf(const EffectProps *props, ALenum param, float *val)
74 switch(param)
76 case AL_ECHO_DELAY:
77 *val = props->Echo.Delay;
78 break;
80 case AL_ECHO_LRDELAY:
81 *val = props->Echo.LRDelay;
82 break;
84 case AL_ECHO_DAMPING:
85 *val = props->Echo.Damping;
86 break;
88 case AL_ECHO_FEEDBACK:
89 *val = props->Echo.Feedback;
90 break;
92 case AL_ECHO_SPREAD:
93 *val = props->Echo.Spread;
94 break;
96 default:
97 throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
100 void Echo_getParamfv(const EffectProps *props, ALenum param, float *vals)
101 { Echo_getParamf(props, param, vals); }
103 EffectProps genDefaultProps() noexcept
105 EffectProps props{};
106 props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
107 props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
108 props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
109 props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
110 props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
111 return props;
114 } // namespace
116 DEFINE_ALEFFECT_VTABLE(Echo);
118 const EffectProps EchoEffectProps{genDefaultProps()};
120 #ifdef ALSOFT_EAX
121 namespace {
123 using EaxEchoEffectDirtyFlagsValue = std::uint_least8_t;
125 struct EaxEchoEffectDirtyFlags
127 using EaxIsBitFieldStruct = bool;
129 EaxEchoEffectDirtyFlagsValue flDelay : 1;
130 EaxEchoEffectDirtyFlagsValue flLRDelay : 1;
131 EaxEchoEffectDirtyFlagsValue flDamping : 1;
132 EaxEchoEffectDirtyFlagsValue flFeedback : 1;
133 EaxEchoEffectDirtyFlagsValue flSpread : 1;
134 }; // EaxEchoEffectDirtyFlags
137 class EaxEchoEffect final :
138 public EaxEffect
140 public:
141 EaxEchoEffect();
144 // [[nodiscard]]
145 bool dispatch(
146 const EaxEaxCall& eax_call) override;
149 private:
150 EAXECHOPROPERTIES eax_{};
151 EAXECHOPROPERTIES eax_d_{};
152 EaxEchoEffectDirtyFlags eax_dirty_flags_{};
155 void set_eax_defaults();
158 void set_efx_delay();
160 void set_efx_lr_delay();
162 void set_efx_damping();
164 void set_efx_feedback();
166 void set_efx_spread();
168 void set_efx_defaults();
171 // [[nodiscard]]
172 bool get(
173 const EaxEaxCall& eax_call);
176 void validate_delay(
177 float flDelay);
179 void validate_lr_delay(
180 float flLRDelay);
182 void validate_damping(
183 float flDamping);
185 void validate_feedback(
186 float flFeedback);
188 void validate_spread(
189 float flSpread);
191 void validate_all(
192 const EAXECHOPROPERTIES& all);
195 void defer_delay(
196 float flDelay);
198 void defer_lr_delay(
199 float flLRDelay);
201 void defer_damping(
202 float flDamping);
204 void defer_feedback(
205 float flFeedback);
207 void defer_spread(
208 float flSpread);
210 void defer_all(
211 const EAXECHOPROPERTIES& all);
214 void defer_delay(
215 const EaxEaxCall& eax_call);
217 void defer_lr_delay(
218 const EaxEaxCall& eax_call);
220 void defer_damping(
221 const EaxEaxCall& eax_call);
223 void defer_feedback(
224 const EaxEaxCall& eax_call);
226 void defer_spread(
227 const EaxEaxCall& eax_call);
229 void defer_all(
230 const EaxEaxCall& eax_call);
233 bool apply_deferred();
235 bool set(
236 const EaxEaxCall& eax_call);
237 }; // EaxEchoEffect
240 class EaxEchoEffectException :
241 public EaxException
243 public:
244 explicit EaxEchoEffectException(
245 const char* message)
247 EaxException{"EAX_ECHO_EFFECT", message}
250 }; // EaxEchoEffectException
253 EaxEchoEffect::EaxEchoEffect()
254 : EaxEffect{AL_EFFECT_ECHO}
256 set_eax_defaults();
257 set_efx_defaults();
260 // [[nodiscard]]
261 bool EaxEchoEffect::dispatch(
262 const EaxEaxCall& eax_call)
264 return eax_call.is_get() ? get(eax_call) : set(eax_call);
267 void EaxEchoEffect::set_eax_defaults()
269 eax_.flDelay = EAXECHO_DEFAULTDELAY;
270 eax_.flLRDelay = EAXECHO_DEFAULTLRDELAY;
271 eax_.flDamping = EAXECHO_DEFAULTDAMPING;
272 eax_.flFeedback = EAXECHO_DEFAULTFEEDBACK;
273 eax_.flSpread = EAXECHO_DEFAULTSPREAD;
275 eax_d_ = eax_;
278 void EaxEchoEffect::set_efx_delay()
280 const auto delay = clamp(
281 eax_.flDelay,
282 AL_ECHO_MIN_DELAY,
283 AL_ECHO_MAX_DELAY);
285 al_effect_props_.Echo.Delay = delay;
288 void EaxEchoEffect::set_efx_lr_delay()
290 const auto lr_delay = clamp(
291 eax_.flLRDelay,
292 AL_ECHO_MIN_LRDELAY,
293 AL_ECHO_MAX_LRDELAY);
295 al_effect_props_.Echo.LRDelay = lr_delay;
298 void EaxEchoEffect::set_efx_damping()
300 const auto damping = clamp(
301 eax_.flDamping,
302 AL_ECHO_MIN_DAMPING,
303 AL_ECHO_MAX_DAMPING);
305 al_effect_props_.Echo.Damping = damping;
308 void EaxEchoEffect::set_efx_feedback()
310 const auto feedback = clamp(
311 eax_.flFeedback,
312 AL_ECHO_MIN_FEEDBACK,
313 AL_ECHO_MAX_FEEDBACK);
315 al_effect_props_.Echo.Feedback = feedback;
318 void EaxEchoEffect::set_efx_spread()
320 const auto spread = clamp(
321 eax_.flSpread,
322 AL_ECHO_MIN_SPREAD,
323 AL_ECHO_MAX_SPREAD);
325 al_effect_props_.Echo.Spread = spread;
328 void EaxEchoEffect::set_efx_defaults()
330 set_efx_delay();
331 set_efx_lr_delay();
332 set_efx_damping();
333 set_efx_feedback();
334 set_efx_spread();
337 // [[nodiscard]]
338 bool EaxEchoEffect::get(
339 const EaxEaxCall& eax_call)
341 switch (eax_call.get_property_id())
343 case EAXECHO_NONE:
344 break;
346 case EAXECHO_ALLPARAMETERS:
347 eax_call.set_value<EaxEchoEffectException>(eax_);
348 break;
350 case EAXECHO_DELAY:
351 eax_call.set_value<EaxEchoEffectException>(eax_.flDelay);
352 break;
354 case EAXECHO_LRDELAY:
355 eax_call.set_value<EaxEchoEffectException>(eax_.flLRDelay);
356 break;
358 case EAXECHO_DAMPING:
359 eax_call.set_value<EaxEchoEffectException>(eax_.flDamping);
360 break;
362 case EAXECHO_FEEDBACK:
363 eax_call.set_value<EaxEchoEffectException>(eax_.flFeedback);
364 break;
366 case EAXECHO_SPREAD:
367 eax_call.set_value<EaxEchoEffectException>(eax_.flSpread);
368 break;
370 default:
371 throw EaxEchoEffectException{"Unsupported property id."};
374 return false;
377 void EaxEchoEffect::validate_delay(
378 float flDelay)
380 eax_validate_range<EaxEchoEffectException>(
381 "Delay",
382 flDelay,
383 EAXECHO_MINDELAY,
384 EAXECHO_MAXDELAY);
387 void EaxEchoEffect::validate_lr_delay(
388 float flLRDelay)
390 eax_validate_range<EaxEchoEffectException>(
391 "LR Delay",
392 flLRDelay,
393 EAXECHO_MINLRDELAY,
394 EAXECHO_MAXLRDELAY);
397 void EaxEchoEffect::validate_damping(
398 float flDamping)
400 eax_validate_range<EaxEchoEffectException>(
401 "Damping",
402 flDamping,
403 EAXECHO_MINDAMPING,
404 EAXECHO_MAXDAMPING);
407 void EaxEchoEffect::validate_feedback(
408 float flFeedback)
410 eax_validate_range<EaxEchoEffectException>(
411 "Feedback",
412 flFeedback,
413 EAXECHO_MINFEEDBACK,
414 EAXECHO_MAXFEEDBACK);
417 void EaxEchoEffect::validate_spread(
418 float flSpread)
420 eax_validate_range<EaxEchoEffectException>(
421 "Spread",
422 flSpread,
423 EAXECHO_MINSPREAD,
424 EAXECHO_MAXSPREAD);
427 void EaxEchoEffect::validate_all(
428 const EAXECHOPROPERTIES& all)
430 validate_delay(all.flDelay);
431 validate_lr_delay(all.flLRDelay);
432 validate_damping(all.flDamping);
433 validate_feedback(all.flFeedback);
434 validate_spread(all.flSpread);
437 void EaxEchoEffect::defer_delay(
438 float flDelay)
440 eax_d_.flDelay = flDelay;
441 eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay);
444 void EaxEchoEffect::defer_lr_delay(
445 float flLRDelay)
447 eax_d_.flLRDelay = flLRDelay;
448 eax_dirty_flags_.flLRDelay = (eax_.flLRDelay != eax_d_.flLRDelay);
451 void EaxEchoEffect::defer_damping(
452 float flDamping)
454 eax_d_.flDamping = flDamping;
455 eax_dirty_flags_.flDamping = (eax_.flDamping != eax_d_.flDamping);
458 void EaxEchoEffect::defer_feedback(
459 float flFeedback)
461 eax_d_.flFeedback = flFeedback;
462 eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback);
465 void EaxEchoEffect::defer_spread(
466 float flSpread)
468 eax_d_.flSpread = flSpread;
469 eax_dirty_flags_.flSpread = (eax_.flSpread != eax_d_.flSpread);
472 void EaxEchoEffect::defer_all(
473 const EAXECHOPROPERTIES& all)
475 defer_delay(all.flDelay);
476 defer_lr_delay(all.flLRDelay);
477 defer_damping(all.flDamping);
478 defer_feedback(all.flFeedback);
479 defer_spread(all.flSpread);
482 void EaxEchoEffect::defer_delay(
483 const EaxEaxCall& eax_call)
485 const auto& delay =
486 eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDelay)>();
488 validate_delay(delay);
489 defer_delay(delay);
492 void EaxEchoEffect::defer_lr_delay(
493 const EaxEaxCall& eax_call)
495 const auto& lr_delay =
496 eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flLRDelay)>();
498 validate_lr_delay(lr_delay);
499 defer_lr_delay(lr_delay);
502 void EaxEchoEffect::defer_damping(
503 const EaxEaxCall& eax_call)
505 const auto& damping =
506 eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDamping)>();
508 validate_damping(damping);
509 defer_damping(damping);
512 void EaxEchoEffect::defer_feedback(
513 const EaxEaxCall& eax_call)
515 const auto& feedback =
516 eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flFeedback)>();
518 validate_feedback(feedback);
519 defer_feedback(feedback);
522 void EaxEchoEffect::defer_spread(
523 const EaxEaxCall& eax_call)
525 const auto& spread =
526 eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flSpread)>();
528 validate_spread(spread);
529 defer_spread(spread);
532 void EaxEchoEffect::defer_all(
533 const EaxEaxCall& eax_call)
535 const auto& all =
536 eax_call.get_value<EaxEchoEffectException, const EAXECHOPROPERTIES>();
538 validate_all(all);
539 defer_all(all);
542 // [[nodiscard]]
543 bool EaxEchoEffect::apply_deferred()
545 if (eax_dirty_flags_ == EaxEchoEffectDirtyFlags{})
547 return false;
550 eax_ = eax_d_;
552 if (eax_dirty_flags_.flDelay)
554 set_efx_delay();
557 if (eax_dirty_flags_.flLRDelay)
559 set_efx_lr_delay();
562 if (eax_dirty_flags_.flDamping)
564 set_efx_damping();
567 if (eax_dirty_flags_.flFeedback)
569 set_efx_feedback();
572 if (eax_dirty_flags_.flSpread)
574 set_efx_spread();
577 eax_dirty_flags_ = EaxEchoEffectDirtyFlags{};
579 return true;
582 // [[nodiscard]]
583 bool EaxEchoEffect::set(
584 const EaxEaxCall& eax_call)
586 switch (eax_call.get_property_id())
588 case EAXECHO_NONE:
589 break;
591 case EAXECHO_ALLPARAMETERS:
592 defer_all(eax_call);
593 break;
595 case EAXECHO_DELAY:
596 defer_delay(eax_call);
597 break;
599 case EAXECHO_LRDELAY:
600 defer_lr_delay(eax_call);
601 break;
603 case EAXECHO_DAMPING:
604 defer_damping(eax_call);
605 break;
607 case EAXECHO_FEEDBACK:
608 defer_feedback(eax_call);
609 break;
611 case EAXECHO_SPREAD:
612 defer_spread(eax_call);
613 break;
615 default:
616 throw EaxEchoEffectException{"Unsupported property id."};
619 if (!eax_call.is_deferred())
621 return apply_deferred();
624 return false;
627 } // namespace
629 EaxEffectUPtr eax_create_eax_echo_effect()
631 return std::make_unique<EaxEchoEffect>();
634 #endif // ALSOFT_EAX