]> git.tdb.fi Git - ext/openal.git/blob - al/eax/effect.h
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / al / eax / effect.h
1 #ifndef EAX_EFFECT_INCLUDED
2 #define EAX_EFFECT_INCLUDED
3
4
5 #include <cassert>
6 #include <memory>
7
8 #include "alnumeric.h"
9 #include "AL/al.h"
10 #include "core/effects/base.h"
11 #include "call.h"
12
13 struct EaxEffectErrorMessages
14 {
15     static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
16     static constexpr auto unknown_version() noexcept { return "Unknown version."; }
17 }; // EaxEffectErrorMessages
18
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
23 };
24 struct EaxEffectProps {
25     EaxEffectType mType;
26     union {
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;
39     };
40 };
41
42 constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
43 {
44     switch(props.mType)
45     {
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;
59     }
60     return AL_EFFECT_NULL;
61 }
62
63 struct EaxReverbCommitter {
64     struct Exception;
65
66     EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
67         : mEaxProps{eaxprops}, mAlProps{alprops}
68     { }
69
70     EaxEffectProps &mEaxProps;
71     EffectProps &mAlProps;
72
73     [[noreturn]] static void fail(const char* message);
74     [[noreturn]] static void fail_unknown_property_id()
75     { fail(EaxEffectErrorMessages::unknown_property_id()); }
76
77     template<typename TValidator, typename TProperty>
78     static void defer(const EaxCall& call, TProperty& property)
79     {
80         const auto& value = call.get_value<Exception, const TProperty>();
81         TValidator{}(value);
82         property = value;
83     }
84
85     template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty>
86     static void defer(const EaxCall& call, TProperties& properties, TProperty&)
87     {
88         const auto& value = call.get_value<Exception, const TProperty>();
89         TValidator{}(value);
90         TDeferrer{}(properties, value);
91     }
92
93     template<typename TValidator, typename TProperty>
94     static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property)
95     {
96         const auto& value = call.get_value<Exception, const TProperty>();
97         TValidator{}(value);
98         if (value == property)
99             return;
100         property = value;
101         properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED;
102     }
103
104
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);
109
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);
114
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);
119
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);
124
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;
128 };
129
130 template<typename T>
131 struct EaxCommitter {
132     struct Exception;
133
134     EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
135         : mEaxProps{eaxprops}, mAlProps{alprops}
136     { }
137
138     EaxEffectProps &mEaxProps;
139     EffectProps &mAlProps;
140
141     template<typename TValidator, typename TProperty>
142     static void defer(const EaxCall& call, TProperty& property)
143     {
144         const auto& value = call.get_value<Exception, const TProperty>();
145         TValidator{}(value);
146         property = value;
147     }
148
149     [[noreturn]] static void fail(const char *message);
150     [[noreturn]] static void fail_unknown_property_id()
151     { fail(EaxEffectErrorMessages::unknown_property_id()); }
152
153     bool commit(const EaxEffectProps &props);
154
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);
158 };
159
160 struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
161     using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
162 };
163 struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
164     using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
165 };
166 struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
167     using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
168 };
169 struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
170     using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
171 };
172 struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
173     using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
174 };
175 struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
176     using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
177 };
178 struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
179     using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
180 };
181 struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
182     using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
183 };
184 struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
185     using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
186 };
187 struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
188     using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
189 };
190 struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
191     using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
192 };
193 struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
194     using EaxCommitter<EaxNullCommitter>::EaxCommitter;
195 };
196
197
198 class EaxEffect {
199 public:
200     EaxEffect() noexcept = default;
201     ~EaxEffect() = default;
202
203     ALenum al_effect_type_{AL_EFFECT_NULL};
204     EffectProps al_effect_props_{};
205
206     using Props1 = EAX_REVERBPROPERTIES;
207     using Props2 = EAX20LISTENERPROPERTIES;
208     using Props3 = EAXREVERBPROPERTIES;
209     using Props4 = EaxEffectProps;
210
211     struct State1 {
212         Props1 i; // Immediate.
213         Props1 d; // Deferred.
214     };
215
216     struct State2 {
217         Props2 i; // Immediate.
218         Props2 d; // Deferred.
219     };
220
221     struct State3 {
222         Props3 i; // Immediate.
223         Props3 d; // Deferred.
224     };
225
226     struct State4 {
227         Props4 i; // Immediate.
228         Props4 d; // Deferred.
229     };
230
231     int version_{};
232     bool changed_{};
233     Props4 props_{};
234     State1 state1_{};
235     State2 state2_{};
236     State3 state3_{};
237     State4 state4_{};
238     State4 state5_{};
239
240
241     template<typename T, typename ...Args>
242     void call_set_defaults(Args&& ...args)
243     { return T::SetDefaults(std::forward<Args>(args)...); }
244
245     void call_set_defaults(const ALenum altype, EaxEffectProps &props)
246     {
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);
272     }
273
274     template<typename T>
275     void init()
276     {
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;
287     }
288
289     void set_defaults(int eax_version, ALenum altype)
290     {
291         switch(eax_version)
292         {
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;
298         }
299         changed_ = true;
300     }
301
302
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__)
329
330     template<typename T, typename ...Args>
331     static void call_set(Args&& ...args)
332     { return T::Set(std::forward<Args>(args)...); }
333
334     static void call_set(const EaxCall &call, EaxEffectProps &props)
335     { EAXCALL(props.mType, call_set, call, props); }
336
337     void set(const EaxCall &call)
338     {
339         switch(call.get_version())
340         {
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;
346         }
347         changed_ = true;
348     }
349
350
351     template<typename T, typename ...Args>
352     static void call_get(Args&& ...args)
353     { return T::Get(std::forward<Args>(args)...); }
354
355     static void call_get(const EaxCall &call, const EaxEffectProps &props)
356     { EAXCALL(props.mType, call_get, call, props); }
357
358     void get(const EaxCall &call)
359     {
360         switch(call.get_version())
361         {
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;
367         }
368     }
369
370
371     template<typename T, typename ...Args>
372     bool call_commit(Args&& ...args)
373     { return T{props_, al_effect_props_}.commit(std::forward<Args>(args)...); }
374
375     bool call_commit(const EaxEffectProps &props)
376     { EAXCALL(props.mType, call_commit, props); }
377
378     bool commit(int eax_version)
379     {
380         changed_ |= version_ != eax_version;
381         if(!changed_) return false;
382
383         bool ret{version_ != eax_version};
384         version_ = eax_version;
385         changed_ = false;
386
387         switch(eax_version)
388         {
389         case 1:
390             state1_.i = state1_.d;
391             ret |= call_commit<EaxReverbCommitter>(state1_.d);
392             break;
393         case 2:
394             state2_.i = state2_.d;
395             ret |= call_commit<EaxReverbCommitter>(state2_.d);
396             break;
397         case 3:
398             state3_.i = state3_.d;
399             ret |= call_commit<EaxReverbCommitter>(state3_.d);
400             break;
401         case 4:
402             state4_.i = state4_.d;
403             ret |= call_commit(state4_.d);
404             break;
405         case 5:
406             state5_.i = state5_.d;
407             ret |= call_commit(state5_.d);
408             break;
409         }
410         al_effect_type_ = EnumFromEaxEffectType(props_);
411         return ret;
412     }
413 #undef EAXCALL
414 }; // EaxEffect
415
416 using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
417
418 #endif // !EAX_EFFECT_INCLUDED