| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- #ifndef EAX_EFFECT_INCLUDED
- #define EAX_EFFECT_INCLUDED
- #include <cassert>
- #include <memory>
- #include <variant>
- #include "alnumeric.h"
- #include "AL/al.h"
- #include "AL/alext.h"
- #include "core/effects/base.h"
- #include "call.h"
- struct EaxEffectErrorMessages {
- static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
- static constexpr auto unknown_version() noexcept { return "Unknown version."; }
- }; // EaxEffectErrorMessages
- using EaxEffectProps = std::variant<std::monostate,
- EAXREVERBPROPERTIES,
- EAXCHORUSPROPERTIES,
- EAXAUTOWAHPROPERTIES,
- EAXAGCCOMPRESSORPROPERTIES,
- EAXDISTORTIONPROPERTIES,
- EAXECHOPROPERTIES,
- EAXEQUALIZERPROPERTIES,
- EAXFLANGERPROPERTIES,
- EAXFREQUENCYSHIFTERPROPERTIES,
- EAXRINGMODULATORPROPERTIES,
- EAXPITCHSHIFTERPROPERTIES,
- EAXVOCALMORPHERPROPERTIES>;
- template<typename... Ts>
- struct overloaded : Ts... { using Ts::operator()...; };
- template<typename... Ts>
- overloaded(Ts...) -> overloaded<Ts...>;
- constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
- {
- return std::visit(overloaded{
- [](const std::monostate&) noexcept { return AL_EFFECT_NULL; },
- [](const EAXREVERBPROPERTIES&) noexcept { return AL_EFFECT_EAXREVERB; },
- [](const EAXCHORUSPROPERTIES&) noexcept { return AL_EFFECT_CHORUS; },
- [](const EAXAUTOWAHPROPERTIES&) noexcept { return AL_EFFECT_AUTOWAH; },
- [](const EAXAGCCOMPRESSORPROPERTIES&) noexcept { return AL_EFFECT_COMPRESSOR; },
- [](const EAXDISTORTIONPROPERTIES&) noexcept { return AL_EFFECT_DISTORTION; },
- [](const EAXECHOPROPERTIES&) noexcept { return AL_EFFECT_ECHO; },
- [](const EAXEQUALIZERPROPERTIES&) noexcept { return AL_EFFECT_EQUALIZER; },
- [](const EAXFLANGERPROPERTIES&) noexcept { return AL_EFFECT_FLANGER; },
- [](const EAXFREQUENCYSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_FREQUENCY_SHIFTER; },
- [](const EAXRINGMODULATORPROPERTIES&) noexcept { return AL_EFFECT_RING_MODULATOR; },
- [](const EAXPITCHSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_PITCH_SHIFTER; },
- [](const EAXVOCALMORPHERPROPERTIES&) noexcept { return AL_EFFECT_VOCAL_MORPHER; }
- }, props);
- }
- struct EaxReverbCommitter {
- struct Exception;
- EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
- : mEaxProps{eaxprops}, mAlProps{alprops}
- { }
- EaxEffectProps &mEaxProps;
- EffectProps &mAlProps;
- [[noreturn]] static void fail(const char* message);
- [[noreturn]] static void fail_unknown_property_id()
- { fail(EaxEffectErrorMessages::unknown_property_id()); }
- template<typename TValidator, typename TProperty>
- static void defer(const EaxCall& call, TProperty& property)
- {
- const auto& value = call.get_value<Exception, const TProperty>();
- TValidator{}(value);
- property = value;
- }
- template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty>
- static void defer(const EaxCall& call, TProperties& properties, TProperty&)
- {
- const auto& value = call.get_value<Exception, const TProperty>();
- TValidator{}(value);
- TDeferrer{}(properties, value);
- }
- template<typename TValidator, typename TProperty>
- static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property)
- {
- const auto& value = call.get_value<Exception, const TProperty>();
- TValidator{}(value);
- if (value == property)
- return;
- property = value;
- properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED;
- }
- bool commit(const EAX_REVERBPROPERTIES &props);
- bool commit(const EAX20LISTENERPROPERTIES &props);
- bool commit(const EAXREVERBPROPERTIES &props);
- static void SetDefaults(EAX_REVERBPROPERTIES &props);
- static void SetDefaults(EAX20LISTENERPROPERTIES &props);
- static void SetDefaults(EAXREVERBPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
- static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
- static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
- static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
- static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
- static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
- static void translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
- static void translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
- };
- template<typename T>
- struct EaxCommitter {
- struct Exception;
- EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
- : mEaxProps{eaxprops}, mAlProps{alprops}
- { }
- EaxEffectProps &mEaxProps;
- EffectProps &mAlProps;
- template<typename TValidator, typename TProperty>
- static void defer(const EaxCall& call, TProperty& property)
- {
- const auto& value = call.get_value<Exception, const TProperty>();
- TValidator{}(value);
- property = value;
- }
- [[noreturn]] static void fail(const char *message);
- [[noreturn]] static void fail_unknown_property_id()
- { fail(EaxEffectErrorMessages::unknown_property_id()); }
- };
- struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
- using EaxCommitter<EaxAutowahCommitter>::EaxCommitter;
- bool commit(const EAXAUTOWAHPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props);
- static void Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props);
- };
- struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
- using EaxCommitter<EaxChorusCommitter>::EaxCommitter;
- bool commit(const EAXCHORUSPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props);
- static void Set(const EaxCall &call, EAXCHORUSPROPERTIES &props);
- };
- struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
- using EaxCommitter<EaxCompressorCommitter>::EaxCommitter;
- bool commit(const EAXAGCCOMPRESSORPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props);
- static void Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props);
- };
- struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
- using EaxCommitter<EaxDistortionCommitter>::EaxCommitter;
- bool commit(const EAXDISTORTIONPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props);
- static void Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props);
- };
- struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
- using EaxCommitter<EaxEchoCommitter>::EaxCommitter;
- bool commit(const EAXECHOPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXECHOPROPERTIES &props);
- static void Set(const EaxCall &call, EAXECHOPROPERTIES &props);
- };
- struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
- using EaxCommitter<EaxEqualizerCommitter>::EaxCommitter;
- bool commit(const EAXEQUALIZERPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props);
- static void Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props);
- };
- struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
- using EaxCommitter<EaxFlangerCommitter>::EaxCommitter;
- bool commit(const EAXFLANGERPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props);
- static void Set(const EaxCall &call, EAXFLANGERPROPERTIES &props);
- };
- struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
- using EaxCommitter<EaxFrequencyShifterCommitter>::EaxCommitter;
- bool commit(const EAXFREQUENCYSHIFTERPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props);
- static void Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props);
- };
- struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
- using EaxCommitter<EaxModulatorCommitter>::EaxCommitter;
- bool commit(const EAXRINGMODULATORPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props);
- static void Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props);
- };
- struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
- using EaxCommitter<EaxPitchShifterCommitter>::EaxCommitter;
- bool commit(const EAXPITCHSHIFTERPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props);
- static void Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props);
- };
- struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
- using EaxCommitter<EaxVocalMorpherCommitter>::EaxCommitter;
- bool commit(const EAXVOCALMORPHERPROPERTIES &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props);
- static void Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props);
- };
- struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
- using EaxCommitter<EaxNullCommitter>::EaxCommitter;
- bool commit(const std::monostate &props);
- static void SetDefaults(EaxEffectProps &props);
- static void Get(const EaxCall &call, const std::monostate &props);
- static void Set(const EaxCall &call, std::monostate &props);
- };
- template<typename T>
- struct CommitterFromProps { };
- template<> struct CommitterFromProps<std::monostate> { using type = EaxNullCommitter; };
- template<> struct CommitterFromProps<EAXREVERBPROPERTIES> { using type = EaxReverbCommitter; };
- template<> struct CommitterFromProps<EAXCHORUSPROPERTIES> { using type = EaxChorusCommitter; };
- template<> struct CommitterFromProps<EAXAGCCOMPRESSORPROPERTIES> { using type = EaxCompressorCommitter; };
- template<> struct CommitterFromProps<EAXAUTOWAHPROPERTIES> { using type = EaxAutowahCommitter; };
- template<> struct CommitterFromProps<EAXDISTORTIONPROPERTIES> { using type = EaxDistortionCommitter; };
- template<> struct CommitterFromProps<EAXECHOPROPERTIES> { using type = EaxEchoCommitter; };
- template<> struct CommitterFromProps<EAXEQUALIZERPROPERTIES> { using type = EaxEqualizerCommitter; };
- template<> struct CommitterFromProps<EAXFLANGERPROPERTIES> { using type = EaxFlangerCommitter; };
- template<> struct CommitterFromProps<EAXFREQUENCYSHIFTERPROPERTIES> { using type = EaxFrequencyShifterCommitter; };
- template<> struct CommitterFromProps<EAXRINGMODULATORPROPERTIES> { using type = EaxModulatorCommitter; };
- template<> struct CommitterFromProps<EAXPITCHSHIFTERPROPERTIES> { using type = EaxPitchShifterCommitter; };
- template<> struct CommitterFromProps<EAXVOCALMORPHERPROPERTIES> { using type = EaxVocalMorpherCommitter; };
- template<typename T>
- using CommitterFor = typename CommitterFromProps<std::remove_cv_t<std::remove_reference_t<T>>>::type;
- class EaxEffect {
- public:
- EaxEffect() noexcept = default;
- ~EaxEffect() = default;
- ALenum al_effect_type_{AL_EFFECT_NULL};
- EffectProps al_effect_props_{};
- using Props1 = EAX_REVERBPROPERTIES;
- using Props2 = EAX20LISTENERPROPERTIES;
- using Props3 = EAXREVERBPROPERTIES;
- using Props4 = EaxEffectProps;
- struct State1 {
- Props1 i; // Immediate.
- Props1 d; // Deferred.
- };
- struct State2 {
- Props2 i; // Immediate.
- Props2 d; // Deferred.
- };
- struct State3 {
- Props3 i; // Immediate.
- Props3 d; // Deferred.
- };
- struct State4 {
- Props4 i; // Immediate.
- Props4 d; // Deferred.
- };
- int version_{};
- bool changed_{};
- Props4 props_{};
- State1 state1_{};
- State2 state2_{};
- State3 state3_{};
- State4 state4_{};
- State4 state5_{};
- static void call_set_defaults(const ALenum altype, EaxEffectProps &props)
- {
- switch(altype)
- {
- case AL_EFFECT_EAXREVERB: return EaxReverbCommitter::SetDefaults(props);
- case AL_EFFECT_CHORUS: return EaxChorusCommitter::SetDefaults(props);
- case AL_EFFECT_AUTOWAH: return EaxAutowahCommitter::SetDefaults(props);
- case AL_EFFECT_COMPRESSOR: return EaxCompressorCommitter::SetDefaults(props);
- case AL_EFFECT_DISTORTION: return EaxDistortionCommitter::SetDefaults(props);
- case AL_EFFECT_ECHO: return EaxEchoCommitter::SetDefaults(props);
- case AL_EFFECT_EQUALIZER: return EaxEqualizerCommitter::SetDefaults(props);
- case AL_EFFECT_FLANGER: return EaxFlangerCommitter::SetDefaults(props);
- case AL_EFFECT_FREQUENCY_SHIFTER: return EaxFrequencyShifterCommitter::SetDefaults(props);
- case AL_EFFECT_RING_MODULATOR: return EaxModulatorCommitter::SetDefaults(props);
- case AL_EFFECT_PITCH_SHIFTER: return EaxPitchShifterCommitter::SetDefaults(props);
- case AL_EFFECT_VOCAL_MORPHER: return EaxVocalMorpherCommitter::SetDefaults(props);
- case AL_EFFECT_NULL: break;
- }
- return EaxNullCommitter::SetDefaults(props);
- }
- template<typename T>
- void init()
- {
- EaxReverbCommitter::SetDefaults(state1_.d);
- state1_.i = state1_.d;
- EaxReverbCommitter::SetDefaults(state2_.d);
- state2_.i = state2_.d;
- EaxReverbCommitter::SetDefaults(state3_.d);
- state3_.i = state3_.d;
- T::SetDefaults(state4_.d);
- state4_.i = state4_.d;
- T::SetDefaults(state5_.d);
- state5_.i = state5_.d;
- }
- void set_defaults(int eax_version, ALenum altype)
- {
- switch(eax_version)
- {
- case 1: EaxReverbCommitter::SetDefaults(state1_.d); break;
- case 2: EaxReverbCommitter::SetDefaults(state2_.d); break;
- case 3: EaxReverbCommitter::SetDefaults(state3_.d); break;
- case 4: call_set_defaults(altype, state4_.d); break;
- case 5: call_set_defaults(altype, state5_.d); break;
- }
- changed_ = true;
- }
- static void call_set(const EaxCall &call, EaxEffectProps &props)
- {
- return std::visit([&](auto &arg)
- { return CommitterFor<decltype(arg)>::Set(call, arg); },
- props);
- }
- void set(const EaxCall &call)
- {
- switch(call.get_version())
- {
- case 1: EaxReverbCommitter::Set(call, state1_.d); break;
- case 2: EaxReverbCommitter::Set(call, state2_.d); break;
- case 3: EaxReverbCommitter::Set(call, state3_.d); break;
- case 4: call_set(call, state4_.d); break;
- case 5: call_set(call, state5_.d); break;
- }
- changed_ = true;
- }
- static void call_get(const EaxCall &call, const EaxEffectProps &props)
- {
- return std::visit([&](auto &arg)
- { return CommitterFor<decltype(arg)>::Get(call, arg); },
- props);
- }
- void get(const EaxCall &call) const
- {
- switch(call.get_version())
- {
- case 1: EaxReverbCommitter::Get(call, state1_.d); break;
- case 2: EaxReverbCommitter::Get(call, state2_.d); break;
- case 3: EaxReverbCommitter::Get(call, state3_.d); break;
- case 4: call_get(call, state4_.d); break;
- case 5: call_get(call, state5_.d); break;
- }
- }
- bool call_commit(const EaxEffectProps &props)
- {
- return std::visit([&](auto &arg)
- { return CommitterFor<decltype(arg)>{props_, al_effect_props_}.commit(arg); },
- props);
- }
- bool commit(int eax_version)
- {
- changed_ |= version_ != eax_version;
- if(!changed_) return false;
- bool ret{version_ != eax_version};
- version_ = eax_version;
- changed_ = false;
- switch(eax_version)
- {
- case 1:
- state1_.i = state1_.d;
- ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state1_.d);
- break;
- case 2:
- state2_.i = state2_.d;
- ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state2_.d);
- break;
- case 3:
- state3_.i = state3_.d;
- ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state3_.d);
- break;
- case 4:
- state4_.i = state4_.d;
- ret |= call_commit(state4_.d);
- break;
- case 5:
- state5_.i = state5_.d;
- ret |= call_commit(state5_.d);
- break;
- }
- al_effect_type_ = EnumFromEaxEffectType(props_);
- return ret;
- }
- #undef EAXCALL
- }; // EaxEffect
- using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
- #endif // !EAX_EFFECT_INCLUDED
|