diff options
author | Boris I. Bendovsky <[email protected]> | 2022-07-12 12:46:51 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2022-07-12 02:46:51 -0700 |
commit | 6fb5cb553f4c2faf4b991ac377ec457a7bba7e4c (patch) | |
tree | 5b62a1111fa1a48f3a2e226b8491bc1615db865d /al/auxeffectslot.h | |
parent | fa51c89549590319cb545a8c81419e2e1ddc5db3 (diff) |
[EAX] Use separate FX slot state for each version (#730)
* [EAX] Use separate FX slot state for each version
[EAX] Don't defer FX slot properties
* [EAX_FXSLOT] Use mPropsDirty to defer update
[EAX_CONTEXT] Commit all updates on first initialization
Diffstat (limited to 'al/auxeffectslot.h')
-rw-r--r-- | al/auxeffectslot.h | 370 |
1 files changed, 250 insertions, 120 deletions
diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 83711372..fb6a2e1e 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -20,13 +20,23 @@ #include <memory> #include "eax/call.h" #include "eax/effect.h" +#include "eax/exception.h" #include "eax/fx_slot_index.h" +#include "eax/utils.h" #endif // ALSOFT_EAX struct ALbuffer; struct ALeffect; struct WetBuffer; +#ifdef ALSOFT_EAX +class EaxFxSlotException : public EaxException { +public: + explicit EaxFxSlotException(const char* message) + : EaxException{"EAX_FX_SLOT", message} + {} +}; +#endif // ALSOFT_EAX enum class SlotState : ALenum { Initial = AL_INITIAL, @@ -79,162 +89,282 @@ public: const EAX50FXSLOTPROPERTIES& eax_get_eax_fx_slot() const noexcept; - - // [[nodiscard]] + // Returns `true` if all sources should be updated, or `false` otherwise. bool eax_dispatch(const EaxCall& call) { return call.is_get() ? eax_get(call) : eax_set(call); } - - void eax_unlock_legacy() noexcept; - - void eax_commit() { eax_apply_deferred(); } + void eax_commit(); private: - ALCcontext* eax_al_context_{}; + static constexpr auto eax_load_effect_dirty_bit = EaxDirtyFlags{1} << 0; + static constexpr auto eax_volume_dirty_bit = EaxDirtyFlags{1} << 1; + static constexpr auto eax_lock_dirty_bit = EaxDirtyFlags{1} << 2; + static constexpr auto eax_flags_dirty_bit = EaxDirtyFlags{1} << 3; + static constexpr auto eax_occlusion_dirty_bit = EaxDirtyFlags{1} << 4; + static constexpr auto eax_occlusion_lf_ratio_dirty_bit = EaxDirtyFlags{1} << 5; + + using Exception = EaxFxSlotException; + + using Eax4Props = EAX40FXSLOTPROPERTIES; + + struct Eax4State { + Eax4Props i; // Immediate. + EaxDirtyFlags df; // Dirty flags. + }; + + using Eax5Props = EAX50FXSLOTPROPERTIES; + + struct Eax5State { + Eax5Props i; // Immediate. + EaxDirtyFlags df; // Dirty flags. + }; + + struct EaxRangeValidator { + template<typename TValue> + void operator()( + const char* name, + const TValue& value, + const TValue& min_value, + const TValue& max_value) const + { + eax_validate_range<Exception>(name, value, min_value, max_value); + } + }; + + struct Eax4GuidLoadEffectValidator { + void operator()(const GUID& guidLoadEffect) const + { + if (guidLoadEffect != EAX_NULL_GUID && + guidLoadEffect != EAX_REVERB_EFFECT && + guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT && + guidLoadEffect != EAX_AUTOWAH_EFFECT && + guidLoadEffect != EAX_CHORUS_EFFECT && + guidLoadEffect != EAX_DISTORTION_EFFECT && + guidLoadEffect != EAX_ECHO_EFFECT && + guidLoadEffect != EAX_EQUALIZER_EFFECT && + guidLoadEffect != EAX_FLANGER_EFFECT && + guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT && + guidLoadEffect != EAX_VOCALMORPHER_EFFECT && + guidLoadEffect != EAX_PITCHSHIFTER_EFFECT && + guidLoadEffect != EAX_RINGMODULATOR_EFFECT) + { + eax_fail_unknown_effect_id(); + } + } + }; + + struct Eax4VolumeValidator { + void operator()(long lVolume) const + { + EaxRangeValidator{}( + "Volume", + lVolume, + EAXFXSLOT_MINVOLUME, + EAXFXSLOT_MAXVOLUME); + } + }; + + struct Eax4LockValidator { + void operator()(long lLock) const + { + EaxRangeValidator{}( + "Lock", + lLock, + EAXFXSLOT_MINLOCK, + EAXFXSLOT_MAXLOCK); + } + }; + + struct Eax4FlagsValidator { + void operator()(unsigned long ulFlags) const + { + EaxRangeValidator{}( + "Flags", + ulFlags, + 0UL, + ~EAX40FXSLOTFLAGS_RESERVED); + } + }; + + struct Eax4AllValidator { + void operator()(const EAX40FXSLOTPROPERTIES& all) const + { + Eax4GuidLoadEffectValidator{}(all.guidLoadEffect); + Eax4VolumeValidator{}(all.lVolume); + Eax4LockValidator{}(all.lLock); + Eax4FlagsValidator{}(all.ulFlags); + } + }; + + struct Eax5OcclusionValidator { + void operator()(long lOcclusion) const + { + EaxRangeValidator{}( + "Occlusion", + lOcclusion, + EAXFXSLOT_MINOCCLUSION, + EAXFXSLOT_MAXOCCLUSION); + } + }; + + struct Eax5OcclusionLfRatioValidator { + void operator()(float flOcclusionLFRatio) const + { + EaxRangeValidator{}( + "Occlusion LF Ratio", + flOcclusionLFRatio, + EAXFXSLOT_MINOCCLUSIONLFRATIO, + EAXFXSLOT_MAXOCCLUSIONLFRATIO); + } + }; + + struct Eax5FlagsValidator { + void operator()(unsigned long ulFlags) const + { + EaxRangeValidator{}( + "Flags", + ulFlags, + 0UL, + ~EAX50FXSLOTFLAGS_RESERVED); + } + }; + + struct Eax5AllValidator { + void operator()(const EAX50FXSLOTPROPERTIES& all) const + { + Eax4AllValidator{}(static_cast<const EAX40FXSLOTPROPERTIES&>(all)); + Eax5OcclusionValidator{}(all.lOcclusion); + Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio); + } + }; + ALCcontext* eax_al_context_{}; EaxFxSlotIndexValue eax_fx_slot_index_{}; - - EAX50FXSLOTPROPERTIES eax_eax_fx_slot_{}; - + int eax_version_{}; // Current EAX version. EaxEffectUPtr eax_effect_{}; - bool eax_is_locked_{}; - - - [[noreturn]] - static void eax_fail( - const char* message); - - - GUID eax_get_eax_default_effect_guid() const noexcept; + Eax5State eax123_{}; // EAX1/EAX2/EAX3 state. + Eax4State eax4_{}; // EAX4 state. + Eax5State eax5_{}; // EAX5 state. + Eax5Props eax_{}; // Current EAX state. + + [[noreturn]] static void eax_fail(const char* message); + [[noreturn]] static void eax_fail_unknown_effect_id(); + [[noreturn]] static void eax_fail_unknown_property_id(); + [[noreturn]] static void eax_fail_unknown_version(); + + // Gets a new value from EAX call, + // validates it, + // sets a dirty flag only if the new value differs form the old one, + // and assigns the new value. + template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties> + void eax_fx_slot_set(const EaxCall& call, TProperties& dst, EaxDirtyFlags& dirty_flags) + { + const auto& src = call.get_value<Exception, const TProperties>(); + TValidator{}(src); + dirty_flags |= (dst != src ? TDirtyBit : EaxDirtyFlags{}); + dst = src; + } + + // Gets a new value from EAX call, + // validates it, + // sets a dirty flag without comparing the values, + // and assigns the new value. + template<typename TValidator, EaxDirtyFlags TDirtyBit, typename TProperties> + void eax_fx_slot_set_dirty(const EaxCall& call, TProperties& dst, EaxDirtyFlags& dirty_flags) + { + const auto& src = call.get_value<Exception, const TProperties>(); + TValidator{}(src); + dirty_flags |= TDirtyBit; + dst = src; + } + + constexpr bool eax4_fx_slot_is_legacy() const noexcept + { return eax_fx_slot_index_ < 2; } + + void eax4_fx_slot_ensure_unlocked() const; + + static ALenum eax_get_efx_effect_type(const GUID& guid); + const GUID& eax_get_eax_default_effect_guid() const noexcept; long eax_get_eax_default_lock() const noexcept; - void eax_set_eax_fx_slot_defaults(); - - void eax_initialize_eax(); - - void eax_initialize_lock(); - - - void eax_initialize_effects(const EaxCall& call); - - - void eax_get_fx_slot_all(const EaxCall& call) const; + void eax4_fx_slot_set_defaults(Eax4Props& props); + void eax4_fx_slot_set_defaults(); + void eax5_fx_slot_set_defaults(Eax5Props& props); + void eax5_fx_slot_set_defaults(); + void eax_fx_slot_set_defaults(); - void eax_get_fx_slot(const EaxCall& call) const; - - // [[nodiscard]] + void eax4_fx_slot_get(const EaxCall& call, const Eax4Props& props) const; + void eax5_fx_slot_get(const EaxCall& call, const Eax5Props& props) const; + void eax_fx_slot_get(const EaxCall& call) const; + // Returns `true` if all sources should be updated, or `false` otherwise. bool eax_get(const EaxCall& call); - - void eax_set_fx_slot_effect(const EaxCall& call, ALenum effect_type); - - void eax_set_fx_slot_effect(const EaxCall& call); - - - void eax_set_efx_effect_slot_gain(); - - void eax_set_fx_slot_volume(); - - - void eax_set_effect_slot_send_auto(); - - void eax_set_fx_slot_flags(); - - - void eax_ensure_is_unlocked() const; - - void eax_validate_fx_slot_effect(const GUID& eax_effect_id); - void eax_validate_fx_slot_volume(long eax_volume); - void eax_validate_fx_slot_lock(long eax_lock); - void eax_validate_fx_slot_flags(const EaxCall& call, unsigned long eax_flags); - void eax_validate_fx_slot_occlusion(long eax_occlusion); - void eax_validate_fx_slot_occlusion_lf_ratio(float eax_occlusion_lf_ratio); - void eax_validate_fx_slot_all(const EaxCall& call, const EAX40FXSLOTPROPERTIES& fx_slot); - void eax_validate_fx_slot_all(const EaxCall& call, const EAX50FXSLOTPROPERTIES& fx_slot); - - void eax_set_fx_slot_effect(const EaxCall& call, const GUID& eax_effect_id); - - void eax_set_fx_slot_volume( - long eax_volume); - - void eax_set_fx_slot_lock( - long eax_lock); - - void eax_set_fx_slot_flags( - unsigned long eax_flags); - - // [[nodiscard]] - bool eax_set_fx_slot_occlusion( - long eax_occlusion); - - // [[nodiscard]] - bool eax_set_fx_slot_occlusion_lf_ratio( - float eax_occlusion_lf_ratio); - - void eax_set_fx_slot_all(const EaxCall& call, const EAX40FXSLOTPROPERTIES& eax_fx_slot); - - // [[nodiscard]] - bool eax_set_fx_slot_all(const EaxCall& call, const EAX50FXSLOTPROPERTIES& eax_fx_slot); - - - void eax_defer_fx_slot_effect(const EaxCall& call); - - void eax_defer_fx_slot_volume(const EaxCall& call); - - void eax_defer_fx_slot_lock(const EaxCall& call); - - void eax_defer_fx_slot_flags(const EaxCall& call); - - // [[nodiscard]] - bool eax_defer_fx_slot_occlusion(const EaxCall& call); - - // [[nodiscard]] - bool eax_defer_fx_slot_occlusion_lf_ratio(const EaxCall& call); - - // [[nodiscard]] - bool eax_defer_fx_slot_all(const EaxCall& call); - - bool eax_set_fx_slot(const EaxCall& call); - - void eax_apply_deferred(); - - // [[nodiscard]] + void eax_fx_slot_load_effect(); + void eax_fx_slot_set_volume(); + void eax_fx_slot_set_environment_flag(); + void eax_fx_slot_set_flags(); + + void eax4_fx_slot_set_all(const EaxCall& call); + void eax5_fx_slot_set_all(const EaxCall& call); + + // Returns `true` if all sources should be updated, or `false` otherwise. + bool eax4_fx_slot_set(const EaxCall& call); + // Returns `true` if all sources should be updated, or `false` otherwise. + bool eax5_fx_slot_set(const EaxCall& call); + // Returns `true` if all sources should be updated, or `false` otherwise. + bool eax_fx_slot_set(const EaxCall& call); + // Returns `true` if all sources should be updated, or `false` otherwise. bool eax_set(const EaxCall& call); + template< + EaxDirtyFlags TDirtyBit, + typename TMemberResult, + typename TProps, + typename TState> + void eax_fx_slot_commit_property( + TState& state, + EaxDirtyFlags& dst_df, + TMemberResult TProps::*member) noexcept + { + auto& src_i = state.i; + auto& src_df = state.df; + auto& dst_i = eax_; + + if ((src_df & TDirtyBit) != EaxDirtyFlags{}) { + dst_df |= TDirtyBit; + dst_i.*member = src_i.*member; + } + } + + void eax4_fx_slot_commit(EaxDirtyFlags& dst_df); + void eax5_fx_slot_commit(Eax5State& state, EaxDirtyFlags& dst_df); void eax_dispatch_effect(const EaxCall& call); - // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)` - void eax_set_effect_slot_effect(EaxEffect &effect); + void eax_set_efx_slot_effect(EaxEffect &effect); // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)` - void eax_set_effect_slot_send_auto(bool is_send_auto); + void eax_set_efx_slot_send_auto(bool is_send_auto); // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)` - void eax_set_effect_slot_gain(ALfloat gain); + void eax_set_efx_slot_gain(ALfloat gain); public: class EaxDeleter { public: void operator()(ALeffectslot *effect_slot); - }; // EaxAlEffectSlotDeleter + }; #endif // ALSOFT_EAX }; void UpdateAllEffectSlotProps(ALCcontext *context); #ifdef ALSOFT_EAX - using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>; - -EaxAlEffectSlotUPtr eax_create_al_effect_slot( - ALCcontext& context); - -void eax_delete_al_effect_slot( - ALCcontext& context, - ALeffectslot& effect_slot); +EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context); +void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot); #endif // ALSOFT_EAX #endif |