🛠️🐜 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.

1357 lines
33 KiB

  1. #include "config.h"
  2. #include <stdexcept>
  3. #include "AL/al.h"
  4. #include "AL/efx.h"
  5. #include "alc/effects/base.h"
  6. #include "aloptional.h"
  7. #include "core/logging.h"
  8. #include "effects.h"
  9. #ifdef ALSOFT_EAX
  10. #include <cassert>
  11. #include "alnumeric.h"
  12. #include "al/eax_exception.h"
  13. #include "al/eax_utils.h"
  14. #endif // ALSOFT_EAX
  15. namespace {
  16. static_assert(ChorusMaxDelay >= AL_CHORUS_MAX_DELAY, "Chorus max delay too small");
  17. static_assert(FlangerMaxDelay >= AL_FLANGER_MAX_DELAY, "Flanger max delay too small");
  18. static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
  19. static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
  20. inline al::optional<ChorusWaveform> WaveformFromEnum(ALenum type)
  21. {
  22. switch(type)
  23. {
  24. case AL_CHORUS_WAVEFORM_SINUSOID: return al::make_optional(ChorusWaveform::Sinusoid);
  25. case AL_CHORUS_WAVEFORM_TRIANGLE: return al::make_optional(ChorusWaveform::Triangle);
  26. }
  27. return al::nullopt;
  28. }
  29. inline ALenum EnumFromWaveform(ChorusWaveform type)
  30. {
  31. switch(type)
  32. {
  33. case ChorusWaveform::Sinusoid: return AL_CHORUS_WAVEFORM_SINUSOID;
  34. case ChorusWaveform::Triangle: return AL_CHORUS_WAVEFORM_TRIANGLE;
  35. }
  36. throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
  37. }
  38. void Chorus_setParami(EffectProps *props, ALenum param, int val)
  39. {
  40. switch(param)
  41. {
  42. case AL_CHORUS_WAVEFORM:
  43. if(auto formopt = WaveformFromEnum(val))
  44. props->Chorus.Waveform = *formopt;
  45. else
  46. throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
  47. break;
  48. case AL_CHORUS_PHASE:
  49. if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
  50. throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range: %d", val};
  51. props->Chorus.Phase = val;
  52. break;
  53. default:
  54. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
  55. }
  56. }
  57. void Chorus_setParamiv(EffectProps *props, ALenum param, const int *vals)
  58. { Chorus_setParami(props, param, vals[0]); }
  59. void Chorus_setParamf(EffectProps *props, ALenum param, float val)
  60. {
  61. switch(param)
  62. {
  63. case AL_CHORUS_RATE:
  64. if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
  65. throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range: %f", val};
  66. props->Chorus.Rate = val;
  67. break;
  68. case AL_CHORUS_DEPTH:
  69. if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
  70. throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range: %f", val};
  71. props->Chorus.Depth = val;
  72. break;
  73. case AL_CHORUS_FEEDBACK:
  74. if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
  75. throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range: %f", val};
  76. props->Chorus.Feedback = val;
  77. break;
  78. case AL_CHORUS_DELAY:
  79. if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
  80. throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range: %f", val};
  81. props->Chorus.Delay = val;
  82. break;
  83. default:
  84. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
  85. }
  86. }
  87. void Chorus_setParamfv(EffectProps *props, ALenum param, const float *vals)
  88. { Chorus_setParamf(props, param, vals[0]); }
  89. void Chorus_getParami(const EffectProps *props, ALenum param, int *val)
  90. {
  91. switch(param)
  92. {
  93. case AL_CHORUS_WAVEFORM:
  94. *val = EnumFromWaveform(props->Chorus.Waveform);
  95. break;
  96. case AL_CHORUS_PHASE:
  97. *val = props->Chorus.Phase;
  98. break;
  99. default:
  100. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
  101. }
  102. }
  103. void Chorus_getParamiv(const EffectProps *props, ALenum param, int *vals)
  104. { Chorus_getParami(props, param, vals); }
  105. void Chorus_getParamf(const EffectProps *props, ALenum param, float *val)
  106. {
  107. switch(param)
  108. {
  109. case AL_CHORUS_RATE:
  110. *val = props->Chorus.Rate;
  111. break;
  112. case AL_CHORUS_DEPTH:
  113. *val = props->Chorus.Depth;
  114. break;
  115. case AL_CHORUS_FEEDBACK:
  116. *val = props->Chorus.Feedback;
  117. break;
  118. case AL_CHORUS_DELAY:
  119. *val = props->Chorus.Delay;
  120. break;
  121. default:
  122. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
  123. }
  124. }
  125. void Chorus_getParamfv(const EffectProps *props, ALenum param, float *vals)
  126. { Chorus_getParamf(props, param, vals); }
  127. const EffectProps genDefaultChorusProps() noexcept
  128. {
  129. EffectProps props{};
  130. props.Chorus.Waveform = *WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM);
  131. props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
  132. props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
  133. props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
  134. props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
  135. props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
  136. return props;
  137. }
  138. void Flanger_setParami(EffectProps *props, ALenum param, int val)
  139. {
  140. switch(param)
  141. {
  142. case AL_FLANGER_WAVEFORM:
  143. if(auto formopt = WaveformFromEnum(val))
  144. props->Chorus.Waveform = *formopt;
  145. else
  146. throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform: 0x%04x", val};
  147. break;
  148. case AL_FLANGER_PHASE:
  149. if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
  150. throw effect_exception{AL_INVALID_VALUE, "Flanger phase out of range: %d", val};
  151. props->Chorus.Phase = val;
  152. break;
  153. default:
  154. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
  155. }
  156. }
  157. void Flanger_setParamiv(EffectProps *props, ALenum param, const int *vals)
  158. { Flanger_setParami(props, param, vals[0]); }
  159. void Flanger_setParamf(EffectProps *props, ALenum param, float val)
  160. {
  161. switch(param)
  162. {
  163. case AL_FLANGER_RATE:
  164. if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
  165. throw effect_exception{AL_INVALID_VALUE, "Flanger rate out of range: %f", val};
  166. props->Chorus.Rate = val;
  167. break;
  168. case AL_FLANGER_DEPTH:
  169. if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
  170. throw effect_exception{AL_INVALID_VALUE, "Flanger depth out of range: %f", val};
  171. props->Chorus.Depth = val;
  172. break;
  173. case AL_FLANGER_FEEDBACK:
  174. if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
  175. throw effect_exception{AL_INVALID_VALUE, "Flanger feedback out of range: %f", val};
  176. props->Chorus.Feedback = val;
  177. break;
  178. case AL_FLANGER_DELAY:
  179. if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
  180. throw effect_exception{AL_INVALID_VALUE, "Flanger delay out of range: %f", val};
  181. props->Chorus.Delay = val;
  182. break;
  183. default:
  184. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
  185. }
  186. }
  187. void Flanger_setParamfv(EffectProps *props, ALenum param, const float *vals)
  188. { Flanger_setParamf(props, param, vals[0]); }
  189. void Flanger_getParami(const EffectProps *props, ALenum param, int *val)
  190. {
  191. switch(param)
  192. {
  193. case AL_FLANGER_WAVEFORM:
  194. *val = EnumFromWaveform(props->Chorus.Waveform);
  195. break;
  196. case AL_FLANGER_PHASE:
  197. *val = props->Chorus.Phase;
  198. break;
  199. default:
  200. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
  201. }
  202. }
  203. void Flanger_getParamiv(const EffectProps *props, ALenum param, int *vals)
  204. { Flanger_getParami(props, param, vals); }
  205. void Flanger_getParamf(const EffectProps *props, ALenum param, float *val)
  206. {
  207. switch(param)
  208. {
  209. case AL_FLANGER_RATE:
  210. *val = props->Chorus.Rate;
  211. break;
  212. case AL_FLANGER_DEPTH:
  213. *val = props->Chorus.Depth;
  214. break;
  215. case AL_FLANGER_FEEDBACK:
  216. *val = props->Chorus.Feedback;
  217. break;
  218. case AL_FLANGER_DELAY:
  219. *val = props->Chorus.Delay;
  220. break;
  221. default:
  222. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
  223. }
  224. }
  225. void Flanger_getParamfv(const EffectProps *props, ALenum param, float *vals)
  226. { Flanger_getParamf(props, param, vals); }
  227. EffectProps genDefaultFlangerProps() noexcept
  228. {
  229. EffectProps props{};
  230. props.Chorus.Waveform = *WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM);
  231. props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE;
  232. props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE;
  233. props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH;
  234. props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
  235. props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY;
  236. return props;
  237. }
  238. } // namespace
  239. DEFINE_ALEFFECT_VTABLE(Chorus);
  240. const EffectProps ChorusEffectProps{genDefaultChorusProps()};
  241. DEFINE_ALEFFECT_VTABLE(Flanger);
  242. const EffectProps FlangerEffectProps{genDefaultFlangerProps()};
  243. #ifdef ALSOFT_EAX
  244. namespace {
  245. void eax_set_efx_waveform(
  246. ALenum waveform,
  247. EffectProps& al_effect_props)
  248. {
  249. const auto efx_waveform = WaveformFromEnum(waveform);
  250. assert(efx_waveform.has_value());
  251. al_effect_props.Chorus.Waveform = *efx_waveform;
  252. }
  253. void eax_set_efx_phase(
  254. ALint phase,
  255. EffectProps& al_effect_props)
  256. {
  257. al_effect_props.Chorus.Phase = phase;
  258. }
  259. void eax_set_efx_rate(
  260. ALfloat rate,
  261. EffectProps& al_effect_props)
  262. {
  263. al_effect_props.Chorus.Rate = rate;
  264. }
  265. void eax_set_efx_depth(
  266. ALfloat depth,
  267. EffectProps& al_effect_props)
  268. {
  269. al_effect_props.Chorus.Depth = depth;
  270. }
  271. void eax_set_efx_feedback(
  272. ALfloat feedback,
  273. EffectProps& al_effect_props)
  274. {
  275. al_effect_props.Chorus.Feedback = feedback;
  276. }
  277. void eax_set_efx_delay(
  278. ALfloat delay,
  279. EffectProps& al_effect_props)
  280. {
  281. al_effect_props.Chorus.Delay = delay;
  282. }
  283. using EaxChorusEffectDirtyFlagsValue = std::uint_least8_t;
  284. struct EaxChorusEffectDirtyFlags
  285. {
  286. using EaxIsBitFieldStruct = bool;
  287. EaxChorusEffectDirtyFlagsValue ulWaveform : 1;
  288. EaxChorusEffectDirtyFlagsValue lPhase : 1;
  289. EaxChorusEffectDirtyFlagsValue flRate : 1;
  290. EaxChorusEffectDirtyFlagsValue flDepth : 1;
  291. EaxChorusEffectDirtyFlagsValue flFeedback : 1;
  292. EaxChorusEffectDirtyFlagsValue flDelay : 1;
  293. }; // EaxChorusEffectDirtyFlags
  294. class EaxChorusEffect final :
  295. public EaxEffect
  296. {
  297. public:
  298. EaxChorusEffect();
  299. void dispatch(const EaxEaxCall& eax_call) override;
  300. // [[nodiscard]]
  301. bool apply_deferred() override;
  302. private:
  303. EAXCHORUSPROPERTIES eax_{};
  304. EAXCHORUSPROPERTIES eax_d_{};
  305. EaxChorusEffectDirtyFlags eax_dirty_flags_{};
  306. void set_eax_defaults() noexcept;
  307. void set_efx_waveform();
  308. void set_efx_phase();
  309. void set_efx_rate();
  310. void set_efx_depth();
  311. void set_efx_feedback();
  312. void set_efx_delay();
  313. void set_efx_defaults();
  314. void get(const EaxEaxCall& eax_call);
  315. void validate_waveform(unsigned long ulWaveform);
  316. void validate_phase(long lPhase);
  317. void validate_rate(float flRate);
  318. void validate_depth(float flDepth);
  319. void validate_feedback(float flFeedback);
  320. void validate_delay(float flDelay);
  321. void validate_all(const EAXCHORUSPROPERTIES& eax_all);
  322. void defer_waveform(unsigned long ulWaveform);
  323. void defer_phase(long lPhase);
  324. void defer_rate(float flRate);
  325. void defer_depth(float flDepth);
  326. void defer_feedback(float flFeedback);
  327. void defer_delay(float flDelay);
  328. void defer_all(const EAXCHORUSPROPERTIES& eax_all);
  329. void defer_waveform(const EaxEaxCall& eax_call);
  330. void defer_phase(const EaxEaxCall& eax_call);
  331. void defer_rate(const EaxEaxCall& eax_call);
  332. void defer_depth(const EaxEaxCall& eax_call);
  333. void defer_feedback(const EaxEaxCall& eax_call);
  334. void defer_delay(const EaxEaxCall& eax_call);
  335. void defer_all(const EaxEaxCall& eax_call);
  336. void set(const EaxEaxCall& eax_call);
  337. }; // EaxChorusEffect
  338. class EaxChorusEffectException :
  339. public EaxException
  340. {
  341. public:
  342. explicit EaxChorusEffectException(
  343. const char* message)
  344. :
  345. EaxException{"EAX_CHORUS_EFFECT", message}
  346. {
  347. }
  348. }; // EaxChorusEffectException
  349. EaxChorusEffect::EaxChorusEffect()
  350. : EaxEffect{AL_EFFECT_CHORUS}
  351. {
  352. set_eax_defaults();
  353. set_efx_defaults();
  354. }
  355. void EaxChorusEffect::dispatch(const EaxEaxCall& eax_call)
  356. {
  357. eax_call.is_get() ? get(eax_call) : set(eax_call);
  358. }
  359. void EaxChorusEffect::set_eax_defaults() noexcept
  360. {
  361. eax_.ulWaveform = EAXCHORUS_DEFAULTWAVEFORM;
  362. eax_.lPhase = EAXCHORUS_DEFAULTPHASE;
  363. eax_.flRate = EAXCHORUS_DEFAULTRATE;
  364. eax_.flDepth = EAXCHORUS_DEFAULTDEPTH;
  365. eax_.flFeedback = EAXCHORUS_DEFAULTFEEDBACK;
  366. eax_.flDelay = EAXCHORUS_DEFAULTDELAY;
  367. eax_d_ = eax_;
  368. }
  369. void EaxChorusEffect::set_efx_waveform()
  370. {
  371. const auto waveform = clamp(
  372. static_cast<ALint>(eax_.ulWaveform),
  373. AL_CHORUS_MIN_WAVEFORM,
  374. AL_CHORUS_MAX_WAVEFORM);
  375. eax_set_efx_waveform(waveform, al_effect_props_);
  376. }
  377. void EaxChorusEffect::set_efx_phase()
  378. {
  379. const auto phase = clamp(
  380. static_cast<ALint>(eax_.lPhase),
  381. AL_CHORUS_MIN_PHASE,
  382. AL_CHORUS_MAX_PHASE);
  383. eax_set_efx_phase(phase, al_effect_props_);
  384. }
  385. void EaxChorusEffect::set_efx_rate()
  386. {
  387. const auto rate = clamp(
  388. eax_.flRate,
  389. AL_CHORUS_MIN_RATE,
  390. AL_CHORUS_MAX_RATE);
  391. eax_set_efx_rate(rate, al_effect_props_);
  392. }
  393. void EaxChorusEffect::set_efx_depth()
  394. {
  395. const auto depth = clamp(
  396. eax_.flDepth,
  397. AL_CHORUS_MIN_DEPTH,
  398. AL_CHORUS_MAX_DEPTH);
  399. eax_set_efx_depth(depth, al_effect_props_);
  400. }
  401. void EaxChorusEffect::set_efx_feedback()
  402. {
  403. const auto feedback = clamp(
  404. eax_.flFeedback,
  405. AL_CHORUS_MIN_FEEDBACK,
  406. AL_CHORUS_MAX_FEEDBACK);
  407. eax_set_efx_feedback(feedback, al_effect_props_);
  408. }
  409. void EaxChorusEffect::set_efx_delay()
  410. {
  411. const auto delay = clamp(
  412. eax_.flDelay,
  413. AL_CHORUS_MIN_DELAY,
  414. AL_CHORUS_MAX_DELAY);
  415. eax_set_efx_delay(delay, al_effect_props_);
  416. }
  417. void EaxChorusEffect::set_efx_defaults()
  418. {
  419. set_efx_waveform();
  420. set_efx_phase();
  421. set_efx_rate();
  422. set_efx_depth();
  423. set_efx_feedback();
  424. set_efx_delay();
  425. }
  426. void EaxChorusEffect::get(const EaxEaxCall& eax_call)
  427. {
  428. switch(eax_call.get_property_id())
  429. {
  430. case EAXCHORUS_NONE:
  431. break;
  432. case EAXCHORUS_ALLPARAMETERS:
  433. eax_call.set_value<EaxChorusEffectException>(eax_);
  434. break;
  435. case EAXCHORUS_WAVEFORM:
  436. eax_call.set_value<EaxChorusEffectException>(eax_.ulWaveform);
  437. break;
  438. case EAXCHORUS_PHASE:
  439. eax_call.set_value<EaxChorusEffectException>(eax_.lPhase);
  440. break;
  441. case EAXCHORUS_RATE:
  442. eax_call.set_value<EaxChorusEffectException>(eax_.flRate);
  443. break;
  444. case EAXCHORUS_DEPTH:
  445. eax_call.set_value<EaxChorusEffectException>(eax_.flDepth);
  446. break;
  447. case EAXCHORUS_FEEDBACK:
  448. eax_call.set_value<EaxChorusEffectException>(eax_.flFeedback);
  449. break;
  450. case EAXCHORUS_DELAY:
  451. eax_call.set_value<EaxChorusEffectException>(eax_.flDelay);
  452. break;
  453. default:
  454. throw EaxChorusEffectException{"Unsupported property id."};
  455. }
  456. }
  457. void EaxChorusEffect::validate_waveform(
  458. unsigned long ulWaveform)
  459. {
  460. eax_validate_range<EaxChorusEffectException>(
  461. "Waveform",
  462. ulWaveform,
  463. EAXCHORUS_MINWAVEFORM,
  464. EAXCHORUS_MAXWAVEFORM);
  465. }
  466. void EaxChorusEffect::validate_phase(
  467. long lPhase)
  468. {
  469. eax_validate_range<EaxChorusEffectException>(
  470. "Phase",
  471. lPhase,
  472. EAXCHORUS_MINPHASE,
  473. EAXCHORUS_MAXPHASE);
  474. }
  475. void EaxChorusEffect::validate_rate(
  476. float flRate)
  477. {
  478. eax_validate_range<EaxChorusEffectException>(
  479. "Rate",
  480. flRate,
  481. EAXCHORUS_MINRATE,
  482. EAXCHORUS_MAXRATE);
  483. }
  484. void EaxChorusEffect::validate_depth(
  485. float flDepth)
  486. {
  487. eax_validate_range<EaxChorusEffectException>(
  488. "Depth",
  489. flDepth,
  490. EAXCHORUS_MINDEPTH,
  491. EAXCHORUS_MAXDEPTH);
  492. }
  493. void EaxChorusEffect::validate_feedback(
  494. float flFeedback)
  495. {
  496. eax_validate_range<EaxChorusEffectException>(
  497. "Feedback",
  498. flFeedback,
  499. EAXCHORUS_MINFEEDBACK,
  500. EAXCHORUS_MAXFEEDBACK);
  501. }
  502. void EaxChorusEffect::validate_delay(
  503. float flDelay)
  504. {
  505. eax_validate_range<EaxChorusEffectException>(
  506. "Delay",
  507. flDelay,
  508. EAXCHORUS_MINDELAY,
  509. EAXCHORUS_MAXDELAY);
  510. }
  511. void EaxChorusEffect::validate_all(
  512. const EAXCHORUSPROPERTIES& eax_all)
  513. {
  514. validate_waveform(eax_all.ulWaveform);
  515. validate_phase(eax_all.lPhase);
  516. validate_rate(eax_all.flRate);
  517. validate_depth(eax_all.flDepth);
  518. validate_feedback(eax_all.flFeedback);
  519. validate_delay(eax_all.flDelay);
  520. }
  521. void EaxChorusEffect::defer_waveform(
  522. unsigned long ulWaveform)
  523. {
  524. eax_d_.ulWaveform = ulWaveform;
  525. eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform);
  526. }
  527. void EaxChorusEffect::defer_phase(
  528. long lPhase)
  529. {
  530. eax_d_.lPhase = lPhase;
  531. eax_dirty_flags_.lPhase = (eax_.lPhase != eax_d_.lPhase);
  532. }
  533. void EaxChorusEffect::defer_rate(
  534. float flRate)
  535. {
  536. eax_d_.flRate = flRate;
  537. eax_dirty_flags_.flRate = (eax_.flRate != eax_d_.flRate);
  538. }
  539. void EaxChorusEffect::defer_depth(
  540. float flDepth)
  541. {
  542. eax_d_.flDepth = flDepth;
  543. eax_dirty_flags_.flDepth = (eax_.flDepth != eax_d_.flDepth);
  544. }
  545. void EaxChorusEffect::defer_feedback(
  546. float flFeedback)
  547. {
  548. eax_d_.flFeedback = flFeedback;
  549. eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback);
  550. }
  551. void EaxChorusEffect::defer_delay(
  552. float flDelay)
  553. {
  554. eax_d_.flDelay = flDelay;
  555. eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay);
  556. }
  557. void EaxChorusEffect::defer_all(
  558. const EAXCHORUSPROPERTIES& eax_all)
  559. {
  560. defer_waveform(eax_all.ulWaveform);
  561. defer_phase(eax_all.lPhase);
  562. defer_rate(eax_all.flRate);
  563. defer_depth(eax_all.flDepth);
  564. defer_feedback(eax_all.flFeedback);
  565. defer_delay(eax_all.flDelay);
  566. }
  567. void EaxChorusEffect::defer_waveform(
  568. const EaxEaxCall& eax_call)
  569. {
  570. const auto& waveform =
  571. eax_call.get_value<EaxChorusEffectException, const decltype(EAXCHORUSPROPERTIES::ulWaveform)>();
  572. validate_waveform(waveform);
  573. defer_waveform(waveform);
  574. }
  575. void EaxChorusEffect::defer_phase(
  576. const EaxEaxCall& eax_call)
  577. {
  578. const auto& phase =
  579. eax_call.get_value<EaxChorusEffectException, const decltype(EAXCHORUSPROPERTIES::lPhase)>();
  580. validate_phase(phase);
  581. defer_phase(phase);
  582. }
  583. void EaxChorusEffect::defer_rate(
  584. const EaxEaxCall& eax_call)
  585. {
  586. const auto& rate =
  587. eax_call.get_value<EaxChorusEffectException, const decltype(EAXCHORUSPROPERTIES::flRate)>();
  588. validate_rate(rate);
  589. defer_rate(rate);
  590. }
  591. void EaxChorusEffect::defer_depth(
  592. const EaxEaxCall& eax_call)
  593. {
  594. const auto& depth =
  595. eax_call.get_value<EaxChorusEffectException, const decltype(EAXCHORUSPROPERTIES::flDepth)>();
  596. validate_depth(depth);
  597. defer_depth(depth);
  598. }
  599. void EaxChorusEffect::defer_feedback(
  600. const EaxEaxCall& eax_call)
  601. {
  602. const auto& feedback =
  603. eax_call.get_value<EaxChorusEffectException, const decltype(EAXCHORUSPROPERTIES::flFeedback)>();
  604. validate_feedback(feedback);
  605. defer_feedback(feedback);
  606. }
  607. void EaxChorusEffect::defer_delay(
  608. const EaxEaxCall& eax_call)
  609. {
  610. const auto& delay =
  611. eax_call.get_value<EaxChorusEffectException, const decltype(EAXCHORUSPROPERTIES::flDelay)>();
  612. validate_delay(delay);
  613. defer_delay(delay);
  614. }
  615. void EaxChorusEffect::defer_all(
  616. const EaxEaxCall& eax_call)
  617. {
  618. const auto& all =
  619. eax_call.get_value<EaxChorusEffectException, const EAXCHORUSPROPERTIES>();
  620. validate_all(all);
  621. defer_all(all);
  622. }
  623. // [[nodiscard]]
  624. bool EaxChorusEffect::apply_deferred()
  625. {
  626. if (eax_dirty_flags_ == EaxChorusEffectDirtyFlags{})
  627. {
  628. return false;
  629. }
  630. eax_ = eax_d_;
  631. if (eax_dirty_flags_.ulWaveform)
  632. {
  633. set_efx_waveform();
  634. }
  635. if (eax_dirty_flags_.lPhase)
  636. {
  637. set_efx_phase();
  638. }
  639. if (eax_dirty_flags_.flRate)
  640. {
  641. set_efx_rate();
  642. }
  643. if (eax_dirty_flags_.flDepth)
  644. {
  645. set_efx_depth();
  646. }
  647. if (eax_dirty_flags_.flFeedback)
  648. {
  649. set_efx_feedback();
  650. }
  651. if (eax_dirty_flags_.flDelay)
  652. {
  653. set_efx_delay();
  654. }
  655. eax_dirty_flags_ = EaxChorusEffectDirtyFlags{};
  656. return true;
  657. }
  658. void EaxChorusEffect::set(const EaxEaxCall& eax_call)
  659. {
  660. switch(eax_call.get_property_id())
  661. {
  662. case EAXCHORUS_NONE:
  663. break;
  664. case EAXCHORUS_ALLPARAMETERS:
  665. defer_all(eax_call);
  666. break;
  667. case EAXCHORUS_WAVEFORM:
  668. defer_waveform(eax_call);
  669. break;
  670. case EAXCHORUS_PHASE:
  671. defer_phase(eax_call);
  672. break;
  673. case EAXCHORUS_RATE:
  674. defer_rate(eax_call);
  675. break;
  676. case EAXCHORUS_DEPTH:
  677. defer_depth(eax_call);
  678. break;
  679. case EAXCHORUS_FEEDBACK:
  680. defer_feedback(eax_call);
  681. break;
  682. case EAXCHORUS_DELAY:
  683. defer_delay(eax_call);
  684. break;
  685. default:
  686. throw EaxChorusEffectException{"Unsupported property id."};
  687. }
  688. }
  689. } // namespace
  690. EaxEffectUPtr eax_create_eax_chorus_effect()
  691. {
  692. return std::make_unique<::EaxChorusEffect>();
  693. }
  694. namespace
  695. {
  696. using EaxFlangerEffectDirtyFlagsValue = std::uint_least8_t;
  697. struct EaxFlangerEffectDirtyFlags
  698. {
  699. using EaxIsBitFieldStruct = bool;
  700. EaxFlangerEffectDirtyFlagsValue ulWaveform : 1;
  701. EaxFlangerEffectDirtyFlagsValue lPhase : 1;
  702. EaxFlangerEffectDirtyFlagsValue flRate : 1;
  703. EaxFlangerEffectDirtyFlagsValue flDepth : 1;
  704. EaxFlangerEffectDirtyFlagsValue flFeedback : 1;
  705. EaxFlangerEffectDirtyFlagsValue flDelay : 1;
  706. }; // EaxFlangerEffectDirtyFlags
  707. class EaxFlangerEffect final :
  708. public EaxEffect
  709. {
  710. public:
  711. EaxFlangerEffect();
  712. void dispatch(const EaxEaxCall& eax_call) override;
  713. // [[nodiscard]]
  714. bool apply_deferred() override;
  715. private:
  716. EAXFLANGERPROPERTIES eax_{};
  717. EAXFLANGERPROPERTIES eax_d_{};
  718. EaxFlangerEffectDirtyFlags eax_dirty_flags_{};
  719. void set_eax_defaults();
  720. void set_efx_waveform();
  721. void set_efx_phase();
  722. void set_efx_rate();
  723. void set_efx_depth();
  724. void set_efx_feedback();
  725. void set_efx_delay();
  726. void set_efx_defaults();
  727. void get(const EaxEaxCall& eax_call);
  728. void validate_waveform(unsigned long ulWaveform);
  729. void validate_phase(long lPhase);
  730. void validate_rate(float flRate);
  731. void validate_depth(float flDepth);
  732. void validate_feedback(float flFeedback);
  733. void validate_delay(float flDelay);
  734. void validate_all(const EAXFLANGERPROPERTIES& all);
  735. void defer_waveform(unsigned long ulWaveform);
  736. void defer_phase(long lPhase);
  737. void defer_rate(float flRate);
  738. void defer_depth(float flDepth);
  739. void defer_feedback(float flFeedback);
  740. void defer_delay(float flDelay);
  741. void defer_all(const EAXFLANGERPROPERTIES& all);
  742. void defer_waveform(const EaxEaxCall& eax_call);
  743. void defer_phase(const EaxEaxCall& eax_call);
  744. void defer_rate(const EaxEaxCall& eax_call);
  745. void defer_depth(const EaxEaxCall& eax_call);
  746. void defer_feedback(const EaxEaxCall& eax_call);
  747. void defer_delay(const EaxEaxCall& eax_call);
  748. void defer_all(const EaxEaxCall& eax_call);
  749. void set(const EaxEaxCall& eax_call);
  750. }; // EaxFlangerEffect
  751. class EaxFlangerEffectException :
  752. public EaxException
  753. {
  754. public:
  755. explicit EaxFlangerEffectException(
  756. const char* message)
  757. :
  758. EaxException{"EAX_FLANGER_EFFECT", message}
  759. {
  760. }
  761. }; // EaxFlangerEffectException
  762. EaxFlangerEffect::EaxFlangerEffect()
  763. : EaxEffect{AL_EFFECT_FLANGER}
  764. {
  765. set_eax_defaults();
  766. set_efx_defaults();
  767. }
  768. void EaxFlangerEffect::dispatch(const EaxEaxCall& eax_call)
  769. {
  770. eax_call.is_get() ? get(eax_call) : set(eax_call);
  771. }
  772. void EaxFlangerEffect::set_eax_defaults()
  773. {
  774. eax_.ulWaveform = EAXFLANGER_DEFAULTWAVEFORM;
  775. eax_.lPhase = EAXFLANGER_DEFAULTPHASE;
  776. eax_.flRate = EAXFLANGER_DEFAULTRATE;
  777. eax_.flDepth = EAXFLANGER_DEFAULTDEPTH;
  778. eax_.flFeedback = EAXFLANGER_DEFAULTFEEDBACK;
  779. eax_.flDelay = EAXFLANGER_DEFAULTDELAY;
  780. eax_d_ = eax_;
  781. }
  782. void EaxFlangerEffect::set_efx_waveform()
  783. {
  784. const auto waveform = clamp(
  785. static_cast<ALint>(eax_.ulWaveform),
  786. AL_FLANGER_MIN_WAVEFORM,
  787. AL_FLANGER_MAX_WAVEFORM);
  788. eax_set_efx_waveform(waveform, al_effect_props_);
  789. }
  790. void EaxFlangerEffect::set_efx_phase()
  791. {
  792. const auto phase = clamp(
  793. static_cast<ALint>(eax_.lPhase),
  794. AL_FLANGER_MIN_PHASE,
  795. AL_FLANGER_MAX_PHASE);
  796. eax_set_efx_phase(phase, al_effect_props_);
  797. }
  798. void EaxFlangerEffect::set_efx_rate()
  799. {
  800. const auto rate = clamp(
  801. eax_.flRate,
  802. AL_FLANGER_MIN_RATE,
  803. AL_FLANGER_MAX_RATE);
  804. eax_set_efx_rate(rate, al_effect_props_);
  805. }
  806. void EaxFlangerEffect::set_efx_depth()
  807. {
  808. const auto depth = clamp(
  809. eax_.flDepth,
  810. AL_FLANGER_MIN_DEPTH,
  811. AL_FLANGER_MAX_DEPTH);
  812. eax_set_efx_depth(depth, al_effect_props_);
  813. }
  814. void EaxFlangerEffect::set_efx_feedback()
  815. {
  816. const auto feedback = clamp(
  817. eax_.flFeedback,
  818. AL_FLANGER_MIN_FEEDBACK,
  819. AL_FLANGER_MAX_FEEDBACK);
  820. eax_set_efx_feedback(feedback, al_effect_props_);
  821. }
  822. void EaxFlangerEffect::set_efx_delay()
  823. {
  824. const auto delay = clamp(
  825. eax_.flDelay,
  826. AL_FLANGER_MIN_DELAY,
  827. AL_FLANGER_MAX_DELAY);
  828. eax_set_efx_delay(delay, al_effect_props_);
  829. }
  830. void EaxFlangerEffect::set_efx_defaults()
  831. {
  832. set_efx_waveform();
  833. set_efx_phase();
  834. set_efx_rate();
  835. set_efx_depth();
  836. set_efx_feedback();
  837. set_efx_delay();
  838. }
  839. void EaxFlangerEffect::get(const EaxEaxCall& eax_call)
  840. {
  841. switch(eax_call.get_property_id())
  842. {
  843. case EAXFLANGER_NONE:
  844. break;
  845. case EAXFLANGER_ALLPARAMETERS:
  846. eax_call.set_value<EaxFlangerEffectException>(eax_);
  847. break;
  848. case EAXFLANGER_WAVEFORM:
  849. eax_call.set_value<EaxFlangerEffectException>(eax_.ulWaveform);
  850. break;
  851. case EAXFLANGER_PHASE:
  852. eax_call.set_value<EaxFlangerEffectException>(eax_.lPhase);
  853. break;
  854. case EAXFLANGER_RATE:
  855. eax_call.set_value<EaxFlangerEffectException>(eax_.flRate);
  856. break;
  857. case EAXFLANGER_DEPTH:
  858. eax_call.set_value<EaxFlangerEffectException>(eax_.flDepth);
  859. break;
  860. case EAXFLANGER_FEEDBACK:
  861. eax_call.set_value<EaxFlangerEffectException>(eax_.flFeedback);
  862. break;
  863. case EAXFLANGER_DELAY:
  864. eax_call.set_value<EaxFlangerEffectException>(eax_.flDelay);
  865. break;
  866. default:
  867. throw EaxFlangerEffectException{"Unsupported property id."};
  868. }
  869. }
  870. void EaxFlangerEffect::validate_waveform(
  871. unsigned long ulWaveform)
  872. {
  873. eax_validate_range<EaxFlangerEffectException>(
  874. "Waveform",
  875. ulWaveform,
  876. EAXFLANGER_MINWAVEFORM,
  877. EAXFLANGER_MAXWAVEFORM);
  878. }
  879. void EaxFlangerEffect::validate_phase(
  880. long lPhase)
  881. {
  882. eax_validate_range<EaxFlangerEffectException>(
  883. "Phase",
  884. lPhase,
  885. EAXFLANGER_MINPHASE,
  886. EAXFLANGER_MAXPHASE);
  887. }
  888. void EaxFlangerEffect::validate_rate(
  889. float flRate)
  890. {
  891. eax_validate_range<EaxFlangerEffectException>(
  892. "Rate",
  893. flRate,
  894. EAXFLANGER_MINRATE,
  895. EAXFLANGER_MAXRATE);
  896. }
  897. void EaxFlangerEffect::validate_depth(
  898. float flDepth)
  899. {
  900. eax_validate_range<EaxFlangerEffectException>(
  901. "Depth",
  902. flDepth,
  903. EAXFLANGER_MINDEPTH,
  904. EAXFLANGER_MAXDEPTH);
  905. }
  906. void EaxFlangerEffect::validate_feedback(
  907. float flFeedback)
  908. {
  909. eax_validate_range<EaxFlangerEffectException>(
  910. "Feedback",
  911. flFeedback,
  912. EAXFLANGER_MINFEEDBACK,
  913. EAXFLANGER_MAXFEEDBACK);
  914. }
  915. void EaxFlangerEffect::validate_delay(
  916. float flDelay)
  917. {
  918. eax_validate_range<EaxFlangerEffectException>(
  919. "Delay",
  920. flDelay,
  921. EAXFLANGER_MINDELAY,
  922. EAXFLANGER_MAXDELAY);
  923. }
  924. void EaxFlangerEffect::validate_all(
  925. const EAXFLANGERPROPERTIES& all)
  926. {
  927. validate_waveform(all.ulWaveform);
  928. validate_phase(all.lPhase);
  929. validate_rate(all.flRate);
  930. validate_depth(all.flDepth);
  931. validate_feedback(all.flDelay);
  932. validate_delay(all.flDelay);
  933. }
  934. void EaxFlangerEffect::defer_waveform(
  935. unsigned long ulWaveform)
  936. {
  937. eax_d_.ulWaveform = ulWaveform;
  938. eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform);
  939. }
  940. void EaxFlangerEffect::defer_phase(
  941. long lPhase)
  942. {
  943. eax_d_.lPhase = lPhase;
  944. eax_dirty_flags_.lPhase = (eax_.lPhase != eax_d_.lPhase);
  945. }
  946. void EaxFlangerEffect::defer_rate(
  947. float flRate)
  948. {
  949. eax_d_.flRate = flRate;
  950. eax_dirty_flags_.flRate = (eax_.flRate != eax_d_.flRate);
  951. }
  952. void EaxFlangerEffect::defer_depth(
  953. float flDepth)
  954. {
  955. eax_d_.flDepth = flDepth;
  956. eax_dirty_flags_.flDepth = (eax_.flDepth != eax_d_.flDepth);
  957. }
  958. void EaxFlangerEffect::defer_feedback(
  959. float flFeedback)
  960. {
  961. eax_d_.flFeedback = flFeedback;
  962. eax_dirty_flags_.flFeedback = (eax_.flFeedback != eax_d_.flFeedback);
  963. }
  964. void EaxFlangerEffect::defer_delay(
  965. float flDelay)
  966. {
  967. eax_d_.flDelay = flDelay;
  968. eax_dirty_flags_.flDelay = (eax_.flDelay != eax_d_.flDelay);
  969. }
  970. void EaxFlangerEffect::defer_all(
  971. const EAXFLANGERPROPERTIES& all)
  972. {
  973. defer_waveform(all.ulWaveform);
  974. defer_phase(all.lPhase);
  975. defer_rate(all.flRate);
  976. defer_depth(all.flDepth);
  977. defer_feedback(all.flDelay);
  978. defer_delay(all.flDelay);
  979. }
  980. void EaxFlangerEffect::defer_waveform(
  981. const EaxEaxCall& eax_call)
  982. {
  983. const auto& waveform =
  984. eax_call.get_value<EaxFlangerEffectException, const decltype(EAXFLANGERPROPERTIES::ulWaveform)>();
  985. validate_waveform(waveform);
  986. defer_waveform(waveform);
  987. }
  988. void EaxFlangerEffect::defer_phase(
  989. const EaxEaxCall& eax_call)
  990. {
  991. const auto& phase =
  992. eax_call.get_value<EaxFlangerEffectException, const decltype(EAXFLANGERPROPERTIES::lPhase)>();
  993. validate_phase(phase);
  994. defer_phase(phase);
  995. }
  996. void EaxFlangerEffect::defer_rate(
  997. const EaxEaxCall& eax_call)
  998. {
  999. const auto& rate =
  1000. eax_call.get_value<EaxFlangerEffectException, const decltype(EAXFLANGERPROPERTIES::flRate)>();
  1001. validate_rate(rate);
  1002. defer_rate(rate);
  1003. }
  1004. void EaxFlangerEffect::defer_depth(
  1005. const EaxEaxCall& eax_call)
  1006. {
  1007. const auto& depth =
  1008. eax_call.get_value<EaxFlangerEffectException, const decltype(EAXFLANGERPROPERTIES::flDepth)>();
  1009. validate_depth(depth);
  1010. defer_depth(depth);
  1011. }
  1012. void EaxFlangerEffect::defer_feedback(
  1013. const EaxEaxCall& eax_call)
  1014. {
  1015. const auto& feedback =
  1016. eax_call.get_value<EaxFlangerEffectException, const decltype(EAXFLANGERPROPERTIES::flFeedback)>();
  1017. validate_feedback(feedback);
  1018. defer_feedback(feedback);
  1019. }
  1020. void EaxFlangerEffect::defer_delay(
  1021. const EaxEaxCall& eax_call)
  1022. {
  1023. const auto& delay =
  1024. eax_call.get_value<EaxFlangerEffectException, const decltype(EAXFLANGERPROPERTIES::flDelay)>();
  1025. validate_delay(delay);
  1026. defer_delay(delay);
  1027. }
  1028. void EaxFlangerEffect::defer_all(
  1029. const EaxEaxCall& eax_call)
  1030. {
  1031. const auto& all =
  1032. eax_call.get_value<EaxFlangerEffectException, const EAXFLANGERPROPERTIES>();
  1033. validate_all(all);
  1034. defer_all(all);
  1035. }
  1036. // [[nodiscard]]
  1037. bool EaxFlangerEffect::apply_deferred()
  1038. {
  1039. if (eax_dirty_flags_ == EaxFlangerEffectDirtyFlags{})
  1040. {
  1041. return false;
  1042. }
  1043. eax_ = eax_d_;
  1044. if (eax_dirty_flags_.ulWaveform)
  1045. {
  1046. set_efx_waveform();
  1047. }
  1048. if (eax_dirty_flags_.lPhase)
  1049. {
  1050. set_efx_phase();
  1051. }
  1052. if (eax_dirty_flags_.flRate)
  1053. {
  1054. set_efx_rate();
  1055. }
  1056. if (eax_dirty_flags_.flDepth)
  1057. {
  1058. set_efx_depth();
  1059. }
  1060. if (eax_dirty_flags_.flFeedback)
  1061. {
  1062. set_efx_feedback();
  1063. }
  1064. if (eax_dirty_flags_.flDelay)
  1065. {
  1066. set_efx_delay();
  1067. }
  1068. eax_dirty_flags_ = EaxFlangerEffectDirtyFlags{};
  1069. return true;
  1070. }
  1071. void EaxFlangerEffect::set(const EaxEaxCall& eax_call)
  1072. {
  1073. switch(eax_call.get_property_id())
  1074. {
  1075. case EAXFLANGER_NONE:
  1076. break;
  1077. case EAXFLANGER_ALLPARAMETERS:
  1078. defer_all(eax_call);
  1079. break;
  1080. case EAXFLANGER_WAVEFORM:
  1081. defer_waveform(eax_call);
  1082. break;
  1083. case EAXFLANGER_PHASE:
  1084. defer_phase(eax_call);
  1085. break;
  1086. case EAXFLANGER_RATE:
  1087. defer_rate(eax_call);
  1088. break;
  1089. case EAXFLANGER_DEPTH:
  1090. defer_depth(eax_call);
  1091. break;
  1092. case EAXFLANGER_FEEDBACK:
  1093. defer_feedback(eax_call);
  1094. break;
  1095. case EAXFLANGER_DELAY:
  1096. defer_delay(eax_call);
  1097. break;
  1098. default:
  1099. throw EaxFlangerEffectException{"Unsupported property id."};
  1100. }
  1101. }
  1102. } // namespace
  1103. EaxEffectUPtr eax_create_eax_flanger_effect()
  1104. {
  1105. return std::make_unique<EaxFlangerEffect>();
  1106. }
  1107. #endif // ALSOFT_EAX