distortion.cpp 8.6 KB

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