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

352 lines
9.7 KiB

  1. #include "config.h"
  2. #include "AL/al.h"
  3. #include "AL/efx.h"
  4. #include "alc/effects/base.h"
  5. #include "effects.h"
  6. #ifdef ALSOFT_EAX
  7. #include "alnumeric.h"
  8. #include "al/eax/exception.h"
  9. #include "al/eax/utils.h"
  10. #endif // ALSOFT_EAX
  11. namespace {
  12. static_assert(EchoMaxDelay >= AL_ECHO_MAX_DELAY, "Echo max delay too short");
  13. static_assert(EchoMaxLRDelay >= AL_ECHO_MAX_LRDELAY, "Echo max left-right delay too short");
  14. void Echo_setParami(EffectProps*, ALenum param, int)
  15. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
  16. void Echo_setParamiv(EffectProps*, ALenum param, const int*)
  17. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
  18. void Echo_setParamf(EffectProps *props, ALenum param, float val)
  19. {
  20. switch(param)
  21. {
  22. case AL_ECHO_DELAY:
  23. if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
  24. throw effect_exception{AL_INVALID_VALUE, "Echo delay out of range"};
  25. props->Echo.Delay = val;
  26. break;
  27. case AL_ECHO_LRDELAY:
  28. if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
  29. throw effect_exception{AL_INVALID_VALUE, "Echo LR delay out of range"};
  30. props->Echo.LRDelay = val;
  31. break;
  32. case AL_ECHO_DAMPING:
  33. if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
  34. throw effect_exception{AL_INVALID_VALUE, "Echo damping out of range"};
  35. props->Echo.Damping = val;
  36. break;
  37. case AL_ECHO_FEEDBACK:
  38. if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
  39. throw effect_exception{AL_INVALID_VALUE, "Echo feedback out of range"};
  40. props->Echo.Feedback = val;
  41. break;
  42. case AL_ECHO_SPREAD:
  43. if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
  44. throw effect_exception{AL_INVALID_VALUE, "Echo spread out of range"};
  45. props->Echo.Spread = val;
  46. break;
  47. default:
  48. throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
  49. }
  50. }
  51. void Echo_setParamfv(EffectProps *props, ALenum param, const float *vals)
  52. { Echo_setParamf(props, param, vals[0]); }
  53. void Echo_getParami(const EffectProps*, ALenum param, int*)
  54. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
  55. void Echo_getParamiv(const EffectProps*, ALenum param, int*)
  56. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
  57. void Echo_getParamf(const EffectProps *props, ALenum param, float *val)
  58. {
  59. switch(param)
  60. {
  61. case AL_ECHO_DELAY:
  62. *val = props->Echo.Delay;
  63. break;
  64. case AL_ECHO_LRDELAY:
  65. *val = props->Echo.LRDelay;
  66. break;
  67. case AL_ECHO_DAMPING:
  68. *val = props->Echo.Damping;
  69. break;
  70. case AL_ECHO_FEEDBACK:
  71. *val = props->Echo.Feedback;
  72. break;
  73. case AL_ECHO_SPREAD:
  74. *val = props->Echo.Spread;
  75. break;
  76. default:
  77. throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
  78. }
  79. }
  80. void Echo_getParamfv(const EffectProps *props, ALenum param, float *vals)
  81. { Echo_getParamf(props, param, vals); }
  82. EffectProps genDefaultProps() noexcept
  83. {
  84. EffectProps props{};
  85. props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
  86. props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
  87. props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
  88. props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
  89. props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
  90. return props;
  91. }
  92. } // namespace
  93. DEFINE_ALEFFECT_VTABLE(Echo);
  94. const EffectProps EchoEffectProps{genDefaultProps()};
  95. #ifdef ALSOFT_EAX
  96. namespace {
  97. class EaxEchoEffectException : public EaxException
  98. {
  99. public:
  100. explicit EaxEchoEffectException(const char* message)
  101. : EaxException{"EAX_ECHO_EFFECT", message}
  102. {}
  103. }; // EaxEchoEffectException
  104. class EaxEchoEffect final : public EaxEffect4<EaxEchoEffectException, EAXECHOPROPERTIES>
  105. {
  106. public:
  107. EaxEchoEffect(const EaxCall& call);
  108. private:
  109. struct DelayValidator {
  110. void operator()(float flDelay) const
  111. {
  112. eax_validate_range<Exception>(
  113. "Delay",
  114. flDelay,
  115. EAXECHO_MINDELAY,
  116. EAXECHO_MAXDELAY);
  117. }
  118. }; // DelayValidator
  119. struct LrDelayValidator {
  120. void operator()(float flLRDelay) const
  121. {
  122. eax_validate_range<Exception>(
  123. "LR Delay",
  124. flLRDelay,
  125. EAXECHO_MINLRDELAY,
  126. EAXECHO_MAXLRDELAY);
  127. }
  128. }; // LrDelayValidator
  129. struct DampingValidator {
  130. void operator()(float flDamping) const
  131. {
  132. eax_validate_range<Exception>(
  133. "Damping",
  134. flDamping,
  135. EAXECHO_MINDAMPING,
  136. EAXECHO_MAXDAMPING);
  137. }
  138. }; // DampingValidator
  139. struct FeedbackValidator {
  140. void operator()(float flFeedback) const
  141. {
  142. eax_validate_range<Exception>(
  143. "Feedback",
  144. flFeedback,
  145. EAXECHO_MINFEEDBACK,
  146. EAXECHO_MAXFEEDBACK);
  147. }
  148. }; // FeedbackValidator
  149. struct SpreadValidator {
  150. void operator()(float flSpread) const
  151. {
  152. eax_validate_range<Exception>(
  153. "Spread",
  154. flSpread,
  155. EAXECHO_MINSPREAD,
  156. EAXECHO_MAXSPREAD);
  157. }
  158. }; // SpreadValidator
  159. struct AllValidator {
  160. void operator()(const Props& all) const
  161. {
  162. DelayValidator{}(all.flDelay);
  163. LrDelayValidator{}(all.flLRDelay);
  164. DampingValidator{}(all.flDamping);
  165. FeedbackValidator{}(all.flFeedback);
  166. SpreadValidator{}(all.flSpread);
  167. }
  168. }; // AllValidator
  169. void set_defaults(Props& props) override;
  170. void set_efx_delay() noexcept;
  171. void set_efx_lr_delay() noexcept;
  172. void set_efx_damping() noexcept;
  173. void set_efx_feedback() noexcept;
  174. void set_efx_spread() noexcept;
  175. void set_efx_defaults() override;
  176. void get(const EaxCall& call, const Props& props) override;
  177. void set(const EaxCall& call, Props& props) override;
  178. bool commit_props(const Props& props) override;
  179. }; // EaxEchoEffect
  180. EaxEchoEffect::EaxEchoEffect(const EaxCall& call)
  181. : EaxEffect4{AL_EFFECT_ECHO, call}
  182. {}
  183. void EaxEchoEffect::set_defaults(Props& props)
  184. {
  185. props.flDelay = EAXECHO_DEFAULTDELAY;
  186. props.flLRDelay = EAXECHO_DEFAULTLRDELAY;
  187. props.flDamping = EAXECHO_DEFAULTDAMPING;
  188. props.flFeedback = EAXECHO_DEFAULTFEEDBACK;
  189. props.flSpread = EAXECHO_DEFAULTSPREAD;
  190. }
  191. void EaxEchoEffect::set_efx_delay() noexcept
  192. {
  193. al_effect_props_.Echo.Delay = clamp(
  194. props_.flDelay,
  195. AL_ECHO_MIN_DELAY,
  196. AL_ECHO_MAX_DELAY);
  197. }
  198. void EaxEchoEffect::set_efx_lr_delay() noexcept
  199. {
  200. al_effect_props_.Echo.LRDelay = clamp(
  201. props_.flLRDelay,
  202. AL_ECHO_MIN_LRDELAY,
  203. AL_ECHO_MAX_LRDELAY);
  204. }
  205. void EaxEchoEffect::set_efx_damping() noexcept
  206. {
  207. al_effect_props_.Echo.Damping = clamp(
  208. props_.flDamping,
  209. AL_ECHO_MIN_DAMPING,
  210. AL_ECHO_MAX_DAMPING);
  211. }
  212. void EaxEchoEffect::set_efx_feedback() noexcept
  213. {
  214. al_effect_props_.Echo.Feedback = clamp(
  215. props_.flFeedback,
  216. AL_ECHO_MIN_FEEDBACK,
  217. AL_ECHO_MAX_FEEDBACK);
  218. }
  219. void EaxEchoEffect::set_efx_spread() noexcept
  220. {
  221. al_effect_props_.Echo.Spread = clamp(
  222. props_.flSpread,
  223. AL_ECHO_MIN_SPREAD,
  224. AL_ECHO_MAX_SPREAD);
  225. }
  226. void EaxEchoEffect::set_efx_defaults()
  227. {
  228. set_efx_delay();
  229. set_efx_lr_delay();
  230. set_efx_damping();
  231. set_efx_feedback();
  232. set_efx_spread();
  233. }
  234. void EaxEchoEffect::get(const EaxCall& call, const Props& props)
  235. {
  236. switch(call.get_property_id())
  237. {
  238. case EAXECHO_NONE: break;
  239. case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props); break;
  240. case EAXECHO_DELAY: call.set_value<Exception>(props.flDelay); break;
  241. case EAXECHO_LRDELAY: call.set_value<Exception>(props.flLRDelay); break;
  242. case EAXECHO_DAMPING: call.set_value<Exception>(props.flDamping); break;
  243. case EAXECHO_FEEDBACK: call.set_value<Exception>(props.flFeedback); break;
  244. case EAXECHO_SPREAD: call.set_value<Exception>(props.flSpread); break;
  245. default: fail_unknown_property_id();
  246. }
  247. }
  248. void EaxEchoEffect::set(const EaxCall& call, Props& props)
  249. {
  250. switch(call.get_property_id())
  251. {
  252. case EAXECHO_NONE: break;
  253. case EAXECHO_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  254. case EAXECHO_DELAY: defer<DelayValidator>(call, props.flDelay); break;
  255. case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.flLRDelay); break;
  256. case EAXECHO_DAMPING: defer<DampingValidator>(call, props.flDamping); break;
  257. case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.flFeedback); break;
  258. case EAXECHO_SPREAD: defer<SpreadValidator>(call, props.flSpread); break;
  259. default: fail_unknown_property_id();
  260. }
  261. }
  262. bool EaxEchoEffect::commit_props(const Props& props)
  263. {
  264. auto is_dirty = false;
  265. if (props_.flDelay != props.flDelay)
  266. {
  267. is_dirty = true;
  268. set_efx_delay();
  269. }
  270. if (props_.flLRDelay != props.flLRDelay)
  271. {
  272. is_dirty = true;
  273. set_efx_lr_delay();
  274. }
  275. if (props_.flDamping != props.flDamping)
  276. {
  277. is_dirty = true;
  278. set_efx_damping();
  279. }
  280. if (props_.flFeedback != props.flFeedback)
  281. {
  282. is_dirty = true;
  283. set_efx_feedback();
  284. }
  285. if (props_.flSpread != props.flSpread)
  286. {
  287. is_dirty = true;
  288. set_efx_spread();
  289. }
  290. return is_dirty;
  291. }
  292. } // namespace
  293. EaxEffectUPtr eax_create_eax_echo_effect(const EaxCall& call)
  294. {
  295. return eax_create_eax4_effect<EaxEchoEffect>(call);
  296. }
  297. #endif // ALSOFT_EAX