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
: ALenum
{
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 Eax5OcclusionValidator
{
198 void operator()(long lOcclusion
) const
203 EAXFXSLOT_MINOCCLUSION
,
204 EAXFXSLOT_MAXOCCLUSION
);
208 struct Eax5OcclusionLfRatioValidator
{
209 void operator()(float flOcclusionLFRatio
) const
212 "Occlusion LF Ratio",
214 EAXFXSLOT_MINOCCLUSIONLFRATIO
,
215 EAXFXSLOT_MAXOCCLUSIONLFRATIO
);
219 struct Eax5FlagsValidator
{
220 void operator()(unsigned long ulFlags
) const
226 ~EAX50FXSLOTFLAGS_RESERVED
);
230 struct Eax5AllValidator
{
231 void operator()(const EAX50FXSLOTPROPERTIES
& all
) const
233 Eax4AllValidator
{}(static_cast<const EAX40FXSLOTPROPERTIES
&>(all
));
234 Eax5OcclusionValidator
{}(all
.lOcclusion
);
235 Eax5OcclusionLfRatioValidator
{}(all
.flOcclusionLFRatio
);
239 ALCcontext
* eax_al_context_
{};
240 EaxFxSlotIndexValue eax_fx_slot_index_
{};
241 int eax_version_
{}; // Current EAX version.
242 EaxDirtyFlags eax_df_
{}; // Dirty flags for the current EAX version.
243 EaxEffectUPtr eax_effect_
{};
244 Eax5State eax123_
{}; // EAX1/EAX2/EAX3 state.
245 Eax4State eax4_
{}; // EAX4 state.
246 Eax5State eax5_
{}; // EAX5 state.
247 Eax5Props eax_
{}; // Current EAX state.
249 [[noreturn
]] static void eax_fail(const char* message
);
250 [[noreturn
]] static void eax_fail_unknown_effect_id();
251 [[noreturn
]] static void eax_fail_unknown_property_id();
252 [[noreturn
]] static void eax_fail_unknown_version();
254 // Gets a new value from EAX call,
256 // sets a dirty flag only if the new value differs form the old one,
257 // and assigns the new value.
258 template<typename TValidator
, EaxDirtyFlags TDirtyBit
, typename TProperties
>
259 static void eax_fx_slot_set(const EaxCall
& call
, TProperties
& dst
, EaxDirtyFlags
& dirty_flags
)
261 const auto& src
= call
.get_value
<Exception
, const TProperties
>();
263 dirty_flags
|= (dst
!= src
? TDirtyBit
: EaxDirtyFlags
{});
267 // Gets a new value from EAX call,
269 // sets a dirty flag without comparing the values,
270 // and assigns the new value.
271 template<typename TValidator
, EaxDirtyFlags TDirtyBit
, typename TProperties
>
272 static void eax_fx_slot_set_dirty(const EaxCall
& call
, TProperties
& dst
,
273 EaxDirtyFlags
& dirty_flags
)
275 const auto& src
= call
.get_value
<Exception
, const TProperties
>();
277 dirty_flags
|= TDirtyBit
;
281 [[nodiscard
]] constexpr auto eax4_fx_slot_is_legacy() const noexcept
-> bool
282 { return eax_fx_slot_index_
< 2; }
284 void eax4_fx_slot_ensure_unlocked() const;
286 [[nodiscard
]] static auto eax_get_efx_effect_type(const GUID
& guid
) -> ALenum
;
287 [[nodiscard
]] auto eax_get_eax_default_effect_guid() const noexcept
-> const GUID
&;
288 [[nodiscard
]] auto eax_get_eax_default_lock() const noexcept
-> long;
290 void eax4_fx_slot_set_defaults(Eax4Props
& props
) noexcept
;
291 void eax5_fx_slot_set_defaults(Eax5Props
& props
) noexcept
;
292 void eax4_fx_slot_set_current_defaults(const Eax4Props
& props
) noexcept
;
293 void eax5_fx_slot_set_current_defaults(const Eax5Props
& props
) noexcept
;
294 void eax_fx_slot_set_current_defaults();
295 void eax_fx_slot_set_defaults();
297 static void eax4_fx_slot_get(const EaxCall
& call
, const Eax4Props
& props
);
298 static void eax5_fx_slot_get(const EaxCall
& call
, const Eax5Props
& props
);
299 void eax_fx_slot_get(const EaxCall
& call
) const;
300 // Returns `true` if all sources should be updated, or `false` otherwise.
301 bool eax_get(const EaxCall
& call
);
303 void eax_fx_slot_load_effect(int version
, ALenum altype
);
304 void eax_fx_slot_set_volume();
305 void eax_fx_slot_set_environment_flag();
306 void eax_fx_slot_set_flags();
308 void eax4_fx_slot_set_all(const EaxCall
& call
);
309 void eax5_fx_slot_set_all(const EaxCall
& call
);
311 [[nodiscard
]] auto eax_fx_slot_should_update_sources() const noexcept
-> bool;
313 // Returns `true` if all sources should be updated, or `false` otherwise.
314 bool eax4_fx_slot_set(const EaxCall
& call
);
315 // Returns `true` if all sources should be updated, or `false` otherwise.
316 bool eax5_fx_slot_set(const EaxCall
& call
);
317 // Returns `true` if all sources should be updated, or `false` otherwise.
318 bool eax_fx_slot_set(const EaxCall
& call
);
319 // Returns `true` if all sources should be updated, or `false` otherwise.
320 bool eax_set(const EaxCall
& call
);
323 EaxDirtyFlags TDirtyBit
,
324 typename TMemberResult
,
327 void eax_fx_slot_commit_property(TState
& state
, EaxDirtyFlags
& dst_df
,
328 TMemberResult
TProps::*member
) noexcept
330 auto& src_i
= state
.i
;
333 if((eax_df_
& TDirtyBit
) != EaxDirtyFlags
{})
336 dst_i
.*member
= src_i
.*member
;
340 void eax4_fx_slot_commit(EaxDirtyFlags
& dst_df
);
341 void eax5_fx_slot_commit(Eax5State
& state
, EaxDirtyFlags
& dst_df
);
343 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
344 void eax_set_efx_slot_effect(EaxEffect
&effect
);
346 // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
347 void eax_set_efx_slot_send_auto(bool is_send_auto
);
349 // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
350 void eax_set_efx_slot_gain(ALfloat gain
);
355 void operator()(ALeffectslot
*effect_slot
);
360 void UpdateAllEffectSlotProps(ALCcontext
*context
);
363 using EaxAlEffectSlotUPtr
= std::unique_ptr
<ALeffectslot
, ALeffectslot::EaxDeleter
>;
365 EaxAlEffectSlotUPtr
eax_create_al_effect_slot(ALCcontext
& context
);
366 void eax_delete_al_effect_slot(ALCcontext
& context
, ALeffectslot
& effect_slot
);
369 struct EffectSlotSubList
{
370 uint64_t FreeMask
{~0_u64
};
371 gsl::owner
<std::array
<ALeffectslot
,64>*> EffectSlots
{nullptr};
373 EffectSlotSubList() noexcept
= default;
374 EffectSlotSubList(const EffectSlotSubList
&) = delete;
375 EffectSlotSubList(EffectSlotSubList
&& rhs
) noexcept
376 : FreeMask
{rhs
.FreeMask
}, EffectSlots
{rhs
.EffectSlots
}
377 { rhs
.FreeMask
= ~0_u64
; rhs
.EffectSlots
= nullptr; }
378 ~EffectSlotSubList();
380 EffectSlotSubList
& operator=(const EffectSlotSubList
&) = delete;
381 EffectSlotSubList
& operator=(EffectSlotSubList
&& rhs
) noexcept
382 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(EffectSlots
, rhs
.EffectSlots
); return *this; }