diff options
Diffstat (limited to 'al/effects/echo.cpp')
-rw-r--r-- | al/effects/echo.cpp | 511 |
1 files changed, 147 insertions, 364 deletions
diff --git a/al/effects/echo.cpp b/al/effects/echo.cpp index 56849b9d..f25c94bf 100644 --- a/al/effects/echo.cpp +++ b/al/effects/echo.cpp @@ -9,7 +9,6 @@ #ifdef ALSOFT_EAX #include "alnumeric.h" - #include "al/eax/exception.h" #include "al/eax/utils.h" #endif // ALSOFT_EAX @@ -120,157 +119,151 @@ const EffectProps EchoEffectProps{genDefaultProps()}; #ifdef ALSOFT_EAX namespace { -using EaxEchoEffectDirtyFlagsValue = std::uint_least8_t; - -struct EaxEchoEffectDirtyFlags +class EaxEchoEffectException : public EaxException { - using EaxIsBitFieldStruct = bool; - - EaxEchoEffectDirtyFlagsValue flDelay : 1; - EaxEchoEffectDirtyFlagsValue flLRDelay : 1; - EaxEchoEffectDirtyFlagsValue flDamping : 1; - EaxEchoEffectDirtyFlagsValue flFeedback : 1; - EaxEchoEffectDirtyFlagsValue flSpread : 1; -}; // EaxEchoEffectDirtyFlags - +public: + explicit EaxEchoEffectException(const char* message) + : EaxException{"EAX_ECHO_EFFECT", message} + {} +}; // EaxEchoEffectException -class EaxEchoEffect final : - public EaxEffect +class EaxEchoEffect final : public EaxEffect4<EaxEchoEffectException, EAXECHOPROPERTIES> { public: - EaxEchoEffect(); - - void dispatch(const EaxEaxCall& eax_call) override; - - // [[nodiscard]] - bool apply_deferred() override; + EaxEchoEffect(const EaxCall& call); private: - EAXECHOPROPERTIES eax_{}; - EAXECHOPROPERTIES eax_d_{}; - EaxEchoEffectDirtyFlags eax_dirty_flags_{}; - - void set_eax_defaults(); - - void set_efx_delay(); - void set_efx_lr_delay(); - void set_efx_damping(); - void set_efx_feedback(); - void set_efx_spread(); - void set_efx_defaults(); - - void get(const EaxEaxCall& eax_call); - - void validate_delay(float flDelay); - void validate_lr_delay(float flLRDelay); - void validate_damping(float flDamping); - void validate_feedback(float flFeedback); - void validate_spread(float flSpread); - void validate_all(const EAXECHOPROPERTIES& all); - - void defer_delay(float flDelay); - void defer_lr_delay(float flLRDelay); - void defer_damping(float flDamping); - void defer_feedback(float flFeedback); - void defer_spread(float flSpread); - void defer_all(const EAXECHOPROPERTIES& all); - - void defer_delay(const EaxEaxCall& eax_call); - void defer_lr_delay(const EaxEaxCall& eax_call); - void defer_damping(const EaxEaxCall& eax_call); - void defer_feedback(const EaxEaxCall& eax_call); - void defer_spread(const EaxEaxCall& eax_call); - void defer_all(const EaxEaxCall& eax_call); - - void set(const EaxEaxCall& eax_call); + struct DelayValidator { + void operator()(float flDelay) const + { + eax_validate_range<Exception>( + "Delay", + flDelay, + EAXECHO_MINDELAY, + EAXECHO_MAXDELAY); + } + }; // DelayValidator + + struct LrDelayValidator { + void operator()(float flLRDelay) const + { + eax_validate_range<Exception>( + "LR Delay", + flLRDelay, + EAXECHO_MINLRDELAY, + EAXECHO_MAXLRDELAY); + } + }; // LrDelayValidator + + struct DampingValidator { + void operator()(float flDamping) const + { + eax_validate_range<Exception>( + "Damping", + flDamping, + EAXECHO_MINDAMPING, + EAXECHO_MAXDAMPING); + } + }; // DampingValidator + + struct FeedbackValidator { + void operator()(float flFeedback) const + { + eax_validate_range<Exception>( + "Feedback", + flFeedback, + EAXECHO_MINFEEDBACK, + EAXECHO_MAXFEEDBACK); + } + }; // FeedbackValidator + + struct SpreadValidator { + void operator()(float flSpread) const + { + eax_validate_range<Exception>( + "Spread", + flSpread, + EAXECHO_MINSPREAD, + EAXECHO_MAXSPREAD); + } + }; // SpreadValidator + + struct AllValidator { + void operator()(const Props& all) const + { + DelayValidator{}(all.flDelay); + LrDelayValidator{}(all.flLRDelay); + DampingValidator{}(all.flDamping); + FeedbackValidator{}(all.flFeedback); + SpreadValidator{}(all.flSpread); + } + }; // AllValidator + + void set_defaults(Props& props) override; + + void set_efx_delay() noexcept; + void set_efx_lr_delay() noexcept; + void set_efx_damping() noexcept; + void set_efx_feedback() noexcept; + void set_efx_spread() noexcept; + void set_efx_defaults() override; + + void get(const EaxCall& call, const Props& props) override; + void set(const EaxCall& call, Props& props) override; + bool commit_props(const Props& props) override; }; // EaxEchoEffect +EaxEchoEffect::EaxEchoEffect(const EaxCall& call) + : EaxEffect4{AL_EFFECT_ECHO, call} +{} -class EaxEchoEffectException : - public EaxException -{ -public: - explicit EaxEchoEffectException( - const char* message) - : - EaxException{"EAX_ECHO_EFFECT", message} - { - } -}; // EaxEchoEffectException - - -EaxEchoEffect::EaxEchoEffect() - : EaxEffect{AL_EFFECT_ECHO} -{ - set_eax_defaults(); - set_efx_defaults(); -} - -void EaxEchoEffect::dispatch( - const EaxEaxCall& eax_call) -{ - eax_call.is_get() ? get(eax_call) : set(eax_call); -} - -void EaxEchoEffect::set_eax_defaults() +void EaxEchoEffect::set_defaults(Props& props) { - eax_.flDelay = EAXECHO_DEFAULTDELAY; - eax_.flLRDelay = EAXECHO_DEFAULTLRDELAY; - eax_.flDamping = EAXECHO_DEFAULTDAMPING; - eax_.flFeedback = EAXECHO_DEFAULTFEEDBACK; - eax_.flSpread = EAXECHO_DEFAULTSPREAD; - - eax_d_ = eax_; + props.flDelay = EAXECHO_DEFAULTDELAY; + props.flLRDelay = EAXECHO_DEFAULTLRDELAY; + props.flDamping = EAXECHO_DEFAULTDAMPING; + props.flFeedback = EAXECHO_DEFAULTFEEDBACK; + props.flSpread = EAXECHO_DEFAULTSPREAD; } -void EaxEchoEffect::set_efx_delay() +void EaxEchoEffect::set_efx_delay() noexcept { - const auto delay = clamp( - eax_.flDelay, + al_effect_props_.Echo.Delay = clamp( + props_.flDelay, AL_ECHO_MIN_DELAY, AL_ECHO_MAX_DELAY); - - al_effect_props_.Echo.Delay = delay; } -void EaxEchoEffect::set_efx_lr_delay() +void EaxEchoEffect::set_efx_lr_delay() noexcept { - const auto lr_delay = clamp( - eax_.flLRDelay, + al_effect_props_.Echo.LRDelay = clamp( + props_.flLRDelay, AL_ECHO_MIN_LRDELAY, AL_ECHO_MAX_LRDELAY); - - al_effect_props_.Echo.LRDelay = lr_delay; } -void EaxEchoEffect::set_efx_damping() +void EaxEchoEffect::set_efx_damping() noexcept { - const auto damping = clamp( - eax_.flDamping, + al_effect_props_.Echo.Damping = clamp( + props_.flDamping, AL_ECHO_MIN_DAMPING, AL_ECHO_MAX_DAMPING); - - al_effect_props_.Echo.Damping = damping; } -void EaxEchoEffect::set_efx_feedback() +void EaxEchoEffect::set_efx_feedback() noexcept { - const auto feedback = clamp( - eax_.flFeedback, + al_effect_props_.Echo.Feedback = clamp( + props_.flFeedback, AL_ECHO_MIN_FEEDBACK, AL_ECHO_MAX_FEEDBACK); - - al_effect_props_.Echo.Feedback = feedback; } -void EaxEchoEffect::set_efx_spread() +void EaxEchoEffect::set_efx_spread() noexcept { - const auto spread = clamp( - eax_.flSpread, + al_effect_props_.Echo.Spread = clamp( + props_.flSpread, AL_ECHO_MIN_SPREAD, AL_ECHO_MAX_SPREAD); - - al_effect_props_.Echo.Spread = spread; } void EaxEchoEffect::set_efx_defaults() @@ -282,288 +275,78 @@ void EaxEchoEffect::set_efx_defaults() set_efx_spread(); } -void EaxEchoEffect::get(const EaxEaxCall& eax_call) +void EaxEchoEffect::get(const EaxCall& call, const Props& props) { - switch(eax_call.get_property_id()) + switch(call.get_property_id()) { - case EAXECHO_NONE: - break; - - case EAXECHO_ALLPARAMETERS: - eax_call.set_value<EaxEchoEffectException>(eax_); - break; - - case EAXECHO_DELAY: - eax_call.set_value<EaxEchoEffectException>(eax_.flDelay); - break; - - case EAXECHO_LRDELAY: - eax_call.set_value<EaxEchoEffectException>(eax_.flLRDelay); - break; - - case EAXECHO_DAMPING: - eax_call.set_value<EaxEchoEffectException>(eax_.flDamping); - break; - - case EAXECHO_FEEDBACK: - eax_call.set_value<EaxEchoEffectException>(eax_.flFeedback); - break; - - case EAXECHO_SPREAD: - eax_call.set_value<EaxEchoEffectException>(eax_.flSpread); - break; - - default: - throw EaxEchoEffectException{"Unsupported property id."}; + case EAXECHO_NONE: break; + case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props); break; + case EAXECHO_DELAY: call.set_value<Exception>(props.flDelay); break; + case EAXECHO_LRDELAY: call.set_value<Exception>(props.flLRDelay); break; + case EAXECHO_DAMPING: call.set_value<Exception>(props.flDamping); break; + case EAXECHO_FEEDBACK: call.set_value<Exception>(props.flFeedback); break; + case EAXECHO_SPREAD: call.set_value<Exception>(props.flSpread); break; + default: fail_unknown_property_id(); } } -void EaxEchoEffect::validate_delay( - float flDelay) -{ - eax_validate_range<EaxEchoEffectException>( - "Delay", - flDelay, - EAXECHO_MINDELAY, - EAXECHO_MAXDELAY); -} - -void EaxEchoEffect::validate_lr_delay( - float flLRDelay) -{ - eax_validate_range<EaxEchoEffectException>( - "LR Delay", - flLRDelay, - EAXECHO_MINLRDELAY, - EAXECHO_MAXLRDELAY); -} - -void EaxEchoEffect::validate_damping( - float flDamping) -{ - eax_validate_range<EaxEchoEffectException>( - "Damping", - flDamping, - EAXECHO_MINDAMPING, - EAXECHO_MAXDAMPING); -} - -void EaxEchoEffect::validate_feedback( - float flFeedback) -{ - eax_validate_range<EaxEchoEffectException>( - "Feedback", - flFeedback, - EAXECHO_MINFEEDBACK, - EAXECHO_MAXFEEDBACK); -} - -void EaxEchoEffect::validate_spread( - float flSpread) -{ - eax_validate_range<EaxEchoEffectException>( - "Spread", - flSpread, - EAXECHO_MINSPREAD, - EAXECHO_MAXSPREAD); -} - -void EaxEchoEffect::validate_all( - const EAXECHOPROPERTIES& all) -{ - validate_delay(all.flDelay); - validate_lr_delay(all.flLRDelay); - validate_damping(all.flDamping); - validate_feedback(all.flFeedback); - validate_spread(all.flSpread); -} - -void EaxEchoEffect::defer_delay( - float flDelay) -{ - eax_d_.flDelay = flDelay; - eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay); -} - -void EaxEchoEffect::defer_lr_delay( - float flLRDelay) +void EaxEchoEffect::set(const EaxCall& call, Props& props) { - eax_d_.flLRDelay = flLRDelay; - eax_dirty_flags_.flLRDelay = (eax_.flLRDelay != eax_d_.flLRDelay); -} - -void EaxEchoEffect::defer_damping( - float flDamping) -{ - eax_d_.flDamping = flDamping; - eax_dirty_flags_.flDamping = (eax_.flDamping != eax_d_.flDamping); -} - -void EaxEchoEffect::defer_feedback( - float flFeedback) -{ - eax_d_.flFeedback = flFeedback; - eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback); -} - -void EaxEchoEffect::defer_spread( - float flSpread) -{ - eax_d_.flSpread = flSpread; - eax_dirty_flags_.flSpread = (eax_.flSpread != eax_d_.flSpread); -} - -void EaxEchoEffect::defer_all( - const EAXECHOPROPERTIES& all) -{ - defer_delay(all.flDelay); - defer_lr_delay(all.flLRDelay); - defer_damping(all.flDamping); - defer_feedback(all.flFeedback); - defer_spread(all.flSpread); -} - -void EaxEchoEffect::defer_delay( - const EaxEaxCall& eax_call) -{ - const auto& delay = - eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDelay)>(); - - validate_delay(delay); - defer_delay(delay); -} - -void EaxEchoEffect::defer_lr_delay( - const EaxEaxCall& eax_call) -{ - const auto& lr_delay = - eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flLRDelay)>(); - - validate_lr_delay(lr_delay); - defer_lr_delay(lr_delay); -} - -void EaxEchoEffect::defer_damping( - const EaxEaxCall& eax_call) -{ - const auto& damping = - eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flDamping)>(); - - validate_damping(damping); - defer_damping(damping); -} - -void EaxEchoEffect::defer_feedback( - const EaxEaxCall& eax_call) -{ - const auto& feedback = - eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flFeedback)>(); - - validate_feedback(feedback); - defer_feedback(feedback); -} - -void EaxEchoEffect::defer_spread( - const EaxEaxCall& eax_call) -{ - const auto& spread = - eax_call.get_value<EaxEchoEffectException, const decltype(EAXECHOPROPERTIES::flSpread)>(); - - validate_spread(spread); - defer_spread(spread); -} - -void EaxEchoEffect::defer_all( - const EaxEaxCall& eax_call) -{ - const auto& all = - eax_call.get_value<EaxEchoEffectException, const EAXECHOPROPERTIES>(); - - validate_all(all); - defer_all(all); -} - -// [[nodiscard]] -bool EaxEchoEffect::apply_deferred() -{ - if (eax_dirty_flags_ == EaxEchoEffectDirtyFlags{}) + switch(call.get_property_id()) { - return false; + case EAXECHO_NONE: break; + case EAXECHO_ALLPARAMETERS: defer<AllValidator>(call, props); break; + case EAXECHO_DELAY: defer<DelayValidator>(call, props.flDelay); break; + case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.flLRDelay); break; + case EAXECHO_DAMPING: defer<DampingValidator>(call, props.flDamping); break; + case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.flFeedback); break; + case EAXECHO_SPREAD: defer<SpreadValidator>(call, props.flSpread); break; + default: fail_unknown_property_id(); } +} - eax_ = eax_d_; +bool EaxEchoEffect::commit_props(const Props& props) +{ + auto is_dirty = false; - if (eax_dirty_flags_.flDelay) + if (props_.flDelay != props.flDelay) { + is_dirty = true; set_efx_delay(); } - if (eax_dirty_flags_.flLRDelay) + if (props_.flLRDelay != props.flLRDelay) { + is_dirty = true; set_efx_lr_delay(); } - if (eax_dirty_flags_.flDamping) + if (props_.flDamping != props.flDamping) { + is_dirty = true; set_efx_damping(); } - if (eax_dirty_flags_.flFeedback) + if (props_.flFeedback != props.flFeedback) { + is_dirty = true; set_efx_feedback(); } - if (eax_dirty_flags_.flSpread) + if (props_.flSpread != props.flSpread) { + is_dirty = true; set_efx_spread(); } - eax_dirty_flags_ = EaxEchoEffectDirtyFlags{}; - - return true; -} - -void EaxEchoEffect::set(const EaxEaxCall& eax_call) -{ - switch(eax_call.get_property_id()) - { - case EAXECHO_NONE: - break; - - case EAXECHO_ALLPARAMETERS: - defer_all(eax_call); - break; - - case EAXECHO_DELAY: - defer_delay(eax_call); - break; - - case EAXECHO_LRDELAY: - defer_lr_delay(eax_call); - break; - - case EAXECHO_DAMPING: - defer_damping(eax_call); - break; - - case EAXECHO_FEEDBACK: - defer_feedback(eax_call); - break; - - case EAXECHO_SPREAD: - defer_spread(eax_call); - break; - - default: - throw EaxEchoEffectException{"Unsupported property id."}; - } + return is_dirty; } } // namespace -EaxEffectUPtr eax_create_eax_echo_effect() +EaxEffectUPtr eax_create_eax_echo_effect(const EaxCall& call) { - return std::make_unique<EaxEchoEffect>(); + return eax_create_eax4_effect<EaxEchoEffect>(call); } #endif // ALSOFT_EAX |