1 #ifndef EAX_EFFECT_INCLUDED
2 #define EAX_EFFECT_INCLUDED
10 #include "core/effects/base.h"
13 struct EaxEffectErrorMessages
15 static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
16 static constexpr auto unknown_version() noexcept { return "Unknown version."; }
17 }; // EaxEffectErrorMessages
19 /* TODO: Use std::variant (C++17). */
20 enum class EaxEffectType {
21 None, Reverb, Chorus, Autowah, Compressor, Distortion, Echo, Equalizer, Flanger,
22 FrequencyShifter, Modulator, PitchShifter, VocalMorpher
24 struct EaxEffectProps {
27 EAXREVERBPROPERTIES mReverb;
28 EAXCHORUSPROPERTIES mChorus;
29 EAXAUTOWAHPROPERTIES mAutowah;
30 EAXAGCCOMPRESSORPROPERTIES mCompressor;
31 EAXDISTORTIONPROPERTIES mDistortion;
32 EAXECHOPROPERTIES mEcho;
33 EAXEQUALIZERPROPERTIES mEqualizer;
34 EAXFLANGERPROPERTIES mFlanger;
35 EAXFREQUENCYSHIFTERPROPERTIES mFrequencyShifter;
36 EAXRINGMODULATORPROPERTIES mModulator;
37 EAXPITCHSHIFTERPROPERTIES mPitchShifter;
38 EAXVOCALMORPHERPROPERTIES mVocalMorpher;
42 constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
46 case EaxEffectType::None: break;
47 case EaxEffectType::Reverb: return AL_EFFECT_EAXREVERB;
48 case EaxEffectType::Chorus: return AL_EFFECT_CHORUS;
49 case EaxEffectType::Autowah: return AL_EFFECT_AUTOWAH;
50 case EaxEffectType::Compressor: return AL_EFFECT_COMPRESSOR;
51 case EaxEffectType::Distortion: return AL_EFFECT_DISTORTION;
52 case EaxEffectType::Echo: return AL_EFFECT_ECHO;
53 case EaxEffectType::Equalizer: return AL_EFFECT_EQUALIZER;
54 case EaxEffectType::Flanger: return AL_EFFECT_FLANGER;
55 case EaxEffectType::FrequencyShifter: return AL_EFFECT_FREQUENCY_SHIFTER;
56 case EaxEffectType::Modulator: return AL_EFFECT_RING_MODULATOR;
57 case EaxEffectType::PitchShifter: return AL_EFFECT_PITCH_SHIFTER;
58 case EaxEffectType::VocalMorpher: return AL_EFFECT_VOCAL_MORPHER;
60 return AL_EFFECT_NULL;
63 struct EaxReverbCommitter {
66 EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
67 : mEaxProps{eaxprops}, mAlProps{alprops}
70 EaxEffectProps &mEaxProps;
71 EffectProps &mAlProps;
73 [[noreturn]] static void fail(const char* message);
74 [[noreturn]] static void fail_unknown_property_id()
75 { fail(EaxEffectErrorMessages::unknown_property_id()); }
77 template<typename TValidator, typename TProperty>
78 static void defer(const EaxCall& call, TProperty& property)
80 const auto& value = call.get_value<Exception, const TProperty>();
85 template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty>
86 static void defer(const EaxCall& call, TProperties& properties, TProperty&)
88 const auto& value = call.get_value<Exception, const TProperty>();
90 TDeferrer{}(properties, value);
93 template<typename TValidator, typename TProperty>
94 static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property)
96 const auto& value = call.get_value<Exception, const TProperty>();
98 if (value == property)
101 properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED;
105 bool commit(const EAX_REVERBPROPERTIES &props);
106 bool commit(const EAX20LISTENERPROPERTIES &props);
107 bool commit(const EAXREVERBPROPERTIES &props);
108 bool commit(const EaxEffectProps &props);
110 static void SetDefaults(EAX_REVERBPROPERTIES &props);
111 static void SetDefaults(EAX20LISTENERPROPERTIES &props);
112 static void SetDefaults(EAXREVERBPROPERTIES &props);
113 static void SetDefaults(EaxEffectProps &props);
115 static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
116 static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
117 static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
118 static void Get(const EaxCall &call, const EaxEffectProps &props);
120 static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
121 static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
122 static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
123 static void Set(const EaxCall &call, EaxEffectProps &props);
125 static void translate(const EAX_REVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
126 static void translate(const EAX20LISTENERPROPERTIES& src, EaxEffectProps& dst) noexcept;
127 static void translate(const EAXREVERBPROPERTIES& src, EaxEffectProps& dst) noexcept;
131 struct EaxCommitter {
134 EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
135 : mEaxProps{eaxprops}, mAlProps{alprops}
138 EaxEffectProps &mEaxProps;
139 EffectProps &mAlProps;
141 template<typename TValidator, typename TProperty>
142 static void defer(const EaxCall& call, TProperty& property)
144 const auto& value = call.get_value<Exception, const TProperty>();
149 [[noreturn]] static void fail(const char *message);
150 [[noreturn]] static void fail_unknown_property_id()
151 { fail(EaxEffectErrorMessages::unknown_property_id()); }
153 bool commit(const EaxEffectProps &props);
155 static void SetDefaults(EaxEffectProps &props);
156 static void Get(const EaxCall &call, const EaxEffectProps &props);
157 static void Set(const EaxCall &call, EaxEffectProps &props);
160 struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
161 using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
163 struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
164 using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
166 struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
167 using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
169 struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
170 using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
172 struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
173 using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
175 struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
176 using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
178 struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
179 using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
181 struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
182 using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
184 struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
185 using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
187 struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
188 using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
190 struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
191 using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
193 struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
194 using EaxCommitter<EaxNullCommitter>::EaxCommitter;
200 EaxEffect() noexcept = default;
201 ~EaxEffect() = default;
203 ALenum al_effect_type_{AL_EFFECT_NULL};
204 EffectProps al_effect_props_{};
206 using Props1 = EAX_REVERBPROPERTIES;
207 using Props2 = EAX20LISTENERPROPERTIES;
208 using Props3 = EAXREVERBPROPERTIES;
209 using Props4 = EaxEffectProps;
212 Props1 i; // Immediate.
213 Props1 d; // Deferred.
217 Props2 i; // Immediate.
218 Props2 d; // Deferred.
222 Props3 i; // Immediate.
223 Props3 d; // Deferred.
227 Props4 i; // Immediate.
228 Props4 d; // Deferred.
241 template<typename T, typename ...Args>
242 void call_set_defaults(Args&& ...args)
243 { return T::SetDefaults(std::forward<Args>(args)...); }
245 void call_set_defaults(const ALenum altype, EaxEffectProps &props)
247 if(altype == AL_EFFECT_EAXREVERB)
248 return call_set_defaults<EaxReverbCommitter>(props);
249 if(altype == AL_EFFECT_CHORUS)
250 return call_set_defaults<EaxChorusCommitter>(props);
251 if(altype == AL_EFFECT_AUTOWAH)
252 return call_set_defaults<EaxAutowahCommitter>(props);
253 if(altype == AL_EFFECT_COMPRESSOR)
254 return call_set_defaults<EaxCompressorCommitter>(props);
255 if(altype == AL_EFFECT_DISTORTION)
256 return call_set_defaults<EaxDistortionCommitter>(props);
257 if(altype == AL_EFFECT_ECHO)
258 return call_set_defaults<EaxEchoCommitter>(props);
259 if(altype == AL_EFFECT_EQUALIZER)
260 return call_set_defaults<EaxEqualizerCommitter>(props);
261 if(altype == AL_EFFECT_FLANGER)
262 return call_set_defaults<EaxFlangerCommitter>(props);
263 if(altype == AL_EFFECT_FREQUENCY_SHIFTER)
264 return call_set_defaults<EaxFrequencyShifterCommitter>(props);
265 if(altype == AL_EFFECT_RING_MODULATOR)
266 return call_set_defaults<EaxModulatorCommitter>(props);
267 if(altype == AL_EFFECT_PITCH_SHIFTER)
268 return call_set_defaults<EaxPitchShifterCommitter>(props);
269 if(altype == AL_EFFECT_VOCAL_MORPHER)
270 return call_set_defaults<EaxVocalMorpherCommitter>(props);
271 return call_set_defaults<EaxNullCommitter>(props);
277 call_set_defaults<EaxReverbCommitter>(state1_.d);
278 state1_.i = state1_.d;
279 call_set_defaults<EaxReverbCommitter>(state2_.d);
280 state2_.i = state2_.d;
281 call_set_defaults<EaxReverbCommitter>(state3_.d);
282 state3_.i = state3_.d;
283 call_set_defaults<T>(state4_.d);
284 state4_.i = state4_.d;
285 call_set_defaults<T>(state5_.d);
286 state5_.i = state5_.d;
289 void set_defaults(int eax_version, ALenum altype)
293 case 1: call_set_defaults<EaxReverbCommitter>(state1_.d); break;
294 case 2: call_set_defaults<EaxReverbCommitter>(state2_.d); break;
295 case 3: call_set_defaults<EaxReverbCommitter>(state3_.d); break;
296 case 4: call_set_defaults(altype, state4_.d); break;
297 case 5: call_set_defaults(altype, state5_.d); break;
303 #define EAXCALL(T, Callable, ...) \
304 if(T == EaxEffectType::Reverb) \
305 return Callable<EaxReverbCommitter>(__VA_ARGS__); \
306 if(T == EaxEffectType::Chorus) \
307 return Callable<EaxChorusCommitter>(__VA_ARGS__); \
308 if(T == EaxEffectType::Autowah) \
309 return Callable<EaxAutowahCommitter>(__VA_ARGS__); \
310 if(T == EaxEffectType::Compressor) \
311 return Callable<EaxCompressorCommitter>(__VA_ARGS__); \
312 if(T == EaxEffectType::Distortion) \
313 return Callable<EaxDistortionCommitter>(__VA_ARGS__); \
314 if(T == EaxEffectType::Echo) \
315 return Callable<EaxEchoCommitter>(__VA_ARGS__); \
316 if(T == EaxEffectType::Equalizer) \
317 return Callable<EaxEqualizerCommitter>(__VA_ARGS__); \
318 if(T == EaxEffectType::Flanger) \
319 return Callable<EaxFlangerCommitter>(__VA_ARGS__); \
320 if(T == EaxEffectType::FrequencyShifter) \
321 return Callable<EaxFrequencyShifterCommitter>(__VA_ARGS__); \
322 if(T == EaxEffectType::Modulator) \
323 return Callable<EaxModulatorCommitter>(__VA_ARGS__); \
324 if(T == EaxEffectType::PitchShifter) \
325 return Callable<EaxPitchShifterCommitter>(__VA_ARGS__); \
326 if(T == EaxEffectType::VocalMorpher) \
327 return Callable<EaxVocalMorpherCommitter>(__VA_ARGS__); \
328 return Callable<EaxNullCommitter>(__VA_ARGS__)
330 template<typename T, typename ...Args>
331 static void call_set(Args&& ...args)
332 { return T::Set(std::forward<Args>(args)...); }
334 static void call_set(const EaxCall &call, EaxEffectProps &props)
335 { EAXCALL(props.mType, call_set, call, props); }
337 void set(const EaxCall &call)
339 switch(call.get_version())
341 case 1: call_set<EaxReverbCommitter>(call, state1_.d); break;
342 case 2: call_set<EaxReverbCommitter>(call, state2_.d); break;
343 case 3: call_set<EaxReverbCommitter>(call, state3_.d); break;
344 case 4: call_set(call, state4_.d); break;
345 case 5: call_set(call, state5_.d); break;
351 template<typename T, typename ...Args>
352 static void call_get(Args&& ...args)
353 { return T::Get(std::forward<Args>(args)...); }
355 static void call_get(const EaxCall &call, const EaxEffectProps &props)
356 { EAXCALL(props.mType, call_get, call, props); }
358 void get(const EaxCall &call)
360 switch(call.get_version())
362 case 1: call_get<EaxReverbCommitter>(call, state1_.d); break;
363 case 2: call_get<EaxReverbCommitter>(call, state2_.d); break;
364 case 3: call_get<EaxReverbCommitter>(call, state3_.d); break;
365 case 4: call_get(call, state4_.d); break;
366 case 5: call_get(call, state5_.d); break;
371 template<typename T, typename ...Args>
372 bool call_commit(Args&& ...args)
373 { return T{props_, al_effect_props_}.commit(std::forward<Args>(args)...); }
375 bool call_commit(const EaxEffectProps &props)
376 { EAXCALL(props.mType, call_commit, props); }
378 bool commit(int eax_version)
380 changed_ |= version_ != eax_version;
381 if(!changed_) return false;
383 bool ret{version_ != eax_version};
384 version_ = eax_version;
390 state1_.i = state1_.d;
391 ret |= call_commit<EaxReverbCommitter>(state1_.d);
394 state2_.i = state2_.d;
395 ret |= call_commit<EaxReverbCommitter>(state2_.d);
398 state3_.i = state3_.d;
399 ret |= call_commit<EaxReverbCommitter>(state3_.d);
402 state4_.i = state4_.d;
403 ret |= call_commit(state4_.d);
406 state5_.i = state5_.d;
407 ret |= call_commit(state5_.d);
410 al_effect_type_ = EnumFromEaxEffectType(props_);
416 using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
418 #endif // !EAX_EFFECT_INCLUDED