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

734 lines
25 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. class EaxChorusEffectException : public EaxException {
  246. public:
  247. explicit EaxChorusEffectException(const char* message)
  248. : EaxException{"EAX_CHORUS_EFFECT", message}
  249. {}
  250. }; // EaxChorusEffectException
  251. class EaxFlangerEffectException : public EaxException {
  252. public:
  253. explicit EaxFlangerEffectException(const char* message)
  254. : EaxException{"EAX_FLANGER_EFFECT", message}
  255. {}
  256. }; // EaxFlangerEffectException
  257. struct EaxChorusTraits
  258. {
  259. using Exception = EaxChorusEffectException;
  260. using Props = EAXCHORUSPROPERTIES;
  261. static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; }
  262. static constexpr auto eax_none_param_id() { return EAXCHORUS_NONE; }
  263. static constexpr auto eax_allparameters_param_id() { return EAXCHORUS_ALLPARAMETERS; }
  264. static constexpr auto eax_waveform_param_id() { return EAXCHORUS_WAVEFORM; }
  265. static constexpr auto eax_phase_param_id() { return EAXCHORUS_PHASE; }
  266. static constexpr auto eax_rate_param_id() { return EAXCHORUS_RATE; }
  267. static constexpr auto eax_depth_param_id() { return EAXCHORUS_DEPTH; }
  268. static constexpr auto eax_feedback_param_id() { return EAXCHORUS_FEEDBACK; }
  269. static constexpr auto eax_delay_param_id() { return EAXCHORUS_DELAY; }
  270. static constexpr auto eax_min_waveform() { return EAXCHORUS_MINWAVEFORM; }
  271. static constexpr auto eax_min_phase() { return EAXCHORUS_MINPHASE; }
  272. static constexpr auto eax_min_rate() { return EAXCHORUS_MINRATE; }
  273. static constexpr auto eax_min_depth() { return EAXCHORUS_MINDEPTH; }
  274. static constexpr auto eax_min_feedback() { return EAXCHORUS_MINFEEDBACK; }
  275. static constexpr auto eax_min_delay() { return EAXCHORUS_MINDELAY; }
  276. static constexpr auto eax_max_waveform() { return EAXCHORUS_MAXWAVEFORM; }
  277. static constexpr auto eax_max_phase() { return EAXCHORUS_MAXPHASE; }
  278. static constexpr auto eax_max_rate() { return EAXCHORUS_MAXRATE; }
  279. static constexpr auto eax_max_depth() { return EAXCHORUS_MAXDEPTH; }
  280. static constexpr auto eax_max_feedback() { return EAXCHORUS_MAXFEEDBACK; }
  281. static constexpr auto eax_max_delay() { return EAXCHORUS_MAXDELAY; }
  282. static constexpr auto eax_default_waveform() { return EAXCHORUS_DEFAULTWAVEFORM; }
  283. static constexpr auto eax_default_phase() { return EAXCHORUS_DEFAULTPHASE; }
  284. static constexpr auto eax_default_rate() { return EAXCHORUS_DEFAULTRATE; }
  285. static constexpr auto eax_default_depth() { return EAXCHORUS_DEFAULTDEPTH; }
  286. static constexpr auto eax_default_feedback() { return EAXCHORUS_DEFAULTFEEDBACK; }
  287. static constexpr auto eax_default_delay() { return EAXCHORUS_DEFAULTDELAY; }
  288. static constexpr auto efx_min_waveform() { return AL_CHORUS_MIN_WAVEFORM; }
  289. static constexpr auto efx_min_phase() { return AL_CHORUS_MIN_PHASE; }
  290. static constexpr auto efx_min_rate() { return AL_CHORUS_MIN_RATE; }
  291. static constexpr auto efx_min_depth() { return AL_CHORUS_MIN_DEPTH; }
  292. static constexpr auto efx_min_feedback() { return AL_CHORUS_MIN_FEEDBACK; }
  293. static constexpr auto efx_min_delay() { return AL_CHORUS_MIN_DELAY; }
  294. static constexpr auto efx_max_waveform() { return AL_CHORUS_MAX_WAVEFORM; }
  295. static constexpr auto efx_max_phase() { return AL_CHORUS_MAX_PHASE; }
  296. static constexpr auto efx_max_rate() { return AL_CHORUS_MAX_RATE; }
  297. static constexpr auto efx_max_depth() { return AL_CHORUS_MAX_DEPTH; }
  298. static constexpr auto efx_max_feedback() { return AL_CHORUS_MAX_FEEDBACK; }
  299. static constexpr auto efx_max_delay() { return AL_CHORUS_MAX_DELAY; }
  300. static constexpr auto efx_default_waveform() { return AL_CHORUS_DEFAULT_WAVEFORM; }
  301. static constexpr auto efx_default_phase() { return AL_CHORUS_DEFAULT_PHASE; }
  302. static constexpr auto efx_default_rate() { return AL_CHORUS_DEFAULT_RATE; }
  303. static constexpr auto efx_default_depth() { return AL_CHORUS_DEFAULT_DEPTH; }
  304. static constexpr auto efx_default_feedback() { return AL_CHORUS_DEFAULT_FEEDBACK; }
  305. static constexpr auto efx_default_delay() { return AL_CHORUS_DEFAULT_DELAY; }
  306. }; // EaxChorusTraits
  307. struct EaxFlangerTraits
  308. {
  309. using Exception = EaxFlangerEffectException;
  310. using Props = EAXFLANGERPROPERTIES;
  311. static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; }
  312. static constexpr auto eax_none_param_id() { return EAXFLANGER_NONE; }
  313. static constexpr auto eax_allparameters_param_id() { return EAXFLANGER_ALLPARAMETERS; }
  314. static constexpr auto eax_waveform_param_id() { return EAXFLANGER_WAVEFORM; }
  315. static constexpr auto eax_phase_param_id() { return EAXFLANGER_PHASE; }
  316. static constexpr auto eax_rate_param_id() { return EAXFLANGER_RATE; }
  317. static constexpr auto eax_depth_param_id() { return EAXFLANGER_DEPTH; }
  318. static constexpr auto eax_feedback_param_id() { return EAXFLANGER_FEEDBACK; }
  319. static constexpr auto eax_delay_param_id() { return EAXFLANGER_DELAY; }
  320. static constexpr auto eax_min_waveform() { return EAXFLANGER_MINWAVEFORM; }
  321. static constexpr auto eax_min_phase() { return EAXFLANGER_MINPHASE; }
  322. static constexpr auto eax_min_rate() { return EAXFLANGER_MINRATE; }
  323. static constexpr auto eax_min_depth() { return EAXFLANGER_MINDEPTH; }
  324. static constexpr auto eax_min_feedback() { return EAXFLANGER_MINFEEDBACK; }
  325. static constexpr auto eax_min_delay() { return EAXFLANGER_MINDELAY; }
  326. static constexpr auto eax_max_waveform() { return EAXFLANGER_MAXWAVEFORM; }
  327. static constexpr auto eax_max_phase() { return EAXFLANGER_MAXPHASE; }
  328. static constexpr auto eax_max_rate() { return EAXFLANGER_MAXRATE; }
  329. static constexpr auto eax_max_depth() { return EAXFLANGER_MAXDEPTH; }
  330. static constexpr auto eax_max_feedback() { return EAXFLANGER_MAXFEEDBACK; }
  331. static constexpr auto eax_max_delay() { return EAXFLANGER_MAXDELAY; }
  332. static constexpr auto eax_default_waveform() { return EAXFLANGER_DEFAULTWAVEFORM; }
  333. static constexpr auto eax_default_phase() { return EAXFLANGER_DEFAULTPHASE; }
  334. static constexpr auto eax_default_rate() { return EAXFLANGER_DEFAULTRATE; }
  335. static constexpr auto eax_default_depth() { return EAXFLANGER_DEFAULTDEPTH; }
  336. static constexpr auto eax_default_feedback() { return EAXFLANGER_DEFAULTFEEDBACK; }
  337. static constexpr auto eax_default_delay() { return EAXFLANGER_DEFAULTDELAY; }
  338. static constexpr auto efx_min_waveform() { return AL_FLANGER_MIN_WAVEFORM; }
  339. static constexpr auto efx_min_phase() { return AL_FLANGER_MIN_PHASE; }
  340. static constexpr auto efx_min_rate() { return AL_FLANGER_MIN_RATE; }
  341. static constexpr auto efx_min_depth() { return AL_FLANGER_MIN_DEPTH; }
  342. static constexpr auto efx_min_feedback() { return AL_FLANGER_MIN_FEEDBACK; }
  343. static constexpr auto efx_min_delay() { return AL_FLANGER_MIN_DELAY; }
  344. static constexpr auto efx_max_waveform() { return AL_FLANGER_MAX_WAVEFORM; }
  345. static constexpr auto efx_max_phase() { return AL_FLANGER_MAX_PHASE; }
  346. static constexpr auto efx_max_rate() { return AL_FLANGER_MAX_RATE; }
  347. static constexpr auto efx_max_depth() { return AL_FLANGER_MAX_DEPTH; }
  348. static constexpr auto efx_max_feedback() { return AL_FLANGER_MAX_FEEDBACK; }
  349. static constexpr auto efx_max_delay() { return AL_FLANGER_MAX_DELAY; }
  350. static constexpr auto efx_default_waveform() { return AL_FLANGER_DEFAULT_WAVEFORM; }
  351. static constexpr auto efx_default_phase() { return AL_FLANGER_DEFAULT_PHASE; }
  352. static constexpr auto efx_default_rate() { return AL_FLANGER_DEFAULT_RATE; }
  353. static constexpr auto efx_default_depth() { return AL_FLANGER_DEFAULT_DEPTH; }
  354. static constexpr auto efx_default_feedback() { return AL_FLANGER_DEFAULT_FEEDBACK; }
  355. static constexpr auto efx_default_delay() { return AL_FLANGER_DEFAULT_DELAY; }
  356. }; // EaxFlangerTraits
  357. template<typename TTraits>
  358. class EaxChorusFlangerEffect final : public EaxEffect4<typename TTraits::Exception, typename TTraits::Props> {
  359. public:
  360. using Traits = TTraits;
  361. using Base = EaxEffect4<typename Traits::Exception, typename Traits::Props>;
  362. using typename Base::Exception;
  363. using typename Base::Props;
  364. using typename Base::State;
  365. using Base::defer;
  366. EaxChorusFlangerEffect(const EaxCall& call)
  367. : Base{Traits::efx_effect(), call}
  368. {}
  369. private:
  370. struct WaveformValidator {
  371. void operator()(unsigned long ulWaveform) const
  372. {
  373. eax_validate_range<Exception>(
  374. "Waveform",
  375. ulWaveform,
  376. Traits::eax_min_waveform(),
  377. Traits::eax_max_waveform());
  378. }
  379. }; // WaveformValidator
  380. struct PhaseValidator {
  381. void operator()(long lPhase) const
  382. {
  383. eax_validate_range<Exception>(
  384. "Phase",
  385. lPhase,
  386. Traits::eax_min_phase(),
  387. Traits::eax_max_phase());
  388. }
  389. }; // PhaseValidator
  390. struct RateValidator {
  391. void operator()(float flRate) const
  392. {
  393. eax_validate_range<Exception>(
  394. "Rate",
  395. flRate,
  396. Traits::eax_min_rate(),
  397. Traits::eax_max_rate());
  398. }
  399. }; // RateValidator
  400. struct DepthValidator {
  401. void operator()(float flDepth) const
  402. {
  403. eax_validate_range<Exception>(
  404. "Depth",
  405. flDepth,
  406. Traits::eax_min_depth(),
  407. Traits::eax_max_depth());
  408. }
  409. }; // DepthValidator
  410. struct FeedbackValidator {
  411. void operator()(float flFeedback) const
  412. {
  413. eax_validate_range<Exception>(
  414. "Feedback",
  415. flFeedback,
  416. Traits::eax_min_feedback(),
  417. Traits::eax_max_feedback());
  418. }
  419. }; // FeedbackValidator
  420. struct DelayValidator {
  421. void operator()(float flDelay) const
  422. {
  423. eax_validate_range<Exception>(
  424. "Delay",
  425. flDelay,
  426. Traits::eax_min_delay(),
  427. Traits::eax_max_delay());
  428. }
  429. }; // DelayValidator
  430. struct AllValidator {
  431. void operator()(const Props& all) const
  432. {
  433. WaveformValidator{}(all.ulWaveform);
  434. PhaseValidator{}(all.lPhase);
  435. RateValidator{}(all.flRate);
  436. DepthValidator{}(all.flDepth);
  437. FeedbackValidator{}(all.flFeedback);
  438. DelayValidator{}(all.flDelay);
  439. }
  440. }; // AllValidator
  441. void set_defaults(Props& props) override
  442. {
  443. props.ulWaveform = Traits::eax_default_waveform();
  444. props.lPhase = Traits::eax_default_phase();
  445. props.flRate = Traits::eax_default_rate();
  446. props.flDepth = Traits::eax_default_depth();
  447. props.flFeedback = Traits::eax_default_feedback();
  448. props.flDelay = Traits::eax_default_delay();
  449. }
  450. void set_efx_waveform()
  451. {
  452. const auto waveform = clamp(
  453. static_cast<ALint>(Base::props_.ulWaveform),
  454. Traits::efx_min_waveform(),
  455. Traits::efx_max_waveform());
  456. const auto efx_waveform = WaveformFromEnum(waveform);
  457. assert(efx_waveform.has_value());
  458. Base::al_effect_props_.Chorus.Waveform = *efx_waveform;
  459. }
  460. void set_efx_phase() noexcept
  461. {
  462. Base::al_effect_props_.Chorus.Phase = clamp(
  463. static_cast<ALint>(Base::props_.lPhase),
  464. Traits::efx_min_phase(),
  465. Traits::efx_max_phase());
  466. }
  467. void set_efx_rate() noexcept
  468. {
  469. Base::al_effect_props_.Chorus.Rate = clamp(
  470. Base::props_.flRate,
  471. Traits::efx_min_rate(),
  472. Traits::efx_max_rate());
  473. }
  474. void set_efx_depth() noexcept
  475. {
  476. Base::al_effect_props_.Chorus.Depth = clamp(
  477. Base::props_.flDepth,
  478. Traits::efx_min_depth(),
  479. Traits::efx_max_depth());
  480. }
  481. void set_efx_feedback() noexcept
  482. {
  483. Base::al_effect_props_.Chorus.Feedback = clamp(
  484. Base::props_.flFeedback,
  485. Traits::efx_min_feedback(),
  486. Traits::efx_max_feedback());
  487. }
  488. void set_efx_delay() noexcept
  489. {
  490. Base::al_effect_props_.Chorus.Delay = clamp(
  491. Base::props_.flDelay,
  492. Traits::efx_min_delay(),
  493. Traits::efx_max_delay());
  494. }
  495. void set_efx_defaults() override
  496. {
  497. set_efx_waveform();
  498. set_efx_phase();
  499. set_efx_rate();
  500. set_efx_depth();
  501. set_efx_feedback();
  502. set_efx_delay();
  503. }
  504. void get(const EaxCall& call, const Props& props) override
  505. {
  506. switch(call.get_property_id())
  507. {
  508. case Traits::eax_none_param_id():
  509. break;
  510. case Traits::eax_allparameters_param_id():
  511. call.template set_value<Exception>(props);
  512. break;
  513. case Traits::eax_waveform_param_id():
  514. call.template set_value<Exception>(props.ulWaveform);
  515. break;
  516. case Traits::eax_phase_param_id():
  517. call.template set_value<Exception>(props.lPhase);
  518. break;
  519. case Traits::eax_rate_param_id():
  520. call.template set_value<Exception>(props.flRate);
  521. break;
  522. case Traits::eax_depth_param_id():
  523. call.template set_value<Exception>(props.flDepth);
  524. break;
  525. case Traits::eax_feedback_param_id():
  526. call.template set_value<Exception>(props.flFeedback);
  527. break;
  528. case Traits::eax_delay_param_id():
  529. call.template set_value<Exception>(props.flDelay);
  530. break;
  531. default:
  532. Base::fail_unknown_property_id();
  533. }
  534. }
  535. void set(const EaxCall& call, Props& props) override
  536. {
  537. switch(call.get_property_id())
  538. {
  539. case Traits::eax_none_param_id():
  540. break;
  541. case Traits::eax_allparameters_param_id():
  542. Base::template defer<AllValidator>(call, props);
  543. break;
  544. case Traits::eax_waveform_param_id():
  545. Base::template defer<WaveformValidator>(call, props.ulWaveform);
  546. break;
  547. case Traits::eax_phase_param_id():
  548. Base::template defer<PhaseValidator>(call, props.lPhase);
  549. break;
  550. case Traits::eax_rate_param_id():
  551. Base::template defer<RateValidator>(call, props.flRate);
  552. break;
  553. case Traits::eax_depth_param_id():
  554. Base::template defer<DepthValidator>(call, props.flDepth);
  555. break;
  556. case Traits::eax_feedback_param_id():
  557. Base::template defer<FeedbackValidator>(call, props.flFeedback);
  558. break;
  559. case Traits::eax_delay_param_id():
  560. Base::template defer<DelayValidator>(call, props.flDelay);
  561. break;
  562. default:
  563. Base::fail_unknown_property_id();
  564. }
  565. }
  566. bool commit_props(const Props& props) override
  567. {
  568. auto is_dirty = false;
  569. if (Base::props_.ulWaveform != props.ulWaveform)
  570. {
  571. is_dirty = true;
  572. set_efx_waveform();
  573. }
  574. if (Base::props_.lPhase != props.lPhase)
  575. {
  576. is_dirty = true;
  577. set_efx_phase();
  578. }
  579. if (Base::props_.flRate != props.flRate)
  580. {
  581. is_dirty = true;
  582. set_efx_rate();
  583. }
  584. if (Base::props_.flDepth != props.flDepth)
  585. {
  586. is_dirty = true;
  587. set_efx_depth();
  588. }
  589. if (Base::props_.flFeedback != props.flFeedback)
  590. {
  591. is_dirty = true;
  592. set_efx_feedback();
  593. }
  594. if (Base::props_.flDelay != props.flDelay)
  595. {
  596. is_dirty = true;
  597. set_efx_delay();
  598. }
  599. return is_dirty;
  600. }
  601. }; // EaxChorusFlangerEffect
  602. template<typename TTraits>
  603. EaxEffectUPtr eax_create_eax_chorus_flanger_effect(const EaxCall& call)
  604. {
  605. return eax_create_eax4_effect<EaxChorusFlangerEffect<TTraits>>(call);
  606. }
  607. } // namespace
  608. // ==========================================================================
  609. EaxEffectUPtr eax_create_eax_chorus_effect(const EaxCall& call)
  610. {
  611. return eax_create_eax_chorus_flanger_effect<EaxChorusTraits>(call);
  612. }
  613. EaxEffectUPtr eax_create_eax_flanger_effect(const EaxCall& call)
  614. {
  615. return eax_create_eax_chorus_flanger_effect<EaxFlangerTraits>(call);
  616. }
  617. #endif // ALSOFT_EAX