Convert the EAX Echo and Equalizer effects
[openal-soft.git] / al / auxeffectslot.h
blob999ea102322123b95b40da0184747cbeacb810fa
1 #ifndef AL_AUXEFFECTSLOT_H
2 #define AL_AUXEFFECTSLOT_H
4 #include <atomic>
5 #include <cstddef>
7 #include "AL/al.h"
8 #include "AL/alc.h"
9 #include "AL/efx.h"
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"
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
28 struct ALbuffer;
29 struct ALeffect;
30 struct WetBuffer;
32 #ifdef ALSOFT_EAX
33 class EaxFxSlotException : public EaxException {
34 public:
35 explicit EaxFxSlotException(const char* message)
36 : EaxException{"EAX_FX_SLOT", message}
39 #endif // ALSOFT_EAX
41 enum class SlotState : ALenum {
42 Initial = AL_INITIAL,
43 Playing = AL_PLAYING,
44 Stopped = AL_STOPPED,
47 struct ALeffectslot {
48 float Gain{1.0f};
49 bool AuxSendAuto{true};
50 ALeffectslot *Target{nullptr};
51 ALbuffer *Buffer{nullptr};
53 struct {
54 EffectSlotType Type{EffectSlotType::None};
55 EffectProps Props{};
57 al::intrusive_ptr<EffectState> State;
58 } Effect;
60 bool mPropsDirty{true};
62 SlotState mState{SlotState::Initial};
64 RefCount ref{0u};
66 EffectSlot *mSlot{nullptr};
68 /* Self ID */
69 ALuint id{};
71 ALeffectslot(ALCcontext *context);
72 ALeffectslot(const ALeffectslot&) = delete;
73 ALeffectslot& operator=(const ALeffectslot&) = delete;
74 ~ALeffectslot();
76 ALenum initEffect(ALenum effectType, const EffectProps &effectProps, ALCcontext *context);
77 void updateProps(ALCcontext *context);
79 /* This can be new'd for the context's default effect slot. */
80 DEF_NEWDEL(ALeffectslot)
83 #ifdef ALSOFT_EAX
84 public:
85 void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index);
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_; }
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); }
95 void eax_commit();
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;
105 using Exception = EaxFxSlotException;
107 using Eax4Props = EAX40FXSLOTPROPERTIES;
109 struct Eax4State {
110 Eax4Props i; // Immediate.
113 using Eax5Props = EAX50FXSLOTPROPERTIES;
115 struct Eax5State {
116 Eax5Props i; // Immediate.
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
127 eax_validate_range<Exception>(name, value, min_value, max_value);
131 struct Eax4GuidLoadEffectValidator {
132 void operator()(const GUID& guidLoadEffect) const
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*/)
148 eax_fail_unknown_effect_id();
153 struct Eax4VolumeValidator {
154 void operator()(long lVolume) const
156 EaxRangeValidator{}(
157 "Volume",
158 lVolume,
159 EAXFXSLOT_MINVOLUME,
160 EAXFXSLOT_MAXVOLUME);
164 struct Eax4LockValidator {
165 void operator()(long lLock) const
167 EaxRangeValidator{}(
168 "Lock",
169 lLock,
170 EAXFXSLOT_MINLOCK,
171 EAXFXSLOT_MAXLOCK);
175 struct Eax4FlagsValidator {
176 void operator()(unsigned long ulFlags) const
178 EaxRangeValidator{}(
179 "Flags",
180 ulFlags,
181 0UL,
182 ~EAX40FXSLOTFLAGS_RESERVED);
186 struct Eax4AllValidator {
187 void operator()(const EAX40FXSLOTPROPERTIES& all) const
189 Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
190 Eax4VolumeValidator{}(all.lVolume);
191 Eax4LockValidator{}(all.lLock);
192 Eax4FlagsValidator{}(all.ulFlags);
196 struct Eax5OcclusionValidator {
197 void operator()(long lOcclusion) const
199 EaxRangeValidator{}(
200 "Occlusion",
201 lOcclusion,
202 EAXFXSLOT_MINOCCLUSION,
203 EAXFXSLOT_MAXOCCLUSION);
207 struct Eax5OcclusionLfRatioValidator {
208 void operator()(float flOcclusionLFRatio) const
210 EaxRangeValidator{}(
211 "Occlusion LF Ratio",
212 flOcclusionLFRatio,
213 EAXFXSLOT_MINOCCLUSIONLFRATIO,
214 EAXFXSLOT_MAXOCCLUSIONLFRATIO);
218 struct Eax5FlagsValidator {
219 void operator()(unsigned long ulFlags) const
221 EaxRangeValidator{}(
222 "Flags",
223 ulFlags,
224 0UL,
225 ~EAX50FXSLOTFLAGS_RESERVED);
229 struct Eax5AllValidator {
230 void operator()(const EAX50FXSLOTPROPERTIES& all) const
232 Eax4AllValidator{}(static_cast<const EAX40FXSLOTPROPERTIES&>(all));
233 Eax5OcclusionValidator{}(all.lOcclusion);
234 Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
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.
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();
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)
260 const auto& src = call.get_value<Exception, const TProperties>();
261 TValidator{}(src);
262 dirty_flags |= (dst != src ? TDirtyBit : EaxDirtyFlags{});
263 dst = src;
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)
274 const auto& src = call.get_value<Exception, const TProperties>();
275 TValidator{}(src);
276 dirty_flags |= TDirtyBit;
277 dst = src;
280 constexpr bool eax4_fx_slot_is_legacy() const noexcept
281 { return eax_fx_slot_index_ < 2; }
283 void eax4_fx_slot_ensure_unlocked() const;
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;
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();
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);
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();
307 void eax4_fx_slot_set_all(const EaxCall& call);
308 void eax5_fx_slot_set_all(const EaxCall& call);
310 bool eax_fx_slot_should_update_sources() const noexcept;
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);
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
329 auto& src_i = state.i;
330 auto& dst_i = eax_;
332 if((eax_df_ & TDirtyBit) != EaxDirtyFlags{})
334 dst_df |= TDirtyBit;
335 dst_i.*member = src_i.*member;
339 void eax4_fx_slot_commit(EaxDirtyFlags& dst_df);
340 void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df);
342 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
343 void eax_set_efx_slot_effect(EaxEffect &effect);
345 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
346 void eax_set_efx_slot_send_auto(bool is_send_auto);
348 // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
349 void eax_set_efx_slot_gain(ALfloat gain);
351 public:
352 class EaxDeleter {
353 public:
354 void operator()(ALeffectslot *effect_slot);
356 #endif // ALSOFT_EAX
359 void UpdateAllEffectSlotProps(ALCcontext *context);
361 #ifdef ALSOFT_EAX
362 using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>;
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
368 #endif