1 #ifndef AL_AUXEFFECTSLOT_H
2 #define AL_AUXEFFECTSLOT_H
16 #include "alnumeric.h"
17 #include "core/effects/base.h"
18 #include "core/effectslot.h"
19 #include "intrusive_ptr.h"
25 #include "eax/effect.h"
26 #include "eax/exception.h"
27 #include "eax/fx_slot_index.h"
28 #include "eax/utils.h"
34 class EaxFxSlotException
: public EaxException
{
36 explicit EaxFxSlotException(const char* message
)
37 : EaxException
{"EAX_FX_SLOT", message
}
42 enum class SlotState
: bool {
49 bool AuxSendAuto
{true};
50 ALeffectslot
*Target
{nullptr};
51 ALbuffer
*Buffer
{nullptr};
54 EffectSlotType Type
{EffectSlotType::None
};
57 al::intrusive_ptr
<EffectState
> State
;
61 bool mPropsDirty
{true};
63 SlotState mState
{SlotState::Initial
};
65 std::atomic
<ALuint
> ref
{0u};
67 EffectSlot
*mSlot
{nullptr};
72 ALeffectslot(ALCcontext
*context
);
73 ALeffectslot(const ALeffectslot
&) = delete;
74 ALeffectslot
& operator=(const ALeffectslot
&) = delete;
77 ALenum
initEffect(ALuint effectId
, ALenum effectType
, const EffectProps
&effectProps
,
79 void updateProps(ALCcontext
*context
) const;
81 static void SetName(ALCcontext
*context
, ALuint id
, std::string_view name
);
86 void eax_initialize(ALCcontext
& al_context
, EaxFxSlotIndexValue index
);
88 [[nodiscard
]] auto eax_get_index() const noexcept
-> EaxFxSlotIndexValue
{ return eax_fx_slot_index_
; }
89 [[nodiscard
]] auto eax_get_eax_fx_slot() const noexcept
-> const EAX50FXSLOTPROPERTIES
&
92 // Returns `true` if all sources should be updated, or `false` otherwise.
93 [[nodiscard
]] auto eax_dispatch(const EaxCall
& call
) -> bool
94 { return call
.is_get() ? eax_get(call
) : eax_set(call
); }
99 static constexpr auto eax_load_effect_dirty_bit
= EaxDirtyFlags
{1} << 0;
100 static constexpr auto eax_volume_dirty_bit
= EaxDirtyFlags
{1} << 1;
101 static constexpr auto eax_lock_dirty_bit
= EaxDirtyFlags
{1} << 2;
102 static constexpr auto eax_flags_dirty_bit
= EaxDirtyFlags
{1} << 3;
103 static constexpr auto eax_occlusion_dirty_bit
= EaxDirtyFlags
{1} << 4;
104 static constexpr auto eax_occlusion_lf_ratio_dirty_bit
= EaxDirtyFlags
{1} << 5;
106 using Exception
= EaxFxSlotException
;
108 using Eax4Props
= EAX40FXSLOTPROPERTIES
;
111 Eax4Props i
; // Immediate.
114 using Eax5Props
= EAX50FXSLOTPROPERTIES
;
117 Eax5Props i
; // Immediate.
120 struct EaxRangeValidator
{
121 template<typename TValue
>
125 const TValue
& min_value
,
126 const TValue
& max_value
) const
128 eax_validate_range
<Exception
>(name
, value
, min_value
, max_value
);
132 struct Eax4GuidLoadEffectValidator
{
133 void operator()(const GUID
& guidLoadEffect
) const
135 if (guidLoadEffect
!= EAX_NULL_GUID
&&
136 guidLoadEffect
!= EAX_REVERB_EFFECT
&&
137 guidLoadEffect
!= EAX_AGCCOMPRESSOR_EFFECT
&&
138 guidLoadEffect
!= EAX_AUTOWAH_EFFECT
&&
139 guidLoadEffect
!= EAX_CHORUS_EFFECT
&&
140 guidLoadEffect
!= EAX_DISTORTION_EFFECT
&&
141 guidLoadEffect
!= EAX_ECHO_EFFECT
&&
142 guidLoadEffect
!= EAX_EQUALIZER_EFFECT
&&
143 guidLoadEffect
!= EAX_FLANGER_EFFECT
&&
144 guidLoadEffect
!= EAX_FREQUENCYSHIFTER_EFFECT
&&
145 guidLoadEffect
!= EAX_VOCALMORPHER_EFFECT
&&
146 guidLoadEffect
!= EAX_PITCHSHIFTER_EFFECT
&&
147 guidLoadEffect
!= EAX_RINGMODULATOR_EFFECT
)
149 eax_fail_unknown_effect_id();
154 struct Eax4VolumeValidator
{
155 void operator()(long lVolume
) const
161 EAXFXSLOT_MAXVOLUME
);
165 struct Eax4LockValidator
{
166 void operator()(long lLock
) const
176 struct Eax4FlagsValidator
{
177 void operator()(unsigned long ulFlags
) const
183 ~EAX40FXSLOTFLAGS_RESERVED
);
187 struct Eax4AllValidator
{
188 void operator()(const EAX40FXSLOTPROPERTIES
& all
) const
190 Eax4GuidLoadEffectValidator
{}(all
.guidLoadEffect
);
191 Eax4VolumeValidator
{}(all
.lVolume
);
192 Eax4LockValidator
{}(all
.lLock
);
193 Eax4FlagsValidator
{}(all
.ulFlags
);
197 struct Eax5FlagsValidator
{
198 void operator()(unsigned long ulFlags
) const
204 ~EAX50FXSLOTFLAGS_RESERVED
);
208 struct Eax5OcclusionValidator
{
209 void operator()(long lOcclusion
) const
214 EAXFXSLOT_MINOCCLUSION
,
215 EAXFXSLOT_MAXOCCLUSION
);
219 struct Eax5OcclusionLfRatioValidator
{
220 void operator()(float flOcclusionLFRatio
) const
223 "Occlusion LF Ratio",
225 EAXFXSLOT_MINOCCLUSIONLFRATIO
,
226 EAXFXSLOT_MAXOCCLUSIONLFRATIO
);
230 struct Eax5AllValidator
{
231 void operator()(const EAX50FXSLOTPROPERTIES
& all
) const
233 Eax4GuidLoadEffectValidator
{}(all
.guidLoadEffect
);
234 Eax4VolumeValidator
{}(all
.lVolume
);
235 Eax4LockValidator
{}(all
.lLock
);
236 Eax5FlagsValidator
{}(all
.ulFlags
);
237 Eax5OcclusionValidator
{}(all
.lOcclusion
);
238 Eax5OcclusionLfRatioValidator
{}(all
.flOcclusionLFRatio
);
242 ALCcontext
* eax_al_context_
{};
243 EaxFxSlotIndexValue eax_fx_slot_index_
{};
244 int eax_version_
{}; // Current EAX version.
245 EaxDirtyFlags eax_df_
{}; // Dirty flags for the current EAX version.
246 EaxEffectUPtr eax_effect_
{};
247 Eax5State eax123_
{}; // EAX1/EAX2/EAX3 state.
248 Eax4State eax4_
{}; // EAX4 state.
249 Eax5State eax5_
{}; // EAX5 state.
250 Eax5Props eax_
{}; // Current EAX state.
252 [[noreturn
]] static void eax_fail(const char* message
);
253 [[noreturn
]] static void eax_fail_unknown_effect_id();
254 [[noreturn
]] static void eax_fail_unknown_property_id();
255 [[noreturn
]] static void eax_fail_unknown_version();
257 // Gets a new value from EAX call,
259 // sets a dirty flag only if the new value differs form the old one,
260 // and assigns the new value.
261 template<typename TValidator
, EaxDirtyFlags TDirtyBit
, typename TProperties
>
262 static void eax_fx_slot_set(const EaxCall
& call
, TProperties
& dst
, EaxDirtyFlags
& dirty_flags
)
264 const auto& src
= call
.get_value
<Exception
, const TProperties
>();
266 dirty_flags
|= (dst
!= src
? TDirtyBit
: EaxDirtyFlags
{});
270 // Gets a new value from EAX call,
272 // sets a dirty flag without comparing the values,
273 // and assigns the new value.
274 template<typename TValidator
, EaxDirtyFlags TDirtyBit
, typename TProperties
>
275 static void eax_fx_slot_set_dirty(const EaxCall
& call
, TProperties
& dst
,
276 EaxDirtyFlags
& dirty_flags
)
278 const auto& src
= call
.get_value
<Exception
, const TProperties
>();
280 dirty_flags
|= TDirtyBit
;
284 [[nodiscard
]] constexpr auto eax4_fx_slot_is_legacy() const noexcept
-> bool
285 { return eax_fx_slot_index_
< 2; }
287 void eax4_fx_slot_ensure_unlocked() const;
289 [[nodiscard
]] static auto eax_get_efx_effect_type(const GUID
& guid
) -> ALenum
;
290 [[nodiscard
]] auto eax_get_eax_default_effect_guid() const noexcept
-> const GUID
&;
291 [[nodiscard
]] auto eax_get_eax_default_lock() const noexcept
-> long;
293 void eax4_fx_slot_set_defaults(Eax4Props
& props
) noexcept
;
294 void eax5_fx_slot_set_defaults(Eax5Props
& props
) noexcept
;
295 void eax4_fx_slot_set_current_defaults(const Eax4Props
& props
) noexcept
;
296 void eax5_fx_slot_set_current_defaults(const Eax5Props
& props
) noexcept
;
297 void eax_fx_slot_set_current_defaults();
298 void eax_fx_slot_set_defaults();
300 static void eax4_fx_slot_get(const EaxCall
& call
, const Eax4Props
& props
);
301 static void eax5_fx_slot_get(const EaxCall
& call
, const Eax5Props
& props
);
302 void eax_fx_slot_get(const EaxCall
& call
) const;
303 // Returns `true` if all sources should be updated, or `false` otherwise.
304 bool eax_get(const EaxCall
& call
);
306 void eax_fx_slot_load_effect(int version
, ALenum altype
);
307 void eax_fx_slot_set_volume();
308 void eax_fx_slot_set_environment_flag();
309 void eax_fx_slot_set_flags();
311 void eax4_fx_slot_set_all(const EaxCall
& call
);
312 void eax5_fx_slot_set_all(const EaxCall
& call
);
314 [[nodiscard
]] auto eax_fx_slot_should_update_sources() const noexcept
-> bool;
316 // Returns `true` if all sources should be updated, or `false` otherwise.
317 bool eax4_fx_slot_set(const EaxCall
& call
);
318 // Returns `true` if all sources should be updated, or `false` otherwise.
319 bool eax5_fx_slot_set(const EaxCall
& call
);
320 // Returns `true` if all sources should be updated, or `false` otherwise.
321 bool eax_fx_slot_set(const EaxCall
& call
);
322 // Returns `true` if all sources should be updated, or `false` otherwise.
323 bool eax_set(const EaxCall
& call
);
326 EaxDirtyFlags TDirtyBit
,
327 typename TMemberResult
,
330 void eax_fx_slot_commit_property(TState
& state
, EaxDirtyFlags
& dst_df
,
331 TMemberResult
TProps::*member
) noexcept
333 auto& src_i
= state
.i
;
336 if((eax_df_
& TDirtyBit
) != EaxDirtyFlags
{})
339 dst_i
.*member
= src_i
.*member
;
343 void eax4_fx_slot_commit(EaxDirtyFlags
& dst_df
);
344 void eax5_fx_slot_commit(Eax5State
& state
, EaxDirtyFlags
& dst_df
);
346 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
347 void eax_set_efx_slot_effect(EaxEffect
&effect
);
349 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
350 void eax_set_efx_slot_send_auto(bool is_send_auto
);
352 // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
353 void eax_set_efx_slot_gain(ALfloat gain
);
358 void operator()(ALeffectslot
*effect_slot
);
363 void UpdateAllEffectSlotProps(ALCcontext
*context
);
366 using EaxAlEffectSlotUPtr
= std::unique_ptr
<ALeffectslot
, ALeffectslot::EaxDeleter
>;
368 EaxAlEffectSlotUPtr
eax_create_al_effect_slot(ALCcontext
& context
);
369 void eax_delete_al_effect_slot(ALCcontext
& context
, ALeffectslot
& effect_slot
);
372 struct EffectSlotSubList
{
373 uint64_t FreeMask
{~0_u64
};
374 gsl::owner
<std::array
<ALeffectslot
,64>*> EffectSlots
{nullptr};
376 EffectSlotSubList() noexcept
= default;
377 EffectSlotSubList(const EffectSlotSubList
&) = delete;
378 EffectSlotSubList(EffectSlotSubList
&& rhs
) noexcept
379 : FreeMask
{rhs
.FreeMask
}, EffectSlots
{rhs
.EffectSlots
}
380 { rhs
.FreeMask
= ~0_u64
; rhs
.EffectSlots
= nullptr; }
381 ~EffectSlotSubList();
383 EffectSlotSubList
& operator=(const EffectSlotSubList
&) = delete;
384 EffectSlotSubList
& operator=(EffectSlotSubList
&& rhs
) noexcept
385 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(EffectSlots
, rhs
.EffectSlots
); return *this; }