diff options
author | Boris I. Bendovsky <[email protected]> | 2022-01-30 14:47:32 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2022-01-30 04:47:32 -0800 |
commit | 19ed994dc30ed84ea7cbbb5152577669fc25caf6 (patch) | |
tree | f68933bf8f778806618bd6c0b1bf9ced1b0ccf08 /al/effects/autowah.cpp | |
parent | 619249371a40f03cf988d1f5750d643df797c485 (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/autowah.cpp')
-rw-r--r-- | al/effects/autowah.cpp | 471 |
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 |