aboutsummaryrefslogtreecommitdiffstats
path: root/al/eax/effect.h
diff options
context:
space:
mode:
Diffstat (limited to 'al/eax/effect.h')
-rw-r--r--al/eax/effect.h165
1 files changed, 147 insertions, 18 deletions
diff --git a/al/eax/effect.h b/al/eax/effect.h
index 9c9fdef4..b57bf240 100644
--- a/al/eax/effect.h
+++ b/al/eax/effect.h
@@ -2,43 +2,172 @@
#define EAX_EFFECT_INCLUDED
+#include <cassert>
#include <memory>
+#include "alnumeric.h"
#include "AL/al.h"
#include "core/effects/base.h"
-#include "eax_call.h"
+#include "call.h"
-class EaxEffect
+struct EaxEffectErrorMessages
{
+ static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
+ static constexpr auto unknown_version() noexcept { return "Unknown version."; }
+}; // EaxEffectErrorMessages
+
+class EaxEffect {
public:
- EaxEffect(ALenum type) : al_effect_type_{type} { }
+ EaxEffect(ALenum type) noexcept : al_effect_type_{type} { }
virtual ~EaxEffect() = default;
const ALenum al_effect_type_;
EffectProps al_effect_props_{};
- virtual void dispatch(const EaxEaxCall& eax_call) = 0;
+ virtual void dispatch(const EaxCall& call) = 0;
// Returns "true" if any immediated property was changed.
- // [[nodiscard]]
- virtual bool apply_deferred() = 0;
+ /*[[nodiscard]]*/ virtual bool commit() = 0;
}; // EaxEffect
+// Base class for EAX4+ effects.
+template<typename TException, typename TProps>
+class EaxEffect4 : public EaxEffect
+{
+public:
+ EaxEffect4(ALenum type, const EaxCall& call)
+ : EaxEffect{type}, version_{clamp(call.get_version(), 4, 5)}
+ {}
+
+ void initialize()
+ {
+ set_defaults();
+ set_efx_defaults();
+ }
+
+ void dispatch(const EaxCall& call) override
+ {
+ call.is_get() ? get(call) : set(call);
+ version_ = call.get_version();
+ }
+
+ bool commit() final
+ {
+ switch (version_)
+ {
+ case 4: return commit_state(state4_);
+ case 5: return commit_state(state5_);
+ default: fail_unknown_version();
+ }
+ }
+
+protected:
+ using Exception = TException;
+ using Props = TProps;
+
+ struct State {
+ Props i; // Immediate.
+ Props d; // Deferred.
+ }; // State
+
+ int version_;
+ Props props_;
+ State state4_;
+ State state5_;
+
+ 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;
+ }
+
+ virtual void set_defaults(Props& props) = 0;
+ virtual void set_efx_defaults() = 0;
+
+ virtual void get(const EaxCall& call, const Props& props) = 0;
+ virtual void set(const EaxCall& call, Props& props) = 0;
+
+ virtual bool commit_props(const Props& props) = 0;
+
+ [[noreturn]] static void fail(const char* message)
+ {
+ throw Exception{message};
+ }
+
+ [[noreturn]] static void fail_unknown_property_id()
+ {
+ fail(EaxEffectErrorMessages::unknown_property_id());
+ }
+
+ [[noreturn]] static void fail_unknown_version()
+ {
+ fail(EaxEffectErrorMessages::unknown_version());
+ }
+
+private:
+ void set_defaults()
+ {
+ set_defaults(props_);
+ state4_.i = props_;
+ state4_.d = props_;
+ state5_.i = props_;
+ state5_.d = props_;
+ }
+
+ void get(const EaxCall& call)
+ {
+ switch (call.get_version())
+ {
+ case 4: get(call, state4_.i); break;
+ case 5: get(call, state5_.i); break;
+ default: fail_unknown_version();
+ }
+ }
+
+ void set(const EaxCall& call)
+ {
+ switch (call.get_version())
+ {
+ case 4: set(call, state4_.d); break;
+ case 5: set(call, state5_.d); break;
+ default: fail_unknown_version();
+ }
+ }
+
+ bool commit_state(State& state)
+ {
+ const auto props = props_;
+ state.i = state.d;
+ props_ = state.d;
+ return commit_props(props);
+ }
+}; // EaxEffect4
using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
+// Creates EAX4+ effect.
+template<typename TEffect>
+EaxEffectUPtr eax_create_eax4_effect(const EaxCall& call)
+{
+ auto effect = std::make_unique<TEffect>(call);
+ effect->initialize();
+ return effect;
+}
+
EaxEffectUPtr eax_create_eax_null_effect();
-EaxEffectUPtr eax_create_eax_chorus_effect();
-EaxEffectUPtr eax_create_eax_distortion_effect();
-EaxEffectUPtr eax_create_eax_echo_effect();
-EaxEffectUPtr eax_create_eax_flanger_effect();
-EaxEffectUPtr eax_create_eax_frequency_shifter_effect();
-EaxEffectUPtr eax_create_eax_vocal_morpher_effect();
-EaxEffectUPtr eax_create_eax_pitch_shifter_effect();
-EaxEffectUPtr eax_create_eax_ring_modulator_effect();
-EaxEffectUPtr eax_create_eax_auto_wah_effect();
-EaxEffectUPtr eax_create_eax_compressor_effect();
-EaxEffectUPtr eax_create_eax_equalizer_effect();
-EaxEffectUPtr eax_create_eax_reverb_effect();
+EaxEffectUPtr eax_create_eax_chorus_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_distortion_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_echo_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_flanger_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_frequency_shifter_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_vocal_morpher_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_pitch_shifter_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_ring_modulator_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_auto_wah_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_compressor_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_equalizer_effect(const EaxCall& call);
+EaxEffectUPtr eax_create_eax_reverb_effect(const EaxCall& call);
#endif // !EAX_EFFECT_INCLUDED