Check some float property values for being finite
[openal-soft.git] / al / eax / effect.h
blob9b1f8bd358d25986689d0330135e11a296061f8a
1 #ifndef EAX_EFFECT_INCLUDED
2 #define EAX_EFFECT_INCLUDED
5 #include <cassert>
6 #include <memory>
7 #include <variant>
9 #include "alnumeric.h"
10 #include "AL/al.h"
11 #include "AL/alext.h"
12 #include "core/effects/base.h"
13 #include "call.h"
15 struct EaxEffectErrorMessages {
16 static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
17 static constexpr auto unknown_version() noexcept { return "Unknown version."; }
18 }; // EaxEffectErrorMessages
20 using EaxEffectProps = std::variant<std::monostate,
21 EAXREVERBPROPERTIES,
22 EAXCHORUSPROPERTIES,
23 EAXAUTOWAHPROPERTIES,
24 EAXAGCCOMPRESSORPROPERTIES,
25 EAXDISTORTIONPROPERTIES,
26 EAXECHOPROPERTIES,
27 EAXEQUALIZERPROPERTIES,
28 EAXFLANGERPROPERTIES,
29 EAXFREQUENCYSHIFTERPROPERTIES,
30 EAXRINGMODULATORPROPERTIES,
31 EAXPITCHSHIFTERPROPERTIES,
32 EAXVOCALMORPHERPROPERTIES>;
34 template<typename... Ts>
35 struct overloaded : Ts... { using Ts::operator()...; };
37 template<typename... Ts>
38 overloaded(Ts...) -> overloaded<Ts...>;
40 constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
42 return std::visit(overloaded{
43 [](const std::monostate&) noexcept { return AL_EFFECT_NULL; },
44 [](const EAXREVERBPROPERTIES&) noexcept { return AL_EFFECT_EAXREVERB; },
45 [](const EAXCHORUSPROPERTIES&) noexcept { return AL_EFFECT_CHORUS; },
46 [](const EAXAUTOWAHPROPERTIES&) noexcept { return AL_EFFECT_AUTOWAH; },
47 [](const EAXAGCCOMPRESSORPROPERTIES&) noexcept { return AL_EFFECT_COMPRESSOR; },
48 [](const EAXDISTORTIONPROPERTIES&) noexcept { return AL_EFFECT_DISTORTION; },
49 [](const EAXECHOPROPERTIES&) noexcept { return AL_EFFECT_ECHO; },
50 [](const EAXEQUALIZERPROPERTIES&) noexcept { return AL_EFFECT_EQUALIZER; },
51 [](const EAXFLANGERPROPERTIES&) noexcept { return AL_EFFECT_FLANGER; },
52 [](const EAXFREQUENCYSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_FREQUENCY_SHIFTER; },
53 [](const EAXRINGMODULATORPROPERTIES&) noexcept { return AL_EFFECT_RING_MODULATOR; },
54 [](const EAXPITCHSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_PITCH_SHIFTER; },
55 [](const EAXVOCALMORPHERPROPERTIES&) noexcept { return AL_EFFECT_VOCAL_MORPHER; }
56 }, props);
59 struct EaxReverbCommitter {
60 struct Exception;
62 EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
63 : mEaxProps{eaxprops}, mAlProps{alprops}
64 { }
66 EaxEffectProps &mEaxProps;
67 EffectProps &mAlProps;
69 [[noreturn]] static void fail(const char* message);
70 [[noreturn]] static void fail_unknown_property_id()
71 { fail(EaxEffectErrorMessages::unknown_property_id()); }
73 template<typename TValidator, typename TProperty>
74 static void defer(const EaxCall& call, TProperty& property)
76 const auto& value = call.get_value<Exception, const TProperty>();
77 TValidator{}(value);
78 property = value;
81 template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty>
82 static void defer(const EaxCall& call, TProperties& properties, TProperty&)
84 const auto& value = call.get_value<Exception, const TProperty>();
85 TValidator{}(value);
86 TDeferrer{}(properties, value);
89 template<typename TValidator, typename TProperty>
90 static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property)
92 const auto& value = call.get_value<Exception, const TProperty>();
93 TValidator{}(value);
94 if (value == property)
95 return;
96 property = value;
97 properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED;
101 bool commit(const EAX_REVERBPROPERTIES &props);
102 bool commit(const EAX20LISTENERPROPERTIES &props);
103 bool commit(const EAXREVERBPROPERTIES &props);
105 static void SetDefaults(EAX_REVERBPROPERTIES &props);
106 static void SetDefaults(EAX20LISTENERPROPERTIES &props);
107 static void SetDefaults(EAXREVERBPROPERTIES &props);
108 static void SetDefaults(EaxEffectProps &props);
110 static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
111 static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
112 static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
114 static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
115 static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
116 static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
118 static void translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
119 static void translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
122 template<typename T>
123 struct EaxCommitter {
124 struct Exception;
126 EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
127 : mEaxProps{eaxprops}, mAlProps{alprops}
130 EaxEffectProps &mEaxProps;
131 EffectProps &mAlProps;
133 template<typename TValidator, typename TProperty>
134 static void defer(const EaxCall& call, TProperty& property)
136 const auto& value = call.get_value<Exception, const TProperty>();
137 TValidator{}(value);
138 property = value;
141 [[noreturn]] static void fail(const char *message);
142 [[noreturn]] static void fail_unknown_property_id()
143 { fail(EaxEffectErrorMessages::unknown_property_id()); }
146 struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
147 using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
149 bool commit(const EAXAUTOWAHPROPERTIES &props);
151 static void SetDefaults(EaxEffectProps &props);
152 static void Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props);
153 static void Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props);
155 struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
156 using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
158 bool commit(const EAXCHORUSPROPERTIES &props);
160 static void SetDefaults(EaxEffectProps &props);
161 static void Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props);
162 static void Set(const EaxCall &call, EAXCHORUSPROPERTIES &props);
164 struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
165 using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
167 bool commit(const EAXAGCCOMPRESSORPROPERTIES &props);
169 static void SetDefaults(EaxEffectProps &props);
170 static void Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props);
171 static void Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props);
173 struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
174 using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
176 bool commit(const EAXDISTORTIONPROPERTIES &props);
178 static void SetDefaults(EaxEffectProps &props);
179 static void Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props);
180 static void Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props);
182 struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
183 using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
185 bool commit(const EAXECHOPROPERTIES &props);
187 static void SetDefaults(EaxEffectProps &props);
188 static void Get(const EaxCall &call, const EAXECHOPROPERTIES &props);
189 static void Set(const EaxCall &call, EAXECHOPROPERTIES &props);
191 struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
192 using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
194 bool commit(const EAXEQUALIZERPROPERTIES &props);
196 static void SetDefaults(EaxEffectProps &props);
197 static void Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props);
198 static void Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props);
200 struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
201 using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
203 bool commit(const EAXFLANGERPROPERTIES &props);
205 static void SetDefaults(EaxEffectProps &props);
206 static void Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props);
207 static void Set(const EaxCall &call, EAXFLANGERPROPERTIES &props);
209 struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
210 using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
212 bool commit(const EAXFREQUENCYSHIFTERPROPERTIES &props);
214 static void SetDefaults(EaxEffectProps &props);
215 static void Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props);
216 static void Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props);
218 struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
219 using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
221 bool commit(const EAXRINGMODULATORPROPERTIES &props);
223 static void SetDefaults(EaxEffectProps &props);
224 static void Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props);
225 static void Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props);
227 struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
228 using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
230 bool commit(const EAXPITCHSHIFTERPROPERTIES &props);
232 static void SetDefaults(EaxEffectProps &props);
233 static void Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props);
234 static void Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props);
236 struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
237 using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
239 bool commit(const EAXVOCALMORPHERPROPERTIES &props);
241 static void SetDefaults(EaxEffectProps &props);
242 static void Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props);
243 static void Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props);
245 struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
246 using EaxCommitter<EaxNullCommitter>::EaxCommitter;
248 bool commit(const std::monostate &props);
250 static void SetDefaults(EaxEffectProps &props);
251 static void Get(const EaxCall &call, const std::monostate &props);
252 static void Set(const EaxCall &call, std::monostate &props);
255 template<typename T>
256 struct CommitterFromProps { };
258 template<> struct CommitterFromProps<std::monostate> { using type = EaxNullCommitter; };
259 template<> struct CommitterFromProps<EAXREVERBPROPERTIES> { using type = EaxReverbCommitter; };
260 template<> struct CommitterFromProps<EAXCHORUSPROPERTIES> { using type = EaxChorusCommitter; };
261 template<> struct CommitterFromProps<EAXAGCCOMPRESSORPROPERTIES> { using type = EaxCompressorCommitter; };
262 template<> struct CommitterFromProps<EAXAUTOWAHPROPERTIES> { using type = EaxAutowahCommitter; };
263 template<> struct CommitterFromProps<EAXDISTORTIONPROPERTIES> { using type = EaxDistortionCommitter; };
264 template<> struct CommitterFromProps<EAXECHOPROPERTIES> { using type = EaxEchoCommitter; };
265 template<> struct CommitterFromProps<EAXEQUALIZERPROPERTIES> { using type = EaxEqualizerCommitter; };
266 template<> struct CommitterFromProps<EAXFLANGERPROPERTIES> { using type = EaxFlangerCommitter; };
267 template<> struct CommitterFromProps<EAXFREQUENCYSHIFTERPROPERTIES> { using type = EaxFrequencyShifterCommitter; };
268 template<> struct CommitterFromProps<EAXRINGMODULATORPROPERTIES> { using type = EaxModulatorCommitter; };
269 template<> struct CommitterFromProps<EAXPITCHSHIFTERPROPERTIES> { using type = EaxPitchShifterCommitter; };
270 template<> struct CommitterFromProps<EAXVOCALMORPHERPROPERTIES> { using type = EaxVocalMorpherCommitter; };
272 template<typename T>
273 using CommitterFor = typename CommitterFromProps<std::remove_cv_t<std::remove_reference_t<T>>>::type;
276 class EaxEffect {
277 public:
278 EaxEffect() noexcept = default;
279 ~EaxEffect() = default;
281 ALenum al_effect_type_{AL_EFFECT_NULL};
282 EffectProps al_effect_props_{};
284 using Props1 = EAX_REVERBPROPERTIES;
285 using Props2 = EAX20LISTENERPROPERTIES;
286 using Props3 = EAXREVERBPROPERTIES;
287 using Props4 = EaxEffectProps;
289 struct State1 {
290 Props1 i; // Immediate.
291 Props1 d; // Deferred.
294 struct State2 {
295 Props2 i; // Immediate.
296 Props2 d; // Deferred.
299 struct State3 {
300 Props3 i; // Immediate.
301 Props3 d; // Deferred.
304 struct State4 {
305 Props4 i; // Immediate.
306 Props4 d; // Deferred.
309 int version_{};
310 bool changed_{};
311 Props4 props_{};
312 State1 state1_{};
313 State2 state2_{};
314 State3 state3_{};
315 State4 state4_{};
316 State4 state5_{};
319 static void call_set_defaults(const ALenum altype, EaxEffectProps &props)
321 switch(altype)
323 case AL_EFFECT_EAXREVERB: return EaxReverbCommitter::SetDefaults(props);
324 case AL_EFFECT_CHORUS: return EaxChorusCommitter::SetDefaults(props);
325 case AL_EFFECT_AUTOWAH: return EaxAutowahCommitter::SetDefaults(props);
326 case AL_EFFECT_COMPRESSOR: return EaxCompressorCommitter::SetDefaults(props);
327 case AL_EFFECT_DISTORTION: return EaxDistortionCommitter::SetDefaults(props);
328 case AL_EFFECT_ECHO: return EaxEchoCommitter::SetDefaults(props);
329 case AL_EFFECT_EQUALIZER: return EaxEqualizerCommitter::SetDefaults(props);
330 case AL_EFFECT_FLANGER: return EaxFlangerCommitter::SetDefaults(props);
331 case AL_EFFECT_FREQUENCY_SHIFTER: return EaxFrequencyShifterCommitter::SetDefaults(props);
332 case AL_EFFECT_RING_MODULATOR: return EaxModulatorCommitter::SetDefaults(props);
333 case AL_EFFECT_PITCH_SHIFTER: return EaxPitchShifterCommitter::SetDefaults(props);
334 case AL_EFFECT_VOCAL_MORPHER: return EaxVocalMorpherCommitter::SetDefaults(props);
335 case AL_EFFECT_NULL: break;
337 return EaxNullCommitter::SetDefaults(props);
340 template<typename T>
341 void init()
343 EaxReverbCommitter::SetDefaults(state1_.d);
344 state1_.i = state1_.d;
345 EaxReverbCommitter::SetDefaults(state2_.d);
346 state2_.i = state2_.d;
347 EaxReverbCommitter::SetDefaults(state3_.d);
348 state3_.i = state3_.d;
349 T::SetDefaults(state4_.d);
350 state4_.i = state4_.d;
351 T::SetDefaults(state5_.d);
352 state5_.i = state5_.d;
355 void set_defaults(int eax_version, ALenum altype)
357 switch(eax_version)
359 case 1: EaxReverbCommitter::SetDefaults(state1_.d); break;
360 case 2: EaxReverbCommitter::SetDefaults(state2_.d); break;
361 case 3: EaxReverbCommitter::SetDefaults(state3_.d); break;
362 case 4: call_set_defaults(altype, state4_.d); break;
363 case 5: call_set_defaults(altype, state5_.d); break;
365 changed_ = true;
369 static void call_set(const EaxCall &call, EaxEffectProps &props)
371 return std::visit([&](auto &arg)
372 { return CommitterFor<decltype(arg)>::Set(call, arg); },
373 props);
376 void set(const EaxCall &call)
378 switch(call.get_version())
380 case 1: EaxReverbCommitter::Set(call, state1_.d); break;
381 case 2: EaxReverbCommitter::Set(call, state2_.d); break;
382 case 3: EaxReverbCommitter::Set(call, state3_.d); break;
383 case 4: call_set(call, state4_.d); break;
384 case 5: call_set(call, state5_.d); break;
386 changed_ = true;
390 static void call_get(const EaxCall &call, const EaxEffectProps &props)
392 return std::visit([&](auto &arg)
393 { return CommitterFor<decltype(arg)>::Get(call, arg); },
394 props);
397 void get(const EaxCall &call) const
399 switch(call.get_version())
401 case 1: EaxReverbCommitter::Get(call, state1_.d); break;
402 case 2: EaxReverbCommitter::Get(call, state2_.d); break;
403 case 3: EaxReverbCommitter::Get(call, state3_.d); break;
404 case 4: call_get(call, state4_.d); break;
405 case 5: call_get(call, state5_.d); break;
410 bool call_commit(const EaxEffectProps &props)
412 return std::visit([&](auto &arg)
413 { return CommitterFor<decltype(arg)>{props_, al_effect_props_}.commit(arg); },
414 props);
417 bool commit(int eax_version)
419 changed_ |= version_ != eax_version;
420 if(!changed_) return false;
422 bool ret{version_ != eax_version};
423 version_ = eax_version;
424 changed_ = false;
426 switch(eax_version)
428 case 1:
429 state1_.i = state1_.d;
430 ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state1_.d);
431 break;
432 case 2:
433 state2_.i = state2_.d;
434 ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state2_.d);
435 break;
436 case 3:
437 state3_.i = state3_.d;
438 ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state3_.d);
439 break;
440 case 4:
441 state4_.i = state4_.d;
442 ret |= call_commit(state4_.d);
443 break;
444 case 5:
445 state5_.i = state5_.d;
446 ret |= call_commit(state5_.d);
447 break;
449 al_effect_type_ = EnumFromEaxEffectType(props_);
450 return ret;
452 #undef EAXCALL
453 }; // EaxEffect
455 using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
457 #endif // !EAX_EFFECT_INCLUDED