1 #ifndef AL_AUXEFFECTSLOT_H
2 #define AL_AUXEFFECTSLOT_H
14 #include "alnumeric.h"
15 #include "core/effects/base.h"
16 #include "core/effectslot.h"
17 #include "intrusive_ptr.h"
23 #include "eax/effect.h"
24 #include "eax/exception.h"
25 #include "eax/fx_slot_index.h"
26 #include "eax/utils.h"
32 class EaxFxSlotException
: public EaxException
{
34 explicit EaxFxSlotException(const char* message
)
35 : EaxException
{"EAX_FX_SLOT", message
}
40 enum class SlotState
: bool {
47 bool AuxSendAuto
{true};
48 ALeffectslot
*Target
{nullptr};
49 ALbuffer
*Buffer
{nullptr};
52 EffectSlotType Type
{EffectSlotType::None
};
55 al::intrusive_ptr
<EffectState
> State
;
59 bool mPropsDirty
{true};
61 SlotState mState
{SlotState::Initial
};
63 std::atomic
<ALuint
> ref
{0u};
65 EffectSlot
*mSlot
{nullptr};
70 ALeffectslot(ALCcontext
*context
);
71 ALeffectslot(const ALeffectslot
&) = delete;
72 ALeffectslot
& operator=(const ALeffectslot
&) = delete;
75 ALenum
initEffect(ALuint effectId
, ALenum effectType
, const EffectProps
&effectProps
,
77 void updateProps(ALCcontext
*context
) const;
79 static void SetName(ALCcontext
*context
, ALuint id
, std::string_view name
);
84 void eax_initialize(ALCcontext
& al_context
, EaxFxSlotIndexValue index
);
86 [[nodiscard
]] auto eax_get_index() const noexcept
-> EaxFxSlotIndexValue
{ return eax_fx_slot_index_
; }
87 [[nodiscard
]] auto eax_get_eax_fx_slot() const noexcept
-> const EAX50FXSLOTPROPERTIES
&
90 // Returns `true` if all sources should be updated, or `false` otherwise.
91 [[nodiscard
]] auto eax_dispatch(const EaxCall
& call
) -> bool
92 { return call
.is_get() ? eax_get(call
) : eax_set(call
); }
97 static constexpr auto eax_load_effect_dirty_bit
= EaxDirtyFlags
{1} << 0;
98 static constexpr auto eax_volume_dirty_bit
= EaxDirtyFlags
{1} << 1;
99 static constexpr auto eax_lock_dirty_bit
= EaxDirtyFlags
{1} << 2;
100 static constexpr auto eax_flags_dirty_bit
= EaxDirtyFlags
{1} << 3;
101 static constexpr auto eax_occlusion_dirty_bit
= EaxDirtyFlags
{1} << 4;
102 static constexpr auto eax_occlusion_lf_ratio_dirty_bit
= EaxDirtyFlags
{1} << 5;
104 using Exception
= EaxFxSlotException
;
106 using Eax4Props
= EAX40FXSLOTPROPERTIES
;
109 Eax4Props i
; // Immediate.
112 using Eax5Props
= EAX50FXSLOTPROPERTIES
;
115 Eax5Props i
; // Immediate.
118 struct EaxRangeValidator
{
119 template<typename TValue
>
123 const TValue
& min_value
,
124 const TValue
& max_value
) const
126 eax_validate_range
<Exception
>(name
, value
, min_value
, max_value
);
130 struct Eax4GuidLoadEffectValidator
{
131 void operator()(const GUID
& guidLoadEffect
) const
133 if (guidLoadEffect
!= EAX_NULL_GUID
&&
134 guidLoadEffect
!= EAX_REVERB_EFFECT
&&
135 guidLoadEffect
!= EAX_AGCCOMPRESSOR_EFFECT
&&
136 guidLoadEffect
!= EAX_AUTOWAH_EFFECT
&&
137 guidLoadEffect
!= EAX_CHORUS_EFFECT
&&
138 guidLoadEffect
!= EAX_DISTORTION_EFFECT
&&
139 guidLoadEffect
!= EAX_ECHO_EFFECT
&&
140 guidLoadEffect
!= EAX_EQUALIZER_EFFECT
&&
141 guidLoadEffect
!= EAX_FLANGER_EFFECT
&&
142 guidLoadEffect
!= EAX_FREQUENCYSHIFTER_EFFECT
&&
143 guidLoadEffect
!= EAX_VOCALMORPHER_EFFECT
&&
144 guidLoadEffect
!= EAX_PITCHSHIFTER_EFFECT
&&
145 guidLoadEffect
!= EAX_RINGMODULATOR_EFFECT
)
147 eax_fail_unknown_effect_id();
152 struct Eax4VolumeValidator
{
153 void operator()(long lVolume
) const
159 EAXFXSLOT_MAXVOLUME
);
163 struct Eax4LockValidator
{
164 void operator()(long lLock
) const
174 struct Eax4FlagsValidator
{
175 void operator()(unsigned long ulFlags
) const
181 ~EAX40FXSLOTFLAGS_RESERVED
);
185 struct Eax4AllValidator
{
186 void operator()(const EAX40FXSLOTPROPERTIES
& all
) const
188 Eax4GuidLoadEffectValidator
{}(all
.guidLoadEffect
);
189 Eax4VolumeValidator
{}(all
.lVolume
);
190 Eax4LockValidator
{}(all
.lLock
);
191 Eax4FlagsValidator
{}(all
.ulFlags
);
195 struct Eax5FlagsValidator
{
196 void operator()(unsigned long ulFlags
) const
202 ~EAX50FXSLOTFLAGS_RESERVED
);
206 struct Eax5OcclusionValidator
{
207 void operator()(long lOcclusion
) const
212 EAXFXSLOT_MINOCCLUSION
,
213 EAXFXSLOT_MAXOCCLUSION
);
217 struct Eax5OcclusionLfRatioValidator
{
218 void operator()(float flOcclusionLFRatio
) const
221 "Occlusion LF Ratio",
223 EAXFXSLOT_MINOCCLUSIONLFRATIO
,
224 EAXFXSLOT_MAXOCCLUSIONLFRATIO
);
228 struct Eax5AllValidator
{
229 void operator()(const EAX50FXSLOTPROPERTIES
& all
) const
231 Eax4GuidLoadEffectValidator
{}(all
.guidLoadEffect
);
232 Eax4VolumeValidator
{}(all
.lVolume
);
233 Eax4LockValidator
{}(all
.lLock
);
234 Eax5FlagsValidator
{}(all
.ulFlags
);
235 Eax5OcclusionValidator
{}(all
.lOcclusion
);
236 Eax5OcclusionLfRatioValidator
{}(all
.flOcclusionLFRatio
);
240 ALCcontext
* eax_al_context_
{};
241 EaxFxSlotIndexValue eax_fx_slot_index_
{};
242 int eax_version_
{}; // Current EAX version.
243 EaxDirtyFlags eax_df_
{}; // Dirty flags for the current EAX version.
244 EaxEffectUPtr eax_effect_
{};
245 Eax5State eax123_
{}; // EAX1/EAX2/EAX3 state.
246 Eax4State eax4_
{}; // EAX4 state.
247 Eax5State eax5_
{}; // EAX5 state.
248 Eax5Props eax_
{}; // Current EAX state.
250 [[noreturn
]] static void eax_fail(const char* message
);
251 [[noreturn
]] static void eax_fail_unknown_effect_id();
252 [[noreturn
]] static void eax_fail_unknown_property_id();
253 [[noreturn
]] static void eax_fail_unknown_version();
255 // Gets a new value from EAX call,
257 // sets a dirty flag only if the new value differs form the old one,
258 // and assigns the new value.
259 template<typename TValidator
, EaxDirtyFlags TDirtyBit
, typename TProperties
>
260 static void eax_fx_slot_set(const EaxCall
& call
, TProperties
& dst
, EaxDirtyFlags
& dirty_flags
)
262 const auto& src
= call
.get_value
<Exception
, const TProperties
>();
264 dirty_flags
|= (dst
!= src
? TDirtyBit
: EaxDirtyFlags
{});
268 // Gets a new value from EAX call,
270 // sets a dirty flag without comparing the values,
271 // and assigns the new value.
272 template<typename TValidator
, EaxDirtyFlags TDirtyBit
, typename TProperties
>
273 static void eax_fx_slot_set_dirty(const EaxCall
& call
, TProperties
& dst
,
274 EaxDirtyFlags
& dirty_flags
)
276 const auto& src
= call
.get_value
<Exception
, const TProperties
>();
278 dirty_flags
|= TDirtyBit
;
282 [[nodiscard
]] constexpr auto eax4_fx_slot_is_legacy() const noexcept
-> bool
283 { return eax_fx_slot_index_
< 2; }
285 void eax4_fx_slot_ensure_unlocked() const;
287 [[nodiscard
]] static auto eax_get_efx_effect_type(const GUID
& guid
) -> ALenum
;
288 [[nodiscard
]] auto eax_get_eax_default_effect_guid() const noexcept
-> const GUID
&;
289 [[nodiscard
]] auto eax_get_eax_default_lock() const noexcept
-> long;
291 void eax4_fx_slot_set_defaults(Eax4Props
& props
) noexcept
;
292 void eax5_fx_slot_set_defaults(Eax5Props
& props
) noexcept
;
293 void eax4_fx_slot_set_current_defaults(const Eax4Props
& props
) noexcept
;
294 void eax5_fx_slot_set_current_defaults(const Eax5Props
& props
) noexcept
;
295 void eax_fx_slot_set_current_defaults();
296 void eax_fx_slot_set_defaults();
298 static void eax4_fx_slot_get(const EaxCall
& call
, const Eax4Props
& props
);
299 static void eax5_fx_slot_get(const EaxCall
& call
, const Eax5Props
& props
);
300 void eax_fx_slot_get(const EaxCall
& call
) const;
301 // Returns `true` if all sources should be updated, or `false` otherwise.
302 bool eax_get(const EaxCall
& call
);
304 void eax_fx_slot_load_effect(int version
, ALenum altype
);
305 void eax_fx_slot_set_volume();
306 void eax_fx_slot_set_environment_flag();
307 void eax_fx_slot_set_flags();
309 void eax4_fx_slot_set_all(const EaxCall
& call
);
310 void eax5_fx_slot_set_all(const EaxCall
& call
);
312 [[nodiscard
]] auto eax_fx_slot_should_update_sources() const noexcept
-> bool;
314 // Returns `true` if all sources should be updated, or `false` otherwise.
315 bool eax4_fx_slot_set(const EaxCall
& call
);
316 // Returns `true` if all sources should be updated, or `false` otherwise.
317 bool eax5_fx_slot_set(const EaxCall
& call
);
318 // Returns `true` if all sources should be updated, or `false` otherwise.
319 bool eax_fx_slot_set(const EaxCall
& call
);
320 // Returns `true` if all sources should be updated, or `false` otherwise.
321 bool eax_set(const EaxCall
& call
);
324 EaxDirtyFlags TDirtyBit
,
325 typename TMemberResult
,
328 void eax_fx_slot_commit_property(TState
& state
, EaxDirtyFlags
& dst_df
,
329 TMemberResult
TProps::*member
) noexcept
331 auto& src_i
= state
.i
;
334 if((eax_df_
& TDirtyBit
) != EaxDirtyFlags
{})
337 dst_i
.*member
= src_i
.*member
;
341 void eax4_fx_slot_commit(EaxDirtyFlags
& dst_df
);
342 void eax5_fx_slot_commit(Eax5State
& state
, EaxDirtyFlags
& dst_df
);
344 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
345 void eax_set_efx_slot_effect(EaxEffect
&effect
);
347 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
348 void eax_set_efx_slot_send_auto(bool is_send_auto
);
350 // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
351 void eax_set_efx_slot_gain(ALfloat gain
);
356 void operator()(ALeffectslot
*effect_slot
);
361 void UpdateAllEffectSlotProps(ALCcontext
*context
);
364 using EaxAlEffectSlotUPtr
= std::unique_ptr
<ALeffectslot
, ALeffectslot::EaxDeleter
>;
366 EaxAlEffectSlotUPtr
eax_create_al_effect_slot(ALCcontext
& context
);
367 void eax_delete_al_effect_slot(ALCcontext
& context
, ALeffectslot
& effect_slot
);
370 struct EffectSlotSubList
{
371 uint64_t FreeMask
{~0_u64
};
372 gsl::owner
<std::array
<ALeffectslot
,64>*> EffectSlots
{nullptr};
374 EffectSlotSubList() noexcept
= default;
375 EffectSlotSubList(const EffectSlotSubList
&) = delete;
376 EffectSlotSubList(EffectSlotSubList
&& rhs
) noexcept
377 : FreeMask
{rhs
.FreeMask
}, EffectSlots
{rhs
.EffectSlots
}
378 { rhs
.FreeMask
= ~0_u64
; rhs
.EffectSlots
= nullptr; }
379 ~EffectSlotSubList();
381 EffectSlotSubList
& operator=(const EffectSlotSubList
&) = delete;
382 EffectSlotSubList
& operator=(EffectSlotSubList
&& rhs
) noexcept
383 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(EffectSlots
, rhs
.EffectSlots
); return *this; }