Move EAX files to their own sub-directory
[openal-soft.git] / al / effects / distortion.cpp
blob441b89a068ecc2283ce8ffd5f928f9dc04bc3103
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();
146 void dispatch(const EaxEaxCall& eax_call) override;
148 // [[nodiscard]]
149 bool apply_deferred() override;
151 private:
152 EAXDISTORTIONPROPERTIES eax_{};
153 EAXDISTORTIONPROPERTIES eax_d_{};
154 EaxDistortionEffectDirtyFlags eax_dirty_flags_{};
156 void set_eax_defaults();
158 void set_efx_edge();
159 void set_efx_gain();
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 :
193 public EaxException
195 public:
196 explicit EaxDistortionEffectException(
197 const char* message)
199 EaxException{"EAX_DISTORTION_EFFECT", message}
202 }; // EaxDistortionEffectException
205 EaxDistortionEffect::EaxDistortionEffect()
206 : EaxEffect{AL_EFFECT_DISTORTION}
208 set_eax_defaults();
209 set_efx_defaults();
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;
225 eax_d_ = eax_;
228 void EaxDistortionEffect::set_efx_edge()
230 const auto edge = clamp(
231 eax_.flEdge,
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(
261 eax_.flEQCenter,
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(
271 eax_.flEdge,
272 AL_DISTORTION_MIN_EQBANDWIDTH,
273 AL_DISTORTION_MAX_EQBANDWIDTH);
275 al_effect_props_.Distortion.EQBandwidth = eq_bandwidth;
278 void EaxDistortionEffect::set_efx_defaults()
280 set_efx_edge();
281 set_efx_gain();
282 set_efx_lowpass_cutoff();
283 set_efx_eq_center();
284 set_efx_eq_bandwidth();
287 void EaxDistortionEffect::get(const EaxEaxCall& eax_call)
289 switch(eax_call.get_property_id())
291 case EAXDISTORTION_NONE:
292 break;
294 case EAXDISTORTION_ALLPARAMETERS:
295 eax_call.set_value<EaxDistortionEffectException>(eax_);
296 break;
298 case EAXDISTORTION_EDGE:
299 eax_call.set_value<EaxDistortionEffectException>(eax_.flEdge);
300 break;
302 case EAXDISTORTION_GAIN:
303 eax_call.set_value<EaxDistortionEffectException>(eax_.lGain);
304 break;
306 case EAXDISTORTION_LOWPASSCUTOFF:
307 eax_call.set_value<EaxDistortionEffectException>(eax_.flLowPassCutOff);
308 break;
310 case EAXDISTORTION_EQCENTER:
311 eax_call.set_value<EaxDistortionEffectException>(eax_.flEQCenter);
312 break;
314 case EAXDISTORTION_EQBANDWIDTH:
315 eax_call.set_value<EaxDistortionEffectException>(eax_.flEQBandwidth);
316 break;
318 default:
319 throw EaxDistortionEffectException{"Unsupported property id."};
323 void EaxDistortionEffect::validate_edge(
324 float flEdge)
326 eax_validate_range<EaxDistortionEffectException>(
327 "Edge",
328 flEdge,
329 EAXDISTORTION_MINEDGE,
330 EAXDISTORTION_MAXEDGE);
333 void EaxDistortionEffect::validate_gain(
334 long lGain)
336 eax_validate_range<EaxDistortionEffectException>(
337 "Gain",
338 lGain,
339 EAXDISTORTION_MINGAIN,
340 EAXDISTORTION_MAXGAIN);
343 void EaxDistortionEffect::validate_lowpass_cutoff(
344 float flLowPassCutOff)
346 eax_validate_range<EaxDistortionEffectException>(
347 "Low-pass Cut-off",
348 flLowPassCutOff,
349 EAXDISTORTION_MINLOWPASSCUTOFF,
350 EAXDISTORTION_MAXLOWPASSCUTOFF);
353 void EaxDistortionEffect::validate_eq_center(
354 float flEQCenter)
356 eax_validate_range<EaxDistortionEffectException>(
357 "EQ Center",
358 flEQCenter,
359 EAXDISTORTION_MINEQCENTER,
360 EAXDISTORTION_MAXEQCENTER);
363 void EaxDistortionEffect::validate_eq_bandwidth(
364 float flEQBandwidth)
366 eax_validate_range<EaxDistortionEffectException>(
367 "EQ Bandwidth",
368 flEQBandwidth,
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(
384 float flEdge)
386 eax_d_.flEdge = flEdge;
387 eax_dirty_flags_.flEdge = (eax_.flEdge != eax_d_.flEdge);
390 void EaxDistortionEffect::defer_gain(
391 long lGain)
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(
405 float flEQCenter)
407 eax_d_.flEQCenter = flEQCenter;
408 eax_dirty_flags_.flEQCenter = (eax_.flEQCenter != eax_d_.flEQCenter);
411 void EaxDistortionEffect::defer_eq_bandwidth(
412 float flEQBandwidth)
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)
431 const auto& edge =
432 eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::flEdge)>();
434 validate_edge(edge);
435 defer_edge(edge);
438 void EaxDistortionEffect::defer_gain(
439 const EaxEaxCall& eax_call)
441 const auto& gain =
442 eax_call.get_value<EaxDistortionEffectException, const decltype(EAXDISTORTIONPROPERTIES::lGain)>();
444 validate_gain(gain);
445 defer_gain(gain);
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)
481 const auto& all =
482 eax_call.get_value<EaxDistortionEffectException, const EAXDISTORTIONPROPERTIES>();
484 validate_all(all);
485 defer_all(all);
488 // [[nodiscard]]
489 bool EaxDistortionEffect::apply_deferred()
491 if (eax_dirty_flags_ == EaxDistortionEffectDirtyFlags{})
493 return false;
496 eax_ = eax_d_;
498 if (eax_dirty_flags_.flEdge)
500 set_efx_edge();
503 if (eax_dirty_flags_.lGain)
505 set_efx_gain();
508 if (eax_dirty_flags_.flLowPassCutOff)
510 set_efx_lowpass_cutoff();
513 if (eax_dirty_flags_.flEQCenter)
515 set_efx_eq_center();
518 if (eax_dirty_flags_.flEQBandwidth)
520 set_efx_eq_bandwidth();
523 eax_dirty_flags_ = EaxDistortionEffectDirtyFlags{};
525 return true;
528 void EaxDistortionEffect::set(const EaxEaxCall& eax_call)
530 switch(eax_call.get_property_id())
532 case EAXDISTORTION_NONE:
533 break;
535 case EAXDISTORTION_ALLPARAMETERS:
536 defer_all(eax_call);
537 break;
539 case EAXDISTORTION_EDGE:
540 defer_edge(eax_call);
541 break;
543 case EAXDISTORTION_GAIN:
544 defer_gain(eax_call);
545 break;
547 case EAXDISTORTION_LOWPASSCUTOFF:
548 defer_low_pass_cutoff(eax_call);
549 break;
551 case EAXDISTORTION_EQCENTER:
552 defer_eq_center(eax_call);
553 break;
555 case EAXDISTORTION_EQBANDWIDTH:
556 defer_eq_bandwidth(eax_call);
557 break;
559 default:
560 throw EaxDistortionEffectException{"Unsupported property id."};
564 } // namespace
566 EaxEffectUPtr eax_create_eax_distortion_effect()
568 return std::make_unique<EaxDistortionEffect>();
571 #endif // ALSOFT_EAX