🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

482 lines
13 KiB

  1. #include "config.h"
  2. #include <stdexcept>
  3. #include "AL/al.h"
  4. #include "AL/efx.h"
  5. #include "alc/effects/base.h"
  6. #include "aloptional.h"
  7. #include "effects.h"
  8. #ifdef ALSOFT_EAX
  9. #include <cassert>
  10. #include "alnumeric.h"
  11. #include "al/eax_exception.h"
  12. #include "al/eax_utils.h"
  13. #endif // ALSOFT_EAX
  14. namespace {
  15. al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
  16. {
  17. switch(value)
  18. {
  19. case AL_RING_MODULATOR_SINUSOID: return al::make_optional(ModulatorWaveform::Sinusoid);
  20. case AL_RING_MODULATOR_SAWTOOTH: return al::make_optional(ModulatorWaveform::Sawtooth);
  21. case AL_RING_MODULATOR_SQUARE: return al::make_optional(ModulatorWaveform::Square);
  22. }
  23. return al::nullopt;
  24. }
  25. ALenum EnumFromWaveform(ModulatorWaveform type)
  26. {
  27. switch(type)
  28. {
  29. case ModulatorWaveform::Sinusoid: return AL_RING_MODULATOR_SINUSOID;
  30. case ModulatorWaveform::Sawtooth: return AL_RING_MODULATOR_SAWTOOTH;
  31. case ModulatorWaveform::Square: return AL_RING_MODULATOR_SQUARE;
  32. }
  33. throw std::runtime_error{"Invalid modulator waveform: " +
  34. std::to_string(static_cast<int>(type))};
  35. }
  36. void Modulator_setParamf(EffectProps *props, ALenum param, float val)
  37. {
  38. switch(param)
  39. {
  40. case AL_RING_MODULATOR_FREQUENCY:
  41. if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
  42. throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
  43. props->Modulator.Frequency = val;
  44. break;
  45. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  46. if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
  47. throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
  48. props->Modulator.HighPassCutoff = val;
  49. break;
  50. default:
  51. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
  52. }
  53. }
  54. void Modulator_setParamfv(EffectProps *props, ALenum param, const float *vals)
  55. { Modulator_setParamf(props, param, vals[0]); }
  56. void Modulator_setParami(EffectProps *props, ALenum param, int val)
  57. {
  58. switch(param)
  59. {
  60. case AL_RING_MODULATOR_FREQUENCY:
  61. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  62. Modulator_setParamf(props, param, static_cast<float>(val));
  63. break;
  64. case AL_RING_MODULATOR_WAVEFORM:
  65. if(auto formopt = WaveformFromEmum(val))
  66. props->Modulator.Waveform = *formopt;
  67. else
  68. throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
  69. break;
  70. default:
  71. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
  72. param};
  73. }
  74. }
  75. void Modulator_setParamiv(EffectProps *props, ALenum param, const int *vals)
  76. { Modulator_setParami(props, param, vals[0]); }
  77. void Modulator_getParami(const EffectProps *props, ALenum param, int *val)
  78. {
  79. switch(param)
  80. {
  81. case AL_RING_MODULATOR_FREQUENCY:
  82. *val = static_cast<int>(props->Modulator.Frequency);
  83. break;
  84. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  85. *val = static_cast<int>(props->Modulator.HighPassCutoff);
  86. break;
  87. case AL_RING_MODULATOR_WAVEFORM:
  88. *val = EnumFromWaveform(props->Modulator.Waveform);
  89. break;
  90. default:
  91. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x",
  92. param};
  93. }
  94. }
  95. void Modulator_getParamiv(const EffectProps *props, ALenum param, int *vals)
  96. { Modulator_getParami(props, param, vals); }
  97. void Modulator_getParamf(const EffectProps *props, ALenum param, float *val)
  98. {
  99. switch(param)
  100. {
  101. case AL_RING_MODULATOR_FREQUENCY:
  102. *val = props->Modulator.Frequency;
  103. break;
  104. case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
  105. *val = props->Modulator.HighPassCutoff;
  106. break;
  107. default:
  108. throw effect_exception{AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param};
  109. }
  110. }
  111. void Modulator_getParamfv(const EffectProps *props, ALenum param, float *vals)
  112. { Modulator_getParamf(props, param, vals); }
  113. EffectProps genDefaultProps() noexcept
  114. {
  115. EffectProps props{};
  116. props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
  117. props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
  118. props.Modulator.Waveform = *WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM);
  119. return props;
  120. }
  121. } // namespace
  122. DEFINE_ALEFFECT_VTABLE(Modulator);
  123. const EffectProps ModulatorEffectProps{genDefaultProps()};
  124. #ifdef ALSOFT_EAX
  125. namespace {
  126. using EaxRingModulatorEffectDirtyFlagsValue = std::uint_least8_t;
  127. struct EaxRingModulatorEffectDirtyFlags
  128. {
  129. using EaxIsBitFieldStruct = bool;
  130. EaxRingModulatorEffectDirtyFlagsValue flFrequency : 1;
  131. EaxRingModulatorEffectDirtyFlagsValue flHighPassCutOff : 1;
  132. EaxRingModulatorEffectDirtyFlagsValue ulWaveform : 1;
  133. }; // EaxPitchShifterEffectDirtyFlags
  134. class EaxRingModulatorEffect final :
  135. public EaxEffect
  136. {
  137. public:
  138. EaxRingModulatorEffect();
  139. void dispatch(const EaxEaxCall& eax_call) override;
  140. // [[nodiscard]]
  141. bool apply_deferred() override;
  142. private:
  143. EAXRINGMODULATORPROPERTIES eax_{};
  144. EAXRINGMODULATORPROPERTIES eax_d_{};
  145. EaxRingModulatorEffectDirtyFlags eax_dirty_flags_{};
  146. void set_eax_defaults();
  147. void set_efx_frequency();
  148. void set_efx_high_pass_cutoff();
  149. void set_efx_waveform();
  150. void set_efx_defaults();
  151. void get(const EaxEaxCall& eax_call);
  152. void validate_frequency(float flFrequency);
  153. void validate_high_pass_cutoff(float flHighPassCutOff);
  154. void validate_waveform(unsigned long ulWaveform);
  155. void validate_all(const EAXRINGMODULATORPROPERTIES& all);
  156. void defer_frequency(float flFrequency);
  157. void defer_high_pass_cutoff(float flHighPassCutOff);
  158. void defer_waveform(unsigned long ulWaveform);
  159. void defer_all(const EAXRINGMODULATORPROPERTIES& all);
  160. void defer_frequency(const EaxEaxCall& eax_call);
  161. void defer_high_pass_cutoff(const EaxEaxCall& eax_call);
  162. void defer_waveform(const EaxEaxCall& eax_call);
  163. void defer_all(const EaxEaxCall& eax_call);
  164. void set(const EaxEaxCall& eax_call);
  165. }; // EaxRingModulatorEffect
  166. class EaxRingModulatorEffectException :
  167. public EaxException
  168. {
  169. public:
  170. explicit EaxRingModulatorEffectException(
  171. const char* message)
  172. :
  173. EaxException{"EAX_RING_MODULATOR_EFFECT", message}
  174. {
  175. }
  176. }; // EaxRingModulatorEffectException
  177. EaxRingModulatorEffect::EaxRingModulatorEffect()
  178. : EaxEffect{AL_EFFECT_RING_MODULATOR}
  179. {
  180. set_eax_defaults();
  181. set_efx_defaults();
  182. }
  183. void EaxRingModulatorEffect::dispatch(const EaxEaxCall& eax_call)
  184. {
  185. eax_call.is_get() ? get(eax_call) : set(eax_call);
  186. }
  187. void EaxRingModulatorEffect::set_eax_defaults()
  188. {
  189. eax_.flFrequency = EAXRINGMODULATOR_DEFAULTFREQUENCY;
  190. eax_.flHighPassCutOff = EAXRINGMODULATOR_DEFAULTHIGHPASSCUTOFF;
  191. eax_.ulWaveform = EAXRINGMODULATOR_DEFAULTWAVEFORM;
  192. eax_d_ = eax_;
  193. }
  194. void EaxRingModulatorEffect::set_efx_frequency()
  195. {
  196. const auto frequency = clamp(
  197. eax_.flFrequency,
  198. AL_RING_MODULATOR_MIN_FREQUENCY,
  199. AL_RING_MODULATOR_MAX_FREQUENCY);
  200. al_effect_props_.Modulator.Frequency = frequency;
  201. }
  202. void EaxRingModulatorEffect::set_efx_high_pass_cutoff()
  203. {
  204. const auto high_pass_cutoff = clamp(
  205. eax_.flHighPassCutOff,
  206. AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF,
  207. AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF);
  208. al_effect_props_.Modulator.HighPassCutoff = high_pass_cutoff;
  209. }
  210. void EaxRingModulatorEffect::set_efx_waveform()
  211. {
  212. const auto waveform = clamp(
  213. static_cast<ALint>(eax_.ulWaveform),
  214. AL_RING_MODULATOR_MIN_WAVEFORM,
  215. AL_RING_MODULATOR_MAX_WAVEFORM);
  216. const auto efx_waveform = WaveformFromEmum(waveform);
  217. assert(efx_waveform.has_value());
  218. al_effect_props_.Modulator.Waveform = *efx_waveform;
  219. }
  220. void EaxRingModulatorEffect::set_efx_defaults()
  221. {
  222. set_efx_frequency();
  223. set_efx_high_pass_cutoff();
  224. set_efx_waveform();
  225. }
  226. void EaxRingModulatorEffect::get(const EaxEaxCall& eax_call)
  227. {
  228. switch(eax_call.get_property_id())
  229. {
  230. case EAXRINGMODULATOR_NONE:
  231. break;
  232. case EAXRINGMODULATOR_ALLPARAMETERS:
  233. eax_call.set_value<EaxRingModulatorEffectException>(eax_);
  234. break;
  235. case EAXRINGMODULATOR_FREQUENCY:
  236. eax_call.set_value<EaxRingModulatorEffectException>(eax_.flFrequency);
  237. break;
  238. case EAXRINGMODULATOR_HIGHPASSCUTOFF:
  239. eax_call.set_value<EaxRingModulatorEffectException>(eax_.flHighPassCutOff);
  240. break;
  241. case EAXRINGMODULATOR_WAVEFORM:
  242. eax_call.set_value<EaxRingModulatorEffectException>(eax_.ulWaveform);
  243. break;
  244. default:
  245. throw EaxRingModulatorEffectException{"Unsupported property id."};
  246. }
  247. }
  248. void EaxRingModulatorEffect::validate_frequency(
  249. float flFrequency)
  250. {
  251. eax_validate_range<EaxRingModulatorEffectException>(
  252. "Frequency",
  253. flFrequency,
  254. EAXRINGMODULATOR_MINFREQUENCY,
  255. EAXRINGMODULATOR_MAXFREQUENCY);
  256. }
  257. void EaxRingModulatorEffect::validate_high_pass_cutoff(
  258. float flHighPassCutOff)
  259. {
  260. eax_validate_range<EaxRingModulatorEffectException>(
  261. "High-Pass Cutoff",
  262. flHighPassCutOff,
  263. EAXRINGMODULATOR_MINHIGHPASSCUTOFF,
  264. EAXRINGMODULATOR_MAXHIGHPASSCUTOFF);
  265. }
  266. void EaxRingModulatorEffect::validate_waveform(
  267. unsigned long ulWaveform)
  268. {
  269. eax_validate_range<EaxRingModulatorEffectException>(
  270. "Waveform",
  271. ulWaveform,
  272. EAXRINGMODULATOR_MINWAVEFORM,
  273. EAXRINGMODULATOR_MAXWAVEFORM);
  274. }
  275. void EaxRingModulatorEffect::validate_all(
  276. const EAXRINGMODULATORPROPERTIES& all)
  277. {
  278. validate_frequency(all.flFrequency);
  279. validate_high_pass_cutoff(all.flHighPassCutOff);
  280. validate_waveform(all.ulWaveform);
  281. }
  282. void EaxRingModulatorEffect::defer_frequency(
  283. float flFrequency)
  284. {
  285. eax_d_.flFrequency = flFrequency;
  286. eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency);
  287. }
  288. void EaxRingModulatorEffect::defer_high_pass_cutoff(
  289. float flHighPassCutOff)
  290. {
  291. eax_d_.flHighPassCutOff = flHighPassCutOff;
  292. eax_dirty_flags_.flHighPassCutOff = (eax_.flHighPassCutOff != eax_d_.flHighPassCutOff);
  293. }
  294. void EaxRingModulatorEffect::defer_waveform(
  295. unsigned long ulWaveform)
  296. {
  297. eax_d_.ulWaveform = ulWaveform;
  298. eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform);
  299. }
  300. void EaxRingModulatorEffect::defer_all(
  301. const EAXRINGMODULATORPROPERTIES& all)
  302. {
  303. defer_frequency(all.flFrequency);
  304. defer_high_pass_cutoff(all.flHighPassCutOff);
  305. defer_waveform(all.ulWaveform);
  306. }
  307. void EaxRingModulatorEffect::defer_frequency(
  308. const EaxEaxCall& eax_call)
  309. {
  310. const auto& frequency =
  311. eax_call.get_value<
  312. EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::flFrequency)>();
  313. validate_frequency(frequency);
  314. defer_frequency(frequency);
  315. }
  316. void EaxRingModulatorEffect::defer_high_pass_cutoff(
  317. const EaxEaxCall& eax_call)
  318. {
  319. const auto& high_pass_cutoff =
  320. eax_call.get_value<
  321. EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::flHighPassCutOff)>();
  322. validate_high_pass_cutoff(high_pass_cutoff);
  323. defer_high_pass_cutoff(high_pass_cutoff);
  324. }
  325. void EaxRingModulatorEffect::defer_waveform(
  326. const EaxEaxCall& eax_call)
  327. {
  328. const auto& waveform =
  329. eax_call.get_value<
  330. EaxRingModulatorEffectException, const decltype(EAXRINGMODULATORPROPERTIES::ulWaveform)>();
  331. validate_waveform(waveform);
  332. defer_waveform(waveform);
  333. }
  334. void EaxRingModulatorEffect::defer_all(
  335. const EaxEaxCall& eax_call)
  336. {
  337. const auto& all =
  338. eax_call.get_value<EaxRingModulatorEffectException, const EAXRINGMODULATORPROPERTIES>();
  339. validate_all(all);
  340. defer_all(all);
  341. }
  342. // [[nodiscard]]
  343. bool EaxRingModulatorEffect::apply_deferred()
  344. {
  345. if (eax_dirty_flags_ == EaxRingModulatorEffectDirtyFlags{})
  346. {
  347. return false;
  348. }
  349. eax_ = eax_d_;
  350. if (eax_dirty_flags_.flFrequency)
  351. {
  352. set_efx_frequency();
  353. }
  354. if (eax_dirty_flags_.flHighPassCutOff)
  355. {
  356. set_efx_high_pass_cutoff();
  357. }
  358. if (eax_dirty_flags_.ulWaveform)
  359. {
  360. set_efx_waveform();
  361. }
  362. eax_dirty_flags_ = EaxRingModulatorEffectDirtyFlags{};
  363. return true;
  364. }
  365. void EaxRingModulatorEffect::set(const EaxEaxCall& eax_call)
  366. {
  367. switch (eax_call.get_property_id())
  368. {
  369. case EAXRINGMODULATOR_NONE:
  370. break;
  371. case EAXRINGMODULATOR_ALLPARAMETERS:
  372. defer_all(eax_call);
  373. break;
  374. case EAXRINGMODULATOR_FREQUENCY:
  375. defer_frequency(eax_call);
  376. break;
  377. case EAXRINGMODULATOR_HIGHPASSCUTOFF:
  378. defer_high_pass_cutoff(eax_call);
  379. break;
  380. case EAXRINGMODULATOR_WAVEFORM:
  381. defer_waveform(eax_call);
  382. break;
  383. default:
  384. throw EaxRingModulatorEffectException{"Unsupported property id."};
  385. }
  386. }
  387. } // namespace
  388. EaxEffectUPtr eax_create_eax_ring_modulator_effect()
  389. {
  390. return std::make_unique<EaxRingModulatorEffect>();
  391. }
  392. #endif // ALSOFT_EAX