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();
146 void dispatch(const EaxEaxCall
& eax_call
) override
;
149 bool apply_deferred() override
;
152 EAXDISTORTIONPROPERTIES eax_
{};
153 EAXDISTORTIONPROPERTIES eax_d_
{};
154 EaxDistortionEffectDirtyFlags eax_dirty_flags_
{};
156 void set_eax_defaults();
160 void set_efx_lowpass_cutoff();
161 void set_efx_eq_center();
162 void set_efx_eq_bandwidth();
163 void set_efx_defaults();
165 void get(const EaxEaxCall
& eax_call
);
167 void validate_edge(float flEdge
);
168 void validate_gain(long lGain
);
169 void validate_lowpass_cutoff(float flLowPassCutOff
);
170 void validate_eq_center(float flEQCenter
);
171 void validate_eq_bandwidth(float flEQBandwidth
);
172 void validate_all(const EAXDISTORTIONPROPERTIES
& eax_all
);
174 void defer_edge(float flEdge
);
175 void defer_gain(long lGain
);
176 void defer_low_pass_cutoff(float flLowPassCutOff
);
177 void defer_eq_center(float flEQCenter
);
178 void defer_eq_bandwidth(float flEQBandwidth
);
179 void defer_all(const EAXDISTORTIONPROPERTIES
& eax_all
);
181 void defer_edge(const EaxEaxCall
& eax_call
);
182 void defer_gain(const EaxEaxCall
& eax_call
);
183 void defer_low_pass_cutoff(const EaxEaxCall
& eax_call
);
184 void defer_eq_center(const EaxEaxCall
& eax_call
);
185 void defer_eq_bandwidth(const EaxEaxCall
& eax_call
);
186 void defer_all(const EaxEaxCall
& eax_call
);
188 void set(const EaxEaxCall
& eax_call
);
189 }; // EaxDistortionEffect
192 class EaxDistortionEffectException
:
196 explicit EaxDistortionEffectException(
199 EaxException
{"EAX_DISTORTION_EFFECT", message
}
202 }; // EaxDistortionEffectException
205 EaxDistortionEffect::EaxDistortionEffect()
206 : EaxEffect
{AL_EFFECT_DISTORTION
}
212 void EaxDistortionEffect::dispatch(const EaxEaxCall
& eax_call
)
214 eax_call
.is_get() ? get(eax_call
) : set(eax_call
);
217 void EaxDistortionEffect::set_eax_defaults()
219 eax_
.flEdge
= EAXDISTORTION_DEFAULTEDGE
;
220 eax_
.lGain
= EAXDISTORTION_DEFAULTGAIN
;
221 eax_
.flLowPassCutOff
= EAXDISTORTION_DEFAULTLOWPASSCUTOFF
;
222 eax_
.flEQCenter
= EAXDISTORTION_DEFAULTEQCENTER
;
223 eax_
.flEQBandwidth
= EAXDISTORTION_DEFAULTEQBANDWIDTH
;
228 void EaxDistortionEffect::set_efx_edge()
230 const auto edge
= clamp(
232 AL_DISTORTION_MIN_EDGE
,
233 AL_DISTORTION_MAX_EDGE
);
235 al_effect_props_
.Distortion
.Edge
= edge
;
238 void EaxDistortionEffect::set_efx_gain()
240 const auto gain
= clamp(
241 level_mb_to_gain(static_cast<float>(eax_
.lGain
)),
242 AL_DISTORTION_MIN_GAIN
,
243 AL_DISTORTION_MAX_GAIN
);
245 al_effect_props_
.Distortion
.Gain
= gain
;
248 void EaxDistortionEffect::set_efx_lowpass_cutoff()
250 const auto lowpass_cutoff
= clamp(
251 eax_
.flLowPassCutOff
,
252 AL_DISTORTION_MIN_LOWPASS_CUTOFF
,
253 AL_DISTORTION_MAX_LOWPASS_CUTOFF
);
255 al_effect_props_
.Distortion
.LowpassCutoff
= lowpass_cutoff
;
258 void EaxDistortionEffect::set_efx_eq_center()
260 const auto eq_center
= clamp(
262 AL_DISTORTION_MIN_EQCENTER
,
263 AL_DISTORTION_MAX_EQCENTER
);
265 al_effect_props_
.Distortion
.EQCenter
= eq_center
;
268 void EaxDistortionEffect::set_efx_eq_bandwidth()
270 const auto eq_bandwidth
= clamp(
272 AL_DISTORTION_MIN_EQBANDWIDTH
,
273 AL_DISTORTION_MAX_EQBANDWIDTH
);
275 al_effect_props_
.Distortion
.EQBandwidth
= eq_bandwidth
;
278 void EaxDistortionEffect::set_efx_defaults()
282 set_efx_lowpass_cutoff();
284 set_efx_eq_bandwidth();
287 void EaxDistortionEffect::get(const EaxEaxCall
& eax_call
)
289 switch(eax_call
.get_property_id())
291 case EAXDISTORTION_NONE
:
294 case EAXDISTORTION_ALLPARAMETERS
:
295 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
);
298 case EAXDISTORTION_EDGE
:
299 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flEdge
);
302 case EAXDISTORTION_GAIN
:
303 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.lGain
);
306 case EAXDISTORTION_LOWPASSCUTOFF
:
307 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flLowPassCutOff
);
310 case EAXDISTORTION_EQCENTER
:
311 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flEQCenter
);
314 case EAXDISTORTION_EQBANDWIDTH
:
315 eax_call
.set_value
<EaxDistortionEffectException
>(eax_
.flEQBandwidth
);
319 throw EaxDistortionEffectException
{"Unsupported property id."};
323 void EaxDistortionEffect::validate_edge(
326 eax_validate_range
<EaxDistortionEffectException
>(
329 EAXDISTORTION_MINEDGE
,
330 EAXDISTORTION_MAXEDGE
);
333 void EaxDistortionEffect::validate_gain(
336 eax_validate_range
<EaxDistortionEffectException
>(
339 EAXDISTORTION_MINGAIN
,
340 EAXDISTORTION_MAXGAIN
);
343 void EaxDistortionEffect::validate_lowpass_cutoff(
344 float flLowPassCutOff
)
346 eax_validate_range
<EaxDistortionEffectException
>(
349 EAXDISTORTION_MINLOWPASSCUTOFF
,
350 EAXDISTORTION_MAXLOWPASSCUTOFF
);
353 void EaxDistortionEffect::validate_eq_center(
356 eax_validate_range
<EaxDistortionEffectException
>(
359 EAXDISTORTION_MINEQCENTER
,
360 EAXDISTORTION_MAXEQCENTER
);
363 void EaxDistortionEffect::validate_eq_bandwidth(
366 eax_validate_range
<EaxDistortionEffectException
>(
369 EAXDISTORTION_MINEQBANDWIDTH
,
370 EAXDISTORTION_MAXEQBANDWIDTH
);
373 void EaxDistortionEffect::validate_all(
374 const EAXDISTORTIONPROPERTIES
& eax_all
)
376 validate_edge(eax_all
.flEdge
);
377 validate_gain(eax_all
.lGain
);
378 validate_lowpass_cutoff(eax_all
.flLowPassCutOff
);
379 validate_eq_center(eax_all
.flEQCenter
);
380 validate_eq_bandwidth(eax_all
.flEQBandwidth
);
383 void EaxDistortionEffect::defer_edge(
386 eax_d_
.flEdge
= flEdge
;
387 eax_dirty_flags_
.flEdge
= (eax_
.flEdge
!= eax_d_
.flEdge
);
390 void EaxDistortionEffect::defer_gain(
393 eax_d_
.lGain
= lGain
;
394 eax_dirty_flags_
.lGain
= (eax_
.lGain
!= eax_d_
.lGain
);
397 void EaxDistortionEffect::defer_low_pass_cutoff(
398 float flLowPassCutOff
)
400 eax_d_
.flLowPassCutOff
= flLowPassCutOff
;
401 eax_dirty_flags_
.flLowPassCutOff
= (eax_
.flLowPassCutOff
!= eax_d_
.flLowPassCutOff
);
404 void EaxDistortionEffect::defer_eq_center(
407 eax_d_
.flEQCenter
= flEQCenter
;
408 eax_dirty_flags_
.flEQCenter
= (eax_
.flEQCenter
!= eax_d_
.flEQCenter
);
411 void EaxDistortionEffect::defer_eq_bandwidth(
414 eax_d_
.flEQBandwidth
= flEQBandwidth
;
415 eax_dirty_flags_
.flEQBandwidth
= (eax_
.flEQBandwidth
!= eax_d_
.flEQBandwidth
);
418 void EaxDistortionEffect::defer_all(
419 const EAXDISTORTIONPROPERTIES
& eax_all
)
421 defer_edge(eax_all
.flEdge
);
422 defer_gain(eax_all
.lGain
);
423 defer_low_pass_cutoff(eax_all
.flLowPassCutOff
);
424 defer_eq_center(eax_all
.flEQCenter
);
425 defer_eq_bandwidth(eax_all
.flEQBandwidth
);
428 void EaxDistortionEffect::defer_edge(
429 const EaxEaxCall
& eax_call
)
432 eax_call
.get_value
<EaxDistortionEffectException
, const decltype(EAXDISTORTIONPROPERTIES::flEdge
)>();
438 void EaxDistortionEffect::defer_gain(
439 const EaxEaxCall
& eax_call
)
442 eax_call
.get_value
<EaxDistortionEffectException
, const decltype(EAXDISTORTIONPROPERTIES::lGain
)>();
448 void EaxDistortionEffect::defer_low_pass_cutoff(
449 const EaxEaxCall
& eax_call
)
451 const auto& lowpass_cutoff
=
452 eax_call
.get_value
<EaxDistortionEffectException
, const decltype(EAXDISTORTIONPROPERTIES::flLowPassCutOff
)>();
454 validate_lowpass_cutoff(lowpass_cutoff
);
455 defer_low_pass_cutoff(lowpass_cutoff
);
458 void EaxDistortionEffect::defer_eq_center(
459 const EaxEaxCall
& eax_call
)
461 const auto& eq_center
=
462 eax_call
.get_value
<EaxDistortionEffectException
, const decltype(EAXDISTORTIONPROPERTIES::flEQCenter
)>();
464 validate_eq_center(eq_center
);
465 defer_eq_center(eq_center
);
468 void EaxDistortionEffect::defer_eq_bandwidth(
469 const EaxEaxCall
& eax_call
)
471 const auto& eq_bandwidth
=
472 eax_call
.get_value
<EaxDistortionEffectException
, const decltype(EAXDISTORTIONPROPERTIES::flEQBandwidth
)>();
474 validate_eq_bandwidth(eq_bandwidth
);
475 defer_eq_bandwidth(eq_bandwidth
);
478 void EaxDistortionEffect::defer_all(
479 const EaxEaxCall
& eax_call
)
482 eax_call
.get_value
<EaxDistortionEffectException
, const EAXDISTORTIONPROPERTIES
>();
489 bool EaxDistortionEffect::apply_deferred()
491 if (eax_dirty_flags_
== EaxDistortionEffectDirtyFlags
{})
498 if (eax_dirty_flags_
.flEdge
)
503 if (eax_dirty_flags_
.lGain
)
508 if (eax_dirty_flags_
.flLowPassCutOff
)
510 set_efx_lowpass_cutoff();
513 if (eax_dirty_flags_
.flEQCenter
)
518 if (eax_dirty_flags_
.flEQBandwidth
)
520 set_efx_eq_bandwidth();
523 eax_dirty_flags_
= EaxDistortionEffectDirtyFlags
{};
528 void EaxDistortionEffect::set(const EaxEaxCall
& eax_call
)
530 switch(eax_call
.get_property_id())
532 case EAXDISTORTION_NONE
:
535 case EAXDISTORTION_ALLPARAMETERS
:
539 case EAXDISTORTION_EDGE
:
540 defer_edge(eax_call
);
543 case EAXDISTORTION_GAIN
:
544 defer_gain(eax_call
);
547 case EAXDISTORTION_LOWPASSCUTOFF
:
548 defer_low_pass_cutoff(eax_call
);
551 case EAXDISTORTION_EQCENTER
:
552 defer_eq_center(eax_call
);
555 case EAXDISTORTION_EQBANDWIDTH
:
556 defer_eq_bandwidth(eax_call
);
560 throw EaxDistortionEffectException
{"Unsupported property id."};
566 EaxEffectUPtr
eax_create_eax_distortion_effect()
568 return std::make_unique
<EaxDistortionEffect
>();