distortion.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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/effect.h"
  9. #include "al/eax/exception.h"
  10. #include "al/eax/utils.h"
  11. #endif // ALSOFT_EAX
  12. namespace {
  13. constexpr EffectProps genDefaultProps() noexcept
  14. {
  15. DistortionProps props{};
  16. props.Edge = AL_DISTORTION_DEFAULT_EDGE;
  17. props.Gain = AL_DISTORTION_DEFAULT_GAIN;
  18. props.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
  19. props.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
  20. props.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
  21. return props;
  22. }
  23. } // namespace
  24. const EffectProps DistortionEffectProps{genDefaultProps()};
  25. void DistortionEffectHandler::SetParami(DistortionProps&, ALenum param, int)
  26. { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
  27. void DistortionEffectHandler::SetParamiv(DistortionProps&, ALenum param, const int*)
  28. {
  29. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
  30. param};
  31. }
  32. void DistortionEffectHandler::SetParamf(DistortionProps &props, ALenum param, float val)
  33. {
  34. switch(param)
  35. {
  36. case AL_DISTORTION_EDGE:
  37. if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
  38. throw effect_exception{AL_INVALID_VALUE, "Distortion edge out of range"};
  39. props.Edge = val;
  40. break;
  41. case AL_DISTORTION_GAIN:
  42. if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
  43. throw effect_exception{AL_INVALID_VALUE, "Distortion gain out of range"};
  44. props.Gain = val;
  45. break;
  46. case AL_DISTORTION_LOWPASS_CUTOFF:
  47. if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
  48. throw effect_exception{AL_INVALID_VALUE, "Distortion low-pass cutoff out of range"};
  49. props.LowpassCutoff = val;
  50. break;
  51. case AL_DISTORTION_EQCENTER:
  52. if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
  53. throw effect_exception{AL_INVALID_VALUE, "Distortion EQ center out of range"};
  54. props.EQCenter = val;
  55. break;
  56. case AL_DISTORTION_EQBANDWIDTH:
  57. if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
  58. throw effect_exception{AL_INVALID_VALUE, "Distortion EQ bandwidth out of range"};
  59. props.EQBandwidth = val;
  60. break;
  61. default:
  62. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
  63. }
  64. }
  65. void DistortionEffectHandler::SetParamfv(DistortionProps &props, ALenum param, const float *vals)
  66. { SetParamf(props, param, *vals); }
  67. void DistortionEffectHandler::GetParami(const DistortionProps&, ALenum param, int*)
  68. { throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param}; }
  69. void DistortionEffectHandler::GetParamiv(const DistortionProps&, ALenum param, int*)
  70. {
  71. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x",
  72. param};
  73. }
  74. void DistortionEffectHandler::GetParamf(const DistortionProps &props, ALenum param, float *val)
  75. {
  76. switch(param)
  77. {
  78. case AL_DISTORTION_EDGE: *val = props.Edge; break;
  79. case AL_DISTORTION_GAIN: *val = props.Gain; break;
  80. case AL_DISTORTION_LOWPASS_CUTOFF: *val = props.LowpassCutoff; break;
  81. case AL_DISTORTION_EQCENTER: *val = props.EQCenter; break;
  82. case AL_DISTORTION_EQBANDWIDTH: *val = props.EQBandwidth; break;
  83. default:
  84. throw effect_exception{AL_INVALID_ENUM, "Invalid distortion float property 0x%04x", param};
  85. }
  86. }
  87. void DistortionEffectHandler::GetParamfv(const DistortionProps &props, ALenum param, float *vals)
  88. { GetParamf(props, param, vals); }
  89. #ifdef ALSOFT_EAX
  90. namespace {
  91. using DistortionCommitter = EaxCommitter<EaxDistortionCommitter>;
  92. struct EdgeValidator {
  93. void operator()(float flEdge) const
  94. {
  95. eax_validate_range<DistortionCommitter::Exception>(
  96. "Edge",
  97. flEdge,
  98. EAXDISTORTION_MINEDGE,
  99. EAXDISTORTION_MAXEDGE);
  100. }
  101. }; // EdgeValidator
  102. struct GainValidator {
  103. void operator()(long lGain) const
  104. {
  105. eax_validate_range<DistortionCommitter::Exception>(
  106. "Gain",
  107. lGain,
  108. EAXDISTORTION_MINGAIN,
  109. EAXDISTORTION_MAXGAIN);
  110. }
  111. }; // GainValidator
  112. struct LowPassCutOffValidator {
  113. void operator()(float flLowPassCutOff) const
  114. {
  115. eax_validate_range<DistortionCommitter::Exception>(
  116. "Low-pass Cut-off",
  117. flLowPassCutOff,
  118. EAXDISTORTION_MINLOWPASSCUTOFF,
  119. EAXDISTORTION_MAXLOWPASSCUTOFF);
  120. }
  121. }; // LowPassCutOffValidator
  122. struct EqCenterValidator {
  123. void operator()(float flEQCenter) const
  124. {
  125. eax_validate_range<DistortionCommitter::Exception>(
  126. "EQ Center",
  127. flEQCenter,
  128. EAXDISTORTION_MINEQCENTER,
  129. EAXDISTORTION_MAXEQCENTER);
  130. }
  131. }; // EqCenterValidator
  132. struct EqBandwidthValidator {
  133. void operator()(float flEQBandwidth) const
  134. {
  135. eax_validate_range<DistortionCommitter::Exception>(
  136. "EQ Bandwidth",
  137. flEQBandwidth,
  138. EAXDISTORTION_MINEQBANDWIDTH,
  139. EAXDISTORTION_MAXEQBANDWIDTH);
  140. }
  141. }; // EqBandwidthValidator
  142. struct AllValidator {
  143. void operator()(const EAXDISTORTIONPROPERTIES& all) const
  144. {
  145. EdgeValidator{}(all.flEdge);
  146. GainValidator{}(all.lGain);
  147. LowPassCutOffValidator{}(all.flLowPassCutOff);
  148. EqCenterValidator{}(all.flEQCenter);
  149. EqBandwidthValidator{}(all.flEQBandwidth);
  150. }
  151. }; // AllValidator
  152. } // namespace
  153. template<>
  154. struct DistortionCommitter::Exception : public EaxException {
  155. explicit Exception(const char *message) : EaxException{"EAX_DISTORTION_EFFECT", message}
  156. { }
  157. };
  158. template<>
  159. [[noreturn]] void DistortionCommitter::fail(const char *message)
  160. {
  161. throw Exception{message};
  162. }
  163. bool EaxDistortionCommitter::commit(const EAXDISTORTIONPROPERTIES &props)
  164. {
  165. if(auto *cur = std::get_if<EAXDISTORTIONPROPERTIES>(&mEaxProps); cur && *cur == props)
  166. return false;
  167. mEaxProps = props;
  168. mAlProps = [&]{
  169. DistortionProps ret{};
  170. ret.Edge = props.flEdge;
  171. ret.Gain = level_mb_to_gain(static_cast<float>(props.lGain));
  172. ret.LowpassCutoff = props.flLowPassCutOff;
  173. ret.EQCenter = props.flEQCenter;
  174. ret.EQBandwidth = props.flEdge;
  175. return ret;
  176. }();
  177. return true;
  178. }
  179. void EaxDistortionCommitter::SetDefaults(EaxEffectProps &props)
  180. {
  181. static constexpr EAXDISTORTIONPROPERTIES defprops{[]
  182. {
  183. EAXDISTORTIONPROPERTIES ret{};
  184. ret.flEdge = EAXDISTORTION_DEFAULTEDGE;
  185. ret.lGain = EAXDISTORTION_DEFAULTGAIN;
  186. ret.flLowPassCutOff = EAXDISTORTION_DEFAULTLOWPASSCUTOFF;
  187. ret.flEQCenter = EAXDISTORTION_DEFAULTEQCENTER;
  188. ret.flEQBandwidth = EAXDISTORTION_DEFAULTEQBANDWIDTH;
  189. return ret;
  190. }()};
  191. props = defprops;
  192. }
  193. void EaxDistortionCommitter::Get(const EaxCall &call, const EAXDISTORTIONPROPERTIES &props)
  194. {
  195. switch(call.get_property_id())
  196. {
  197. case EAXDISTORTION_NONE: break;
  198. case EAXDISTORTION_ALLPARAMETERS: call.set_value<Exception>(props); break;
  199. case EAXDISTORTION_EDGE: call.set_value<Exception>(props.flEdge); break;
  200. case EAXDISTORTION_GAIN: call.set_value<Exception>(props.lGain); break;
  201. case EAXDISTORTION_LOWPASSCUTOFF: call.set_value<Exception>(props.flLowPassCutOff); break;
  202. case EAXDISTORTION_EQCENTER: call.set_value<Exception>(props.flEQCenter); break;
  203. case EAXDISTORTION_EQBANDWIDTH: call.set_value<Exception>(props.flEQBandwidth); break;
  204. default: fail_unknown_property_id();
  205. }
  206. }
  207. void EaxDistortionCommitter::Set(const EaxCall &call, EAXDISTORTIONPROPERTIES &props)
  208. {
  209. switch(call.get_property_id())
  210. {
  211. case EAXDISTORTION_NONE: break;
  212. case EAXDISTORTION_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  213. case EAXDISTORTION_EDGE: defer<EdgeValidator>(call, props.flEdge); break;
  214. case EAXDISTORTION_GAIN: defer<GainValidator>(call, props.lGain); break;
  215. case EAXDISTORTION_LOWPASSCUTOFF: defer<LowPassCutOffValidator>(call, props.flLowPassCutOff); break;
  216. case EAXDISTORTION_EQCENTER: defer<EqCenterValidator>(call, props.flEQCenter); break;
  217. case EAXDISTORTION_EQBANDWIDTH: defer<EqBandwidthValidator>(call, props.flEQBandwidth); break;
  218. default: fail_unknown_property_id();
  219. }
  220. }
  221. #endif // ALSOFT_EAX