aboutsummaryrefslogtreecommitdiffstats
path: root/al
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-03-10 22:44:02 -0800
committerChris Robinson <[email protected]>2023-03-10 23:03:07 -0800
commitc9bedb1a4c8f79e361992e979dbfb2f6f5da2b8b (patch)
tree877b59be5b3a77088ec83c83b0a50813f1c0b7e7 /al
parent5aeeffec8063e51f647403b2bbff68bf900b0f9c (diff)
Convert EAX chorus and flanger effects
Diffstat (limited to 'al')
-rw-r--r--al/auxeffectslot.cpp2
-rw-r--r--al/auxeffectslot.h8
-rw-r--r--al/eax/effect.h22
-rw-r--r--al/effects/chorus.cpp370
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