diff options
author | Chris Robinson <[email protected]> | 2023-03-10 22:44:02 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2023-03-10 23:03:07 -0800 |
commit | c9bedb1a4c8f79e361992e979dbfb2f6f5da2b8b (patch) | |
tree | 877b59be5b3a77088ec83c83b0a50813f1c0b7e7 /al | |
parent | 5aeeffec8063e51f647403b2bbff68bf900b0f9c (diff) |
Convert EAX chorus and flanger effects
Diffstat (limited to 'al')
-rw-r--r-- | al/auxeffectslot.cpp | 2 | ||||
-rw-r--r-- | al/auxeffectslot.h | 8 | ||||
-rw-r--r-- | al/eax/effect.h | 22 | ||||
-rw-r--r-- | al/effects/chorus.cpp | 370 |
4 files changed, 207 insertions, 195 deletions
diff --git a/al/auxeffectslot.cpp b/al/auxeffectslot.cpp index e716beb7..7bfd14ae 100644 --- a/al/auxeffectslot.cpp +++ b/al/auxeffectslot.cpp @@ -1058,7 +1058,7 @@ void ALeffectslot::eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue in eax_effect_ = std::make_unique<EaxEffect>(); if(index == 0) eax_effect_->init<EaxReverbCommitter>(); - //else if(index == 1) eax_effect_->init<EaxChorusCommitter>(); + else if(index == 1) eax_effect_->init<EaxChorusCommitter>(); else eax_effect_->init<EaxNullCommitter>(); } diff --git a/al/auxeffectslot.h b/al/auxeffectslot.h index 10f69270..e9889bff 100644 --- a/al/auxeffectslot.h +++ b/al/auxeffectslot.h @@ -134,12 +134,12 @@ private: if (guidLoadEffect != EAX_NULL_GUID && guidLoadEffect != EAX_REVERB_EFFECT /*&& guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT && - guidLoadEffect != EAX_AUTOWAH_EFFECT && - guidLoadEffect != EAX_CHORUS_EFFECT && + guidLoadEffect != EAX_AUTOWAH_EFFECT*/ && + guidLoadEffect != EAX_CHORUS_EFFECT /*&& guidLoadEffect != EAX_DISTORTION_EFFECT && guidLoadEffect != EAX_ECHO_EFFECT && - guidLoadEffect != EAX_EQUALIZER_EFFECT && - guidLoadEffect != EAX_FLANGER_EFFECT && + guidLoadEffect != EAX_EQUALIZER_EFFECT*/ && + guidLoadEffect != EAX_FLANGER_EFFECT /*&& guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT && guidLoadEffect != EAX_VOCALMORPHER_EFFECT && guidLoadEffect != EAX_PITCHSHIFTER_EFFECT && diff --git a/al/eax/effect.h b/al/eax/effect.h index 15fa34dc..5308ae10 100644 --- a/al/eax/effect.h +++ b/al/eax/effect.h @@ -165,6 +165,12 @@ struct EaxCommitter { static void Set(const EaxCall &call, EaxEffectProps &props); }; +struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> { + using EaxCommitter<EaxChorusCommitter>::EaxCommitter; +}; +struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> { + using EaxCommitter<EaxFlangerCommitter>::EaxCommitter; +}; struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> { using EaxCommitter<EaxNullCommitter>::EaxCommitter; }; @@ -225,6 +231,10 @@ public: { if(altype == AL_EFFECT_EAXREVERB) return call_set_defaults<EaxReverbCommitter>(props); + if(altype == AL_EFFECT_CHORUS) + return call_set_defaults<EaxChorusCommitter>(props); + if(altype == AL_EFFECT_FLANGER) + return call_set_defaults<EaxFlangerCommitter>(props); return call_set_defaults<EaxNullCommitter>(props); } @@ -265,6 +275,10 @@ public: { if(props.mType == EaxEffectType::Reverb) return do_set<EaxReverbCommitter>(call, props); + if(props.mType == EaxEffectType::Chorus) + return do_set<EaxChorusCommitter>(call, props); + if(props.mType == EaxEffectType::Flanger) + return do_set<EaxFlangerCommitter>(call, props); return do_set<EaxNullCommitter>(call, props); } @@ -290,6 +304,10 @@ public: { if(props.mType == EaxEffectType::Reverb) return do_get<EaxReverbCommitter>(call, props); + if(props.mType == EaxEffectType::Chorus) + return do_get<EaxChorusCommitter>(call, props); + if(props.mType == EaxEffectType::Flanger) + return do_get<EaxFlangerCommitter>(call, props); return do_get<EaxNullCommitter>(call, props); } @@ -314,6 +332,10 @@ public: { if(props.mType == EaxEffectType::Reverb) return call_commit<EaxReverbCommitter>(props); + if(props.mType == EaxEffectType::Chorus) + return call_commit<EaxChorusCommitter>(props); + if(props.mType == EaxEffectType::Flanger) + return call_commit<EaxFlangerCommitter>(props); return call_commit<EaxNullCommitter>(props); } diff --git a/al/effects/chorus.cpp b/al/effects/chorus.cpp index 47be502d..a9088157 100644 --- a/al/effects/chorus.cpp +++ b/al/effects/chorus.cpp @@ -291,24 +291,9 @@ const EffectProps FlangerEffectProps{genDefaultFlangerProps()}; #ifdef ALSOFT_EAX namespace { -class EaxChorusEffectException : public EaxException { -public: - explicit EaxChorusEffectException(const char* message) - : EaxException{"EAX_CHORUS_EFFECT", message} - {} -}; // EaxChorusEffectException - -class EaxFlangerEffectException : public EaxException { -public: - explicit EaxFlangerEffectException(const char* message) - : EaxException{"EAX_FLANGER_EFFECT", message} - {} -}; // EaxFlangerEffectException - -struct EaxChorusTraits -{ - using Exception = EaxChorusEffectException; +struct EaxChorusTraits { using Props = EAXCHORUSPROPERTIES; + using Committer = EaxChorusCommitter; static constexpr auto Field = &EaxEffectProps::mChorus; static constexpr auto eax_effect_type() { return EaxEffectType::Chorus; } @@ -364,12 +349,21 @@ struct EaxChorusTraits static constexpr auto efx_default_depth() { return AL_CHORUS_DEFAULT_DEPTH; } static constexpr auto efx_default_feedback() { return AL_CHORUS_DEFAULT_FEEDBACK; } static constexpr auto efx_default_delay() { return AL_CHORUS_DEFAULT_DELAY; } + + static al::optional<ChorusWaveform> eax_waveform(unsigned long type) + { + switch(type) + { + case EAX_CHORUS_SINUSOID: return ChorusWaveform::Sinusoid; + case EAX_CHORUS_TRIANGLE: return ChorusWaveform::Triangle; + } + return al::nullopt; + } }; // EaxChorusTraits -struct EaxFlangerTraits -{ - using Exception = EaxFlangerEffectException; +struct EaxFlangerTraits { using Props = EAXFLANGERPROPERTIES; + using Committer = EaxFlangerCommitter; static constexpr auto Field = &EaxEffectProps::mFlanger; static constexpr auto eax_effect_type() { return EaxEffectType::Flanger; } @@ -425,24 +419,26 @@ struct EaxFlangerTraits static constexpr auto efx_default_depth() { return AL_FLANGER_DEFAULT_DEPTH; } static constexpr auto efx_default_feedback() { return AL_FLANGER_DEFAULT_FEEDBACK; } static constexpr auto efx_default_delay() { return AL_FLANGER_DEFAULT_DELAY; } + + static al::optional<ChorusWaveform> eax_waveform(unsigned long type) + { + switch(type) + { + case EAX_FLANGER_SINUSOID: return ChorusWaveform::Sinusoid; + case EAX_FLANGER_TRIANGLE: return ChorusWaveform::Triangle; + } + return al::nullopt; + } }; // EaxFlangerTraits template<typename TTraits> -class EaxChorusFlangerEffect final : public EaxEffect4<typename TTraits::Exception> { -public: +struct ChorusFlangerEffect { using Traits = TTraits; - using Base = EaxEffect4<typename Traits::Exception>; - using typename Base::Exception; - using typename Base::Props4; - using Base::defer; + using Committer = typename Traits::Committer; + using Exception = typename Committer::Exception; static constexpr auto Field = Traits::Field; - EaxChorusFlangerEffect(int eax_version) - : Base{Traits::efx_effect(), eax_version} - {} - -private: struct WaveformValidator { void operator()(unsigned long ulWaveform) const { @@ -521,7 +517,8 @@ private: } }; // AllValidator - void set_defaults(Props4& props) override +public: + static void SetDefaults(EaxEffectProps &props) { auto&& all = props.*Field; props.mType = Traits::eax_effect_type(); @@ -533,213 +530,206 @@ private: all.flDelay = Traits::eax_default_delay(); } - void set_efx_waveform() - { - const auto waveform = clamp( - static_cast<ALint>((Base::props_.*Field).ulWaveform), - Traits::efx_min_waveform(), - Traits::efx_max_waveform()); - const auto efx_waveform = WaveformFromEnum(waveform); - assert(efx_waveform.has_value()); - Base::al_effect_props_.Chorus.Waveform = *efx_waveform; - } - - void set_efx_phase() noexcept - { - Base::al_effect_props_.Chorus.Phase = clamp( - static_cast<ALint>((Base::props_.*Field).lPhase), - Traits::efx_min_phase(), - Traits::efx_max_phase()); - } - - void set_efx_rate() noexcept - { - Base::al_effect_props_.Chorus.Rate = clamp( - (Base::props_.*Field).flRate, - Traits::efx_min_rate(), - Traits::efx_max_rate()); - } - - void set_efx_depth() noexcept - { - Base::al_effect_props_.Chorus.Depth = clamp( - (Base::props_.*Field).flDepth, - Traits::efx_min_depth(), - Traits::efx_max_depth()); - } - void set_efx_feedback() noexcept - { - Base::al_effect_props_.Chorus.Feedback = clamp( - (Base::props_.*Field).flFeedback, - Traits::efx_min_feedback(), - Traits::efx_max_feedback()); - } - - void set_efx_delay() noexcept - { - Base::al_effect_props_.Chorus.Delay = clamp( - (Base::props_.*Field).flDelay, - Traits::efx_min_delay(), - Traits::efx_max_delay()); - } - - void set_efx_defaults() override - { - set_efx_waveform(); - set_efx_phase(); - set_efx_rate(); - set_efx_depth(); - set_efx_feedback(); - set_efx_delay(); - } - - void get(const EaxCall& call, const Props4& props) override + static void Get(const EaxCall &call, const EaxEffectProps &props) { auto&& all = props.*Field; switch(call.get_property_id()) { - case Traits::eax_none_param_id(): - break; + case Traits::eax_none_param_id(): + break; - case Traits::eax_allparameters_param_id(): - call.template set_value<Exception>(all); - break; + case Traits::eax_allparameters_param_id(): + call.template set_value<Exception>(all); + break; - case Traits::eax_waveform_param_id(): - call.template set_value<Exception>(all.ulWaveform); - break; + case Traits::eax_waveform_param_id(): + call.template set_value<Exception>(all.ulWaveform); + break; - case Traits::eax_phase_param_id(): - call.template set_value<Exception>(all.lPhase); - break; + case Traits::eax_phase_param_id(): + call.template set_value<Exception>(all.lPhase); + break; - case Traits::eax_rate_param_id(): - call.template set_value<Exception>(all.flRate); - break; + case Traits::eax_rate_param_id(): + call.template set_value<Exception>(all.flRate); + break; - case Traits::eax_depth_param_id(): - call.template set_value<Exception>(all.flDepth); - break; + case Traits::eax_depth_param_id(): + call.template set_value<Exception>(all.flDepth); + break; - case Traits::eax_feedback_param_id(): - call.template set_value<Exception>(all.flFeedback); - break; + case Traits::eax_feedback_param_id(): + call.template set_value<Exception>(all.flFeedback); + break; - case Traits::eax_delay_param_id(): - call.template set_value<Exception>(all.flDelay); - break; + case Traits::eax_delay_param_id(): + call.template set_value<Exception>(all.flDelay); + break; - default: - Base::fail_unknown_property_id(); + default: + Committer::fail_unknown_property_id(); } } - void set(const EaxCall& call, Props4& props) override + static void Set(const EaxCall &call, EaxEffectProps &props) { auto&& all = props.*Field; switch(call.get_property_id()) { - case Traits::eax_none_param_id(): - break; + case Traits::eax_none_param_id(): + break; - case Traits::eax_allparameters_param_id(): - Base::template defer<AllValidator>(call, all); - break; + case Traits::eax_allparameters_param_id(): + Committer::template defer<AllValidator>(call, all); + break; - case Traits::eax_waveform_param_id(): - Base::template defer<WaveformValidator>(call, all.ulWaveform); - break; + case Traits::eax_waveform_param_id(): + Committer::template defer<WaveformValidator>(call, all.ulWaveform); + break; - case Traits::eax_phase_param_id(): - Base::template defer<PhaseValidator>(call, all.lPhase); - break; + case Traits::eax_phase_param_id(): + Committer::template defer<PhaseValidator>(call, all.lPhase); + break; - case Traits::eax_rate_param_id(): - Base::template defer<RateValidator>(call, all.flRate); - break; + case Traits::eax_rate_param_id(): + Committer::template defer<RateValidator>(call, all.flRate); + break; - case Traits::eax_depth_param_id(): - Base::template defer<DepthValidator>(call, all.flDepth); - break; + case Traits::eax_depth_param_id(): + Committer::template defer<DepthValidator>(call, all.flDepth); + break; - case Traits::eax_feedback_param_id(): - Base::template defer<FeedbackValidator>(call, all.flFeedback); - break; + case Traits::eax_feedback_param_id(): + Committer::template defer<FeedbackValidator>(call, all.flFeedback); + break; - case Traits::eax_delay_param_id(): - Base::template defer<DelayValidator>(call, all.flDelay); - break; + case Traits::eax_delay_param_id(): + Committer::template defer<DelayValidator>(call, all.flDelay); + break; - default: - Base::fail_unknown_property_id(); + default: + Committer::fail_unknown_property_id(); } } - bool commit_props(const Props4& props) override + static bool Commit(const EaxEffectProps &props, EaxEffectProps &props_, + EffectProps &al_effect_props_) { - auto is_dirty = false; - auto&& src = props.*Field; - auto&& dst = Base::props_.*Field; + const auto orig = props_; + props_ = props; - if (dst.ulWaveform != src.ulWaveform) - { - is_dirty = true; - set_efx_waveform(); - } + auto&& src = orig.*Field; + auto&& dst = props_.*Field; + if(orig.mType == props_.mType && dst.ulWaveform == src.ulWaveform + && dst.lPhase == src.lPhase && dst.flRate == src.flRate && dst.flDepth == src.flDepth + && dst.flFeedback == src.flFeedback && dst.flDelay == src.flDelay) + return false; - if (dst.lPhase != src.lPhase) - { - is_dirty = true; - set_efx_phase(); - } + const auto efx_waveform = Traits::eax_waveform(dst.ulWaveform); + assert(efx_waveform.has_value()); + al_effect_props_.Chorus.Waveform = *efx_waveform; + al_effect_props_.Chorus.Phase = clamp(static_cast<ALint>(dst.lPhase), + Traits::efx_min_phase(), Traits::efx_max_phase()); + al_effect_props_.Chorus.Rate = clamp(dst.flRate, + Traits::efx_min_rate(), Traits::efx_max_rate()); + al_effect_props_.Chorus.Depth = clamp(dst.flDepth, + Traits::efx_min_depth(), Traits::efx_max_depth()); + al_effect_props_.Chorus.Feedback = clamp(dst.flFeedback, + Traits::efx_min_feedback(), Traits::efx_max_feedback()); + al_effect_props_.Chorus.Delay = clamp(dst.flDelay, + Traits::efx_min_delay(), Traits::efx_max_delay()); + + return true; + } +}; // EaxChorusFlangerEffect - if (dst.flRate != src.flRate) - { - is_dirty = true; - set_efx_rate(); - } - if (dst.flDepth != src.flDepth) - { - is_dirty = true; - set_efx_depth(); - } +using ChorusCommitter = EaxCommitter<EaxChorusCommitter>; +using FlangerCommitter = EaxCommitter<EaxFlangerCommitter>; - if (dst.flFeedback != src.flFeedback) - { - is_dirty = true; - set_efx_feedback(); - } +} // namespace - if (dst.flDelay != src.flDelay) - { - is_dirty = true; - set_efx_delay(); - } +template<> +struct ChorusCommitter::Exception : public EaxException +{ + explicit Exception(const char *message) : EaxException{"EAX_CHORUS_EFFECT", message} + { } +}; - return is_dirty; - } -}; // EaxChorusFlangerEffect +template<> +[[noreturn]] void ChorusCommitter::fail(const char *message) +{ + throw Exception{message}; +} -template<typename TTraits> -EaxEffectUPtr eax_create_eax_chorus_flanger_effect(int eax_version) +template<> +bool ChorusCommitter::commit(const EaxEffectProps &props) { - return eax_create_eax4_effect<EaxChorusFlangerEffect<TTraits>>(eax_version); + using Committer = ChorusFlangerEffect<EaxChorusTraits>; + return Committer::Commit(props, props_, al_effect_props_); } -} // namespace +template<> +void ChorusCommitter::SetDefaults(EaxEffectProps &props) +{ + using Committer = ChorusFlangerEffect<EaxChorusTraits>; + Committer::SetDefaults(props); +} + +template<> +void ChorusCommitter::Get(const EaxCall &call, const EaxEffectProps &props) +{ + using Committer = ChorusFlangerEffect<EaxChorusTraits>; + Committer::Get(call, props); +} + +template<> +void ChorusCommitter::Set(const EaxCall &call, EaxEffectProps &props) +{ + using Committer = ChorusFlangerEffect<EaxChorusTraits>; + Committer::Set(call, props); +} -// ========================================================================== +template<> +struct FlangerCommitter::Exception : public EaxException +{ + explicit Exception(const char *message) : EaxException{"EAX_FLANGER_EFFECT", message} + { } +}; + +template<> +[[noreturn]] void FlangerCommitter::fail(const char *message) +{ + throw Exception{message}; +} + +template<> +bool FlangerCommitter::commit(const EaxEffectProps &props) +{ + using Committer = ChorusFlangerEffect<EaxFlangerTraits>; + return Committer::Commit(props, props_, al_effect_props_); +} + +template<> +void FlangerCommitter::SetDefaults(EaxEffectProps &props) +{ + using Committer = ChorusFlangerEffect<EaxFlangerTraits>; + Committer::SetDefaults(props); +} -EaxEffectUPtr eax_create_eax_chorus_effect(int eax_version) +template<> +void FlangerCommitter::Get(const EaxCall &call, const EaxEffectProps &props) { - return eax_create_eax_chorus_flanger_effect<EaxChorusTraits>(eax_version); + using Committer = ChorusFlangerEffect<EaxFlangerTraits>; + Committer::Get(call, props); } -EaxEffectUPtr eax_create_eax_flanger_effect(int eax_version) +template<> +void FlangerCommitter::Set(const EaxCall &call, EaxEffectProps &props) { - return eax_create_eax_chorus_flanger_effect<EaxFlangerTraits>(eax_version); + using Committer = ChorusFlangerEffect<EaxFlangerTraits>; + Committer::Set(call, props); } #endif // ALSOFT_EAX |