modulator.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include "config.h"
  2. #include <optional>
  3. #include <stdexcept>
  4. #include "AL/al.h"
  5. #include "AL/efx.h"
  6. #include "alc/effects/base.h"
  7. #include "effects.h"
  8. #ifdef ALSOFT_EAX
  9. #include <cassert>
  10. #include "alnumeric.h"
  11. #include "al/eax/effect.h"
  12. #include "al/eax/exception.h"
  13. #include "al/eax/utils.h"
  14. #endif // ALSOFT_EAX
  15. namespace {
  16. constexpr std::optional<ModulatorWaveform> WaveformFromEmum(ALenum value) noexcept
  17. {
  18. switch(value)
  19. {
  20. case AL_RING_MODULATOR_SINUSOID: return ModulatorWaveform::Sinusoid;
  21. case AL_RING_MODULATOR_SAWTOOTH: return ModulatorWaveform::Sawtooth;
  22. case AL_RING_MODULATOR_SQUARE: return ModulatorWaveform::Square;
  23. }
  24. return std::nullopt;
  25. }
  26. constexpr ALenum EnumFromWaveform(ModulatorWaveform type)
  27. {
  28. switch(type)
  29. {
  30. case ModulatorWaveform::Sinusoid: return AL_RING_MODULATOR_SINUSOID;
  31. case ModulatorWaveform::Sawtooth: return AL_RING_MODULATOR_SAWTOOTH;
  32. case ModulatorWaveform::Square: return AL_RING_MODULATOR_SQUARE;
  33. }
  34. throw std::runtime_error{"Invalid modulator waveform: " +
  35. std::to_string(static_cast<int>(type))};
  36. }
  37. constexpr EffectProps genDefaultProps() noexcept
  38. {
  39. ModulatorProps props{};
  40. props.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
  41. props.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
  42. props.Waveform = WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM).value();
  43. return props;
  44. }
  45. } // namespace
  46. const EffectProps ModulatorEffectProps{genDefaultProps()};
  47. void ModulatorEffectHandler::SetParami(ModulatorProps &props, ALenum param, int val)
  48. {
  49. switch(param)
  50. {
  51. case AL_RING_MODULATOR_FREQUENCY:
  52. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  53. SetParamf(props, param, static_cast<float>(val));
  54. break;
  55. case AL_RING_MODULATOR_WAVEFORM:
  56. if(auto formopt = WaveformFromEmum(val))
  57. props.Waveform = *formopt;
  58. else
  59. throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
  60. break;
  61. default:
  62. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
  63. param};
  64. }
  65. }
  66. void ModulatorEffectHandler::SetParamiv(ModulatorProps &props, ALenum param, const int *vals)
  67. { SetParami(props, param, *vals); }
  68. void ModulatorEffectHandler::SetParamf(ModulatorProps &props, ALenum param, float val)
  69. {
  70. switch(param)
  71. {
  72. case AL_RING_MODULATOR_FREQUENCY:
  73. if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
  74. throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
  75. props.Frequency = val;
  76. break;
  77. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  78. if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
  79. throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
  80. props.HighPassCutoff = val;
  81. break;
  82. default:
  83. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
  84. }
  85. }
  86. void ModulatorEffectHandler::SetParamfv(ModulatorProps &props, ALenum param, const float *vals)
  87. { SetParamf(props, param, *vals); }
  88. void ModulatorEffectHandler::GetParami(const ModulatorProps &props, ALenum param, int *val)
  89. {
  90. switch(param)
  91. {
  92. case AL_RING_MODULATOR_FREQUENCY: *val = static_cast<int>(props.Frequency); break;
  93. case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = static_cast<int>(props.HighPassCutoff); break;
  94. case AL_RING_MODULATOR_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
  95. default:
  96. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
  97. param};
  98. }
  99. }
  100. void ModulatorEffectHandler::GetParamiv(const ModulatorProps &props, ALenum param, int *vals)
  101. { GetParami(props, param, vals); }
  102. void ModulatorEffectHandler::GetParamf(const ModulatorProps &props, ALenum param, float *val)
  103. {
  104. switch(param)
  105. {
  106. case AL_RING_MODULATOR_FREQUENCY: *val = props.Frequency; break;
  107. case AL_RING_MODULATOR_HIGHPASS_CUTOFF: *val = props.HighPassCutoff; break;
  108. default:
  109. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
  110. }
  111. }
  112. void ModulatorEffectHandler::GetParamfv(const ModulatorProps &props, ALenum param, float *vals)
  113. { GetParamf(props, param, vals); }
  114. #ifdef ALSOFT_EAX
  115. namespace {
  116. using ModulatorCommitter = EaxCommitter<EaxModulatorCommitter>;
  117. struct FrequencyValidator {
  118. void operator()(float flFrequency) const
  119. {
  120. eax_validate_range<ModulatorCommitter::Exception>(
  121. "Frequency",
  122. flFrequency,
  123. EAXRINGMODULATOR_MINFREQUENCY,
  124. EAXRINGMODULATOR_MAXFREQUENCY);
  125. }
  126. }; // FrequencyValidator
  127. struct HighPassCutOffValidator {
  128. void operator()(float flHighPassCutOff) const
  129. {
  130. eax_validate_range<ModulatorCommitter::Exception>(
  131. "High-Pass Cutoff",
  132. flHighPassCutOff,
  133. EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
  134. EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
  135. }
  136. }; // HighPassCutOffValidator
  137. struct WaveformValidator {
  138. void operator()(unsigned long ulWaveform) const
  139. {
  140. eax_validate_range<ModulatorCommitter::Exception>(
  141. "Waveform",
  142. ulWaveform,
  143. EAXRINGMODULATOR_MINWAVEFORM,
  144. EAXRINGMODULATOR_MAXWAVEFORM);
  145. }
  146. }; // WaveformValidator
  147. struct AllValidator {
  148. void operator()(const EAXRINGMODULATORPROPERTIES& all) const
  149. {
  150. FrequencyValidator{}(all.flFrequency);
  151. HighPassCutOffValidator{}(all.flHighPassCutOff);
  152. WaveformValidator{}(all.ulWaveform);
  153. }
  154. }; // AllValidator
  155. } // namespace
  156. template<>
  157. struct ModulatorCommitter::Exception : public EaxException {
  158. explicit Exception(const char *message) : EaxException{"EAX_RING_MODULATOR_EFFECT", message}
  159. { }
  160. };
  161. template<>
  162. [[noreturn]] void ModulatorCommitter::fail(const char *message)
  163. {
  164. throw Exception{message};
  165. }
  166. bool EaxModulatorCommitter::commit(const EAXRINGMODULATORPROPERTIES &props)
  167. {
  168. if(auto *cur = std::get_if<EAXRINGMODULATORPROPERTIES>(&mEaxProps); cur && *cur == props)
  169. return false;
  170. mEaxProps = props;
  171. auto get_waveform = [](unsigned long form)
  172. {
  173. if(form == EAX_RINGMODULATOR_SINUSOID)
  174. return ModulatorWaveform::Sinusoid;
  175. if(form == EAX_RINGMODULATOR_SAWTOOTH)
  176. return ModulatorWaveform::Sawtooth;
  177. if(form == EAX_RINGMODULATOR_SQUARE)
  178. return ModulatorWaveform::Square;
  179. return ModulatorWaveform::Sinusoid;
  180. };
  181. mAlProps = [&]{
  182. ModulatorProps ret{};
  183. ret.Frequency = props.flFrequency;
  184. ret.HighPassCutoff = props.flHighPassCutOff;
  185. ret.Waveform = get_waveform(props.ulWaveform);
  186. return ret;
  187. }();
  188. return true;
  189. }
  190. void EaxModulatorCommitter::SetDefaults(EaxEffectProps &props)
  191. {
  192. static constexpr EAXRINGMODULATORPROPERTIES defprops{[]
  193. {
  194. EAXRINGMODULATORPROPERTIES ret{};
  195. ret.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
  196. ret.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
  197. ret.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
  198. return ret;
  199. }()};
  200. props = defprops;
  201. }
  202. void EaxModulatorCommitter::Get(const EaxCall &call, const EAXRINGMODULATORPROPERTIES &props)
  203. {
  204. switch(call.get_property_id())
  205. {
  206. case EAXRINGMODULATOR_NONE: break;
  207. case EAXRINGMODULATOR_ALLPARAMETERS: call.set_value<Exception>(props); break;
  208. case EAXRINGMODULATOR_FREQUENCY: call.set_value<Exception>(props.flFrequency); break;
  209. case EAXRINGMODULATOR_HIGHPASSCUTOFF: call.set_value<Exception>(props.flHighPassCutOff); break;
  210. case EAXRINGMODULATOR_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
  211. default: fail_unknown_property_id();
  212. }
  213. }
  214. void EaxModulatorCommitter::Set(const EaxCall &call, EAXRINGMODULATORPROPERTIES &props)
  215. {
  216. switch(call.get_property_id())
  217. {
  218. case EAXRINGMODULATOR_NONE: break;
  219. case EAXRINGMODULATOR_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  220. case EAXRINGMODULATOR_FREQUENCY: defer<FrequencyValidator>(call, props.flFrequency); break;
  221. case EAXRINGMODULATOR_HIGHPASSCUTOFF: defer<HighPassCutOffValidator>(call, props.flHighPassCutOff); break;
  222. case EAXRINGMODULATOR_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
  223. default: fail_unknown_property_id();
  224. }
  225. }
  226. #endif // ALSOFT_EAX