7 #include "alc/effects/base.h"
11 #include "alnumeric.h"
13 #include "al/eax_exception.h"
14 #include "al/eax_utils.h"
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",
27 void Distortion_setParamf(EffectProps
*props
, ALenum param
, float val
)
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
;
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
;
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
;
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
;
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
;
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",
75 void Distortion_getParamf(const EffectProps
*props
, ALenum param
, float *val
)
79 case AL_DISTORTION_EDGE
:
80 *val
= props
->Distortion
.Edge
;
83 case AL_DISTORTION_GAIN
:
84 *val
= props
->Distortion
.Gain
;
87 case AL_DISTORTION_LOWPASS_CUTOFF
:
88 *val
= props
->Distortion
.LowpassCutoff
;
91 case AL_DISTORTION_EQCENTER
:
92 *val
= props
->Distortion
.EQCenter
;
95 case AL_DISTORTION_EQBANDWIDTH
:
96 *val
= props
->Distortion
.EQBandwidth
;
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
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
;
119 DEFINE_ALEFFECT_VTABLE(Distortion
);
121 const EffectProps DistortionEffectProps
{genDefaultProps()};
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
:
144 EaxDistortionEffect();
149 const EaxEaxCall
& eax_call
) override
;
153 EAXDISTORTIONPROPERTIES eax_
{};
154 EAXDISTORTIONPROPERTIES eax_d_
{};
155 EaxDistortionEffectDirtyFlags eax_dirty_flags_
{};
158 void set_eax_defaults();
165 void set_efx_lowpass_cutoff();
167 void set_efx_eq_center();
169 void set_efx_eq_bandwidth();
171 void set_efx_defaults();
176 const EaxEaxCall
& eax_call
);
185 void validate_lowpass_cutoff(
186 float flLowPassCutOff
);
188 void validate_eq_center(
191 void validate_eq_bandwidth(
192 float flEQBandwidth
);
195 const EAXDISTORTIONPROPERTIES
& eax_all
);
204 void defer_low_pass_cutoff(
205 float flLowPassCutOff
);
207 void defer_eq_center(
210 void defer_eq_bandwidth(
211 float flEQBandwidth
);
214 const EAXDISTORTIONPROPERTIES
& eax_all
);
218 const EaxEaxCall
& eax_call
);
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
);
233 const EaxEaxCall
& eax_call
);
237 bool apply_deferred();
241 const EaxEaxCall
& eax_call
);
242 }; // EaxDistortionEffect
245 class EaxDistortionEffectException
:
249 explicit EaxDistortionEffectException(
252 EaxException
{"EAX_DISTORTION_EFFECT", message
}
255 }; // EaxDistortionEffectException
258 EaxDistortionEffect::EaxDistortionEffect()
259 : EaxEffect
{AL_EFFECT_DISTORTION
}
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
;
283 void EaxDistortionEffect::set_efx_edge()
285 const auto edge
= clamp(
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(
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(
327 AL_DISTORTION_MIN_EQBANDWIDTH
,
328 AL_DISTORTION_MAX_EQBANDWIDTH
);
330 al_effect_props_
.Distortion
.EQBandwidth
= eq_bandwidth
;
333 void EaxDistortionEffect::set_efx_defaults()
337 set_efx_lowpass_cutoff();
339 set_efx_eq_bandwidth();
343 bool EaxDistortionEffect::get(
344 const EaxEaxCall
& eax_call
)
346 switch (eax_call
.get_property_id())
348 case EAXDISTORTION_NONE
:
351 case EAXDISTORTION_ALLPARAMETERS
:
352 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
);
355 case EAXDISTORTION_EDGE
:
356 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flEdge
);
359 case EAXDISTORTION_GAIN
:
360 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.lGain
);
363 case EAXDISTORTION_LOWPASSCUTOFF
:
364 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flLowPassCutOff
);
367 case EAXDISTORTION_EQCENTER
:
368 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flEQCenter
);
371 case EAXDISTORTION_EQBANDWIDTH
:
372 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flEQBandwidth
);
376 throw EaxDistortionEffectException
{"Unsupported property id."};
382 void EaxDistortionEffect::validate_edge(
385 eax_validate_range
<EaxDistortionEffectException
>(
388 EAXDISTORTION_MINEDGE
,
389 EAXDISTORTION_MAXEDGE
);
392 void EaxDistortionEffect::validate_gain(
395 eax_validate_range
<EaxDistortionEffectException
>(
398 EAXDISTORTION_MINGAIN
,
399 EAXDISTORTION_MAXGAIN
);
402 void EaxDistortionEffect::validate_lowpass_cutoff(
403 float flLowPassCutOff
)
405 eax_validate_range
<EaxDistortionEffectException
>(
408 EAXDISTORTION_MINLOWPASSCUTOFF
,
409 EAXDISTORTION_MAXLOWPASSCUTOFF
);
412 void EaxDistortionEffect::validate_eq_center(
415 eax_validate_range
<EaxDistortionEffectException
>(
418 EAXDISTORTION_MINEQCENTER
,
419 EAXDISTORTION_MAXEQCENTER
);
422 void EaxDistortionEffect::validate_eq_bandwidth(
425 eax_validate_range
<EaxDistortionEffectException
>(
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(
445 eax_d_
.flEdge
= flEdge
;
446 eax_dirty_flags_
.flEdge
= (eax_
.flEdge
!= eax_d_
.flEdge
);
449 void EaxDistortionEffect::defer_gain(
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(
466 eax_d_
.flEQCenter
= flEQCenter
;
467 eax_dirty_flags_
.flEQCenter
= (eax_
.flEQCenter
!= eax_d_
.flEQCenter
);
470 void EaxDistortionEffect::defer_eq_bandwidth(
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
)
491 eax_call
.get_value
<EaxDistortionEffectException
, const decltype(EAXDISTORTIONPROPERTIES::flEdge
)>();
497 void EaxDistortionEffect::defer_gain(
498 const EaxEaxCall
& eax_call
)
501 eax_call
.get_value
<EaxDistortionEffectException
, const decltype(EAXDISTORTIONPROPERTIES::lGain
)>();
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
)
541 eax_call
.get_value
<EaxDistortionEffectException
, const EAXDISTORTIONPROPERTIES
>();
548 bool EaxDistortionEffect::apply_deferred()
550 if (eax_dirty_flags_
== EaxDistortionEffectDirtyFlags
{})
557 if (eax_dirty_flags_
.flEdge
)
562 if (eax_dirty_flags_
.lGain
)
567 if (eax_dirty_flags_
.flLowPassCutOff
)
569 set_efx_lowpass_cutoff();
572 if (eax_dirty_flags_
.flEQCenter
)
577 if (eax_dirty_flags_
.flEQBandwidth
)
579 set_efx_eq_bandwidth();
582 eax_dirty_flags_
= EaxDistortionEffectDirtyFlags
{};
588 bool EaxDistortionEffect::set(
589 const EaxEaxCall
& eax_call
)
591 switch (eax_call
.get_property_id())
593 case EAXDISTORTION_NONE
:
596 case EAXDISTORTION_ALLPARAMETERS
:
600 case EAXDISTORTION_EDGE
:
601 defer_edge(eax_call
);
604 case EAXDISTORTION_GAIN
:
605 defer_gain(eax_call
);
608 case EAXDISTORTION_LOWPASSCUTOFF
:
609 defer_low_pass_cutoff(eax_call
);
612 case EAXDISTORTION_EQCENTER
:
613 defer_eq_center(eax_call
);
616 case EAXDISTORTION_EQBANDWIDTH
:
617 defer_eq_bandwidth(eax_call
);
621 throw EaxDistortionEffectException
{"Unsupported property id."};
624 if (!eax_call
.is_deferred())
626 return apply_deferred();
634 EaxEffectUPtr
eax_create_eax_distortion_effect()
636 return std::make_unique
<EaxDistortionEffect
>();