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

355 lines
11 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. void Distortion_setParami(EffectProps*, ALenum param, int)
  13. { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
  14. void Distortion_setParamiv(EffectProps*, ALenum param, const int*)
  15. {
  16. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
  17. param};
  18. }
  19. void Distortion_setParamf(EffectProps *props, ALenum param, float val)
  20. {
  21. switch(param)
  22. {
  23. case AL_DISTORTION_EDGE:
  24. if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
  25. throw effect_exception{AL_INVALID_VALUE, "Distortion edge out of range"};
  26. props->Distortion.Edge = val;
  27. break;
  28. case AL_DISTORTION_GAIN:
  29. if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
  30. throw effect_exception{AL_INVALID_VALUE, "Distortion gain out of range"};
  31. props->Distortion.Gain = val;
  32. break;
  33. case AL_DISTORTION_LOWPASS_CUTOFF:
  34. if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
  35. throw effect_exception{AL_INVALID_VALUE, "Distortion low-pass cutoff out of range"};
  36. props->Distortion.LowpassCutoff = val;
  37. break;
  38. case AL_DISTORTION_EQCENTER:
  39. if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
  40. throw effect_exception{AL_INVALID_VALUE, "Distortion EQ center out of range"};
  41. props->Distortion.EQCenter = val;
  42. break;
  43. case AL_DISTORTION_EQBANDWIDTH:
  44. if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
  45. throw effect_exception{AL_INVALID_VALUE, "Distortion EQ bandwidth out of range"};
  46. props->Distortion.EQBandwidth = val;
  47. break;
  48. default:
  49. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
  50. }
  51. }
  52. void Distortion_setParamfv(EffectProps *props, ALenum param, const float *vals)
  53. { Distortion_setParamf(props, param, vals[0]); }
  54. void Distortion_getParami(const EffectProps*, ALenum param, int*)
  55. { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
  56. void Distortion_getParamiv(const EffectProps*, ALenum param, int*)
  57. {
  58. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
  59. param};
  60. }
  61. void Distortion_getParamf(const EffectProps *props, ALenum param, float *val)
  62. {
  63. switch(param)
  64. {
  65. case AL_DISTORTION_EDGE:
  66. *val = props->Distortion.Edge;
  67. break;
  68. case AL_DISTORTION_GAIN:
  69. *val = props->Distortion.Gain;
  70. break;
  71. case AL_DISTORTION_LOWPASS_CUTOFF:
  72. *val = props->Distortion.LowpassCutoff;
  73. break;
  74. case AL_DISTORTION_EQCENTER:
  75. *val = props->Distortion.EQCenter;
  76. break;
  77. case AL_DISTORTION_EQBANDWIDTH:
  78. *val = props->Distortion.EQBandwidth;
  79. break;
  80. default:
  81. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
  82. }
  83. }
  84. void Distortion_getParamfv(const EffectProps *props, ALenum param, float *vals)
  85. { Distortion_getParamf(props, param, vals); }
  86. EffectProps genDefaultProps() noexcept
  87. {
  88. EffectProps props{};
  89. props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
  90. props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
  91. props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
  92. props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
  93. props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
  94. return props;
  95. }
  96. } // namespace
  97. DEFINE_ALEFFECT_VTABLE(Distortion);
  98. const EffectProps DistortionEffectProps{genDefaultProps()};
  99. #ifdef ALSOFT_EAX
  100. namespace {
  101. class EaxDistortionEffectException : public EaxException
  102. {
  103. public:
  104. explicit EaxDistortionEffectException(const char* message)
  105. : EaxException{"EAX_DISTORTION_EFFECT", message}
  106. {}
  107. }; // EaxDistortionEffectException
  108. class EaxDistortionEffect final : public EaxEffect4<EaxDistortionEffectException, EAXDISTORTIONPROPERTIES>
  109. {
  110. public:
  111. EaxDistortionEffect(const EaxCall& call);
  112. private:
  113. struct EdgeValidator {
  114. void operator()(float flEdge) const
  115. {
  116. eax_validate_range<Exception>(
  117. "Edge",
  118. flEdge,
  119. EAXDISTORTION_MINEDGE,
  120. EAXDISTORTION_MAXEDGE);
  121. }
  122. }; // EdgeValidator
  123. struct GainValidator {
  124. void operator()(long lGain) const
  125. {
  126. eax_validate_range<Exception>(
  127. "Gain",
  128. lGain,
  129. EAXDISTORTION_MINGAIN,
  130. EAXDISTORTION_MAXGAIN);
  131. }
  132. }; // GainValidator
  133. struct LowPassCutOffValidator {
  134. void operator()(float flLowPassCutOff) const
  135. {
  136. eax_validate_range<Exception>(
  137. "Low-pass Cut-off",
  138. flLowPassCutOff,
  139. EAXDISTORTION_MINLOWPASSCUTOFF,
  140. EAXDISTORTION_MAXLOWPASSCUTOFF);
  141. }
  142. }; // LowPassCutOffValidator
  143. struct EqCenterValidator {
  144. void operator()(float flEQCenter) const
  145. {
  146. eax_validate_range<Exception>(
  147. "EQ Center",
  148. flEQCenter,
  149. EAXDISTORTION_MINEQCENTER,
  150. EAXDISTORTION_MAXEQCENTER);
  151. }
  152. }; // EqCenterValidator
  153. struct EqBandwidthValidator {
  154. void operator()(float flEQBandwidth) const
  155. {
  156. eax_validate_range<Exception>(
  157. "EQ Bandwidth",
  158. flEQBandwidth,
  159. EAXDISTORTION_MINEQBANDWIDTH,
  160. EAXDISTORTION_MAXEQBANDWIDTH);
  161. }
  162. }; // EqBandwidthValidator
  163. struct AllValidator {
  164. void operator()(const Props& all) const
  165. {
  166. EdgeValidator{}(all.flEdge);
  167. GainValidator{}(all.lGain);
  168. LowPassCutOffValidator{}(all.flLowPassCutOff);
  169. EqCenterValidator{}(all.flEQCenter);
  170. EqBandwidthValidator{}(all.flEQBandwidth);
  171. }
  172. }; // AllValidator
  173. void set_defaults(Props& props) override;
  174. void set_efx_edge() noexcept;
  175. void set_efx_gain() noexcept;
  176. void set_efx_lowpass_cutoff() noexcept;
  177. void set_efx_eq_center() noexcept;
  178. void set_efx_eq_bandwidth() noexcept;
  179. void set_efx_defaults() override;
  180. void get(const EaxCall& call, const Props& props) override;
  181. void set(const EaxCall& call, Props& props) override;
  182. bool commit_props(const Props& props) override;
  183. }; // EaxDistortionEffect
  184. EaxDistortionEffect::EaxDistortionEffect(const EaxCall& call)
  185. : EaxEffect4{AL_EFFECT_DISTORTION, call}
  186. {}
  187. void EaxDistortionEffect::set_defaults(Props& props)
  188. {
  189. props.flEdge = EAXDISTORTION_DEFAULTEDGE;
  190. props.lGain = EAXDISTORTION_DEFAULTGAIN;
  191. props.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF;
  192. props.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER;
  193. props.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH;
  194. }
  195. void EaxDistortionEffect::set_efx_edge() noexcept
  196. {
  197. al_effect_props_.Distortion.Edge = clamp(
  198. props_.flEdge,
  199. AL_DISTORTION_MIN_EDGE,
  200. AL_DISTORTION_MAX_EDGE);
  201. }
  202. void EaxDistortionEffect::set_efx_gain() noexcept
  203. {
  204. al_effect_props_.Distortion.Gain = clamp(
  205. level_mb_to_gain(static_cast<float>(props_.lGain)),
  206. AL_DISTORTION_MIN_GAIN,
  207. AL_DISTORTION_MAX_GAIN);
  208. }
  209. void EaxDistortionEffect::set_efx_lowpass_cutoff() noexcept
  210. {
  211. al_effect_props_.Distortion.LowpassCutoff = clamp(
  212. props_.flLowPassCutOff,
  213. AL_DISTORTION_MIN_LOWPASS_CUTOFF,
  214. AL_DISTORTION_MAX_LOWPASS_CUTOFF);
  215. }
  216. void EaxDistortionEffect::set_efx_eq_center() noexcept
  217. {
  218. al_effect_props_.Distortion.EQCenter = clamp(
  219. props_.flEQCenter,
  220. AL_DISTORTION_MIN_EQCENTER,
  221. AL_DISTORTION_MAX_EQCENTER);
  222. }
  223. void EaxDistortionEffect::set_efx_eq_bandwidth() noexcept
  224. {
  225. al_effect_props_.Distortion.EQBandwidth = clamp(
  226. props_.flEdge,
  227. AL_DISTORTION_MIN_EQBANDWIDTH,
  228. AL_DISTORTION_MAX_EQBANDWIDTH);
  229. }
  230. void EaxDistortionEffect::set_efx_defaults()
  231. {
  232. set_efx_edge();
  233. set_efx_gain();
  234. set_efx_lowpass_cutoff();
  235. set_efx_eq_center();
  236. set_efx_eq_bandwidth();
  237. }
  238. void EaxDistortionEffect::get(const EaxCall& call, const Props& props)
  239. {
  240. switch(call.get_property_id())
  241. {
  242. case EAXDISTORTION_NONE: break;
  243. case EAXDISTORTION_ALLPARAMETERS: call.set_value<Exception>(props); break;
  244. case EAXDISTORTION_EDGE: call.set_value<Exception>(props.flEdge); break;
  245. case EAXDISTORTION_GAIN: call.set_value<Exception>(props.lGain); break;
  246. case EAXDISTORTION_LOWPASSCUTOFF: call.set_value<Exception>(props.flLowPassCutOff); break;
  247. case EAXDISTORTION_EQCENTER: call.set_value<Exception>(props.flEQCenter); break;
  248. case EAXDISTORTION_EQBANDWIDTH: call.set_value<Exception>(props.flEQBandwidth); break;
  249. default: fail_unknown_property_id();
  250. }
  251. }
  252. void EaxDistortionEffect::set(const EaxCall& call, Props& props)
  253. {
  254. switch(call.get_property_id())
  255. {
  256. case EAXDISTORTION_NONE: break;
  257. case EAXDISTORTION_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  258. case EAXDISTORTION_EDGE: defer<EdgeValidator>(call, props.flEdge); break;
  259. case EAXDISTORTION_GAIN: defer<GainValidator>(call, props.lGain); break;
  260. case EAXDISTORTION_LOWPASSCUTOFF: defer<LowPassCutOffValidator>(call, props.flLowPassCutOff); break;
  261. case EAXDISTORTION_EQCENTER: defer<EqCenterValidator>(call, props.flEQCenter); break;
  262. case EAXDISTORTION_EQBANDWIDTH: defer<EqBandwidthValidator>(call, props.flEQBandwidth); break;
  263. default: fail_unknown_property_id();
  264. }
  265. }
  266. bool EaxDistortionEffect::commit_props(const Props& props)
  267. {
  268. auto is_dirty = false;
  269. if (props_.flEdge != props.flEdge)
  270. {
  271. is_dirty = true;
  272. set_efx_edge();
  273. }
  274. if (props_.lGain != props.lGain)
  275. {
  276. is_dirty = true;
  277. set_efx_gain();
  278. }
  279. if (props_.flLowPassCutOff != props.flLowPassCutOff)
  280. {
  281. is_dirty = true;
  282. set_efx_lowpass_cutoff();
  283. }
  284. if (props_.flEQCenter != props.flEQCenter)
  285. {
  286. is_dirty = true;
  287. set_efx_eq_center();
  288. }
  289. if (props_.flEQBandwidth != props.flEQBandwidth)
  290. {
  291. is_dirty = true;
  292. set_efx_eq_bandwidth();
  293. }
  294. return is_dirty;
  295. }
  296. } // namespace
  297. EaxEffectUPtr eax_create_eax_distortion_effect(const EaxCall& call)
  298. {
  299. return eax_create_eax4_effect<EaxDistortionEffect>(call);
  300. }
  301. #endif // ALSOFT_EAX