Define the CoreAudio default name only when needed
[openal-soft.git] / al / effects / distortion.cpp
blob4554901c9c77b3ceb886a19143aa4f196fd400a6
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 void Distortion_setParami(EffectProps*, ALenum param, int)
21 { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
22 void Distortion_setParamiv(EffectProps*, ALenum param, const int*)
24 throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
25 param};
27 void Distortion_setParamf(EffectProps *props, ALenum param, float val)
29 switch(param)
31 case AL_DISTORTION_EDGE:
32 if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
33 throw effect_exception{AL_INVALID_VALUE, "Distortion edge out of range"};
34 props->Distortion.Edge = val;
35 break;
37 case AL_DISTORTION_GAIN:
38 if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
39 throw effect_exception{AL_INVALID_VALUE, "Distortion gain out of range"};
40 props->Distortion.Gain = val;
41 break;
43 case AL_DISTORTION_LOWPASS_CUTOFF:
44 if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
45 throw effect_exception{AL_INVALID_VALUE, "Distortion low-pass cutoff out of range"};
46 props->Distortion.LowpassCutoff = val;
47 break;
49 case AL_DISTORTION_EQCENTER:
50 if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
51 throw effect_exception{AL_INVALID_VALUE, "Distortion EQ center out of range"};
52 props->Distortion.EQCenter = val;
53 break;
55 case AL_DISTORTION_EQBANDWIDTH:
56 if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
57 throw effect_exception{AL_INVALID_VALUE, "Distortion EQ bandwidth out of range"};
58 props->Distortion.EQBandwidth = val;
59 break;
61 default:
62 throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
65 void Distortion_setParamfv(EffectProps *props, ALenum param, const float *vals)
66 { Distortion_setParamf(props, param, vals[0]); }
68 void Distortion_getParami(const EffectProps*, ALenum param, int*)
69 { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
70 void Distortion_getParamiv(const EffectProps*, ALenum param, int*)
72 throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
73 param};
75 void Distortion_getParamf(const EffectProps *props, ALenum param, float *val)
77 switch(param)
79 case AL_DISTORTION_EDGE:
80 *val = props->Distortion.Edge;
81 break;
83 case AL_DISTORTION_GAIN:
84 *val = props->Distortion.Gain;
85 break;
87 case AL_DISTORTION_LOWPASS_CUTOFF:
88 *val = props->Distortion.LowpassCutoff;
89 break;
91 case AL_DISTORTION_EQCENTER:
92 *val = props->Distortion.EQCenter;
93 break;
95 case AL_DISTORTION_EQBANDWIDTH:
96 *val = props->Distortion.EQBandwidth;
97 break;
99 default:
100 throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
103 void Distortion_getParamfv(const EffectProps *props, ALenum param, float *vals)
104 { Distortion_getParamf(props, param, vals); }
106 EffectProps genDefaultProps() noexcept
108 EffectProps props{};
109 props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
110 props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
111 props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
112 props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
113 props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
114 return props;
117 } // namespace
119 DEFINE_ALEFFECT_VTABLE(Distortion);
121 const EffectProps DistortionEffectProps{genDefaultProps()};
123 #ifdef ALSOFT_EAX
124 namespace {
126 using EaxDistortionEffectDirtyFlagsValue = std::uint_least8_t;
128 struct EaxDistortionEffectDirtyFlags
130 using EaxIsBitFieldStruct = bool;
132 EaxDistortionEffectDirtyFlagsValue flEdge : 1;
133 EaxDistortionEffectDirtyFlagsValue lGain : 1;
134 EaxDistortionEffectDirtyFlagsValue flLowPassCutOff : 1;
135 EaxDistortionEffectDirtyFlagsValue flEQCenter : 1;
136 EaxDistortionEffectDirtyFlagsValue flEQBandwidth : 1;
137 }; // EaxDistortionEffectDirtyFlags
140 class EaxDistortionEffect final :
141 public EaxEffect
143 public:
144 EaxDistortionEffect();
147 // [[nodiscard]]
148 bool dispatch(
149 const EaxEaxCall& eax_call) override;
152 private:
153 EAXDISTORTIONPROPERTIES eax_{};
154 EAXDISTORTIONPROPERTIES eax_d_{};
155 EaxDistortionEffectDirtyFlags eax_dirty_flags_{};
158 void set_eax_defaults();
161 void set_efx_edge();
163 void set_efx_gain();
165 void set_efx_lowpass_cutoff();
167 void set_efx_eq_center();
169 void set_efx_eq_bandwidth();
171 void set_efx_defaults();
174 // [[nodiscard]]
175 bool get(
176 const EaxEaxCall& eax_call);
179 void validate_edge(
180 float flEdge);
182 void validate_gain(
183 long lGain);
185 void validate_lowpass_cutoff(
186 float flLowPassCutOff);
188 void validate_eq_center(
189 float flEQCenter);
191 void validate_eq_bandwidth(
192 float flEQBandwidth);
194 void validate_all(
195 const EAXDISTORTIONPROPERTIES& eax_all);
198 void defer_edge(
199 float flEdge);
201 void defer_gain(
202 long lGain);
204 void defer_low_pass_cutoff(
205 float flLowPassCutOff);
207 void defer_eq_center(
208 float flEQCenter);
210 void defer_eq_bandwidth(
211 float flEQBandwidth);
213 void defer_all(
214 const EAXDISTORTIONPROPERTIES& eax_all);
217 void defer_edge(
218 const EaxEaxCall& eax_call);
220 void defer_gain(
221 const EaxEaxCall& eax_call);
223 void defer_low_pass_cutoff(
224 const EaxEaxCall& eax_call);
226 void defer_eq_center(
227 const EaxEaxCall& eax_call);
229 void defer_eq_bandwidth(
230 const EaxEaxCall& eax_call);
232 void defer_all(
233 const EaxEaxCall& eax_call);
236 // [[nodiscard]]
237 bool apply_deferred();
239 // [[nodiscard]]
240 bool set(
241 const EaxEaxCall& eax_call);
242 }; // EaxDistortionEffect
245 class EaxDistortionEffectException :
246 public EaxException
248 public:
249 explicit EaxDistortionEffectException(
250 const char* message)
252 EaxException{"EAX_DISTORTION_EFFECT", message}
255 }; // EaxDistortionEffectException
258 EaxDistortionEffect::EaxDistortionEffect()
259 : EaxEffect{AL_EFFECT_DISTORTION}
261 set_eax_defaults();
262 set_efx_defaults();
265 // [[nodiscard]]
266 bool EaxDistortionEffect::dispatch(
267 const EaxEaxCall& eax_call)
269 return eax_call.is_get() ? get(eax_call) : set(eax_call);
272 void EaxDistortionEffect::set_eax_defaults()
274 eax_.flEdge = EAXDISTORTION_DEFAULTEDGE;
275 eax_.lGain = EAXDISTORTION_DEFAULTGAIN;
276 eax_.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF;
277 eax_.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER;
278 eax_.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH;
280 eax_d_ = eax_;
283 void EaxDistortionEffect::set_efx_edge()
285 const auto edge = clamp(
286 eax_.flEdge,
287 AL_DISTORTION_MIN_EDGE,
288 AL_DISTORTION_MAX_EDGE);
290 al_effect_props_.Distortion.Edge = edge;
293 void EaxDistortionEffect::set_efx_gain()
295 const auto gain = clamp(
296 level_mb_to_gain(static_cast<float>(eax_.lGain)),
297 AL_DISTORTION_MIN_GAIN,
298 AL_DISTORTION_MAX_GAIN);
300 al_effect_props_.Distortion.Gain = gain;
303 void EaxDistortionEffect::set_efx_lowpass_cutoff()
305 const auto lowpass_cutoff = clamp(
306 eax_.flLowPassCutOff,
307 AL_DISTORTION_MIN_LOWPASS_CUTOFF,
308 AL_DISTORTION_MAX_LOWPASS_CUTOFF);
310 al_effect_props_.Distortion.LowpassCutoff = lowpass_cutoff;
313 void EaxDistortionEffect::set_efx_eq_center()
315 const auto eq_center = clamp(
316 eax_.flEQCenter,
317 AL_DISTORTION_MIN_EQCENTER,
318 AL_DISTORTION_MAX_EQCENTER);
320 al_effect_props_.Distortion.EQCenter = eq_center;
323 void EaxDistortionEffect::set_efx_eq_bandwidth()
325 const auto eq_bandwidth = clamp(
326 eax_.flEdge,
327 AL_DISTORTION_MIN_EQBANDWIDTH,
328 AL_DISTORTION_MAX_EQBANDWIDTH);
330 al_effect_props_.Distortion.EQBandwidth = eq_bandwidth;
333 void EaxDistortionEffect::set_efx_defaults()
335 set_efx_edge();
336 set_efx_gain();
337 set_efx_lowpass_cutoff();
338 set_efx_eq_center();
339 set_efx_eq_bandwidth();
342 // [[nodiscard]]
343 bool EaxDistortionEffect::get(
344 const EaxEaxCall& eax_call)
346 switch (eax_call.get_property_id())
348 case EAXDISTORTION_NONE:
349 break;
351 case EAXDISTORTION_ALLPARAMETERS:
352 eax_call.set_value<EaxDistortionEffectException>(eax_);
353 break;
355 case EAXDISTORTION_EDGE:
356 eax_call.set_value<EaxDistortionEffectException>(eax_.flEdge);
357 break;
359 case EAXDISTORTION_GAIN:
360 eax_call.set_value<EaxDistortionEffectException>(eax_.lGain);
361 break;
363 case EAXDISTORTION_LOWPASSCUTOFF:
364 eax_call.set_value<EaxDistortionEffectException>(eax_.flLowPassCutOff);
365 break;
367 case EAXDISTORTION_EQCENTER:
368 eax_call.set_value<EaxDistortionEffectException>(eax_.flEQCenter);
369 break;
371 case EAXDISTORTION_EQBANDWIDTH:
372 eax_call.set_value<EaxDistortionEffectException>(eax_.flEQBandwidth);
373 break;
375 default:
376 throw EaxDistortionEffectException{"Unsupported property id."};
379 return false;
382 void EaxDistortionEffect::validate_edge(
383 float flEdge)
385 eax_validate_range<EaxDistortionEffectException>(
386 "Edge",
387 flEdge,
388 EAXDISTORTION_MINEDGE,
389 EAXDISTORTION_MAXEDGE);
392 void EaxDistortionEffect::validate_gain(
393 long lGain)
395 eax_validate_range<EaxDistortionEffectException>(
396 "Gain",
397 lGain,
398 EAXDISTORTION_MINGAIN,
399 EAXDISTORTION_MAXGAIN);
402 void EaxDistortionEffect::validate_lowpass_cutoff(
403 float flLowPassCutOff)
405 eax_validate_range<EaxDistortionEffectException>(
406 "Low-pass Cut-off",
407 flLowPassCutOff,
408 EAXDISTORTION_MINLOWPASSCUTOFF,
409 EAXDISTORTION_MAXLOWPASSCUTOFF);
412 void EaxDistortionEffect::validate_eq_center(
413 float flEQCenter)
415 eax_validate_range<EaxDistortionEffectException>(
416 "EQ Center",
417 flEQCenter,
418 EAXDISTORTION_MINEQCENTER,
419 EAXDISTORTION_MAXEQCENTER);
422 void EaxDistortionEffect::validate_eq_bandwidth(
423 float flEQBandwidth)
425 eax_validate_range<EaxDistortionEffectException>(
426 "EQ Bandwidth",
427 flEQBandwidth,
428 EAXDISTORTION_MINEQBANDWIDTH,
429 EAXDISTORTION_MAXEQBANDWIDTH);
432 void EaxDistortionEffect::validate_all(
433 const EAXDISTORTIONPROPERTIES& eax_all)
435 validate_edge(eax_all.flEdge);
436 validate_gain(eax_all.lGain);
437 validate_lowpass_cutoff(eax_all.flLowPassCutOff);
438 validate_eq_center(eax_all.flEQCenter);
439 validate_eq_bandwidth(eax_all.flEQBandwidth);
442 void EaxDistortionEffect::defer_edge(
443 float flEdge)
445 eax_d_.flEdge = flEdge;
446 eax_dirty_flags_.flEdge = (eax_.flEdge != eax_d_.flEdge);
449 void EaxDistortionEffect::defer_gain(
450 long lGain)
452 eax_d_.lGain = lGain;
453 eax_dirty_flags_.lGain = (eax_.lGain != eax_d_.lGain);
456 void EaxDistortionEffect::defer_low_pass_cutoff(
457 float flLowPassCutOff)
459 eax_d_.flLowPassCutOff = flLowPassCutOff;
460 eax_dirty_flags_.flLowPassCutOff = (eax_.flLowPassCutOff != eax_d_.flLowPassCutOff);
463 void EaxDistortionEffect::defer_eq_center(
464 float flEQCenter)
466 eax_d_.flEQCenter = flEQCenter;
467 eax_dirty_flags_.flEQCenter = (eax_.flEQCenter != eax_d_.flEQCenter);
470 void EaxDistortionEffect::defer_eq_bandwidth(
471 float flEQBandwidth)
473 eax_d_.flEQBandwidth = flEQBandwidth;
474 eax_dirty_flags_.flEQBandwidth = (eax_.flEQBandwidth != eax_d_.flEQBandwidth);
477 void EaxDistortionEffect::defer_all(
478 const EAXDISTORTIONPROPERTIES& eax_all)
480 defer_edge(eax_all.flEdge);
481 defer_gain(eax_all.lGain);
482 defer_low_pass_cutoff(eax_all.flLowPassCutOff);
483 defer_eq_center(eax_all.flEQCenter);
484 defer_eq_bandwidth(eax_all.flEQBandwidth);
487 void EaxDistortionEffect::defer_edge(
488 const EaxEaxCall& eax_call)
490 const auto& edge =
491 eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEdge)>();
493 validate_edge(edge);
494 defer_edge(edge);
497 void EaxDistortionEffect::defer_gain(
498 const EaxEaxCall& eax_call)
500 const auto& gain =
501 eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::lGain)>();
503 validate_gain(gain);
504 defer_gain(gain);
507 void EaxDistortionEffect::defer_low_pass_cutoff(
508 const EaxEaxCall& eax_call)
510 const auto& lowpass_cutoff =
511 eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flLowPassCutOff)>();
513 validate_lowpass_cutoff(lowpass_cutoff);
514 defer_low_pass_cutoff(lowpass_cutoff);
517 void EaxDistortionEffect::defer_eq_center(
518 const EaxEaxCall& eax_call)
520 const auto& eq_center =
521 eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQCenter)>();
523 validate_eq_center(eq_center);
524 defer_eq_center(eq_center);
527 void EaxDistortionEffect::defer_eq_bandwidth(
528 const EaxEaxCall& eax_call)
530 const auto& eq_bandwidth =
531 eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEQBandwidth)>();
533 validate_eq_bandwidth(eq_bandwidth);
534 defer_eq_bandwidth(eq_bandwidth);
537 void EaxDistortionEffect::defer_all(
538 const EaxEaxCall& eax_call)
540 const auto& all =
541 eax_call.get_value<EaxDistortionEffectException, const EAXDISTORTIONPROPERTIES>();
543 validate_all(all);
544 defer_all(all);
547 // [[nodiscard]]
548 bool EaxDistortionEffect::apply_deferred()
550 if (eax_dirty_flags_ == EaxDistortionEffectDirtyFlags{})
552 return false;
555 eax_ = eax_d_;
557 if (eax_dirty_flags_.flEdge)
559 set_efx_edge();
562 if (eax_dirty_flags_.lGain)
564 set_efx_gain();
567 if (eax_dirty_flags_.flLowPassCutOff)
569 set_efx_lowpass_cutoff();
572 if (eax_dirty_flags_.flEQCenter)
574 set_efx_eq_center();
577 if (eax_dirty_flags_.flEQBandwidth)
579 set_efx_eq_bandwidth();
582 eax_dirty_flags_ = EaxDistortionEffectDirtyFlags{};
584 return true;
587 // [[nodiscard]]
588 bool EaxDistortionEffect::set(
589 const EaxEaxCall& eax_call)
591 switch (eax_call.get_property_id())
593 case EAXDISTORTION_NONE:
594 break;
596 case EAXDISTORTION_ALLPARAMETERS:
597 defer_all(eax_call);
598 break;
600 case EAXDISTORTION_EDGE:
601 defer_edge(eax_call);
602 break;
604 case EAXDISTORTION_GAIN:
605 defer_gain(eax_call);
606 break;
608 case EAXDISTORTION_LOWPASSCUTOFF:
609 defer_low_pass_cutoff(eax_call);
610 break;
612 case EAXDISTORTION_EQCENTER:
613 defer_eq_center(eax_call);
614 break;
616 case EAXDISTORTION_EQBANDWIDTH:
617 defer_eq_bandwidth(eax_call);
618 break;
620 default:
621 throw EaxDistortionEffectException{"Unsupported property id."};
624 if (!eax_call.is_deferred())
626 return apply_deferred();
629 return false;
632 } // namespace
634 EaxEffectUPtr eax_create_eax_distortion_effect()
636 return std::make_unique<EaxDistortionEffect>();
639 #endif // ALSOFT_EAX