chorus.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. #include "config.h"
  2. #include <optional>
  3. #include <stdexcept>
  4. #include "AL/al.h"
  5. #include "AL/efx.h"
  6. #include "effects.h"
  7. #ifdef ALSOFT_EAX
  8. #include <cassert>
  9. #include "al/eax/effect.h"
  10. #include "al/eax/exception.h"
  11. #include "al/eax/utils.h"
  12. #endif // ALSOFT_EAX
  13. namespace {
  14. static_assert(ChorusMaxDelay >= AL_CHORUS_MAX_DELAY, "Chorus max delay too small");
  15. static_assert(FlangerMaxDelay >= AL_FLANGER_MAX_DELAY, "Flanger max delay too small");
  16. static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
  17. static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
  18. constexpr std::optional<ChorusWaveform> WaveformFromEnum(ALenum type) noexcept
  19. {
  20. switch(type)
  21. {
  22. case AL_CHORUS_WAVEFORM_SINUSOID: return ChorusWaveform::Sinusoid;
  23. case AL_CHORUS_WAVEFORM_TRIANGLE: return ChorusWaveform::Triangle;
  24. }
  25. return std::nullopt;
  26. }
  27. constexpr ALenum EnumFromWaveform(ChorusWaveform type)
  28. {
  29. switch(type)
  30. {
  31. case ChorusWaveform::Sinusoid: return AL_CHORUS_WAVEFORM_SINUSOID;
  32. case ChorusWaveform::Triangle: return AL_CHORUS_WAVEFORM_TRIANGLE;
  33. }
  34. throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
  35. }
  36. constexpr EffectProps genDefaultChorusProps() noexcept
  37. {
  38. ChorusProps props{};
  39. props.Waveform = WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM).value();
  40. props.Phase = AL_CHORUS_DEFAULT_PHASE;
  41. props.Rate = AL_CHORUS_DEFAULT_RATE;
  42. props.Depth = AL_CHORUS_DEFAULT_DEPTH;
  43. props.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
  44. props.Delay = AL_CHORUS_DEFAULT_DELAY;
  45. return props;
  46. }
  47. constexpr EffectProps genDefaultFlangerProps() noexcept
  48. {
  49. ChorusProps props{};
  50. props.Waveform = WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM).value();
  51. props.Phase = AL_FLANGER_DEFAULT_PHASE;
  52. props.Rate = AL_FLANGER_DEFAULT_RATE;
  53. props.Depth = AL_FLANGER_DEFAULT_DEPTH;
  54. props.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
  55. props.Delay = AL_FLANGER_DEFAULT_DELAY;
  56. return props;
  57. }
  58. } // namespace
  59. const EffectProps ChorusEffectProps{genDefaultChorusProps()};
  60. void ChorusEffectHandler::SetParami(ChorusProps &props, ALenum param, int val)
  61. {
  62. switch(param)
  63. {
  64. case AL_CHORUS_WAVEFORM:
  65. if(auto formopt = WaveformFromEnum(val))
  66. props.Waveform = *formopt;
  67. else
  68. throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
  69. break;
  70. case AL_CHORUS_PHASE:
  71. if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
  72. throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range: %d", val};
  73. props.Phase = val;
  74. break;
  75. default:
  76. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
  77. }
  78. }
  79. void ChorusEffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals)
  80. { SetParami(props, param, *vals); }
  81. void ChorusEffectHandler::SetParamf(ChorusProps &props, ALenum param, float val)
  82. {
  83. switch(param)
  84. {
  85. case AL_CHORUS_RATE:
  86. if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
  87. throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range: %f", val};
  88. props.Rate = val;
  89. break;
  90. case AL_CHORUS_DEPTH:
  91. if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
  92. throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range: %f", val};
  93. props.Depth = val;
  94. break;
  95. case AL_CHORUS_FEEDBACK:
  96. if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
  97. throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range: %f", val};
  98. props.Feedback = val;
  99. break;
  100. case AL_CHORUS_DELAY:
  101. if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
  102. throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range: %f", val};
  103. props.Delay = val;
  104. break;
  105. default:
  106. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
  107. }
  108. }
  109. void ChorusEffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals)
  110. { SetParamf(props, param, *vals); }
  111. void ChorusEffectHandler::GetParami(const ChorusProps &props, ALenum param, int *val)
  112. {
  113. switch(param)
  114. {
  115. case AL_CHORUS_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
  116. case AL_CHORUS_PHASE: *val = props.Phase; break;
  117. default:
  118. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param};
  119. }
  120. }
  121. void ChorusEffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals)
  122. { GetParami(props, param, vals); }
  123. void ChorusEffectHandler::GetParamf(const ChorusProps &props, ALenum param, float *val)
  124. {
  125. switch(param)
  126. {
  127. case AL_CHORUS_RATE: *val = props.Rate; break;
  128. case AL_CHORUS_DEPTH: *val = props.Depth; break;
  129. case AL_CHORUS_FEEDBACK: *val = props.Feedback; break;
  130. case AL_CHORUS_DELAY: *val = props.Delay; break;
  131. default:
  132. throw effect_exception{AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param};
  133. }
  134. }
  135. void ChorusEffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals)
  136. { GetParamf(props, param, vals); }
  137. const EffectProps FlangerEffectProps{genDefaultFlangerProps()};
  138. void FlangerEffectHandler::SetParami(ChorusProps &props, ALenum param, int val)
  139. {
  140. switch(param)
  141. {
  142. case AL_FLANGER_WAVEFORM:
  143. if(auto formopt = WaveformFromEnum(val))
  144. props.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.Phase = val;
  152. break;
  153. default:
  154. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
  155. }
  156. }
  157. void FlangerEffectHandler::SetParamiv(ChorusProps &props, ALenum param, const int *vals)
  158. { SetParami(props, param, *vals); }
  159. void FlangerEffectHandler::SetParamf(ChorusProps &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.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.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.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.Delay = val;
  182. break;
  183. default:
  184. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
  185. }
  186. }
  187. void FlangerEffectHandler::SetParamfv(ChorusProps &props, ALenum param, const float *vals)
  188. { SetParamf(props, param, *vals); }
  189. void FlangerEffectHandler::GetParami(const ChorusProps &props, ALenum param, int *val)
  190. {
  191. switch(param)
  192. {
  193. case AL_FLANGER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
  194. case AL_FLANGER_PHASE: *val = props.Phase; break;
  195. default:
  196. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param};
  197. }
  198. }
  199. void FlangerEffectHandler::GetParamiv(const ChorusProps &props, ALenum param, int *vals)
  200. { GetParami(props, param, vals); }
  201. void FlangerEffectHandler::GetParamf(const ChorusProps &props, ALenum param, float *val)
  202. {
  203. switch(param)
  204. {
  205. case AL_FLANGER_RATE: *val = props.Rate; break;
  206. case AL_FLANGER_DEPTH: *val = props.Depth; break;
  207. case AL_FLANGER_FEEDBACK: *val = props.Feedback; break;
  208. case AL_FLANGER_DELAY: *val = props.Delay; break;
  209. default:
  210. throw effect_exception{AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param};
  211. }
  212. }
  213. void FlangerEffectHandler::GetParamfv(const ChorusProps &props, ALenum param, float *vals)
  214. { GetParamf(props, param, vals); }
  215. #ifdef ALSOFT_EAX
  216. namespace {
  217. struct EaxChorusTraits {
  218. using EaxProps = EAXCHORUSPROPERTIES;
  219. using Committer = EaxChorusCommitter;
  220. static constexpr auto efx_effect() { return AL_EFFECT_CHORUS; }
  221. static constexpr auto eax_none_param_id() { return EAXCHORUS_NONE; }
  222. static constexpr auto eax_allparameters_param_id() { return EAXCHORUS_ALLPARAMETERS; }
  223. static constexpr auto eax_waveform_param_id() { return EAXCHORUS_WAVEFORM; }
  224. static constexpr auto eax_phase_param_id() { return EAXCHORUS_PHASE; }
  225. static constexpr auto eax_rate_param_id() { return EAXCHORUS_RATE; }
  226. static constexpr auto eax_depth_param_id() { return EAXCHORUS_DEPTH; }
  227. static constexpr auto eax_feedback_param_id() { return EAXCHORUS_FEEDBACK; }
  228. static constexpr auto eax_delay_param_id() { return EAXCHORUS_DELAY; }
  229. static constexpr auto eax_min_waveform() { return EAXCHORUS_MINWAVEFORM; }
  230. static constexpr auto eax_min_phase() { return EAXCHORUS_MINPHASE; }
  231. static constexpr auto eax_min_rate() { return EAXCHORUS_MINRATE; }
  232. static constexpr auto eax_min_depth() { return EAXCHORUS_MINDEPTH; }
  233. static constexpr auto eax_min_feedback() { return EAXCHORUS_MINFEEDBACK; }
  234. static constexpr auto eax_min_delay() { return EAXCHORUS_MINDELAY; }
  235. static constexpr auto eax_max_waveform() { return EAXCHORUS_MAXWAVEFORM; }
  236. static constexpr auto eax_max_phase() { return EAXCHORUS_MAXPHASE; }
  237. static constexpr auto eax_max_rate() { return EAXCHORUS_MAXRATE; }
  238. static constexpr auto eax_max_depth() { return EAXCHORUS_MAXDEPTH; }
  239. static constexpr auto eax_max_feedback() { return EAXCHORUS_MAXFEEDBACK; }
  240. static constexpr auto eax_max_delay() { return EAXCHORUS_MAXDELAY; }
  241. static constexpr auto eax_default_waveform() { return EAXCHORUS_DEFAULTWAVEFORM; }
  242. static constexpr auto eax_default_phase() { return EAXCHORUS_DEFAULTPHASE; }
  243. static constexpr auto eax_default_rate() { return EAXCHORUS_DEFAULTRATE; }
  244. static constexpr auto eax_default_depth() { return EAXCHORUS_DEFAULTDEPTH; }
  245. static constexpr auto eax_default_feedback() { return EAXCHORUS_DEFAULTFEEDBACK; }
  246. static constexpr auto eax_default_delay() { return EAXCHORUS_DEFAULTDELAY; }
  247. static constexpr auto efx_min_waveform() { return AL_CHORUS_MIN_WAVEFORM; }
  248. static constexpr auto efx_min_phase() { return AL_CHORUS_MIN_PHASE; }
  249. static constexpr auto efx_min_rate() { return AL_CHORUS_MIN_RATE; }
  250. static constexpr auto efx_min_depth() { return AL_CHORUS_MIN_DEPTH; }
  251. static constexpr auto efx_min_feedback() { return AL_CHORUS_MIN_FEEDBACK; }
  252. static constexpr auto efx_min_delay() { return AL_CHORUS_MIN_DELAY; }
  253. static constexpr auto efx_max_waveform() { return AL_CHORUS_MAX_WAVEFORM; }
  254. static constexpr auto efx_max_phase() { return AL_CHORUS_MAX_PHASE; }
  255. static constexpr auto efx_max_rate() { return AL_CHORUS_MAX_RATE; }
  256. static constexpr auto efx_max_depth() { return AL_CHORUS_MAX_DEPTH; }
  257. static constexpr auto efx_max_feedback() { return AL_CHORUS_MAX_FEEDBACK; }
  258. static constexpr auto efx_max_delay() { return AL_CHORUS_MAX_DELAY; }
  259. static constexpr auto efx_default_waveform() { return AL_CHORUS_DEFAULT_WAVEFORM; }
  260. static constexpr auto efx_default_phase() { return AL_CHORUS_DEFAULT_PHASE; }
  261. static constexpr auto efx_default_rate() { return AL_CHORUS_DEFAULT_RATE; }
  262. static constexpr auto efx_default_depth() { return AL_CHORUS_DEFAULT_DEPTH; }
  263. static constexpr auto efx_default_feedback() { return AL_CHORUS_DEFAULT_FEEDBACK; }
  264. static constexpr auto efx_default_delay() { return AL_CHORUS_DEFAULT_DELAY; }
  265. static ChorusWaveform eax_waveform(unsigned long type)
  266. {
  267. if(type == EAX_CHORUS_SINUSOID) return ChorusWaveform::Sinusoid;
  268. if(type == EAX_CHORUS_TRIANGLE) return ChorusWaveform::Triangle;
  269. return ChorusWaveform::Sinusoid;
  270. }
  271. }; // EaxChorusTraits
  272. struct EaxFlangerTraits {
  273. using EaxProps = EAXFLANGERPROPERTIES;
  274. using Committer = EaxFlangerCommitter;
  275. static constexpr auto efx_effect() { return AL_EFFECT_FLANGER; }
  276. static constexpr auto eax_none_param_id() { return EAXFLANGER_NONE; }
  277. static constexpr auto eax_allparameters_param_id() { return EAXFLANGER_ALLPARAMETERS; }
  278. static constexpr auto eax_waveform_param_id() { return EAXFLANGER_WAVEFORM; }
  279. static constexpr auto eax_phase_param_id() { return EAXFLANGER_PHASE; }
  280. static constexpr auto eax_rate_param_id() { return EAXFLANGER_RATE; }
  281. static constexpr auto eax_depth_param_id() { return EAXFLANGER_DEPTH; }
  282. static constexpr auto eax_feedback_param_id() { return EAXFLANGER_FEEDBACK; }
  283. static constexpr auto eax_delay_param_id() { return EAXFLANGER_DELAY; }
  284. static constexpr auto eax_min_waveform() { return EAXFLANGER_MINWAVEFORM; }
  285. static constexpr auto eax_min_phase() { return EAXFLANGER_MINPHASE; }
  286. static constexpr auto eax_min_rate() { return EAXFLANGER_MINRATE; }
  287. static constexpr auto eax_min_depth() { return EAXFLANGER_MINDEPTH; }
  288. static constexpr auto eax_min_feedback() { return EAXFLANGER_MINFEEDBACK; }
  289. static constexpr auto eax_min_delay() { return EAXFLANGER_MINDELAY; }
  290. static constexpr auto eax_max_waveform() { return EAXFLANGER_MAXWAVEFORM; }
  291. static constexpr auto eax_max_phase() { return EAXFLANGER_MAXPHASE; }
  292. static constexpr auto eax_max_rate() { return EAXFLANGER_MAXRATE; }
  293. static constexpr auto eax_max_depth() { return EAXFLANGER_MAXDEPTH; }
  294. static constexpr auto eax_max_feedback() { return EAXFLANGER_MAXFEEDBACK; }
  295. static constexpr auto eax_max_delay() { return EAXFLANGER_MAXDELAY; }
  296. static constexpr auto eax_default_waveform() { return EAXFLANGER_DEFAULTWAVEFORM; }
  297. static constexpr auto eax_default_phase() { return EAXFLANGER_DEFAULTPHASE; }
  298. static constexpr auto eax_default_rate() { return EAXFLANGER_DEFAULTRATE; }
  299. static constexpr auto eax_default_depth() { return EAXFLANGER_DEFAULTDEPTH; }
  300. static constexpr auto eax_default_feedback() { return EAXFLANGER_DEFAULTFEEDBACK; }
  301. static constexpr auto eax_default_delay() { return EAXFLANGER_DEFAULTDELAY; }
  302. static constexpr auto efx_min_waveform() { return AL_FLANGER_MIN_WAVEFORM; }
  303. static constexpr auto efx_min_phase() { return AL_FLANGER_MIN_PHASE; }
  304. static constexpr auto efx_min_rate() { return AL_FLANGER_MIN_RATE; }
  305. static constexpr auto efx_min_depth() { return AL_FLANGER_MIN_DEPTH; }
  306. static constexpr auto efx_min_feedback() { return AL_FLANGER_MIN_FEEDBACK; }
  307. static constexpr auto efx_min_delay() { return AL_FLANGER_MIN_DELAY; }
  308. static constexpr auto efx_max_waveform() { return AL_FLANGER_MAX_WAVEFORM; }
  309. static constexpr auto efx_max_phase() { return AL_FLANGER_MAX_PHASE; }
  310. static constexpr auto efx_max_rate() { return AL_FLANGER_MAX_RATE; }
  311. static constexpr auto efx_max_depth() { return AL_FLANGER_MAX_DEPTH; }
  312. static constexpr auto efx_max_feedback() { return AL_FLANGER_MAX_FEEDBACK; }
  313. static constexpr auto efx_max_delay() { return AL_FLANGER_MAX_DELAY; }
  314. static constexpr auto efx_default_waveform() { return AL_FLANGER_DEFAULT_WAVEFORM; }
  315. static constexpr auto efx_default_phase() { return AL_FLANGER_DEFAULT_PHASE; }
  316. static constexpr auto efx_default_rate() { return AL_FLANGER_DEFAULT_RATE; }
  317. static constexpr auto efx_default_depth() { return AL_FLANGER_DEFAULT_DEPTH; }
  318. static constexpr auto efx_default_feedback() { return AL_FLANGER_DEFAULT_FEEDBACK; }
  319. static constexpr auto efx_default_delay() { return AL_FLANGER_DEFAULT_DELAY; }
  320. static ChorusWaveform eax_waveform(unsigned long type)
  321. {
  322. if(type == EAX_FLANGER_SINUSOID) return ChorusWaveform::Sinusoid;
  323. if(type == EAX_FLANGER_TRIANGLE) return ChorusWaveform::Triangle;
  324. return ChorusWaveform::Sinusoid;
  325. }
  326. }; // EaxFlangerTraits
  327. template<typename TTraits>
  328. struct ChorusFlangerEffect {
  329. using Traits = TTraits;
  330. using EaxProps = typename Traits::EaxProps;
  331. using Committer = typename Traits::Committer;
  332. using Exception = typename Committer::Exception;
  333. struct WaveformValidator {
  334. void operator()(unsigned long ulWaveform) const
  335. {
  336. eax_validate_range<Exception>(
  337. "Waveform",
  338. ulWaveform,
  339. Traits::eax_min_waveform(),
  340. Traits::eax_max_waveform());
  341. }
  342. }; // WaveformValidator
  343. struct PhaseValidator {
  344. void operator()(long lPhase) const
  345. {
  346. eax_validate_range<Exception>(
  347. "Phase",
  348. lPhase,
  349. Traits::eax_min_phase(),
  350. Traits::eax_max_phase());
  351. }
  352. }; // PhaseValidator
  353. struct RateValidator {
  354. void operator()(float flRate) const
  355. {
  356. eax_validate_range<Exception>(
  357. "Rate",
  358. flRate,
  359. Traits::eax_min_rate(),
  360. Traits::eax_max_rate());
  361. }
  362. }; // RateValidator
  363. struct DepthValidator {
  364. void operator()(float flDepth) const
  365. {
  366. eax_validate_range<Exception>(
  367. "Depth",
  368. flDepth,
  369. Traits::eax_min_depth(),
  370. Traits::eax_max_depth());
  371. }
  372. }; // DepthValidator
  373. struct FeedbackValidator {
  374. void operator()(float flFeedback) const
  375. {
  376. eax_validate_range<Exception>(
  377. "Feedback",
  378. flFeedback,
  379. Traits::eax_min_feedback(),
  380. Traits::eax_max_feedback());
  381. }
  382. }; // FeedbackValidator
  383. struct DelayValidator {
  384. void operator()(float flDelay) const
  385. {
  386. eax_validate_range<Exception>(
  387. "Delay",
  388. flDelay,
  389. Traits::eax_min_delay(),
  390. Traits::eax_max_delay());
  391. }
  392. }; // DelayValidator
  393. struct AllValidator {
  394. void operator()(const EaxProps& all) const
  395. {
  396. WaveformValidator{}(all.ulWaveform);
  397. PhaseValidator{}(all.lPhase);
  398. RateValidator{}(all.flRate);
  399. DepthValidator{}(all.flDepth);
  400. FeedbackValidator{}(all.flFeedback);
  401. DelayValidator{}(all.flDelay);
  402. }
  403. }; // AllValidator
  404. public:
  405. static void SetDefaults(EaxEffectProps &props)
  406. {
  407. auto&& all = props.emplace<EaxProps>();
  408. all.ulWaveform = Traits::eax_default_waveform();
  409. all.lPhase = Traits::eax_default_phase();
  410. all.flRate = Traits::eax_default_rate();
  411. all.flDepth = Traits::eax_default_depth();
  412. all.flFeedback = Traits::eax_default_feedback();
  413. all.flDelay = Traits::eax_default_delay();
  414. }
  415. static void Get(const EaxCall &call, const EaxProps &all)
  416. {
  417. switch(call.get_property_id())
  418. {
  419. case Traits::eax_none_param_id():
  420. break;
  421. case Traits::eax_allparameters_param_id():
  422. call.template set_value<Exception>(all);
  423. break;
  424. case Traits::eax_waveform_param_id():
  425. call.template set_value<Exception>(all.ulWaveform);
  426. break;
  427. case Traits::eax_phase_param_id():
  428. call.template set_value<Exception>(all.lPhase);
  429. break;
  430. case Traits::eax_rate_param_id():
  431. call.template set_value<Exception>(all.flRate);
  432. break;
  433. case Traits::eax_depth_param_id():
  434. call.template set_value<Exception>(all.flDepth);
  435. break;
  436. case Traits::eax_feedback_param_id():
  437. call.template set_value<Exception>(all.flFeedback);
  438. break;
  439. case Traits::eax_delay_param_id():
  440. call.template set_value<Exception>(all.flDelay);
  441. break;
  442. default:
  443. Committer::fail_unknown_property_id();
  444. }
  445. }
  446. static void Set(const EaxCall &call, EaxProps &all)
  447. {
  448. switch(call.get_property_id())
  449. {
  450. case Traits::eax_none_param_id():
  451. break;
  452. case Traits::eax_allparameters_param_id():
  453. Committer::template defer<AllValidator>(call, all);
  454. break;
  455. case Traits::eax_waveform_param_id():
  456. Committer::template defer<WaveformValidator>(call, all.ulWaveform);
  457. break;
  458. case Traits::eax_phase_param_id():
  459. Committer::template defer<PhaseValidator>(call, all.lPhase);
  460. break;
  461. case Traits::eax_rate_param_id():
  462. Committer::template defer<RateValidator>(call, all.flRate);
  463. break;
  464. case Traits::eax_depth_param_id():
  465. Committer::template defer<DepthValidator>(call, all.flDepth);
  466. break;
  467. case Traits::eax_feedback_param_id():
  468. Committer::template defer<FeedbackValidator>(call, all.flFeedback);
  469. break;
  470. case Traits::eax_delay_param_id():
  471. Committer::template defer<DelayValidator>(call, all.flDelay);
  472. break;
  473. default:
  474. Committer::fail_unknown_property_id();
  475. }
  476. }
  477. static bool Commit(const EaxProps &props, EaxEffectProps &props_, ChorusProps &al_props_)
  478. {
  479. if(auto *cur = std::get_if<EaxProps>(&props_); cur && *cur == props)
  480. return false;
  481. props_ = props;
  482. al_props_.Waveform = Traits::eax_waveform(props.ulWaveform);
  483. al_props_.Phase = static_cast<int>(props.lPhase);
  484. al_props_.Rate = props.flRate;
  485. al_props_.Depth = props.flDepth;
  486. al_props_.Feedback = props.flFeedback;
  487. al_props_.Delay = props.flDelay;
  488. return true;
  489. }
  490. }; // EaxChorusFlangerEffect
  491. using ChorusCommitter = EaxCommitter<EaxChorusCommitter>;
  492. using FlangerCommitter = EaxCommitter<EaxFlangerCommitter>;
  493. } // namespace
  494. template<>
  495. struct ChorusCommitter::Exception : public EaxException
  496. {
  497. explicit Exception(const char *message) : EaxException{"EAX_CHORUS_EFFECT", message}
  498. { }
  499. };
  500. template<>
  501. [[noreturn]] void ChorusCommitter::fail(const char *message)
  502. {
  503. throw Exception{message};
  504. }
  505. bool EaxChorusCommitter::commit(const EAXCHORUSPROPERTIES &props)
  506. {
  507. using Committer = ChorusFlangerEffect<EaxChorusTraits>;
  508. return Committer::Commit(props, mEaxProps, mAlProps.emplace<ChorusProps>());
  509. }
  510. void EaxChorusCommitter::SetDefaults(EaxEffectProps &props)
  511. {
  512. using Committer = ChorusFlangerEffect<EaxChorusTraits>;
  513. Committer::SetDefaults(props);
  514. }
  515. void EaxChorusCommitter::Get(const EaxCall &call, const EAXCHORUSPROPERTIES &props)
  516. {
  517. using Committer = ChorusFlangerEffect<EaxChorusTraits>;
  518. Committer::Get(call, props);
  519. }
  520. void EaxChorusCommitter::Set(const EaxCall &call, EAXCHORUSPROPERTIES &props)
  521. {
  522. using Committer = ChorusFlangerEffect<EaxChorusTraits>;
  523. Committer::Set(call, props);
  524. }
  525. template<>
  526. struct FlangerCommitter::Exception : public EaxException
  527. {
  528. explicit Exception(const char *message) : EaxException{"EAX_FLANGER_EFFECT", message}
  529. { }
  530. };
  531. template<>
  532. [[noreturn]] void FlangerCommitter::fail(const char *message)
  533. {
  534. throw Exception{message};
  535. }
  536. bool EaxFlangerCommitter::commit(const EAXFLANGERPROPERTIES &props)
  537. {
  538. using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
  539. return Committer::Commit(props, mEaxProps, mAlProps.emplace<ChorusProps>());
  540. }
  541. void EaxFlangerCommitter::SetDefaults(EaxEffectProps &props)
  542. {
  543. using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
  544. Committer::SetDefaults(props);
  545. }
  546. void EaxFlangerCommitter::Get(const EaxCall &call, const EAXFLANGERPROPERTIES &props)
  547. {
  548. using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
  549. Committer::Get(call, props);
  550. }
  551. void EaxFlangerCommitter::Set(const EaxCall &call, EAXFLANGERPROPERTIES &props)
  552. {
  553. using Committer = ChorusFlangerEffect<EaxFlangerTraits>;
  554. Committer::Set(call, props);
  555. }
  556. #endif // ALSOFT_EAX