aboutsummaryrefslogtreecommitdiffstats
path: root/al/effects/autowah.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'al/effects/autowah.cpp')
-rw-r--r--al/effects/autowah.cpp471
1 files changed, 471 insertions, 0 deletions
diff --git a/al/effects/autowah.cpp b/al/effects/autowah.cpp
index 9abef1f7..bdd1bc09 100644
--- a/al/effects/autowah.cpp
+++ b/al/effects/autowah.cpp
@@ -11,6 +11,14 @@
#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 {
void Autowah_setParamf(EffectProps *props, ALenum param, float val)
@@ -107,3 +115,466 @@ EffectProps genDefaultProps() noexcept
DEFINE_ALEFFECT_VTABLE(Autowah);
const EffectProps AutowahEffectProps{genDefaultProps()};
+
+#if ALSOFT_EAX
+namespace
+{
+
+
+using EaxAutoWahEffectDirtyFlagsValue = std::uint_least8_t;
+
+struct EaxAutoWahEffectDirtyFlags
+{
+ using EaxIsBitFieldStruct = bool;
+
+ EaxAutoWahEffectDirtyFlagsValue flAttackTime : 1;
+ EaxAutoWahEffectDirtyFlagsValue flReleaseTime : 1;
+ EaxAutoWahEffectDirtyFlagsValue lResonance : 1;
+ EaxAutoWahEffectDirtyFlagsValue lPeakLevel : 1;
+}; // EaxAutoWahEffectDirtyFlags
+
+
+class EaxAutoWahEffect final :
+ public EaxEffect
+{
+public:
+ EaxAutoWahEffect(
+ EffectProps& al_effect_props);
+
+
+ // [[nodiscard]]
+ bool dispatch(
+ const EaxEaxCall& eax_call) override;
+
+
+private:
+ EffectProps& al_effect_props_;
+
+ EAXAUTOWAHPROPERTIES eax_{};
+ EAXAUTOWAHPROPERTIES eax_d_{};
+ EaxAutoWahEffectDirtyFlags eax_dirty_flags_{};
+
+
+ void set_eax_defaults();
+
+
+ void set_efx_attack_time();
+
+ void set_efx_release_time();
+
+ void set_efx_resonance();
+
+ void set_efx_peak_gain();
+
+ void set_efx_defaults();
+
+
+ // [[nodiscard]]
+ bool get(
+ const EaxEaxCall& eax_call);
+
+
+ void validate_attack_time(
+ float flAttackTime);
+
+ void validate_release_time(
+ float flReleaseTime);
+
+ void validate_resonance(
+ long lResonance);
+
+ void validate_peak_level(
+ long lPeakLevel);
+
+ void validate_all(
+ const EAXAUTOWAHPROPERTIES& eax_all);
+
+
+ void defer_attack_time(
+ float flAttackTime);
+
+ void defer_release_time(
+ float flReleaseTime);
+
+ void defer_resonance(
+ long lResonance);
+
+ void defer_peak_level(
+ long lPeakLevel);
+
+ void defer_all(
+ const EAXAUTOWAHPROPERTIES& eax_all);
+
+
+ void defer_attack_time(
+ const EaxEaxCall& eax_call);
+
+ void defer_release_time(
+ const EaxEaxCall& eax_call);
+
+ void defer_resonance(
+ const EaxEaxCall& eax_call);
+
+ void defer_peak_level(
+ const EaxEaxCall& eax_call);
+
+ void defer_all(
+ const EaxEaxCall& eax_call);
+
+ // [[nodiscard]]
+ bool apply_deferred();
+
+ // [[nodiscard]]
+ bool set(
+ const EaxEaxCall& eax_call);
+}; // EaxAutoWahEffect
+
+
+class EaxAutoWahEffectException :
+ public EaxException
+{
+public:
+ explicit EaxAutoWahEffectException(
+ const char* message)
+ :
+ EaxException{"EAX_AUTO_WAH_EFFECT", message}
+ {
+ }
+}; // EaxAutoWahEffectException
+
+
+EaxAutoWahEffect::EaxAutoWahEffect(
+ EffectProps& al_effect_props)
+ :
+ al_effect_props_{al_effect_props}
+{
+ set_eax_defaults();
+ set_efx_defaults();
+}
+
+// [[nodiscard]]
+bool EaxAutoWahEffect::dispatch(
+ const EaxEaxCall& eax_call)
+{
+ return eax_call.is_get() ? get(eax_call) : set(eax_call);
+}
+
+void EaxAutoWahEffect::set_eax_defaults()
+{
+ eax_.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
+ eax_.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
+ eax_.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
+ eax_.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
+
+ eax_d_ = eax_;
+}
+
+void EaxAutoWahEffect::set_efx_attack_time()
+{
+ const auto attack_time = clamp(
+ eax_.flAttackTime,
+ AL_AUTOWAH_MIN_ATTACK_TIME,
+ AL_AUTOWAH_MAX_ATTACK_TIME);
+
+ al_effect_props_.Autowah.AttackTime = attack_time;
+}
+
+void EaxAutoWahEffect::set_efx_release_time()
+{
+ const auto release_time = clamp(
+ eax_.flReleaseTime,
+ AL_AUTOWAH_MIN_RELEASE_TIME,
+ AL_AUTOWAH_MAX_RELEASE_TIME);
+
+ al_effect_props_.Autowah.ReleaseTime = release_time;
+}
+
+void EaxAutoWahEffect::set_efx_resonance()
+{
+ const auto resonance = clamp(
+ level_mb_to_gain(static_cast<float>(eax_.lResonance)),
+ AL_AUTOWAH_MIN_RESONANCE,
+ AL_AUTOWAH_MAX_RESONANCE);
+
+ al_effect_props_.Autowah.Resonance = resonance;
+}
+
+void EaxAutoWahEffect::set_efx_peak_gain()
+{
+ const auto peak_gain = clamp(
+ level_mb_to_gain(static_cast<float>(eax_.lPeakLevel)),
+ AL_AUTOWAH_MIN_PEAK_GAIN,
+ AL_AUTOWAH_MAX_PEAK_GAIN);
+
+ al_effect_props_.Autowah.PeakGain = peak_gain;
+}
+
+void EaxAutoWahEffect::set_efx_defaults()
+{
+ set_efx_attack_time();
+ set_efx_release_time();
+ set_efx_resonance();
+ set_efx_peak_gain();
+}
+
+bool EaxAutoWahEffect::get(
+ const EaxEaxCall& eax_call)
+{
+ switch (eax_call.get_property_id())
+ {
+ case EAXAUTOWAH_NONE:
+ break;
+
+ case EAXAUTOWAH_ALLPARAMETERS:
+ eax_call.set_value<EaxAutoWahEffectException>(eax_);
+ break;
+
+ case EAXAUTOWAH_ATTACKTIME:
+ eax_call.set_value<EaxAutoWahEffectException>(eax_.flAttackTime);
+ break;
+
+ case EAXAUTOWAH_RELEASETIME:
+ eax_call.set_value<EaxAutoWahEffectException>(eax_.flReleaseTime);
+ break;
+
+ case EAXAUTOWAH_RESONANCE:
+ eax_call.set_value<EaxAutoWahEffectException>(eax_.lResonance);
+ break;
+
+ case EAXAUTOWAH_PEAKLEVEL:
+ eax_call.set_value<EaxAutoWahEffectException>(eax_.lPeakLevel);
+ break;
+
+ default:
+ throw EaxAutoWahEffectException{"Unsupported property id."};
+ }
+
+ return false;
+}
+
+void EaxAutoWahEffect::validate_attack_time(
+ float flAttackTime)
+{
+ eax_validate_range<EaxAutoWahEffectException>(
+ "Attack Time",
+ flAttackTime,
+ EAXAUTOWAH_MINATTACKTIME,
+ EAXAUTOWAH_MAXATTACKTIME);
+}
+
+void EaxAutoWahEffect::validate_release_time(
+ float flReleaseTime)
+{
+ eax_validate_range<EaxAutoWahEffectException>(
+ "Release Time",
+ flReleaseTime,
+ EAXAUTOWAH_MINRELEASETIME,
+ EAXAUTOWAH_MAXRELEASETIME);
+}
+
+void EaxAutoWahEffect::validate_resonance(
+ long lResonance)
+{
+ eax_validate_range<EaxAutoWahEffectException>(
+ "Resonance",
+ lResonance,
+ EAXAUTOWAH_MINRESONANCE,
+ EAXAUTOWAH_MAXRESONANCE);
+}
+
+void EaxAutoWahEffect::validate_peak_level(
+ long lPeakLevel)
+{
+ eax_validate_range<EaxAutoWahEffectException>(
+ "Peak Level",
+ lPeakLevel,
+ EAXAUTOWAH_MINPEAKLEVEL,
+ EAXAUTOWAH_MAXPEAKLEVEL);
+}
+
+void EaxAutoWahEffect::validate_all(
+ const EAXAUTOWAHPROPERTIES& eax_all)
+{
+ validate_attack_time(eax_all.flAttackTime);
+ validate_release_time(eax_all.flReleaseTime);
+ validate_resonance(eax_all.lResonance);
+ validate_peak_level(eax_all.lPeakLevel);
+}
+
+void EaxAutoWahEffect::defer_attack_time(
+ float flAttackTime)
+{
+ eax_d_.flAttackTime = flAttackTime;
+ eax_dirty_flags_.flAttackTime = (eax_.flAttackTime != eax_d_.flAttackTime);
+}
+
+void EaxAutoWahEffect::defer_release_time(
+ float flReleaseTime)
+{
+ eax_d_.flReleaseTime = flReleaseTime;
+ eax_dirty_flags_.flReleaseTime = (eax_.flReleaseTime != eax_d_.flReleaseTime);
+}
+
+void EaxAutoWahEffect::defer_resonance(
+ long lResonance)
+{
+ eax_d_.lResonance = lResonance;
+ eax_dirty_flags_.lResonance = (eax_.lResonance != eax_d_.lResonance);
+}
+
+void EaxAutoWahEffect::defer_peak_level(
+ long lPeakLevel)
+{
+ eax_d_.lPeakLevel = lPeakLevel;
+ eax_dirty_flags_.lPeakLevel = (eax_.lPeakLevel != eax_d_.lPeakLevel);
+}
+
+void EaxAutoWahEffect::defer_all(
+ const EAXAUTOWAHPROPERTIES& eax_all)
+{
+ validate_all(eax_all);
+
+ defer_attack_time(eax_all.flAttackTime);
+ defer_release_time(eax_all.flReleaseTime);
+ defer_resonance(eax_all.lResonance);
+ defer_peak_level(eax_all.lPeakLevel);
+}
+
+void EaxAutoWahEffect::defer_attack_time(
+ const EaxEaxCall& eax_call)
+{
+ const auto& attack_time =
+ eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flAttackTime)>();
+
+ validate_attack_time(attack_time);
+ defer_attack_time(attack_time);
+}
+
+void EaxAutoWahEffect::defer_release_time(
+ const EaxEaxCall& eax_call)
+{
+ const auto& release_time =
+ eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::flReleaseTime)>();
+
+ validate_release_time(release_time);
+ defer_release_time(release_time);
+}
+
+void EaxAutoWahEffect::defer_resonance(
+ const EaxEaxCall& eax_call)
+{
+ const auto& resonance =
+ eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lResonance)>();
+
+ validate_resonance(resonance);
+ defer_resonance(resonance);
+}
+
+void EaxAutoWahEffect::defer_peak_level(
+ const EaxEaxCall& eax_call)
+{
+ const auto& peak_level =
+ eax_call.get_value<EaxAutoWahEffectException, const decltype(EAXAUTOWAHPROPERTIES::lPeakLevel)>();
+
+ validate_peak_level(peak_level);
+ defer_peak_level(peak_level);
+}
+
+void EaxAutoWahEffect::defer_all(
+ const EaxEaxCall& eax_call)
+{
+ const auto& all =
+ eax_call.get_value<EaxAutoWahEffectException, const EAXAUTOWAHPROPERTIES>();
+
+ validate_all(all);
+ defer_all(all);
+}
+
+// [[nodiscard]]
+bool EaxAutoWahEffect::apply_deferred()
+{
+ if (eax_dirty_flags_ == EaxAutoWahEffectDirtyFlags{})
+ {
+ return false;
+ }
+
+ eax_ = eax_d_;
+
+ if (eax_dirty_flags_.flAttackTime)
+ {
+ set_efx_attack_time();
+ }
+
+ if (eax_dirty_flags_.flReleaseTime)
+ {
+ set_efx_release_time();
+ }
+
+ if (eax_dirty_flags_.lResonance)
+ {
+ set_efx_resonance();
+ }
+
+ if (eax_dirty_flags_.lPeakLevel)
+ {
+ set_efx_peak_gain();
+ }
+
+ eax_dirty_flags_ = EaxAutoWahEffectDirtyFlags{};
+
+ return true;
+}
+
+// [[nodiscard]]
+bool EaxAutoWahEffect::set(
+ const EaxEaxCall& eax_call)
+{
+ switch (eax_call.get_property_id())
+ {
+ case EAXAUTOWAH_NONE:
+ break;
+
+ case EAXAUTOWAH_ALLPARAMETERS:
+ defer_all(eax_call);
+ break;
+
+ case EAXAUTOWAH_ATTACKTIME:
+ defer_attack_time(eax_call);
+ break;
+
+ case EAXAUTOWAH_RELEASETIME:
+ defer_release_time(eax_call);
+ break;
+
+ case EAXAUTOWAH_RESONANCE:
+ defer_resonance(eax_call);
+ break;
+
+ case EAXAUTOWAH_PEAKLEVEL:
+ defer_peak_level(eax_call);
+ break;
+
+ default:
+ throw EaxAutoWahEffectException{"Unsupported property id."};
+ }
+
+ if (!eax_call.is_deferred())
+ {
+ return apply_deferred();
+ }
+
+ return false;
+}
+
+
+} // namespace
+
+
+EaxEffectUPtr eax_create_eax_auto_wah_effect(
+ EffectProps& al_effect_props)
+{
+ return std::make_unique<::EaxAutoWahEffect>(al_effect_props);
+}
+
+
+#endif // ALSOFT_EAX