🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
4.6 KiB

  1. #ifndef EAX_EFFECT_INCLUDED
  2. #define EAX_EFFECT_INCLUDED
  3. #include <cassert>
  4. #include <memory>
  5. #include "alnumeric.h"
  6. #include "AL/al.h"
  7. #include "core/effects/base.h"
  8. #include "call.h"
  9. struct EaxEffectErrorMessages
  10. {
  11. static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
  12. static constexpr auto unknown_version() noexcept { return "Unknown version."; }
  13. }; // EaxEffectErrorMessages
  14. class EaxEffect {
  15. public:
  16. EaxEffect(ALenum type) noexcept : al_effect_type_{type} { }
  17. virtual ~EaxEffect() = default;
  18. const ALenum al_effect_type_;
  19. EffectProps al_effect_props_{};
  20. virtual void dispatch(const EaxCall& call) = 0;
  21. // Returns "true" if any immediated property was changed.
  22. /*[[nodiscard]]*/ virtual bool commit() = 0;
  23. }; // EaxEffect
  24. // Base class for EAX4+ effects.
  25. template<typename TException, typename TProps>
  26. class EaxEffect4 : public EaxEffect
  27. {
  28. public:
  29. EaxEffect4(ALenum type, const EaxCall& call)
  30. : EaxEffect{type}, version_{clamp(call.get_version(), 4, 5)}
  31. {}
  32. void initialize()
  33. {
  34. set_defaults();
  35. set_efx_defaults();
  36. }
  37. void dispatch(const EaxCall& call) override
  38. {
  39. call.is_get() ? get(call) : set(call);
  40. version_ = call.get_version();
  41. }
  42. bool commit() final
  43. {
  44. switch (version_)
  45. {
  46. case 4: return commit_state(state4_);
  47. case 5: return commit_state(state5_);
  48. default: fail_unknown_version();
  49. }
  50. }
  51. protected:
  52. using Exception = TException;
  53. using Props = TProps;
  54. struct State {
  55. Props i; // Immediate.
  56. Props d; // Deferred.
  57. }; // State
  58. int version_;
  59. Props props_;
  60. State state4_;
  61. State state5_;
  62. template<typename TValidator, typename TProperty>
  63. static void defer(const EaxCall& call, TProperty& property)
  64. {
  65. const auto& value = call.get_value<Exception, const TProperty>();
  66. TValidator{}(value);
  67. property = value;
  68. }
  69. virtual void set_defaults(Props& props) = 0;
  70. virtual void set_efx_defaults() = 0;
  71. virtual void get(const EaxCall& call, const Props& props) = 0;
  72. virtual void set(const EaxCall& call, Props& props) = 0;
  73. virtual bool commit_props(const Props& props) = 0;
  74. [[noreturn]] static void fail(const char* message)
  75. {
  76. throw Exception{message};
  77. }
  78. [[noreturn]] static void fail_unknown_property_id()
  79. {
  80. fail(EaxEffectErrorMessages::unknown_property_id());
  81. }
  82. [[noreturn]] static void fail_unknown_version()
  83. {
  84. fail(EaxEffectErrorMessages::unknown_version());
  85. }
  86. private:
  87. void set_defaults()
  88. {
  89. set_defaults(props_);
  90. state4_.i = props_;
  91. state4_.d = props_;
  92. state5_.i = props_;
  93. state5_.d = props_;
  94. }
  95. void get(const EaxCall& call)
  96. {
  97. switch (call.get_version())
  98. {
  99. case 4: get(call, state4_.i); break;
  100. case 5: get(call, state5_.i); break;
  101. default: fail_unknown_version();
  102. }
  103. }
  104. void set(const EaxCall& call)
  105. {
  106. switch (call.get_version())
  107. {
  108. case 4: set(call, state4_.d); break;
  109. case 5: set(call, state5_.d); break;
  110. default: fail_unknown_version();
  111. }
  112. }
  113. bool commit_state(State& state)
  114. {
  115. const auto props = props_;
  116. state.i = state.d;
  117. props_ = state.d;
  118. return commit_props(props);
  119. }
  120. }; // EaxEffect4
  121. using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
  122. // Creates EAX4+ effect.
  123. template<typename TEffect>
  124. EaxEffectUPtr eax_create_eax4_effect(const EaxCall& call)
  125. {
  126. auto effect = std::make_unique<TEffect>(call);
  127. effect->initialize();
  128. return effect;
  129. }
  130. EaxEffectUPtr eax_create_eax_null_effect();
  131. EaxEffectUPtr eax_create_eax_chorus_effect(const EaxCall& call);
  132. EaxEffectUPtr eax_create_eax_distortion_effect(const EaxCall& call);
  133. EaxEffectUPtr eax_create_eax_echo_effect(const EaxCall& call);
  134. EaxEffectUPtr eax_create_eax_flanger_effect(const EaxCall& call);
  135. EaxEffectUPtr eax_create_eax_frequency_shifter_effect(const EaxCall& call);
  136. EaxEffectUPtr eax_create_eax_vocal_morpher_effect(const EaxCall& call);
  137. EaxEffectUPtr eax_create_eax_pitch_shifter_effect(const EaxCall& call);
  138. EaxEffectUPtr eax_create_eax_ring_modulator_effect(const EaxCall& call);
  139. EaxEffectUPtr eax_create_eax_auto_wah_effect(const EaxCall& call);
  140. EaxEffectUPtr eax_create_eax_compressor_effect(const EaxCall& call);
  141. EaxEffectUPtr eax_create_eax_equalizer_effect(const EaxCall& call);
  142. EaxEffectUPtr eax_create_eax_reverb_effect(const EaxCall& call);
  143. #endif // !EAX_EFFECT_INCLUDED