aboutsummaryrefslogtreecommitdiffstats
path: root/al/effects/echo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'al/effects/echo.cpp')
-rw-r--r--al/effects/echo.cpp534
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