diff options
Diffstat (limited to 'al/eax/effect.h')
-rw-r--r-- | al/eax/effect.h | 165 |
1 files changed, 147 insertions, 18 deletions
diff --git a/al/eax/effect.h b/al/eax/effect.h index 9c9fdef4..b57bf240 100644 --- a/al/eax/effect.h +++ b/al/eax/effect.h @@ -2,43 +2,172 @@ #define EAX_EFFECT_INCLUDED +#include <cassert> #include <memory> +#include "alnumeric.h" #include "AL/al.h" #include "core/effects/base.h" -#include "eax_call.h" +#include "call.h" -class EaxEffect +struct EaxEffectErrorMessages { + static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; } + static constexpr auto unknown_version() noexcept { return "Unknown version."; } +}; // EaxEffectErrorMessages + +class EaxEffect { public: - EaxEffect(ALenum type) : al_effect_type_{type} { } + EaxEffect(ALenum type) noexcept : al_effect_type_{type} { } virtual ~EaxEffect() = default; const ALenum al_effect_type_; EffectProps al_effect_props_{}; - virtual void dispatch(const EaxEaxCall& eax_call) = 0; + virtual void dispatch(const EaxCall& call) = 0; // Returns "true" if any immediated property was changed. - // [[nodiscard]] - virtual bool apply_deferred() = 0; + /*[[nodiscard]]*/ virtual bool commit() = 0; }; // EaxEffect +// Base class for EAX4+ effects. +template<typename TException, typename TProps> +class EaxEffect4 : public EaxEffect +{ +public: + EaxEffect4(ALenum type, const EaxCall& call) + : EaxEffect{type}, version_{clamp(call.get_version(), 4, 5)} + {} + + void initialize() + { + set_defaults(); + set_efx_defaults(); + } + + void dispatch(const EaxCall& call) override + { + call.is_get() ? get(call) : set(call); + version_ = call.get_version(); + } + + bool commit() final + { + switch (version_) + { + case 4: return commit_state(state4_); + case 5: return commit_state(state5_); + default: fail_unknown_version(); + } + } + +protected: + using Exception = TException; + using Props = TProps; + + struct State { + Props i; // Immediate. + Props d; // Deferred. + }; // State + + int version_; + Props props_; + State state4_; + State state5_; + + template<typename TValidator, typename TProperty> + static void defer(const EaxCall& call, TProperty& property) + { + const auto& value = call.get_value<Exception, const TProperty>(); + TValidator{}(value); + property = value; + } + + virtual void set_defaults(Props& props) = 0; + virtual void set_efx_defaults() = 0; + + virtual void get(const EaxCall& call, const Props& props) = 0; + virtual void set(const EaxCall& call, Props& props) = 0; + + virtual bool commit_props(const Props& props) = 0; + + [[noreturn]] static void fail(const char* message) + { + throw Exception{message}; + } + + [[noreturn]] static void fail_unknown_property_id() + { + fail(EaxEffectErrorMessages::unknown_property_id()); + } + + [[noreturn]] static void fail_unknown_version() + { + fail(EaxEffectErrorMessages::unknown_version()); + } + +private: + void set_defaults() + { + set_defaults(props_); + state4_.i = props_; + state4_.d = props_; + state5_.i = props_; + state5_.d = props_; + } + + void get(const EaxCall& call) + { + switch (call.get_version()) + { + case 4: get(call, state4_.i); break; + case 5: get(call, state5_.i); break; + default: fail_unknown_version(); + } + } + + void set(const EaxCall& call) + { + switch (call.get_version()) + { + case 4: set(call, state4_.d); break; + case 5: set(call, state5_.d); break; + default: fail_unknown_version(); + } + } + + bool commit_state(State& state) + { + const auto props = props_; + state.i = state.d; + props_ = state.d; + return commit_props(props); + } +}; // EaxEffect4 using EaxEffectUPtr = std::unique_ptr<EaxEffect>; +// Creates EAX4+ effect. +template<typename TEffect> +EaxEffectUPtr eax_create_eax4_effect(const EaxCall& call) +{ + auto effect = std::make_unique<TEffect>(call); + effect->initialize(); + return effect; +} + EaxEffectUPtr eax_create_eax_null_effect(); -EaxEffectUPtr eax_create_eax_chorus_effect(); -EaxEffectUPtr eax_create_eax_distortion_effect(); -EaxEffectUPtr eax_create_eax_echo_effect(); -EaxEffectUPtr eax_create_eax_flanger_effect(); -EaxEffectUPtr eax_create_eax_frequency_shifter_effect(); -EaxEffectUPtr eax_create_eax_vocal_morpher_effect(); -EaxEffectUPtr eax_create_eax_pitch_shifter_effect(); -EaxEffectUPtr eax_create_eax_ring_modulator_effect(); -EaxEffectUPtr eax_create_eax_auto_wah_effect(); -EaxEffectUPtr eax_create_eax_compressor_effect(); -EaxEffectUPtr eax_create_eax_equalizer_effect(); -EaxEffectUPtr eax_create_eax_reverb_effect(); +EaxEffectUPtr eax_create_eax_chorus_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_distortion_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_echo_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_flanger_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_frequency_shifter_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_vocal_morpher_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_pitch_shifter_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_ring_modulator_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_auto_wah_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_compressor_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_equalizer_effect(const EaxCall& call); +EaxEffectUPtr eax_create_eax_reverb_effect(const EaxCall& call); #endif // !EAX_EFFECT_INCLUDED |