]> git.tdb.fi Git - ext/openal.git/blob - al/auxeffectslot.h
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / al / auxeffectslot.h
1 #ifndef AL_AUXEFFECTSLOT_H
2 #define AL_AUXEFFECTSLOT_H
3
4 #include <atomic>
5 #include <cstddef>
6
7 #include "AL/al.h"
8 #include "AL/alc.h"
9 #include "AL/efx.h"
10
11 #include "alc/device.h"
12 #include "alc/effects/base.h"
13 #include "almalloc.h"
14 #include "atomic.h"
15 #include "core/effectslot.h"
16 #include "intrusive_ptr.h"
17 #include "vector.h"
18
19 #ifdef ALSOFT_EAX
20 #include <memory>
21 #include "eax/call.h"
22 #include "eax/effect.h"
23 #include "eax/exception.h"
24 #include "eax/fx_slot_index.h"
25 #include "eax/utils.h"
26 #endif // ALSOFT_EAX
27
28 struct ALbuffer;
29 struct ALeffect;
30 struct WetBuffer;
31
32 #ifdef ALSOFT_EAX
33 class EaxFxSlotException : public EaxException {
34 public:
35         explicit EaxFxSlotException(const char* message)
36                 : EaxException{"EAX_FX_SLOT", message}
37         {}
38 };
39 #endif // ALSOFT_EAX
40
41 enum class SlotState : ALenum {
42     Initial = AL_INITIAL,
43     Playing = AL_PLAYING,
44     Stopped = AL_STOPPED,
45 };
46
47 struct ALeffectslot {
48     float Gain{1.0f};
49     bool  AuxSendAuto{true};
50     ALeffectslot *Target{nullptr};
51     ALbuffer *Buffer{nullptr};
52
53     struct {
54         EffectSlotType Type{EffectSlotType::None};
55         EffectProps Props{};
56
57         al::intrusive_ptr<EffectState> State;
58     } Effect;
59
60     bool mPropsDirty{true};
61
62     SlotState mState{SlotState::Initial};
63
64     RefCount ref{0u};
65
66     EffectSlot *mSlot{nullptr};
67
68     /* Self ID */
69     ALuint id{};
70
71     ALeffectslot(ALCcontext *context);
72     ALeffectslot(const ALeffectslot&) = delete;
73     ALeffectslot& operator=(const ALeffectslot&) = delete;
74     ~ALeffectslot();
75
76     ALenum initEffect(ALenum effectType, const EffectProps &effectProps, ALCcontext *context);
77     void updateProps(ALCcontext *context);
78
79     /* This can be new'd for the context's default effect slot. */
80     DEF_NEWDEL(ALeffectslot)
81
82
83 #ifdef ALSOFT_EAX
84 public:
85     void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index);
86
87     EaxFxSlotIndexValue eax_get_index() const noexcept { return eax_fx_slot_index_; }
88     const EAX50FXSLOTPROPERTIES& eax_get_eax_fx_slot() const noexcept
89     { return eax_; }
90
91     // Returns `true` if all sources should be updated, or `false` otherwise.
92     bool eax_dispatch(const EaxCall& call)
93     { return call.is_get() ? eax_get(call) : eax_set(call); }
94
95     void eax_commit();
96
97 private:
98     static constexpr auto eax_load_effect_dirty_bit = EaxDirtyFlags{1} << 0;
99     static constexpr auto eax_volume_dirty_bit = EaxDirtyFlags{1} << 1;
100     static constexpr auto eax_lock_dirty_bit = EaxDirtyFlags{1} << 2;
101     static constexpr auto eax_flags_dirty_bit = EaxDirtyFlags{1} << 3;
102     static constexpr auto eax_occlusion_dirty_bit = EaxDirtyFlags{1} << 4;
103     static constexpr auto eax_occlusion_lf_ratio_dirty_bit = EaxDirtyFlags{1} << 5;
104
105     using Exception = EaxFxSlotException;
106
107     using Eax4Props = EAX40FXSLOTPROPERTIES;
108
109     struct Eax4State {
110         Eax4Props i; // Immediate.
111     };
112
113     using Eax5Props = EAX50FXSLOTPROPERTIES;
114
115     struct Eax5State {
116         Eax5Props i; // Immediate.
117     };
118
119     struct EaxRangeValidator {
120         template<typename TValue>
121         void operator()(
122             const char* name,
123             const TValue& value,
124             const TValue& min_value,
125             const TValue& max_value) const
126         {
127             eax_validate_range<Exception>(name, value, min_value, max_value);
128         }
129     };
130
131     struct Eax4GuidLoadEffectValidator {
132         void operator()(const GUID& guidLoadEffect) const
133         {
134             if (guidLoadEffect != EAX_NULL_GUID &&
135                 guidLoadEffect != EAX_REVERB_EFFECT &&
136                 guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT &&
137                 guidLoadEffect != EAX_AUTOWAH_EFFECT &&
138                 guidLoadEffect != EAX_CHORUS_EFFECT &&
139                 guidLoadEffect != EAX_DISTORTION_EFFECT &&
140                 guidLoadEffect != EAX_ECHO_EFFECT &&
141                 guidLoadEffect != EAX_EQUALIZER_EFFECT &&
142                 guidLoadEffect != EAX_FLANGER_EFFECT &&
143                 guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT &&
144                 guidLoadEffect != EAX_VOCALMORPHER_EFFECT &&
145                 guidLoadEffect != EAX_PITCHSHIFTER_EFFECT &&
146                 guidLoadEffect != EAX_RINGMODULATOR_EFFECT)
147             {
148                 eax_fail_unknown_effect_id();
149             }
150         }
151     };
152
153     struct Eax4VolumeValidator {
154         void operator()(long lVolume) const
155         {
156             EaxRangeValidator{}(
157                 "Volume",
158                 lVolume,
159                 EAXFXSLOT_MINVOLUME,
160                 EAXFXSLOT_MAXVOLUME);
161         }
162     };
163
164     struct Eax4LockValidator {
165         void operator()(long lLock) const
166         {
167             EaxRangeValidator{}(
168                 "Lock",
169                 lLock,
170                 EAXFXSLOT_MINLOCK,
171                 EAXFXSLOT_MAXLOCK);
172         }
173     };
174
175     struct Eax4FlagsValidator {
176         void operator()(unsigned long ulFlags) const
177         {
178             EaxRangeValidator{}(
179                 "Flags",
180                 ulFlags,
181                 0UL,
182                 ~EAX40FXSLOTFLAGS_RESERVED);
183         }
184     };
185
186     struct Eax4AllValidator {
187         void operator()(const EAX40FXSLOTPROPERTIES& all) const
188         {
189             Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
190             Eax4VolumeValidator{}(all.lVolume);
191             Eax4LockValidator{}(all.lLock);
192             Eax4FlagsValidator{}(all.ulFlags);
193         }
194     };
195
196     struct Eax5OcclusionValidator {
197         void operator()(long lOcclusion) const
198         {
199             EaxRangeValidator{}(
200                 "Occlusion",
201                 lOcclusion,
202                 EAXFXSLOT_MINOCCLUSION,
203                 EAXFXSLOT_MAXOCCLUSION);
204         }
205     };
206
207     struct Eax5OcclusionLfRatioValidator {
208         void operator()(float flOcclusionLFRatio) const
209         {
210             EaxRangeValidator{}(
211                 "Occlusion LF Ratio",
212                 flOcclusionLFRatio,
213                 EAXFXSLOT_MINOCCLUSIONLFRATIO,
214                 EAXFXSLOT_MAXOCCLUSIONLFRATIO);
215         }
216     };
217
218     struct Eax5FlagsValidator {
219         void operator()(unsigned long ulFlags) const
220         {
221             EaxRangeValidator{}(
222                 "Flags",
223                 ulFlags,
224                 0UL,
225                 ~EAX50FXSLOTFLAGS_RESERVED);
226         }
227     };
228
229     struct Eax5AllValidator {
230         void operator()(const EAX50FXSLOTPROPERTIES& all) const
231         {
232             Eax4AllValidator{}(static_cast<const EAX40FXSLOTPROPERTIES&>(all));
233             Eax5OcclusionValidator{}(all.lOcclusion);
234             Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
235         }
236     };
237
238     ALCcontext* eax_al_context_{};
239     EaxFxSlotIndexValue eax_fx_slot_index_{};
240     int eax_version_{}; // Current EAX version.
241     EaxDirtyFlags eax_df_{}; // Dirty flags for the current EAX version.
242     EaxEffectUPtr eax_effect_{};
243     Eax5State eax123_{}; // EAX1/EAX2/EAX3 state.
244     Eax4State eax4_{}; // EAX4 state.
245     Eax5State eax5_{}; // EAX5 state.
246     Eax5Props eax_{}; // Current EAX state.
247
248     [[noreturn]] static void eax_fail(const char* message);
249     [[noreturn]] static void eax_fail_unknown_effect_id();
250     [[noreturn]] static void eax_fail_unknown_property_id();
251     [[noreturn]] static void eax_fail_unknown_version();
252
253     // Gets a new value from EAX call,
254     // validates it,
255     // sets a dirty flag only if the new value differs form the old one,
256     // and assigns the new value.
257     template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
258     static void eax_fx_slot_set(const EaxCall& call, TProperties& dst, EaxDirtyFlags& dirty_flags)
259     {
260         const auto& src = call.get_value<Exception, const TProperties>();
261         TValidator{}(src);
262         dirty_flags |= (dst != src ? TDirtyBit : EaxDirtyFlags{});
263         dst = src;
264     }
265
266     // Gets a new value from EAX call,
267     // validates it,
268     // sets a dirty flag without comparing the values,
269     // and assigns the new value.
270     template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties>
271     static void eax_fx_slot_set_dirty(const EaxCall& call, TProperties& dst,
272         EaxDirtyFlags& dirty_flags)
273     {
274         const auto& src = call.get_value<Exception, const TProperties>();
275         TValidator{}(src);
276         dirty_flags |= TDirtyBit;
277         dst = src;
278     }
279
280     constexpr bool eax4_fx_slot_is_legacy() const noexcept
281     { return eax_fx_slot_index_ < 2; }
282
283     void eax4_fx_slot_ensure_unlocked() const;
284
285     static ALenum eax_get_efx_effect_type(const GUID& guid);
286     const GUID& eax_get_eax_default_effect_guid() const noexcept;
287     long eax_get_eax_default_lock() const noexcept;
288
289     void eax4_fx_slot_set_defaults(Eax4Props& props) noexcept;
290     void eax5_fx_slot_set_defaults(Eax5Props& props) noexcept;
291     void eax4_fx_slot_set_current_defaults(const Eax4Props& props) noexcept;
292     void eax5_fx_slot_set_current_defaults(const Eax5Props& props) noexcept;
293     void eax_fx_slot_set_current_defaults();
294     void eax_fx_slot_set_defaults();
295
296     void eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props) const;
297     void eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props) const;
298     void eax_fx_slot_get(const EaxCall& call) const;
299     // Returns `true` if all sources should be updated, or `false` otherwise.
300     bool eax_get(const EaxCall& call);
301
302     void eax_fx_slot_load_effect(int version, ALenum altype);
303     void eax_fx_slot_set_volume();
304     void eax_fx_slot_set_environment_flag();
305     void eax_fx_slot_set_flags();
306
307     void eax4_fx_slot_set_all(const EaxCall& call);
308     void eax5_fx_slot_set_all(const EaxCall& call);
309
310     bool eax_fx_slot_should_update_sources() const noexcept;
311
312     // Returns `true` if all sources should be updated, or `false` otherwise.
313     bool eax4_fx_slot_set(const EaxCall& call);
314     // Returns `true` if all sources should be updated, or `false` otherwise.
315     bool eax5_fx_slot_set(const EaxCall& call);
316     // Returns `true` if all sources should be updated, or `false` otherwise.
317     bool eax_fx_slot_set(const EaxCall& call);
318     // Returns `true` if all sources should be updated, or `false` otherwise.
319     bool eax_set(const EaxCall& call);
320
321     template<
322         EaxDirtyFlags TDirtyBit,
323         typename TMemberResult,
324         typename TProps,
325         typename TState>
326     void eax_fx_slot_commit_property(TState& state, EaxDirtyFlags& dst_df,
327         TMemberResult TProps::*member) noexcept
328     {
329         auto& src_i = state.i;
330         auto& dst_i = eax_;
331
332         if((eax_df_ & TDirtyBit) != EaxDirtyFlags{})
333         {
334             dst_df |= TDirtyBit;
335             dst_i.*member = src_i.*member;
336         }
337     }
338
339     void eax4_fx_slot_commit(EaxDirtyFlags& dst_df);
340     void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df);
341
342     // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
343     void eax_set_efx_slot_effect(EaxEffect &effect);
344
345     // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
346     void eax_set_efx_slot_send_auto(bool is_send_auto);
347
348     // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
349     void eax_set_efx_slot_gain(ALfloat gain);
350
351 public:
352     class EaxDeleter {
353     public:
354         void operator()(ALeffectslot *effect_slot);
355     };
356 #endif // ALSOFT_EAX
357 };
358
359 void UpdateAllEffectSlotProps(ALCcontext *context);
360
361 #ifdef ALSOFT_EAX
362 using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>;
363
364 EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
365 void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
366 #endif // ALSOFT_EAX
367
368 #endif