auxeffectslot.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #ifndef AL_AUXEFFECTSLOT_H
  2. #define AL_AUXEFFECTSLOT_H
  3. #include "config.h"
  4. #include <array>
  5. #include <atomic>
  6. #include <bitset>
  7. #include <cstdint>
  8. #include <string_view>
  9. #include <utility>
  10. #include "AL/al.h"
  11. #include "AL/alc.h"
  12. #include "almalloc.h"
  13. #include "alnumeric.h"
  14. #include "core/effects/base.h"
  15. #include "core/effectslot.h"
  16. #include "intrusive_ptr.h"
  17. #if ALSOFT_EAX
  18. #include <memory>
  19. #include "eax/api.h"
  20. #include "eax/call.h"
  21. #include "eax/effect.h"
  22. #include "eax/exception.h"
  23. #include "eax/fx_slot_index.h"
  24. #include "eax/utils.h"
  25. #endif // ALSOFT_EAX
  26. struct ALbuffer;
  27. #if ALSOFT_EAX
  28. class EaxFxSlotException : public EaxException {
  29. public:
  30. explicit EaxFxSlotException(const char* message)
  31. : EaxException{"EAX_FX_SLOT", message}
  32. {}
  33. };
  34. #endif // ALSOFT_EAX
  35. enum class SlotState : bool {
  36. Initial, Playing,
  37. };
  38. struct ALeffectslot {
  39. ALuint EffectId{};
  40. float Gain{1.0f};
  41. bool AuxSendAuto{true};
  42. ALeffectslot *Target{nullptr};
  43. ALbuffer *Buffer{nullptr};
  44. struct EffectData {
  45. EffectSlotType Type{EffectSlotType::None};
  46. EffectProps Props;
  47. al::intrusive_ptr<EffectState> State;
  48. };
  49. EffectData Effect;
  50. bool mPropsDirty{true};
  51. SlotState mState{SlotState::Initial};
  52. std::atomic<ALuint> ref{0u};
  53. EffectSlot *mSlot{nullptr};
  54. /* Self ID */
  55. ALuint id{};
  56. explicit ALeffectslot(ALCcontext *context);
  57. ALeffectslot(const ALeffectslot&) = delete;
  58. ALeffectslot& operator=(const ALeffectslot&) = delete;
  59. ~ALeffectslot();
  60. ALenum initEffect(ALuint effectId, ALenum effectType, const EffectProps &effectProps,
  61. ALCcontext *context);
  62. void updateProps(ALCcontext *context) const;
  63. static void SetName(ALCcontext *context, ALuint id, std::string_view name);
  64. #if ALSOFT_EAX
  65. public:
  66. void eax_initialize(ALCcontext& al_context, EaxFxSlotIndexValue index);
  67. [[nodiscard]]
  68. auto eax_get_index() const noexcept -> EaxFxSlotIndexValue { return mEaxFXSlotIndex; }
  69. [[nodiscard]]
  70. auto eax_get_eax_fx_slot() const noexcept -> const EAX50FXSLOTPROPERTIES& { return mEax; }
  71. // Returns `true` if all sources should be updated, or `false` otherwise.
  72. [[nodiscard]] auto eax_dispatch(const EaxCall& call) -> bool
  73. { return call.is_get() ? eax_get(call) : eax_set(call); }
  74. void eax_commit();
  75. private:
  76. enum {
  77. eax_load_effect_dirty_bit,
  78. eax_volume_dirty_bit,
  79. eax_lock_dirty_bit,
  80. eax_flags_dirty_bit,
  81. eax_occlusion_dirty_bit,
  82. eax_occlusion_lf_ratio_dirty_bit,
  83. eax_dirty_bit_count
  84. };
  85. using Exception = EaxFxSlotException;
  86. struct Eax4State {
  87. EAX40FXSLOTPROPERTIES i; // Immediate.
  88. };
  89. struct Eax5State {
  90. EAX50FXSLOTPROPERTIES i; // Immediate.
  91. };
  92. struct EaxRangeValidator {
  93. template<typename TValue>
  94. void operator()(
  95. const char* name,
  96. const TValue& value,
  97. const TValue& min_value,
  98. const TValue& max_value) const
  99. {
  100. eax_validate_range<Exception>(name, value, min_value, max_value);
  101. }
  102. };
  103. struct Eax4GuidLoadEffectValidator {
  104. void operator()(const GUID& guidLoadEffect) const
  105. {
  106. if (guidLoadEffect != EAX_NULL_GUID &&
  107. guidLoadEffect != EAX_REVERB_EFFECT &&
  108. guidLoadEffect != EAX_AGCCOMPRESSOR_EFFECT &&
  109. guidLoadEffect != EAX_AUTOWAH_EFFECT &&
  110. guidLoadEffect != EAX_CHORUS_EFFECT &&
  111. guidLoadEffect != EAX_DISTORTION_EFFECT &&
  112. guidLoadEffect != EAX_ECHO_EFFECT &&
  113. guidLoadEffect != EAX_EQUALIZER_EFFECT &&
  114. guidLoadEffect != EAX_FLANGER_EFFECT &&
  115. guidLoadEffect != EAX_FREQUENCYSHIFTER_EFFECT &&
  116. guidLoadEffect != EAX_VOCALMORPHER_EFFECT &&
  117. guidLoadEffect != EAX_PITCHSHIFTER_EFFECT &&
  118. guidLoadEffect != EAX_RINGMODULATOR_EFFECT)
  119. {
  120. eax_fail_unknown_effect_id();
  121. }
  122. }
  123. };
  124. struct Eax4VolumeValidator {
  125. void operator()(long lVolume) const
  126. {
  127. EaxRangeValidator{}(
  128. "Volume",
  129. lVolume,
  130. EAXFXSLOT_MINVOLUME,
  131. EAXFXSLOT_MAXVOLUME);
  132. }
  133. };
  134. struct Eax4LockValidator {
  135. void operator()(long lLock) const
  136. {
  137. EaxRangeValidator{}(
  138. "Lock",
  139. lLock,
  140. EAXFXSLOT_MINLOCK,
  141. EAXFXSLOT_MAXLOCK);
  142. }
  143. };
  144. struct Eax4FlagsValidator {
  145. void operator()(unsigned long ulFlags) const
  146. {
  147. EaxRangeValidator{}(
  148. "Flags",
  149. ulFlags,
  150. 0UL,
  151. ~EAX40FXSLOTFLAGS_RESERVED);
  152. }
  153. };
  154. struct Eax4AllValidator {
  155. void operator()(const EAX40FXSLOTPROPERTIES& all) const
  156. {
  157. Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
  158. Eax4VolumeValidator{}(all.lVolume);
  159. Eax4LockValidator{}(all.lLock);
  160. Eax4FlagsValidator{}(all.ulFlags);
  161. }
  162. };
  163. struct Eax5FlagsValidator {
  164. void operator()(unsigned long ulFlags) const
  165. {
  166. EaxRangeValidator{}(
  167. "Flags",
  168. ulFlags,
  169. 0UL,
  170. ~EAX50FXSLOTFLAGS_RESERVED);
  171. }
  172. };
  173. struct Eax5OcclusionValidator {
  174. void operator()(long lOcclusion) const
  175. {
  176. EaxRangeValidator{}(
  177. "Occlusion",
  178. lOcclusion,
  179. EAXFXSLOT_MINOCCLUSION,
  180. EAXFXSLOT_MAXOCCLUSION);
  181. }
  182. };
  183. struct Eax5OcclusionLfRatioValidator {
  184. void operator()(float flOcclusionLFRatio) const
  185. {
  186. EaxRangeValidator{}(
  187. "Occlusion LF Ratio",
  188. flOcclusionLFRatio,
  189. EAXFXSLOT_MINOCCLUSIONLFRATIO,
  190. EAXFXSLOT_MAXOCCLUSIONLFRATIO);
  191. }
  192. };
  193. struct Eax5AllValidator {
  194. void operator()(const EAX50FXSLOTPROPERTIES& all) const
  195. {
  196. Eax4GuidLoadEffectValidator{}(all.guidLoadEffect);
  197. Eax4VolumeValidator{}(all.lVolume);
  198. Eax4LockValidator{}(all.lLock);
  199. Eax5FlagsValidator{}(all.ulFlags);
  200. Eax5OcclusionValidator{}(all.lOcclusion);
  201. Eax5OcclusionLfRatioValidator{}(all.flOcclusionLFRatio);
  202. }
  203. };
  204. ALCcontext* mEaxALContext{};
  205. EaxFxSlotIndexValue mEaxFXSlotIndex{};
  206. int mEaxVersion{}; // Current EAX version.
  207. std::bitset<eax_dirty_bit_count> mEaxDf; // Dirty flags for the current EAX version.
  208. EaxEffectUPtr mEaxEffect;
  209. Eax5State mEax123{}; // EAX1/EAX2/EAX3 state.
  210. Eax4State mEax4{}; // EAX4 state.
  211. Eax5State mEax5{}; // EAX5 state.
  212. EAX50FXSLOTPROPERTIES mEax{}; // Current EAX state.
  213. [[noreturn]] static void eax_fail(const char* message);
  214. [[noreturn]] static void eax_fail_unknown_effect_id();
  215. [[noreturn]] static void eax_fail_unknown_property_id();
  216. [[noreturn]] static void eax_fail_unknown_version();
  217. // Gets a new value from EAX call,
  218. // validates it,
  219. // sets a dirty flag only if the new value differs form the old one,
  220. // and assigns the new value.
  221. template<typename TValidator, size_t DirtyBit, typename TProperties>
  222. static void eax_fx_slot_set(const EaxCall& call, TProperties& dst,
  223. std::bitset<eax_dirty_bit_count>& dirty_flags)
  224. {
  225. const auto& src = call.get_value<Exception, const TProperties>();
  226. TValidator{}(src);
  227. if(dst != src)
  228. dirty_flags.set(DirtyBit);
  229. dst = src;
  230. }
  231. // Gets a new value from EAX call,
  232. // validates it,
  233. // sets a dirty flag without comparing the values,
  234. // and assigns the new value.
  235. template<typename TValidator, size_t DirtyBit, typename TProperties>
  236. static void eax_fx_slot_set_dirty(const EaxCall& call, TProperties& dst,
  237. std::bitset<eax_dirty_bit_count>& dirty_flags)
  238. {
  239. const auto& src = call.get_value<Exception, const TProperties>();
  240. TValidator{}(src);
  241. dirty_flags.set(DirtyBit);
  242. dst = src;
  243. }
  244. [[nodiscard]] constexpr auto eax4_fx_slot_is_legacy() const noexcept -> bool
  245. { return mEaxFXSlotIndex < 2; }
  246. void eax4_fx_slot_ensure_unlocked() const;
  247. [[nodiscard]] static auto eax_get_efx_effect_type(const GUID& guid) -> ALenum;
  248. [[nodiscard]] auto eax_get_eax_default_effect_guid() const noexcept -> const GUID&;
  249. [[nodiscard]] auto eax_get_eax_default_lock() const noexcept -> long;
  250. void eax4_fx_slot_set_defaults(EAX40FXSLOTPROPERTIES& props) noexcept;
  251. void eax5_fx_slot_set_defaults(EAX50FXSLOTPROPERTIES& props) noexcept;
  252. void eax4_fx_slot_set_current_defaults(const EAX40FXSLOTPROPERTIES& props) noexcept;
  253. void eax5_fx_slot_set_current_defaults(const EAX50FXSLOTPROPERTIES& props) noexcept;
  254. void eax_fx_slot_set_current_defaults();
  255. void eax_fx_slot_set_defaults();
  256. static void eax4_fx_slot_get(const EaxCall& call, const EAX40FXSLOTPROPERTIES& props);
  257. static void eax5_fx_slot_get(const EaxCall& call, const EAX50FXSLOTPROPERTIES& props);
  258. void eax_fx_slot_get(const EaxCall& call) const;
  259. // Returns `true` if all sources should be updated, or `false` otherwise.
  260. bool eax_get(const EaxCall& call);
  261. void eax_fx_slot_load_effect(int version, ALenum altype);
  262. void eax_fx_slot_set_volume();
  263. void eax_fx_slot_set_environment_flag();
  264. void eax_fx_slot_set_flags();
  265. void eax4_fx_slot_set_all(const EaxCall& call);
  266. void eax5_fx_slot_set_all(const EaxCall& call);
  267. [[nodiscard]] auto eax_fx_slot_should_update_sources() const noexcept -> bool;
  268. // Returns `true` if all sources should be updated, or `false` otherwise.
  269. bool eax4_fx_slot_set(const EaxCall& call);
  270. // Returns `true` if all sources should be updated, or `false` otherwise.
  271. bool eax5_fx_slot_set(const EaxCall& call);
  272. // Returns `true` if all sources should be updated, or `false` otherwise.
  273. bool eax_fx_slot_set(const EaxCall& call);
  274. // Returns `true` if all sources should be updated, or `false` otherwise.
  275. bool eax_set(const EaxCall& call);
  276. template<
  277. size_t DirtyBit,
  278. typename TMemberResult,
  279. typename TProps,
  280. typename TState>
  281. void eax_fx_slot_commit_property(TState& state, std::bitset<eax_dirty_bit_count>& dst_df,
  282. TMemberResult TProps::*member) noexcept
  283. {
  284. auto& src_i = state.i;
  285. auto& dst_i = mEax;
  286. if(mEaxDf.test(DirtyBit))
  287. {
  288. dst_df.set(DirtyBit);
  289. dst_i.*member = src_i.*member;
  290. }
  291. }
  292. void eax4_fx_slot_commit(std::bitset<eax_dirty_bit_count>& dst_df);
  293. void eax5_fx_slot_commit(Eax5State& state, std::bitset<eax_dirty_bit_count>& dst_df);
  294. // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_EFFECT, effect)`
  295. void eax_set_efx_slot_effect(EaxEffect &effect);
  296. // `alAuxiliaryEffectSloti(effect_slot, AL_EFFECTSLOT_AUXILIARY_SEND_AUTO, value)`
  297. void eax_set_efx_slot_send_auto(bool is_send_auto);
  298. // `alAuxiliaryEffectSlotf(effect_slot, AL_EFFECTSLOT_GAIN, gain)`
  299. void eax_set_efx_slot_gain(ALfloat gain);
  300. public:
  301. class EaxDeleter {
  302. public:
  303. void operator()(ALeffectslot *effect_slot);
  304. };
  305. #endif // ALSOFT_EAX
  306. };
  307. void UpdateAllEffectSlotProps(ALCcontext *context);
  308. #if ALSOFT_EAX
  309. using EaxAlEffectSlotUPtr = std::unique_ptr<ALeffectslot, ALeffectslot::EaxDeleter>;
  310. EaxAlEffectSlotUPtr eax_create_al_effect_slot(ALCcontext& context);
  311. void eax_delete_al_effect_slot(ALCcontext& context, ALeffectslot& effect_slot);
  312. #endif // ALSOFT_EAX
  313. struct EffectSlotSubList {
  314. uint64_t FreeMask{~0_u64};
  315. gsl::owner<std::array<ALeffectslot,64>*> EffectSlots{nullptr};
  316. EffectSlotSubList() noexcept = default;
  317. EffectSlotSubList(const EffectSlotSubList&) = delete;
  318. EffectSlotSubList(EffectSlotSubList&& rhs) noexcept
  319. : FreeMask{rhs.FreeMask}, EffectSlots{rhs.EffectSlots}
  320. { rhs.FreeMask = ~0_u64; rhs.EffectSlots = nullptr; }
  321. ~EffectSlotSubList();
  322. EffectSlotSubList& operator=(const EffectSlotSubList&) = delete;
  323. EffectSlotSubList& operator=(EffectSlotSubList&& rhs) noexcept
  324. { std::swap(FreeMask, rhs.FreeMask); std::swap(EffectSlots, rhs.EffectSlots); return *this; }
  325. };
  326. #endif