|
|
-
- #include "config.h"
-
- #include "AL/al.h"
- #include "AL/efx.h"
-
- #include "alc/effects/base.h"
- #include "effects.h"
-
- #ifdef ALSOFT_EAX
- #include "alnumeric.h"
-
- #include "al/eax_exception.h"
- #include "al/eax_utils.h"
- #endif // ALSOFT_EAX
-
-
- namespace {
-
- static_assert(EchoMaxDelay >= AL_ECHO_MAX_DELAY, "Echo max delay too short");
- static_assert(EchoMaxLRDelay >= AL_ECHO_MAX_LRDELAY, "Echo max left-right delay too short");
-
- void Echo_setParami(EffectProps*, ALenum param, int)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
- void Echo_setParamiv(EffectProps*, ALenum param, const int*)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
- void Echo_setParamf(EffectProps *props, ALenum param, float val)
- {
- switch(param)
- {
- case AL_ECHO_DELAY:
- if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
- throw effect_exception{AL_INVALID_VALUE, "Echo delay out of range"};
- props->Echo.Delay = val;
- break;
-
- case AL_ECHO_LRDELAY:
- if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
- throw effect_exception{AL_INVALID_VALUE, "Echo LR delay out of range"};
- props->Echo.LRDelay = val;
- break;
-
- case AL_ECHO_DAMPING:
- if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
- throw effect_exception{AL_INVALID_VALUE, "Echo damping out of range"};
- props->Echo.Damping = val;
- break;
-
- case AL_ECHO_FEEDBACK:
- if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
- throw effect_exception{AL_INVALID_VALUE, "Echo feedback out of range"};
- props->Echo.Feedback = val;
- break;
-
- case AL_ECHO_SPREAD:
- if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
- throw effect_exception{AL_INVALID_VALUE, "Echo spread out of range"};
- props->Echo.Spread = val;
- break;
-
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
- }
- }
- void Echo_setParamfv(EffectProps *props, ALenum param, const float *vals)
- { Echo_setParamf(props, param, vals[0]); }
-
- void Echo_getParami(const EffectProps*, ALenum param, int*)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
- void Echo_getParamiv(const EffectProps*, ALenum param, int*)
- { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
- void Echo_getParamf(const EffectProps *props, ALenum param, float *val)
- {
- switch(param)
- {
- case AL_ECHO_DELAY:
- *val = props->Echo.Delay;
- break;
-
- case AL_ECHO_LRDELAY:
- *val = props->Echo.LRDelay;
- break;
-
- case AL_ECHO_DAMPING:
- *val = props->Echo.Damping;
- break;
-
- case AL_ECHO_FEEDBACK:
- *val = props->Echo.Feedback;
- break;
-
- case AL_ECHO_SPREAD:
- *val = props->Echo.Spread;
- break;
-
- default:
- throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
- }
- }
- void Echo_getParamfv(const EffectProps *props, ALenum param, float *vals)
- { Echo_getParamf(props, param, vals); }
-
- EffectProps genDefaultProps() noexcept
- {
- EffectProps props{};
- props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
- props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
- props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
- props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
- props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
- return props;
- }
-
- } // namespace
-
- DEFINE_ALEFFECT_VTABLE(Echo);
-
- const EffectProps EchoEffectProps{genDefaultProps()};
-
- #ifdef 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();
-
- void dispatch(const EaxEaxCall& eax_call) override;
-
- // [[nodiscard]]
- bool apply_deferred() override;
-
- 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);
- }; // EaxEchoEffect
-
-
- 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()
- {
- 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();
- }
-
- void 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."};
- }
- }
-
- 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;
- }
-
- 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."};
- }
- }
-
- } // namespace
-
- EaxEffectUPtr eax_create_eax_echo_effect()
- {
- return std::make_unique<EaxEchoEffect>();
- }
-
- #endif // ALSOFT_EAX
|