🛠️🐜 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.

364 lines
9.1 KiB

  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_exception.h"
  9. #include "al/eax_utils.h"
  10. #endif // ALSOFT_EAX
  11. namespace {
  12. void Pshifter_setParamf(EffectProps*, ALenum param, float)
  13. { throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
  14. void Pshifter_setParamfv(EffectProps*, ALenum param, const float*)
  15. {
  16. throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x",
  17. param};
  18. }
  19. void Pshifter_setParami(EffectProps *props, ALenum param, int val)
  20. {
  21. switch(param)
  22. {
  23. case AL_PITCH_SHIFTER_COARSE_TUNE:
  24. if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE))
  25. throw effect_exception{AL_INVALID_VALUE, "Pitch shifter coarse tune out of range"};
  26. props->Pshifter.CoarseTune = val;
  27. break;
  28. case AL_PITCH_SHIFTER_FINE_TUNE:
  29. if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE))
  30. throw effect_exception{AL_INVALID_VALUE, "Pitch shifter fine tune out of range"};
  31. props->Pshifter.FineTune = val;
  32. break;
  33. default:
  34. throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x",
  35. param};
  36. }
  37. }
  38. void Pshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
  39. { Pshifter_setParami(props, param, vals[0]); }
  40. void Pshifter_getParami(const EffectProps *props, ALenum param, int *val)
  41. {
  42. switch(param)
  43. {
  44. case AL_PITCH_SHIFTER_COARSE_TUNE:
  45. *val = props->Pshifter.CoarseTune;
  46. break;
  47. case AL_PITCH_SHIFTER_FINE_TUNE:
  48. *val = props->Pshifter.FineTune;
  49. break;
  50. default:
  51. throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x",
  52. param};
  53. }
  54. }
  55. void Pshifter_getParamiv(const EffectProps *props, ALenum param, int *vals)
  56. { Pshifter_getParami(props, param, vals); }
  57. void Pshifter_getParamf(const EffectProps*, ALenum param, float*)
  58. { throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param}; }
  59. void Pshifter_getParamfv(const EffectProps*, ALenum param, float*)
  60. {
  61. throw effect_exception{AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x",
  62. param};
  63. }
  64. EffectProps genDefaultProps() noexcept
  65. {
  66. EffectProps props{};
  67. props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
  68. props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
  69. return props;
  70. }
  71. } // namespace
  72. DEFINE_ALEFFECT_VTABLE(Pshifter);
  73. const EffectProps PshifterEffectProps{genDefaultProps()};
  74. #ifdef ALSOFT_EAX
  75. namespace {
  76. using EaxPitchShifterEffectDirtyFlagsValue = std::uint_least8_t;
  77. struct EaxPitchShifterEffectDirtyFlags
  78. {
  79. using EaxIsBitFieldStruct = bool;
  80. EaxPitchShifterEffectDirtyFlagsValue lCoarseTune : 1;
  81. EaxPitchShifterEffectDirtyFlagsValue lFineTune : 1;
  82. }; // EaxPitchShifterEffectDirtyFlags
  83. class EaxPitchShifterEffect final :
  84. public EaxEffect
  85. {
  86. public:
  87. EaxPitchShifterEffect();
  88. void dispatch(const EaxEaxCall& eax_call) override;
  89. // [[nodiscard]]
  90. bool apply_deferred() override;
  91. private:
  92. EAXPITCHSHIFTERPROPERTIES eax_{};
  93. EAXPITCHSHIFTERPROPERTIES eax_d_{};
  94. EaxPitchShifterEffectDirtyFlags eax_dirty_flags_{};
  95. void set_eax_defaults();
  96. void set_efx_coarse_tune();
  97. void set_efx_fine_tune();
  98. void set_efx_defaults();
  99. void get(const EaxEaxCall& eax_call);
  100. void validate_coarse_tune(long lCoarseTune);
  101. void validate_fine_tune(long lFineTune);
  102. void validate_all(const EAXPITCHSHIFTERPROPERTIES& all);
  103. void defer_coarse_tune(long lCoarseTune);
  104. void defer_fine_tune(long lFineTune);
  105. void defer_all(const EAXPITCHSHIFTERPROPERTIES& all);
  106. void defer_coarse_tune(const EaxEaxCall& eax_call);
  107. void defer_fine_tune(const EaxEaxCall& eax_call);
  108. void defer_all(const EaxEaxCall& eax_call);
  109. void set(const EaxEaxCall& eax_call);
  110. }; // EaxPitchShifterEffect
  111. class EaxPitchShifterEffectException :
  112. public EaxException
  113. {
  114. public:
  115. explicit EaxPitchShifterEffectException(
  116. const char* message)
  117. :
  118. EaxException{"EAX_PITCH_SHIFTER_EFFECT", message}
  119. {
  120. }
  121. }; // EaxPitchShifterEffectException
  122. EaxPitchShifterEffect::EaxPitchShifterEffect()
  123. : EaxEffect{AL_EFFECT_PITCH_SHIFTER}
  124. {
  125. set_eax_defaults();
  126. set_efx_defaults();
  127. }
  128. void EaxPitchShifterEffect::dispatch(const EaxEaxCall& eax_call)
  129. {
  130. eax_call.is_get() ? get(eax_call) : set(eax_call);
  131. }
  132. void EaxPitchShifterEffect::set_eax_defaults()
  133. {
  134. eax_.lCoarseTune = EAXPITCHSHIFTER_DEFAULTCOARSETUNE;
  135. eax_.lFineTune = EAXPITCHSHIFTER_DEFAULTFINETUNE;
  136. eax_d_ = eax_;
  137. }
  138. void EaxPitchShifterEffect::set_efx_coarse_tune()
  139. {
  140. const auto coarse_tune = clamp(
  141. static_cast<ALint>(eax_.lCoarseTune),
  142. AL_PITCH_SHIFTER_MIN_COARSE_TUNE,
  143. AL_PITCH_SHIFTER_MAX_COARSE_TUNE);
  144. al_effect_props_.Pshifter.CoarseTune = coarse_tune;
  145. }
  146. void EaxPitchShifterEffect::set_efx_fine_tune()
  147. {
  148. const auto fine_tune = clamp(
  149. static_cast<ALint>(eax_.lFineTune),
  150. AL_PITCH_SHIFTER_MIN_FINE_TUNE,
  151. AL_PITCH_SHIFTER_MAX_FINE_TUNE);
  152. al_effect_props_.Pshifter.FineTune = fine_tune;
  153. }
  154. void EaxPitchShifterEffect::set_efx_defaults()
  155. {
  156. set_efx_coarse_tune();
  157. set_efx_fine_tune();
  158. }
  159. void EaxPitchShifterEffect::get(const EaxEaxCall& eax_call)
  160. {
  161. switch(eax_call.get_property_id())
  162. {
  163. case EAXPITCHSHIFTER_NONE:
  164. break;
  165. case EAXPITCHSHIFTER_ALLPARAMETERS:
  166. eax_call.set_value<EaxPitchShifterEffectException>(eax_);
  167. break;
  168. case EAXPITCHSHIFTER_COARSETUNE:
  169. eax_call.set_value<EaxPitchShifterEffectException>(eax_.lCoarseTune);
  170. break;
  171. case EAXPITCHSHIFTER_FINETUNE:
  172. eax_call.set_value<EaxPitchShifterEffectException>(eax_.lFineTune);
  173. break;
  174. default:
  175. throw EaxPitchShifterEffectException{"Unsupported property id."};
  176. }
  177. }
  178. void EaxPitchShifterEffect::validate_coarse_tune(
  179. long lCoarseTune)
  180. {
  181. eax_validate_range<EaxPitchShifterEffectException>(
  182. "Coarse Tune",
  183. lCoarseTune,
  184. EAXPITCHSHIFTER_MINCOARSETUNE,
  185. EAXPITCHSHIFTER_MAXCOARSETUNE);
  186. }
  187. void EaxPitchShifterEffect::validate_fine_tune(
  188. long lFineTune)
  189. {
  190. eax_validate_range<EaxPitchShifterEffectException>(
  191. "Fine Tune",
  192. lFineTune,
  193. EAXPITCHSHIFTER_MINFINETUNE,
  194. EAXPITCHSHIFTER_MAXFINETUNE);
  195. }
  196. void EaxPitchShifterEffect::validate_all(
  197. const EAXPITCHSHIFTERPROPERTIES& all)
  198. {
  199. validate_coarse_tune(all.lCoarseTune);
  200. validate_fine_tune(all.lFineTune);
  201. }
  202. void EaxPitchShifterEffect::defer_coarse_tune(
  203. long lCoarseTune)
  204. {
  205. eax_d_.lCoarseTune = lCoarseTune;
  206. eax_dirty_flags_.lCoarseTune = (eax_.lCoarseTune != eax_d_.lCoarseTune);
  207. }
  208. void EaxPitchShifterEffect::defer_fine_tune(
  209. long lFineTune)
  210. {
  211. eax_d_.lFineTune = lFineTune;
  212. eax_dirty_flags_.lFineTune = (eax_.lFineTune != eax_d_.lFineTune);
  213. }
  214. void EaxPitchShifterEffect::defer_all(
  215. const EAXPITCHSHIFTERPROPERTIES& all)
  216. {
  217. defer_coarse_tune(all.lCoarseTune);
  218. defer_fine_tune(all.lFineTune);
  219. }
  220. void EaxPitchShifterEffect::defer_coarse_tune(
  221. const EaxEaxCall& eax_call)
  222. {
  223. const auto& coarse_tune =
  224. eax_call.get_value<EaxPitchShifterEffectException, const decltype(EAXPITCHSHIFTERPROPERTIES::lCoarseTune)>();
  225. validate_coarse_tune(coarse_tune);
  226. defer_coarse_tune(coarse_tune);
  227. }
  228. void EaxPitchShifterEffect::defer_fine_tune(
  229. const EaxEaxCall& eax_call)
  230. {
  231. const auto& fine_tune =
  232. eax_call.get_value<EaxPitchShifterEffectException, const decltype(EAXPITCHSHIFTERPROPERTIES::lFineTune)>();
  233. validate_fine_tune(fine_tune);
  234. defer_fine_tune(fine_tune);
  235. }
  236. void EaxPitchShifterEffect::defer_all(
  237. const EaxEaxCall& eax_call)
  238. {
  239. const auto& all =
  240. eax_call.get_value<EaxPitchShifterEffectException, const EAXPITCHSHIFTERPROPERTIES>();
  241. validate_all(all);
  242. defer_all(all);
  243. }
  244. // [[nodiscard]]
  245. bool EaxPitchShifterEffect::apply_deferred()
  246. {
  247. if (eax_dirty_flags_ == EaxPitchShifterEffectDirtyFlags{})
  248. {
  249. return false;
  250. }
  251. eax_ = eax_d_;
  252. if (eax_dirty_flags_.lCoarseTune)
  253. {
  254. set_efx_coarse_tune();
  255. }
  256. if (eax_dirty_flags_.lFineTune)
  257. {
  258. set_efx_fine_tune();
  259. }
  260. eax_dirty_flags_ = EaxPitchShifterEffectDirtyFlags{};
  261. return true;
  262. }
  263. void EaxPitchShifterEffect::set(const EaxEaxCall& eax_call)
  264. {
  265. switch(eax_call.get_property_id())
  266. {
  267. case EAXPITCHSHIFTER_NONE:
  268. break;
  269. case EAXPITCHSHIFTER_ALLPARAMETERS:
  270. defer_all(eax_call);
  271. break;
  272. case EAXPITCHSHIFTER_COARSETUNE:
  273. defer_coarse_tune(eax_call);
  274. break;
  275. case EAXPITCHSHIFTER_FINETUNE:
  276. defer_fine_tune(eax_call);
  277. break;
  278. default:
  279. throw EaxPitchShifterEffectException{"Unsupported property id."};
  280. }
  281. }
  282. } // namespace
  283. EaxEffectUPtr eax_create_eax_pitch_shifter_effect()
  284. {
  285. return std::make_unique<EaxPitchShifterEffect>();
  286. }
  287. #endif // ALSOFT_EAX