effect.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. #ifndef EAX_EFFECT_INCLUDED
  2. #define EAX_EFFECT_INCLUDED
  3. #include <cassert>
  4. #include <memory>
  5. #include <variant>
  6. #include "AL/al.h"
  7. #include "AL/alext.h"
  8. #include "core/effects/base.h"
  9. #include "call.h"
  10. inline bool EaxTraceCommits{false};
  11. struct EaxEffectErrorMessages {
  12. static constexpr auto unknown_property_id() noexcept { return "Unknown property id."; }
  13. static constexpr auto unknown_version() noexcept { return "Unknown version."; }
  14. }; // EaxEffectErrorMessages
  15. using EaxEffectProps = std::variant<std::monostate,
  16. EAXREVERBPROPERTIES,
  17. EAXCHORUSPROPERTIES,
  18. EAXAUTOWAHPROPERTIES,
  19. EAXAGCCOMPRESSORPROPERTIES,
  20. EAXDISTORTIONPROPERTIES,
  21. EAXECHOPROPERTIES,
  22. EAXEQUALIZERPROPERTIES,
  23. EAXFLANGERPROPERTIES,
  24. EAXFREQUENCYSHIFTERPROPERTIES,
  25. EAXRINGMODULATORPROPERTIES,
  26. EAXPITCHSHIFTERPROPERTIES,
  27. EAXVOCALMORPHERPROPERTIES>;
  28. template<typename... Ts>
  29. struct overloaded : Ts... { using Ts::operator()...; };
  30. template<typename... Ts>
  31. overloaded(Ts...) -> overloaded<Ts...>;
  32. constexpr ALenum EnumFromEaxEffectType(const EaxEffectProps &props)
  33. {
  34. return std::visit(overloaded{
  35. [](const std::monostate&) noexcept { return AL_EFFECT_NULL; },
  36. [](const EAXREVERBPROPERTIES&) noexcept { return AL_EFFECT_EAXREVERB; },
  37. [](const EAXCHORUSPROPERTIES&) noexcept { return AL_EFFECT_CHORUS; },
  38. [](const EAXAUTOWAHPROPERTIES&) noexcept { return AL_EFFECT_AUTOWAH; },
  39. [](const EAXAGCCOMPRESSORPROPERTIES&) noexcept { return AL_EFFECT_COMPRESSOR; },
  40. [](const EAXDISTORTIONPROPERTIES&) noexcept { return AL_EFFECT_DISTORTION; },
  41. [](const EAXECHOPROPERTIES&) noexcept { return AL_EFFECT_ECHO; },
  42. [](const EAXEQUALIZERPROPERTIES&) noexcept { return AL_EFFECT_EQUALIZER; },
  43. [](const EAXFLANGERPROPERTIES&) noexcept { return AL_EFFECT_FLANGER; },
  44. [](const EAXFREQUENCYSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_FREQUENCY_SHIFTER; },
  45. [](const EAXRINGMODULATORPROPERTIES&) noexcept { return AL_EFFECT_RING_MODULATOR; },
  46. [](const EAXPITCHSHIFTERPROPERTIES&) noexcept { return AL_EFFECT_PITCH_SHIFTER; },
  47. [](const EAXVOCALMORPHERPROPERTIES&) noexcept { return AL_EFFECT_VOCAL_MORPHER; }
  48. }, props);
  49. }
  50. struct EaxReverbCommitter {
  51. struct Exception;
  52. EaxReverbCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
  53. : mEaxProps{eaxprops}, mAlProps{alprops}
  54. { }
  55. EaxEffectProps &mEaxProps;
  56. EffectProps &mAlProps;
  57. [[noreturn]] static void fail(const char* message);
  58. [[noreturn]] static void fail_unknown_property_id()
  59. { fail(EaxEffectErrorMessages::unknown_property_id()); }
  60. template<typename TValidator, typename TProperty>
  61. static void defer(const EaxCall& call, TProperty& property)
  62. {
  63. const auto& value = call.get_value<Exception, const TProperty>();
  64. TValidator{}(value);
  65. property = value;
  66. }
  67. template<typename TValidator, typename TDeferrer, typename TProperties, typename TProperty>
  68. static void defer(const EaxCall& call, TProperties& properties, TProperty&)
  69. {
  70. const auto& value = call.get_value<Exception, const TProperty>();
  71. TValidator{}(value);
  72. TDeferrer{}(properties, value);
  73. }
  74. template<typename TValidator, typename TProperty>
  75. static void defer3(const EaxCall& call, EAXREVERBPROPERTIES& properties, TProperty& property)
  76. {
  77. const auto& value = call.get_value<Exception, const TProperty>();
  78. TValidator{}(value);
  79. if (value == property)
  80. return;
  81. property = value;
  82. properties.ulEnvironment = EAX_ENVIRONMENT_UNDEFINED;
  83. }
  84. bool commit(const EAX_REVERBPROPERTIES &props);
  85. bool commit(const EAX20LISTENERPROPERTIES &props);
  86. bool commit(const EAXREVERBPROPERTIES &props);
  87. static void SetDefaults(EAX_REVERBPROPERTIES &props);
  88. static void SetDefaults(EAX20LISTENERPROPERTIES &props);
  89. static void SetDefaults(EAXREVERBPROPERTIES &props);
  90. static void SetDefaults(EaxEffectProps &props);
  91. static void Get(const EaxCall &call, const EAX_REVERBPROPERTIES &props);
  92. static void Get(const EaxCall &call, const EAX20LISTENERPROPERTIES &props);
  93. static void Get(const EaxCall &call, const EAXREVERBPROPERTIES &props);
  94. static void Set(const EaxCall &call, EAX_REVERBPROPERTIES &props);
  95. static void Set(const EaxCall &call, EAX20LISTENERPROPERTIES &props);
  96. static void Set(const EaxCall &call, EAXREVERBPROPERTIES &props);
  97. static void translate(const EAX_REVERBPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
  98. static void translate(const EAX20LISTENERPROPERTIES& src, EAXREVERBPROPERTIES& dst) noexcept;
  99. };
  100. template<typename T>
  101. struct EaxCommitter {
  102. struct Exception;
  103. EaxEffectProps &mEaxProps;
  104. EffectProps &mAlProps;
  105. template<typename TValidator, typename TProperty>
  106. static void defer(const EaxCall& call, TProperty& property)
  107. {
  108. const auto& value = call.get_value<Exception, const TProperty>();
  109. TValidator{}(value);
  110. property = value;
  111. }
  112. [[noreturn]] static void fail(const char *message);
  113. [[noreturn]] static void fail_unknown_property_id()
  114. { fail(EaxEffectErrorMessages::unknown_property_id()); }
  115. private:
  116. EaxCommitter(EaxEffectProps &eaxprops, EffectProps &alprops)
  117. : mEaxProps{eaxprops}, mAlProps{alprops}
  118. { }
  119. friend T;
  120. };
  121. struct EaxAutowahCommitter : public EaxCommitter<EaxAutowahCommitter> {
  122. template<typename ...Args>
  123. explicit EaxAutowahCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  124. bool commit(const EAXAUTOWAHPROPERTIES &props);
  125. static void SetDefaults(EaxEffectProps &props);
  126. static void Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props);
  127. static void Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props);
  128. };
  129. struct EaxChorusCommitter : public EaxCommitter<EaxChorusCommitter> {
  130. template<typename ...Args>
  131. explicit EaxChorusCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  132. bool commit(const EAXCHORUSPROPERTIES &props);
  133. static void SetDefaults(EaxEffectProps &props);
  134. static void Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props);
  135. static void Set(const EaxCall &call, EAXCHORUSPROPERTIES &props);
  136. };
  137. struct EaxCompressorCommitter : public EaxCommitter<EaxCompressorCommitter> {
  138. template<typename ...Args>
  139. explicit EaxCompressorCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  140. bool commit(const EAXAGCCOMPRESSORPROPERTIES &props);
  141. static void SetDefaults(EaxEffectProps &props);
  142. static void Get(const EaxCall &call, const EAXAGCCOMPRESSORPROPERTIES &props);
  143. static void Set(const EaxCall &call, EAXAGCCOMPRESSORPROPERTIES &props);
  144. };
  145. struct EaxDistortionCommitter : public EaxCommitter<EaxDistortionCommitter> {
  146. template<typename ...Args>
  147. explicit EaxDistortionCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  148. bool commit(const EAXDISTORTIONPROPERTIES &props);
  149. static void SetDefaults(EaxEffectProps &props);
  150. static void Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props);
  151. static void Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props);
  152. };
  153. struct EaxEchoCommitter : public EaxCommitter<EaxEchoCommitter> {
  154. template<typename ...Args>
  155. explicit EaxEchoCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  156. bool commit(const EAXECHOPROPERTIES &props);
  157. static void SetDefaults(EaxEffectProps &props);
  158. static void Get(const EaxCall &call, const EAXECHOPROPERTIES &props);
  159. static void Set(const EaxCall &call, EAXECHOPROPERTIES &props);
  160. };
  161. struct EaxEqualizerCommitter : public EaxCommitter<EaxEqualizerCommitter> {
  162. template<typename ...Args>
  163. explicit EaxEqualizerCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  164. bool commit(const EAXEQUALIZERPROPERTIES &props);
  165. static void SetDefaults(EaxEffectProps &props);
  166. static void Get(const EaxCall &call, const EAXEQUALIZERPROPERTIES &props);
  167. static void Set(const EaxCall &call, EAXEQUALIZERPROPERTIES &props);
  168. };
  169. struct EaxFlangerCommitter : public EaxCommitter<EaxFlangerCommitter> {
  170. template<typename ...Args>
  171. explicit EaxFlangerCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  172. bool commit(const EAXFLANGERPROPERTIES &props);
  173. static void SetDefaults(EaxEffectProps &props);
  174. static void Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props);
  175. static void Set(const EaxCall &call, EAXFLANGERPROPERTIES &props);
  176. };
  177. struct EaxFrequencyShifterCommitter : public EaxCommitter<EaxFrequencyShifterCommitter> {
  178. template<typename ...Args>
  179. explicit EaxFrequencyShifterCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  180. bool commit(const EAXFREQUENCYSHIFTERPROPERTIES &props);
  181. static void SetDefaults(EaxEffectProps &props);
  182. static void Get(const EaxCall &call, const EAXFREQUENCYSHIFTERPROPERTIES &props);
  183. static void Set(const EaxCall &call, EAXFREQUENCYSHIFTERPROPERTIES &props);
  184. };
  185. struct EaxModulatorCommitter : public EaxCommitter<EaxModulatorCommitter> {
  186. template<typename ...Args>
  187. explicit EaxModulatorCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  188. bool commit(const EAXRINGMODULATORPROPERTIES &props);
  189. static void SetDefaults(EaxEffectProps &props);
  190. static void Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props);
  191. static void Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props);
  192. };
  193. struct EaxPitchShifterCommitter : public EaxCommitter<EaxPitchShifterCommitter> {
  194. template<typename ...Args>
  195. explicit EaxPitchShifterCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  196. bool commit(const EAXPITCHSHIFTERPROPERTIES &props);
  197. static void SetDefaults(EaxEffectProps &props);
  198. static void Get(const EaxCall &call, const EAXPITCHSHIFTERPROPERTIES &props);
  199. static void Set(const EaxCall &call, EAXPITCHSHIFTERPROPERTIES &props);
  200. };
  201. struct EaxVocalMorpherCommitter : public EaxCommitter<EaxVocalMorpherCommitter> {
  202. template<typename ...Args>
  203. explicit EaxVocalMorpherCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  204. bool commit(const EAXVOCALMORPHERPROPERTIES &props);
  205. static void SetDefaults(EaxEffectProps &props);
  206. static void Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props);
  207. static void Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props);
  208. };
  209. struct EaxNullCommitter : public EaxCommitter<EaxNullCommitter> {
  210. template<typename ...Args>
  211. explicit EaxNullCommitter(Args&& ...args) : EaxCommitter{std::forward<Args>(args)...} { }
  212. bool commit(const std::monostate &props);
  213. static void SetDefaults(EaxEffectProps &props);
  214. static void Get(const EaxCall &call, const std::monostate &props);
  215. static void Set(const EaxCall &call, std::monostate &props);
  216. };
  217. template<typename T>
  218. struct CommitterFromProps { };
  219. template<> struct CommitterFromProps<std::monostate> { using type = EaxNullCommitter; };
  220. template<> struct CommitterFromProps<EAXREVERBPROPERTIES> { using type = EaxReverbCommitter; };
  221. template<> struct CommitterFromProps<EAXCHORUSPROPERTIES> { using type = EaxChorusCommitter; };
  222. template<> struct CommitterFromProps<EAXAGCCOMPRESSORPROPERTIES> { using type = EaxCompressorCommitter; };
  223. template<> struct CommitterFromProps<EAXAUTOWAHPROPERTIES> { using type = EaxAutowahCommitter; };
  224. template<> struct CommitterFromProps<EAXDISTORTIONPROPERTIES> { using type = EaxDistortionCommitter; };
  225. template<> struct CommitterFromProps<EAXECHOPROPERTIES> { using type = EaxEchoCommitter; };
  226. template<> struct CommitterFromProps<EAXEQUALIZERPROPERTIES> { using type = EaxEqualizerCommitter; };
  227. template<> struct CommitterFromProps<EAXFLANGERPROPERTIES> { using type = EaxFlangerCommitter; };
  228. template<> struct CommitterFromProps<EAXFREQUENCYSHIFTERPROPERTIES> { using type = EaxFrequencyShifterCommitter; };
  229. template<> struct CommitterFromProps<EAXRINGMODULATORPROPERTIES> { using type = EaxModulatorCommitter; };
  230. template<> struct CommitterFromProps<EAXPITCHSHIFTERPROPERTIES> { using type = EaxPitchShifterCommitter; };
  231. template<> struct CommitterFromProps<EAXVOCALMORPHERPROPERTIES> { using type = EaxVocalMorpherCommitter; };
  232. template<typename T>
  233. using CommitterFor = typename CommitterFromProps<std::remove_cv_t<std::remove_reference_t<T>>>::type;
  234. class EaxEffect {
  235. public:
  236. EaxEffect() noexcept = default;
  237. ~EaxEffect() = default;
  238. ALenum al_effect_type_{AL_EFFECT_NULL};
  239. EffectProps al_effect_props_;
  240. using Props1 = EAX_REVERBPROPERTIES;
  241. using Props2 = EAX20LISTENERPROPERTIES;
  242. using Props3 = EAXREVERBPROPERTIES;
  243. using Props4 = EaxEffectProps;
  244. struct State1 {
  245. Props1 i; // Immediate.
  246. Props1 d; // Deferred.
  247. };
  248. struct State2 {
  249. Props2 i; // Immediate.
  250. Props2 d; // Deferred.
  251. };
  252. struct State3 {
  253. Props3 i; // Immediate.
  254. Props3 d; // Deferred.
  255. };
  256. struct State4 {
  257. Props4 i; // Immediate.
  258. Props4 d; // Deferred.
  259. };
  260. int version_{};
  261. bool changed_{};
  262. Props4 props_;
  263. State1 state1_{};
  264. State2 state2_{};
  265. State3 state3_{};
  266. State4 state4_{};
  267. State4 state5_{};
  268. static void call_set_defaults(const ALenum altype, EaxEffectProps &props)
  269. {
  270. switch(altype)
  271. {
  272. case AL_EFFECT_EAXREVERB: return EaxReverbCommitter::SetDefaults(props);
  273. case AL_EFFECT_CHORUS: return EaxChorusCommitter::SetDefaults(props);
  274. case AL_EFFECT_AUTOWAH: return EaxAutowahCommitter::SetDefaults(props);
  275. case AL_EFFECT_COMPRESSOR: return EaxCompressorCommitter::SetDefaults(props);
  276. case AL_EFFECT_DISTORTION: return EaxDistortionCommitter::SetDefaults(props);
  277. case AL_EFFECT_ECHO: return EaxEchoCommitter::SetDefaults(props);
  278. case AL_EFFECT_EQUALIZER: return EaxEqualizerCommitter::SetDefaults(props);
  279. case AL_EFFECT_FLANGER: return EaxFlangerCommitter::SetDefaults(props);
  280. case AL_EFFECT_FREQUENCY_SHIFTER: return EaxFrequencyShifterCommitter::SetDefaults(props);
  281. case AL_EFFECT_RING_MODULATOR: return EaxModulatorCommitter::SetDefaults(props);
  282. case AL_EFFECT_PITCH_SHIFTER: return EaxPitchShifterCommitter::SetDefaults(props);
  283. case AL_EFFECT_VOCAL_MORPHER: return EaxVocalMorpherCommitter::SetDefaults(props);
  284. case AL_EFFECT_NULL: break;
  285. }
  286. return EaxNullCommitter::SetDefaults(props);
  287. }
  288. template<typename T>
  289. void init()
  290. {
  291. EaxReverbCommitter::SetDefaults(state1_.d);
  292. state1_.i = state1_.d;
  293. EaxReverbCommitter::SetDefaults(state2_.d);
  294. state2_.i = state2_.d;
  295. EaxReverbCommitter::SetDefaults(state3_.d);
  296. state3_.i = state3_.d;
  297. T::SetDefaults(state4_.d);
  298. state4_.i = state4_.d;
  299. T::SetDefaults(state5_.d);
  300. state5_.i = state5_.d;
  301. }
  302. void set_defaults(int eax_version, ALenum altype)
  303. {
  304. switch(eax_version)
  305. {
  306. case 1: EaxReverbCommitter::SetDefaults(state1_.d); break;
  307. case 2: EaxReverbCommitter::SetDefaults(state2_.d); break;
  308. case 3: EaxReverbCommitter::SetDefaults(state3_.d); break;
  309. case 4: call_set_defaults(altype, state4_.d); break;
  310. case 5: call_set_defaults(altype, state5_.d); break;
  311. }
  312. changed_ = true;
  313. }
  314. static void call_set(const EaxCall &call, EaxEffectProps &props)
  315. {
  316. return std::visit([&](auto &arg)
  317. { return CommitterFor<decltype(arg)>::Set(call, arg); },
  318. props);
  319. }
  320. void set(const EaxCall &call)
  321. {
  322. switch(call.get_version())
  323. {
  324. case 1: EaxReverbCommitter::Set(call, state1_.d); break;
  325. case 2: EaxReverbCommitter::Set(call, state2_.d); break;
  326. case 3: EaxReverbCommitter::Set(call, state3_.d); break;
  327. case 4: call_set(call, state4_.d); break;
  328. case 5: call_set(call, state5_.d); break;
  329. }
  330. changed_ = true;
  331. }
  332. static void call_get(const EaxCall &call, const EaxEffectProps &props)
  333. {
  334. return std::visit([&](auto &arg)
  335. { return CommitterFor<decltype(arg)>::Get(call, arg); },
  336. props);
  337. }
  338. void get(const EaxCall &call) const
  339. {
  340. switch(call.get_version())
  341. {
  342. case 1: EaxReverbCommitter::Get(call, state1_.d); break;
  343. case 2: EaxReverbCommitter::Get(call, state2_.d); break;
  344. case 3: EaxReverbCommitter::Get(call, state3_.d); break;
  345. case 4: call_get(call, state4_.d); break;
  346. case 5: call_get(call, state5_.d); break;
  347. }
  348. }
  349. bool call_commit(const EaxEffectProps &props)
  350. {
  351. return std::visit([&](auto &arg)
  352. { return CommitterFor<decltype(arg)>{props_, al_effect_props_}.commit(arg); },
  353. props);
  354. }
  355. bool commit(int eax_version)
  356. {
  357. changed_ |= version_ != eax_version;
  358. if(!changed_) return false;
  359. bool ret{version_ != eax_version};
  360. version_ = eax_version;
  361. changed_ = false;
  362. switch(eax_version)
  363. {
  364. case 1:
  365. state1_.i = state1_.d;
  366. ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state1_.d);
  367. break;
  368. case 2:
  369. state2_.i = state2_.d;
  370. ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state2_.d);
  371. break;
  372. case 3:
  373. state3_.i = state3_.d;
  374. ret |= EaxReverbCommitter{props_, al_effect_props_}.commit(state3_.d);
  375. break;
  376. case 4:
  377. state4_.i = state4_.d;
  378. ret |= call_commit(state4_.d);
  379. break;
  380. case 5:
  381. state5_.i = state5_.d;
  382. ret |= call_commit(state5_.d);
  383. break;
  384. }
  385. al_effect_type_ = EnumFromEaxEffectType(props_);
  386. return ret;
  387. }
  388. #undef EAXCALL
  389. }; // EaxEffect
  390. using EaxEffectUPtr = std::unique_ptr<EaxEffect>;
  391. #endif // !EAX_EFFECT_INCLUDED