autowah.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #include "config.h"
  2. #include <cmath>
  3. #include <cstdlib>
  4. #include "AL/efx.h"
  5. #include "alc/context.h"
  6. #include "alnumeric.h"
  7. #include "effects.h"
  8. #if ALSOFT_EAX
  9. #include "al/eax/effect.h"
  10. #include "al/eax/exception.h"
  11. #include "al/eax/utils.h"
  12. #endif // ALSOFT_EAX
  13. namespace {
  14. constexpr EffectProps genDefaultProps() noexcept
  15. {
  16. AutowahProps props{};
  17. props.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
  18. props.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
  19. props.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
  20. props.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
  21. return props;
  22. }
  23. } // namespace
  24. const EffectProps AutowahEffectProps{genDefaultProps()};
  25. void AutowahEffectHandler::SetParami(ALCcontext *context, AutowahProps&, ALenum param, int)
  26. { context->throw_error(AL_INVALID_ENUM, "Invalid autowah integer property {:#04x}", as_unsigned(param)); }
  27. void AutowahEffectHandler::SetParamiv(ALCcontext *context, AutowahProps&, ALenum param, const int*)
  28. { context->throw_error(AL_INVALID_ENUM, "Invalid autowah integer vector property {:#04x}", as_unsigned(param)); }
  29. void AutowahEffectHandler::SetParamf(ALCcontext *context, AutowahProps &props, ALenum param, float val)
  30. {
  31. switch(param)
  32. {
  33. case AL_AUTOWAH_ATTACK_TIME:
  34. if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME))
  35. context->throw_error(AL_INVALID_VALUE, "Autowah attack time out of range");
  36. props.AttackTime = val;
  37. return;
  38. case AL_AUTOWAH_RELEASE_TIME:
  39. if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME))
  40. context->throw_error(AL_INVALID_VALUE, "Autowah release time out of range");
  41. props.ReleaseTime = val;
  42. return;
  43. case AL_AUTOWAH_RESONANCE:
  44. if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE))
  45. context->throw_error(AL_INVALID_VALUE, "Autowah resonance out of range");
  46. props.Resonance = val;
  47. return;
  48. case AL_AUTOWAH_PEAK_GAIN:
  49. if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN))
  50. context->throw_error(AL_INVALID_VALUE, "Autowah peak gain out of range");
  51. props.PeakGain = val;
  52. return;
  53. }
  54. context->throw_error(AL_INVALID_ENUM, "Invalid autowah float property {:#04x}",
  55. as_unsigned(param));
  56. }
  57. void AutowahEffectHandler::SetParamfv(ALCcontext *context, AutowahProps &props, ALenum param, const float *vals)
  58. { SetParamf(context, props, param, *vals); }
  59. void AutowahEffectHandler::GetParami(ALCcontext *context, const AutowahProps&, ALenum param, int*)
  60. { context->throw_error(AL_INVALID_ENUM, "Invalid autowah integer property {:#04x}", as_unsigned(param)); }
  61. void AutowahEffectHandler::GetParamiv(ALCcontext *context, const AutowahProps&, ALenum param, int*)
  62. { context->throw_error(AL_INVALID_ENUM, "Invalid autowah integer vector property {:#04x}", as_unsigned(param)); }
  63. void AutowahEffectHandler::GetParamf(ALCcontext *context, const AutowahProps &props, ALenum param, float *val)
  64. {
  65. switch(param)
  66. {
  67. case AL_AUTOWAH_ATTACK_TIME: *val = props.AttackTime; return;
  68. case AL_AUTOWAH_RELEASE_TIME: *val = props.ReleaseTime; return;
  69. case AL_AUTOWAH_RESONANCE: *val = props.Resonance; return;
  70. case AL_AUTOWAH_PEAK_GAIN: *val = props.PeakGain; return;
  71. }
  72. context->throw_error(AL_INVALID_ENUM, "Invalid autowah float property {:#04x}",
  73. as_unsigned(param));
  74. }
  75. void AutowahEffectHandler::GetParamfv(ALCcontext *context, const AutowahProps &props, ALenum param, float *vals)
  76. { GetParamf(context, props, param, vals); }
  77. #if ALSOFT_EAX
  78. namespace {
  79. using AutowahCommitter = EaxCommitter<EaxAutowahCommitter>;
  80. struct AttackTimeValidator {
  81. void operator()(float flAttackTime) const
  82. {
  83. eax_validate_range<AutowahCommitter::Exception>(
  84. "Attack Time",
  85. flAttackTime,
  86. EAXAUTOWAH_MINATTACKTIME,
  87. EAXAUTOWAH_MAXATTACKTIME);
  88. }
  89. }; // AttackTimeValidator
  90. struct ReleaseTimeValidator {
  91. void operator()(float flReleaseTime) const
  92. {
  93. eax_validate_range<AutowahCommitter::Exception>(
  94. "Release Time",
  95. flReleaseTime,
  96. EAXAUTOWAH_MINRELEASETIME,
  97. EAXAUTOWAH_MAXRELEASETIME);
  98. }
  99. }; // ReleaseTimeValidator
  100. struct ResonanceValidator {
  101. void operator()(long lResonance) const
  102. {
  103. eax_validate_range<AutowahCommitter::Exception>(
  104. "Resonance",
  105. lResonance,
  106. EAXAUTOWAH_MINRESONANCE,
  107. EAXAUTOWAH_MAXRESONANCE);
  108. }
  109. }; // ResonanceValidator
  110. struct PeakLevelValidator {
  111. void operator()(long lPeakLevel) const
  112. {
  113. eax_validate_range<AutowahCommitter::Exception>(
  114. "Peak Level",
  115. lPeakLevel,
  116. EAXAUTOWAH_MINPEAKLEVEL,
  117. EAXAUTOWAH_MAXPEAKLEVEL);
  118. }
  119. }; // PeakLevelValidator
  120. struct AllValidator {
  121. void operator()(const EAXAUTOWAHPROPERTIES& all) const
  122. {
  123. AttackTimeValidator{}(all.flAttackTime);
  124. ReleaseTimeValidator{}(all.flReleaseTime);
  125. ResonanceValidator{}(all.lResonance);
  126. PeakLevelValidator{}(all.lPeakLevel);
  127. }
  128. }; // AllValidator
  129. } // namespace
  130. template<>
  131. struct AutowahCommitter::Exception : public EaxException
  132. {
  133. explicit Exception(const char *message) : EaxException{"EAX_AUTOWAH_EFFECT", message}
  134. { }
  135. };
  136. template<>
  137. [[noreturn]] void AutowahCommitter::fail(const char *message)
  138. {
  139. throw Exception{message};
  140. }
  141. bool EaxAutowahCommitter::commit(const EAXAUTOWAHPROPERTIES &props)
  142. {
  143. if(auto *cur = std::get_if<EAXAUTOWAHPROPERTIES>(&mEaxProps); cur && *cur == props)
  144. return false;
  145. mEaxProps = props;
  146. mAlProps = [&]{
  147. AutowahProps ret{};
  148. ret.AttackTime = props.flAttackTime;
  149. ret.ReleaseTime = props.flReleaseTime;
  150. ret.Resonance = level_mb_to_gain(static_cast<float>(props.lResonance));
  151. ret.PeakGain = level_mb_to_gain(static_cast<float>(props.lPeakLevel));
  152. return ret;
  153. }();
  154. return true;
  155. }
  156. void EaxAutowahCommitter::SetDefaults(EaxEffectProps &props)
  157. {
  158. static constexpr EAXAUTOWAHPROPERTIES defprops{[]
  159. {
  160. EAXAUTOWAHPROPERTIES ret{};
  161. ret.flAttackTime = EAXAUTOWAH_DEFAULTATTACKTIME;
  162. ret.flReleaseTime = EAXAUTOWAH_DEFAULTRELEASETIME;
  163. ret.lResonance = EAXAUTOWAH_DEFAULTRESONANCE;
  164. ret.lPeakLevel = EAXAUTOWAH_DEFAULTPEAKLEVEL;
  165. return ret;
  166. }()};
  167. props = defprops;
  168. }
  169. void EaxAutowahCommitter::Get(const EaxCall &call, const EAXAUTOWAHPROPERTIES &props)
  170. {
  171. switch(call.get_property_id())
  172. {
  173. case EAXAUTOWAH_NONE: break;
  174. case EAXAUTOWAH_ALLPARAMETERS: call.set_value<Exception>(props); break;
  175. case EAXAUTOWAH_ATTACKTIME: call.set_value<Exception>(props.flAttackTime); break;
  176. case EAXAUTOWAH_RELEASETIME: call.set_value<Exception>(props.flReleaseTime); break;
  177. case EAXAUTOWAH_RESONANCE: call.set_value<Exception>(props.lResonance); break;
  178. case EAXAUTOWAH_PEAKLEVEL: call.set_value<Exception>(props.lPeakLevel); break;
  179. default: fail_unknown_property_id();
  180. }
  181. }
  182. void EaxAutowahCommitter::Set(const EaxCall &call, EAXAUTOWAHPROPERTIES &props)
  183. {
  184. switch(call.get_property_id())
  185. {
  186. case EAXAUTOWAH_NONE: break;
  187. case EAXAUTOWAH_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  188. case EAXAUTOWAH_ATTACKTIME: defer<AttackTimeValidator>(call, props.flAttackTime); break;
  189. case EAXAUTOWAH_RELEASETIME: defer<ReleaseTimeValidator>(call, props.flReleaseTime); break;
  190. case EAXAUTOWAH_RESONANCE: defer<ResonanceValidator>(call, props.lResonance); break;
  191. case EAXAUTOWAH_PEAKLEVEL: defer<PeakLevelValidator>(call, props.lPeakLevel); break;
  192. default: fail_unknown_property_id();
  193. }
  194. }
  195. #endif // ALSOFT_EAX