echo.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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. static_assert(EchoMaxDelay >= AL_ECHO_MAX_DELAY, "Echo max delay too short");
  14. static_assert(EchoMaxLRDelay >= AL_ECHO_MAX_LRDELAY, "Echo max left-right delay too short");
  15. constexpr EffectProps genDefaultProps() noexcept
  16. {
  17. EchoProps props{};
  18. props.Delay = AL_ECHO_DEFAULT_DELAY;
  19. props.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
  20. props.Damping = AL_ECHO_DEFAULT_DAMPING;
  21. props.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
  22. props.Spread = AL_ECHO_DEFAULT_SPREAD;
  23. return props;
  24. }
  25. } // namespace
  26. const EffectProps EchoEffectProps{genDefaultProps()};
  27. void EchoEffectHandler::SetParami(EchoProps&, ALenum param, int)
  28. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
  29. void EchoEffectHandler::SetParamiv(EchoProps&, ALenum param, const int*)
  30. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
  31. void EchoEffectHandler::SetParamf(EchoProps &props, ALenum param, float val)
  32. {
  33. switch(param)
  34. {
  35. case AL_ECHO_DELAY:
  36. if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
  37. throw effect_exception{AL_INVALID_VALUE, "Echo delay out of range"};
  38. props.Delay = val;
  39. break;
  40. case AL_ECHO_LRDELAY:
  41. if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
  42. throw effect_exception{AL_INVALID_VALUE, "Echo LR delay out of range"};
  43. props.LRDelay = val;
  44. break;
  45. case AL_ECHO_DAMPING:
  46. if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
  47. throw effect_exception{AL_INVALID_VALUE, "Echo damping out of range"};
  48. props.Damping = val;
  49. break;
  50. case AL_ECHO_FEEDBACK:
  51. if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
  52. throw effect_exception{AL_INVALID_VALUE, "Echo feedback out of range"};
  53. props.Feedback = val;
  54. break;
  55. case AL_ECHO_SPREAD:
  56. if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
  57. throw effect_exception{AL_INVALID_VALUE, "Echo spread out of range"};
  58. props.Spread = val;
  59. break;
  60. default:
  61. throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
  62. }
  63. }
  64. void EchoEffectHandler::SetParamfv(EchoProps &props, ALenum param, const float *vals)
  65. { SetParamf(props, param, *vals); }
  66. void EchoEffectHandler::GetParami(const EchoProps&, ALenum param, int*)
  67. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
  68. void EchoEffectHandler::GetParamiv(const EchoProps&, ALenum param, int*)
  69. { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param}; }
  70. void EchoEffectHandler::GetParamf(const EchoProps &props, ALenum param, float *val)
  71. {
  72. switch(param)
  73. {
  74. case AL_ECHO_DELAY: *val = props.Delay; break;
  75. case AL_ECHO_LRDELAY: *val = props.LRDelay; break;
  76. case AL_ECHO_DAMPING: *val = props.Damping; break;
  77. case AL_ECHO_FEEDBACK: *val = props.Feedback; break;
  78. case AL_ECHO_SPREAD: *val = props.Spread; break;
  79. default:
  80. throw effect_exception{AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param};
  81. }
  82. }
  83. void EchoEffectHandler::GetParamfv(const EchoProps &props, ALenum param, float *vals)
  84. { GetParamf(props, param, vals); }
  85. #ifdef ALSOFT_EAX
  86. namespace {
  87. using EchoCommitter = EaxCommitter<EaxEchoCommitter>;
  88. struct DelayValidator {
  89. void operator()(float flDelay) const
  90. {
  91. eax_validate_range<EchoCommitter::Exception>(
  92. "Delay",
  93. flDelay,
  94. EAXECHO_MINDELAY,
  95. EAXECHO_MAXDELAY);
  96. }
  97. }; // DelayValidator
  98. struct LrDelayValidator {
  99. void operator()(float flLRDelay) const
  100. {
  101. eax_validate_range<EchoCommitter::Exception>(
  102. "LR Delay",
  103. flLRDelay,
  104. EAXECHO_MINLRDELAY,
  105. EAXECHO_MAXLRDELAY);
  106. }
  107. }; // LrDelayValidator
  108. struct DampingValidator {
  109. void operator()(float flDamping) const
  110. {
  111. eax_validate_range<EchoCommitter::Exception>(
  112. "Damping",
  113. flDamping,
  114. EAXECHO_MINDAMPING,
  115. EAXECHO_MAXDAMPING);
  116. }
  117. }; // DampingValidator
  118. struct FeedbackValidator {
  119. void operator()(float flFeedback) const
  120. {
  121. eax_validate_range<EchoCommitter::Exception>(
  122. "Feedback",
  123. flFeedback,
  124. EAXECHO_MINFEEDBACK,
  125. EAXECHO_MAXFEEDBACK);
  126. }
  127. }; // FeedbackValidator
  128. struct SpreadValidator {
  129. void operator()(float flSpread) const
  130. {
  131. eax_validate_range<EchoCommitter::Exception>(
  132. "Spread",
  133. flSpread,
  134. EAXECHO_MINSPREAD,
  135. EAXECHO_MAXSPREAD);
  136. }
  137. }; // SpreadValidator
  138. struct AllValidator {
  139. void operator()(const EAXECHOPROPERTIES& all) const
  140. {
  141. DelayValidator{}(all.flDelay);
  142. LrDelayValidator{}(all.flLRDelay);
  143. DampingValidator{}(all.flDamping);
  144. FeedbackValidator{}(all.flFeedback);
  145. SpreadValidator{}(all.flSpread);
  146. }
  147. }; // AllValidator
  148. } // namespace
  149. template<>
  150. struct EchoCommitter::Exception : public EaxException {
  151. explicit Exception(const char* message) : EaxException{"EAX_ECHO_EFFECT", message}
  152. { }
  153. };
  154. template<>
  155. [[noreturn]] void EchoCommitter::fail(const char *message)
  156. {
  157. throw Exception{message};
  158. }
  159. bool EaxEchoCommitter::commit(const EAXECHOPROPERTIES &props)
  160. {
  161. if(auto *cur = std::get_if<EAXECHOPROPERTIES>(&mEaxProps); cur && *cur == props)
  162. return false;
  163. mEaxProps = props;
  164. mAlProps = [&]{
  165. EchoProps ret{};
  166. ret.Delay = props.flDelay;
  167. ret.LRDelay = props.flLRDelay;
  168. ret.Damping = props.flDamping;
  169. ret.Feedback = props.flFeedback;
  170. ret.Spread = props.flSpread;
  171. return ret;
  172. }();
  173. return true;
  174. }
  175. void EaxEchoCommitter::SetDefaults(EaxEffectProps &props)
  176. {
  177. static constexpr EAXECHOPROPERTIES defprops{[]
  178. {
  179. EAXECHOPROPERTIES ret{};
  180. ret.flDelay = EAXECHO_DEFAULTDELAY;
  181. ret.flLRDelay = EAXECHO_DEFAULTLRDELAY;
  182. ret.flDamping = EAXECHO_DEFAULTDAMPING;
  183. ret.flFeedback = EAXECHO_DEFAULTFEEDBACK;
  184. ret.flSpread = EAXECHO_DEFAULTSPREAD;
  185. return ret;
  186. }()};
  187. props = defprops;
  188. }
  189. void EaxEchoCommitter::Get(const EaxCall &call, const EAXECHOPROPERTIES &props)
  190. {
  191. switch(call.get_property_id())
  192. {
  193. case EAXECHO_NONE: break;
  194. case EAXECHO_ALLPARAMETERS: call.set_value<Exception>(props); break;
  195. case EAXECHO_DELAY: call.set_value<Exception>(props.flDelay); break;
  196. case EAXECHO_LRDELAY: call.set_value<Exception>(props.flLRDelay); break;
  197. case EAXECHO_DAMPING: call.set_value<Exception>(props.flDamping); break;
  198. case EAXECHO_FEEDBACK: call.set_value<Exception>(props.flFeedback); break;
  199. case EAXECHO_SPREAD: call.set_value<Exception>(props.flSpread); break;
  200. default: fail_unknown_property_id();
  201. }
  202. }
  203. void EaxEchoCommitter::Set(const EaxCall &call, EAXECHOPROPERTIES &props)
  204. {
  205. switch(call.get_property_id())
  206. {
  207. case EAXECHO_NONE: break;
  208. case EAXECHO_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  209. case EAXECHO_DELAY: defer<DelayValidator>(call, props.flDelay); break;
  210. case EAXECHO_LRDELAY: defer<LrDelayValidator>(call, props.flLRDelay); break;
  211. case EAXECHO_DAMPING: defer<DampingValidator>(call, props.flDamping); break;
  212. case EAXECHO_FEEDBACK: defer<FeedbackValidator>(call, props.flFeedback); break;
  213. case EAXECHO_SPREAD: defer<SpreadValidator>(call, props.flSpread); break;
  214. default: fail_unknown_property_id();
  215. }
  216. }
  217. #endif // ALSOFT_EAX