diff options
Diffstat (limited to 'al/effects/echo.cpp')
-rw-r--r-- | al/effects/echo.cpp | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/al/effects/echo.cpp b/al/effects/echo.cpp index 65f691c6..5ceb161d 100644 --- a/al/effects/echo.cpp +++ b/al/effects/echo.cpp @@ -7,6 +7,13 @@ #include "alc/effects/base.h" #include "effects.h" +#if ALSOFT_EAX +#include "alnumeric.h" + +#include "al/eax_exception.h" +#include "al/eax_utils.h" +#endif // ALSOFT_EAX + namespace { @@ -109,3 +116,530 @@ EffectProps genDefaultProps() noexcept DEFINE_ALEFFECT_VTABLE(Echo); const EffectProps EchoEffectProps{genDefaultProps()}; + +#if ALSOFT_EAX +namespace +{ + + +using EaxEchoEffectDirtyFlagsValue = std::uint_least8_t; + +struct EaxEchoEffectDirtyFlags +{ + using EaxIsBitFieldStruct = bool; + + EaxEchoEffectDirtyFlagsValue flDelay : 1; + EaxEchoEffectDirtyFlagsValue flLRDelay : 1; + EaxEchoEffectDirtyFlagsValue flDamping : 1; + EaxEchoEffectDirtyFlagsValue flFeedback : 1; + EaxEchoEffectDirtyFlagsValue flSpread : 1; +}; // EaxEchoEffectDirtyFlags + + +class EaxEchoEffect final : + public EaxEffect +{ +public: + EaxEchoEffect( + EffectProps& al_effect_props); + + + // [[nodiscard]] + bool dispatch( + const EaxEaxCall& eax_call) override; + + +private: + EffectProps& al_effect_props_; + + 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(); + + + // [[nodiscard]] + bool 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); + + + bool apply_deferred(); + + bool set( + const EaxEaxCall& eax_call); +}; // EaxEchoEffect + + +class EaxEchoEffectException : + public EaxException +{ +public: + explicit EaxEchoEffectException( + const char* message) + : + EaxException{"EAX_ECHO_EFFECT", message} + { + } +}; // EaxEchoEffectException + + +EaxEchoEffect::EaxEchoEffect( + EffectProps& al_effect_props) + : + al_effect_props_{al_effect_props} +{ + set_eax_defaults(); + set_efx_defaults(); +} + +// [[nodiscard]] +bool EaxEchoEffect::dispatch( + const EaxEaxCall& eax_call) +{ + return eax_call.is_get() ? get(eax_call) : set(eax_call); +} + +void EaxEchoEffect::set_eax_defaults() +{ + eax_.flDelay = EAXECHO_DEFAULTDELAY; + eax_.flLRDelay = EAXECHO_DEFAULTLRDELAY; + eax_.flDamping = EAXECHO_DEFAULTDAMPING; + eax_.flFeedback = EAXECHO_DEFAULTFEEDBACK; + eax_.flSpread = EAXECHO_DEFAULTSPREAD; + + eax_d_ = eax_; +} + +void EaxEchoEffect::set_efx_delay() +{ + const auto delay = clamp( + eax_.flDelay, + AL_ECHO_MIN_DELAY, + AL_ECHO_MAX_DELAY); + + al_effect_props_.Echo.Delay = delay; +} + +void EaxEchoEffect::set_efx_lr_delay() +{ + const auto lr_delay = clamp( + eax_.flLRDelay, + AL_ECHO_MIN_LRDELAY, + AL_ECHO_MAX_LRDELAY); + + al_effect_props_.Echo.LRDelay = lr_delay; +} + +void EaxEchoEffect::set_efx_damping() +{ + const auto damping = clamp( + eax_.flDamping, + AL_ECHO_MIN_DAMPING, + AL_ECHO_MAX_DAMPING); + + al_effect_props_.Echo.Damping = damping; +} + +void EaxEchoEffect::set_efx_feedback() +{ + const auto feedback = clamp( + eax_.flFeedback, + AL_ECHO_MIN_FEEDBACK, + AL_ECHO_MAX_FEEDBACK); + + al_effect_props_.Echo.Feedback = feedback; +} + +void EaxEchoEffect::set_efx_spread() +{ + const auto spread = clamp( + eax_.flSpread, + AL_ECHO_MIN_SPREAD, + AL_ECHO_MAX_SPREAD); + + al_effect_props_.Echo.Spread = spread; +} + +void EaxEchoEffect::set_efx_defaults() +{ + set_efx_delay(); + set_efx_lr_delay(); + set_efx_damping(); + set_efx_feedback(); + set_efx_spread(); +} + +// [[nodiscard]] +bool EaxEchoEffect::get( + const EaxEaxCall& eax_call) +{ + switch (eax_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."}; + } + + return false; +} + +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) +{ + 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{}) + { + return false; + } + + eax_ = eax_d_; + + if (eax_dirty_flags_.flDelay) + { + set_efx_delay(); + } + + if (eax_dirty_flags_.flLRDelay) + { + set_efx_lr_delay(); + } + + if (eax_dirty_flags_.flDamping) + { + set_efx_damping(); + } + + if (eax_dirty_flags_.flFeedback) + { + set_efx_feedback(); + } + + if (eax_dirty_flags_.flSpread) + { + set_efx_spread(); + } + + eax_dirty_flags_ = EaxEchoEffectDirtyFlags{}; + + return true; +} + +// [[nodiscard]] +bool 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."}; + } + + if (!eax_call.is_deferred()) + { + return apply_deferred(); + } + + return false; +} + + +} // namespace + + +EaxEffectUPtr eax_create_eax_echo_effect( + EffectProps& al_effect_props) +{ + return std::make_unique<EaxEchoEffect>(al_effect_props); +} + + +#endif // ALSOFT_EAX |