aboutsummaryrefslogtreecommitdiffstats
path: root/al/effects/fshifter.cpp
diff options
context:
space:
mode:
authorBoris I. Bendovsky <[email protected]>2022-01-30 14:47:32 +0200
committerGitHub <[email protected]>2022-01-30 04:47:32 -0800
commit19ed994dc30ed84ea7cbbb5152577669fc25caf6 (patch)
treef68933bf8f778806618bd6c0b1bf9ced1b0ccf08 /al/effects/fshifter.cpp
parent619249371a40f03cf988d1f5750d643df797c485 (diff)
Add EAX extensions (EAX 2.0-5.0, X-RAM) (#632)
* Add EAX extensions (EAX 2.0-5.0, X-RAM) * Comment out C++17 leftovers * Remove everything related to patching * Update alsoftrc.sample * Rewrite integration * Fix GCC compilation under Linux * Always reset EAX effect properties when loading it into FX slot
Diffstat (limited to 'al/effects/fshifter.cpp')
-rw-r--r--al/effects/fshifter.cpp414
1 files changed, 414 insertions, 0 deletions
diff --git a/al/effects/fshifter.cpp b/al/effects/fshifter.cpp
index 4aa860a2..aa4ddadb 100644
--- a/al/effects/fshifter.cpp
+++ b/al/effects/fshifter.cpp
@@ -10,6 +10,15 @@
#include "aloptional.h"
#include "effects.h"
+#if ALSOFT_EAX
+#include <cassert>
+
+#include "alnumeric.h"
+
+#include "al/eax_exception.h"
+#include "al/eax_utils.h"
+#endif // ALSOFT_EAX
+
namespace {
@@ -128,3 +137,408 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Fshifter);
const EffectProps FshifterEffectProps{genDefaultProps()};
+
+#if ALSOFT_EAX
+namespace
+{
+
+
+using EaxFrequencyShifterEffectDirtyFlagsValue = std::uint_least8_t;
+
+struct EaxFrequencyShifterEffectDirtyFlags
+{
+ using EaxIsBitFieldStruct = bool;
+
+ EaxFrequencyShifterEffectDirtyFlagsValue flFrequency : 1;
+ EaxFrequencyShifterEffectDirtyFlagsValue ulLeftDirection : 1;
+ EaxFrequencyShifterEffectDirtyFlagsValue ulRightDirection : 1;
+}; // EaxFrequencyShifterEffectDirtyFlags
+
+
+class EaxFrequencyShifterEffect final :
+ public EaxEffect
+{
+public:
+ EaxFrequencyShifterEffect(
+ EffectProps& al_effect_props);
+
+
+ // [[nodiscard]]
+ bool dispatch(
+ const EaxEaxCall& eax_call) override;
+
+
+private:
+ EffectProps& al_effect_props_;
+
+ EAXFREQUENCYSHIFTERPROPERTIES eax_{};
+ EAXFREQUENCYSHIFTERPROPERTIES eax_d_{};
+ EaxFrequencyShifterEffectDirtyFlags eax_dirty_flags_{};
+
+
+ void set_eax_defaults();
+
+
+ void set_efx_frequency();
+
+ void set_efx_left_direction();
+
+ void set_efx_right_direction();
+
+ void set_efx_defaults();
+
+
+ // [[nodiscard]]
+ bool get(
+ const EaxEaxCall& eax_call);
+
+
+ void validate_frequency(
+ float flFrequency);
+
+ void validate_left_direction(
+ unsigned long ulLeftDirection);
+
+ void validate_right_direction(
+ unsigned long ulRightDirection);
+
+ void validate_all(
+ const EAXFREQUENCYSHIFTERPROPERTIES& all);
+
+
+ void defer_frequency(
+ float flFrequency);
+
+ void defer_left_direction(
+ unsigned long ulLeftDirection);
+
+ void defer_right_direction(
+ unsigned long ulRightDirection);
+
+ void defer_all(
+ const EAXFREQUENCYSHIFTERPROPERTIES& all);
+
+
+ void defer_frequency(
+ const EaxEaxCall& eax_call);
+
+ void defer_left_direction(
+ const EaxEaxCall& eax_call);
+
+ void defer_right_direction(
+ const EaxEaxCall& eax_call);
+
+ void defer_all(
+ const EaxEaxCall& eax_call);
+
+
+ // [[nodiscard]]
+ bool apply_deferred();
+
+ // [[nodiscard]]
+ bool set(
+ const EaxEaxCall& eax_call);
+}; // EaxFrequencyShifterEffect
+
+
+class EaxFrequencyShifterEffectException :
+ public EaxException
+{
+public:
+ explicit EaxFrequencyShifterEffectException(
+ const char* message)
+ :
+ EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message}
+ {
+ }
+}; // EaxFrequencyShifterEffectException
+
+
+EaxFrequencyShifterEffect::EaxFrequencyShifterEffect(
+ EffectProps& al_effect_props)
+ :
+ al_effect_props_{al_effect_props}
+{
+ set_eax_defaults();
+ set_efx_defaults();
+}
+
+// [[nodiscard]]
+bool EaxFrequencyShifterEffect::dispatch(
+ const EaxEaxCall& eax_call)
+{
+ return eax_call.is_get() ? get(eax_call) : set(eax_call);
+}
+
+void EaxFrequencyShifterEffect::set_eax_defaults()
+{
+ eax_.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
+ eax_.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
+ eax_.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
+
+ eax_d_ = eax_;
+}
+
+void EaxFrequencyShifterEffect::set_efx_frequency()
+{
+ const auto frequency = clamp(
+ eax_.flFrequency,
+ AL_FREQUENCY_SHIFTER_MIN_FREQUENCY,
+ AL_FREQUENCY_SHIFTER_MAX_FREQUENCY);
+
+ al_effect_props_.Fshifter.Frequency = frequency;
+}
+
+void EaxFrequencyShifterEffect::set_efx_left_direction()
+{
+ const auto left_direction = clamp(
+ static_cast<ALint>(eax_.ulLeftDirection),
+ AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION,
+ AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION);
+
+ const auto efx_left_direction = DirectionFromEmum(left_direction);
+ assert(efx_left_direction.has_value());
+ al_effect_props_.Fshifter.LeftDirection = *efx_left_direction;
+}
+
+void EaxFrequencyShifterEffect::set_efx_right_direction()
+{
+ const auto right_direction = clamp(
+ static_cast<ALint>(eax_.ulRightDirection),
+ AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION,
+ AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION);
+
+ const auto efx_right_direction = DirectionFromEmum(right_direction);
+ assert(efx_right_direction.has_value());
+ al_effect_props_.Fshifter.RightDirection = *efx_right_direction;
+}
+
+void EaxFrequencyShifterEffect::set_efx_defaults()
+{
+ set_efx_frequency();
+ set_efx_left_direction();
+ set_efx_right_direction();
+}
+
+// [[nodiscard]]
+bool EaxFrequencyShifterEffect::get(
+ const EaxEaxCall& eax_call)
+{
+ switch (eax_call.get_property_id())
+ {
+ case EAXFREQUENCYSHIFTER_NONE:
+ break;
+
+ case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
+ eax_call.set_value<EaxFrequencyShifterEffectException>(eax_);
+ break;
+
+ case EAXFREQUENCYSHIFTER_FREQUENCY:
+ eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.flFrequency);
+ break;
+
+ case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
+ eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulLeftDirection);
+ break;
+
+ case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
+ eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulRightDirection);
+ break;
+
+ default:
+ throw EaxFrequencyShifterEffectException{"Unsupported property id."};
+ }
+
+ return false;
+}
+
+void EaxFrequencyShifterEffect::validate_frequency(
+ float flFrequency)
+{
+ eax_validate_range<EaxFrequencyShifterEffectException>(
+ "Frequency",
+ flFrequency,
+ EAXFREQUENCYSHIFTER_MINFREQUENCY,
+ EAXFREQUENCYSHIFTER_MAXFREQUENCY);
+}
+
+void EaxFrequencyShifterEffect::validate_left_direction(
+ unsigned long ulLeftDirection)
+{
+ eax_validate_range<EaxFrequencyShifterEffectException>(
+ "Left Direction",
+ ulLeftDirection,
+ EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
+ EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
+}
+
+void EaxFrequencyShifterEffect::validate_right_direction(
+ unsigned long ulRightDirection)
+{
+ eax_validate_range<EaxFrequencyShifterEffectException>(
+ "Right Direction",
+ ulRightDirection,
+ EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION,
+ EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION);
+}
+
+void EaxFrequencyShifterEffect::validate_all(
+ const EAXFREQUENCYSHIFTERPROPERTIES& all)
+{
+ validate_frequency(all.flFrequency);
+ validate_left_direction(all.ulLeftDirection);
+ validate_right_direction(all.ulRightDirection);
+}
+
+void EaxFrequencyShifterEffect::defer_frequency(
+ float flFrequency)
+{
+ eax_d_.flFrequency = flFrequency;
+ eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency);
+}
+
+void EaxFrequencyShifterEffect::defer_left_direction(
+ unsigned long ulLeftDirection)
+{
+ eax_d_.ulLeftDirection = ulLeftDirection;
+ eax_dirty_flags_.ulLeftDirection = (eax_.ulLeftDirection != eax_d_.ulLeftDirection);
+}
+
+void EaxFrequencyShifterEffect::defer_right_direction(
+ unsigned long ulRightDirection)
+{
+ eax_d_.ulRightDirection = ulRightDirection;
+ eax_dirty_flags_.ulRightDirection = (eax_.ulRightDirection != eax_d_.ulRightDirection);
+}
+
+void EaxFrequencyShifterEffect::defer_all(
+ const EAXFREQUENCYSHIFTERPROPERTIES& all)
+{
+ defer_frequency(all.flFrequency);
+ defer_left_direction(all.ulLeftDirection);
+ defer_right_direction(all.ulRightDirection);
+}
+
+void EaxFrequencyShifterEffect::defer_frequency(
+ const EaxEaxCall& eax_call)
+{
+ const auto& frequency =
+ eax_call.get_value<
+ EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::flFrequency)>();
+
+ validate_frequency(frequency);
+ defer_frequency(frequency);
+}
+
+void EaxFrequencyShifterEffect::defer_left_direction(
+ const EaxEaxCall& eax_call)
+{
+ const auto& left_direction =
+ eax_call.get_value<
+ EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulLeftDirection)>();
+
+ validate_left_direction(left_direction);
+ defer_left_direction(left_direction);
+}
+
+void EaxFrequencyShifterEffect::defer_right_direction(
+ const EaxEaxCall& eax_call)
+{
+ const auto& right_direction =
+ eax_call.get_value<
+ EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulRightDirection)>();
+
+ validate_right_direction(right_direction);
+ defer_right_direction(right_direction);
+}
+
+void EaxFrequencyShifterEffect::defer_all(
+ const EaxEaxCall& eax_call)
+{
+ const auto& all =
+ eax_call.get_value<
+ EaxFrequencyShifterEffectException, const EAXFREQUENCYSHIFTERPROPERTIES>();
+
+ validate_all(all);
+ defer_all(all);
+}
+
+// [[nodiscard]]
+bool EaxFrequencyShifterEffect::apply_deferred()
+{
+ if (eax_dirty_flags_ == EaxFrequencyShifterEffectDirtyFlags{})
+ {
+ return false;
+ }
+
+ eax_ = eax_d_;
+
+ if (eax_dirty_flags_.flFrequency)
+ {
+ set_efx_frequency();
+ }
+
+ if (eax_dirty_flags_.ulLeftDirection)
+ {
+ set_efx_left_direction();
+ }
+
+ if (eax_dirty_flags_.ulRightDirection)
+ {
+ set_efx_right_direction();
+ }
+
+ eax_dirty_flags_ = EaxFrequencyShifterEffectDirtyFlags{};
+
+ return true;
+}
+
+// [[nodiscard]]
+bool EaxFrequencyShifterEffect::set(
+ const EaxEaxCall& eax_call)
+{
+ switch (eax_call.get_property_id())
+ {
+ case EAXFREQUENCYSHIFTER_NONE:
+ break;
+
+ case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
+ defer_all(eax_call);
+ break;
+
+ case EAXFREQUENCYSHIFTER_FREQUENCY:
+ defer_frequency(eax_call);
+ break;
+
+ case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
+ defer_left_direction(eax_call);
+ break;
+
+ case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
+ defer_right_direction(eax_call);
+ break;
+
+ default:
+ throw EaxFrequencyShifterEffectException{"Unsupported property id."};
+ }
+
+ if (!eax_call.is_deferred())
+ {
+ return apply_deferred();
+ }
+
+ return false;
+}
+
+
+} // namespace
+
+
+EaxEffectUPtr eax_create_eax_frequency_shifter_effect(
+ EffectProps& al_effect_props)
+{
+ return std::make_unique<EaxFrequencyShifterEffect>(al_effect_props);
+}
+
+
+#endif // ALSOFT_EAX