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

479 lines
14 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<FShifterDirection> DirectionFromEmum(ALenum value)
  16. {
  17. switch(value)
  18. {
  19. case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: return al::make_optional(FShifterDirection::Down);
  20. case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return al::make_optional(FShifterDirection::Up);
  21. case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return al::make_optional(FShifterDirection::Off);
  22. }
  23. return al::nullopt;
  24. }
  25. ALenum EnumFromDirection(FShifterDirection dir)
  26. {
  27. switch(dir)
  28. {
  29. case FShifterDirection::Down: return AL_FREQUENCY_SHIFTER_DIRECTION_DOWN;
  30. case FShifterDirection::Up: return AL_FREQUENCY_SHIFTER_DIRECTION_UP;
  31. case FShifterDirection::Off: return AL_FREQUENCY_SHIFTER_DIRECTION_OFF;
  32. }
  33. throw std::runtime_error{"Invalid direction: "+std::to_string(static_cast<int>(dir))};
  34. }
  35. void Fshifter_setParamf(EffectProps *props, ALenum param, float val)
  36. {
  37. switch(param)
  38. {
  39. case AL_FREQUENCY_SHIFTER_FREQUENCY:
  40. if(!(val >= AL_FREQUENCY_SHIFTER_MIN_FREQUENCY && val <= AL_FREQUENCY_SHIFTER_MAX_FREQUENCY))
  41. throw effect_exception{AL_INVALID_VALUE, "Frequency shifter frequency out of range"};
  42. props->Fshifter.Frequency = val;
  43. break;
  44. default:
  45. throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
  46. param};
  47. }
  48. }
  49. void Fshifter_setParamfv(EffectProps *props, ALenum param, const float *vals)
  50. { Fshifter_setParamf(props, param, vals[0]); }
  51. void Fshifter_setParami(EffectProps *props, ALenum param, int val)
  52. {
  53. switch(param)
  54. {
  55. case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
  56. if(auto diropt = DirectionFromEmum(val))
  57. props->Fshifter.LeftDirection = *diropt;
  58. else
  59. throw effect_exception{AL_INVALID_VALUE,
  60. "Unsupported frequency shifter left direction: 0x%04x", val};
  61. break;
  62. case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
  63. if(auto diropt = DirectionFromEmum(val))
  64. props->Fshifter.RightDirection = *diropt;
  65. else
  66. throw effect_exception{AL_INVALID_VALUE,
  67. "Unsupported frequency shifter right direction: 0x%04x", val};
  68. break;
  69. default:
  70. throw effect_exception{AL_INVALID_ENUM,
  71. "Invalid frequency shifter integer property 0x%04x", param};
  72. }
  73. }
  74. void Fshifter_setParamiv(EffectProps *props, ALenum param, const int *vals)
  75. { Fshifter_setParami(props, param, vals[0]); }
  76. void Fshifter_getParami(const EffectProps *props, ALenum param, int *val)
  77. {
  78. switch(param)
  79. {
  80. case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
  81. *val = EnumFromDirection(props->Fshifter.LeftDirection);
  82. break;
  83. case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
  84. *val = EnumFromDirection(props->Fshifter.RightDirection);
  85. break;
  86. default:
  87. throw effect_exception{AL_INVALID_ENUM,
  88. "Invalid frequency shifter integer property 0x%04x", param};
  89. }
  90. }
  91. void Fshifter_getParamiv(const EffectProps *props, ALenum param, int *vals)
  92. { Fshifter_getParami(props, param, vals); }
  93. void Fshifter_getParamf(const EffectProps *props, ALenum param, float *val)
  94. {
  95. switch(param)
  96. {
  97. case AL_FREQUENCY_SHIFTER_FREQUENCY:
  98. *val = props->Fshifter.Frequency;
  99. break;
  100. default:
  101. throw effect_exception{AL_INVALID_ENUM, "Invalid frequency shifter float property 0x%04x",
  102. param};
  103. }
  104. }
  105. void Fshifter_getParamfv(const EffectProps *props, ALenum param, float *vals)
  106. { Fshifter_getParamf(props, param, vals); }
  107. EffectProps genDefaultProps() noexcept
  108. {
  109. EffectProps props{};
  110. props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
  111. props.Fshifter.LeftDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION);
  112. props.Fshifter.RightDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION);
  113. return props;
  114. }
  115. } // namespace
  116. DEFINE_ALEFFECT_VTABLE(Fshifter);
  117. const EffectProps FshifterEffectProps{genDefaultProps()};
  118. #ifdef ALSOFT_EAX
  119. namespace {
  120. using EaxFrequencyShifterEffectDirtyFlagsValue = std::uint_least8_t;
  121. struct EaxFrequencyShifterEffectDirtyFlags
  122. {
  123. using EaxIsBitFieldStruct = bool;
  124. EaxFrequencyShifterEffectDirtyFlagsValue flFrequency : 1;
  125. EaxFrequencyShifterEffectDirtyFlagsValue ulLeftDirection : 1;
  126. EaxFrequencyShifterEffectDirtyFlagsValue ulRightDirection : 1;
  127. }; // EaxFrequencyShifterEffectDirtyFlags
  128. class EaxFrequencyShifterEffect final :
  129. public EaxEffect
  130. {
  131. public:
  132. EaxFrequencyShifterEffect();
  133. void dispatch(const EaxEaxCall& eax_call) override;
  134. // [[nodiscard]]
  135. bool apply_deferred() override;
  136. private:
  137. EAXFREQUENCYSHIFTERPROPERTIES eax_{};
  138. EAXFREQUENCYSHIFTERPROPERTIES eax_d_{};
  139. EaxFrequencyShifterEffectDirtyFlags eax_dirty_flags_{};
  140. void set_eax_defaults();
  141. void set_efx_frequency();
  142. void set_efx_left_direction();
  143. void set_efx_right_direction();
  144. void set_efx_defaults();
  145. void get(const EaxEaxCall& eax_call);
  146. void validate_frequency(float flFrequency);
  147. void validate_left_direction(unsigned long ulLeftDirection);
  148. void validate_right_direction(unsigned long ulRightDirection);
  149. void validate_all(const EAXFREQUENCYSHIFTERPROPERTIES& all);
  150. void defer_frequency(float flFrequency);
  151. void defer_left_direction(unsigned long ulLeftDirection);
  152. void defer_right_direction(unsigned long ulRightDirection);
  153. void defer_all(const EAXFREQUENCYSHIFTERPROPERTIES& all);
  154. void defer_frequency(const EaxEaxCall& eax_call);
  155. void defer_left_direction(const EaxEaxCall& eax_call);
  156. void defer_right_direction(const EaxEaxCall& eax_call);
  157. void defer_all(const EaxEaxCall& eax_call);
  158. void set(const EaxEaxCall& eax_call);
  159. }; // EaxFrequencyShifterEffect
  160. class EaxFrequencyShifterEffectException :
  161. public EaxException
  162. {
  163. public:
  164. explicit EaxFrequencyShifterEffectException(
  165. const char* message)
  166. :
  167. EaxException{"EAX_FREQUENCY_SHIFTER_EFFECT", message}
  168. {
  169. }
  170. }; // EaxFrequencyShifterEffectException
  171. EaxFrequencyShifterEffect::EaxFrequencyShifterEffect()
  172. : EaxEffect{AL_EFFECT_FREQUENCY_SHIFTER}
  173. {
  174. set_eax_defaults();
  175. set_efx_defaults();
  176. }
  177. void EaxFrequencyShifterEffect::dispatch(const EaxEaxCall& eax_call)
  178. {
  179. eax_call.is_get() ? get(eax_call) : set(eax_call);
  180. }
  181. void EaxFrequencyShifterEffect::set_eax_defaults()
  182. {
  183. eax_.flFrequency = EAXFREQUENCYSHIFTER_DEFAULTFREQUENCY;
  184. eax_.ulLeftDirection = EAXFREQUENCYSHIFTER_DEFAULTLEFTDIRECTION;
  185. eax_.ulRightDirection = EAXFREQUENCYSHIFTER_DEFAULTRIGHTDIRECTION;
  186. eax_d_ = eax_;
  187. }
  188. void EaxFrequencyShifterEffect::set_efx_frequency()
  189. {
  190. const auto frequency = clamp(
  191. eax_.flFrequency,
  192. AL_FREQUENCY_SHIFTER_MIN_FREQUENCY,
  193. AL_FREQUENCY_SHIFTER_MAX_FREQUENCY);
  194. al_effect_props_.Fshifter.Frequency = frequency;
  195. }
  196. void EaxFrequencyShifterEffect::set_efx_left_direction()
  197. {
  198. const auto left_direction = clamp(
  199. static_cast<ALint>(eax_.ulLeftDirection),
  200. AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION,
  201. AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION);
  202. const auto efx_left_direction = DirectionFromEmum(left_direction);
  203. assert(efx_left_direction.has_value());
  204. al_effect_props_.Fshifter.LeftDirection = *efx_left_direction;
  205. }
  206. void EaxFrequencyShifterEffect::set_efx_right_direction()
  207. {
  208. const auto right_direction = clamp(
  209. static_cast<ALint>(eax_.ulRightDirection),
  210. AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION,
  211. AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION);
  212. const auto efx_right_direction = DirectionFromEmum(right_direction);
  213. assert(efx_right_direction.has_value());
  214. al_effect_props_.Fshifter.RightDirection = *efx_right_direction;
  215. }
  216. void EaxFrequencyShifterEffect::set_efx_defaults()
  217. {
  218. set_efx_frequency();
  219. set_efx_left_direction();
  220. set_efx_right_direction();
  221. }
  222. void EaxFrequencyShifterEffect::get(const EaxEaxCall& eax_call)
  223. {
  224. switch(eax_call.get_property_id())
  225. {
  226. case EAXFREQUENCYSHIFTER_NONE:
  227. break;
  228. case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
  229. eax_call.set_value<EaxFrequencyShifterEffectException>(eax_);
  230. break;
  231. case EAXFREQUENCYSHIFTER_FREQUENCY:
  232. eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.flFrequency);
  233. break;
  234. case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
  235. eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulLeftDirection);
  236. break;
  237. case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
  238. eax_call.set_value<EaxFrequencyShifterEffectException>(eax_.ulRightDirection);
  239. break;
  240. default:
  241. throw EaxFrequencyShifterEffectException{"Unsupported property id."};
  242. }
  243. }
  244. void EaxFrequencyShifterEffect::validate_frequency(
  245. float flFrequency)
  246. {
  247. eax_validate_range<EaxFrequencyShifterEffectException>(
  248. "Frequency",
  249. flFrequency,
  250. EAXFREQUENCYSHIFTER_MINFREQUENCY,
  251. EAXFREQUENCYSHIFTER_MAXFREQUENCY);
  252. }
  253. void EaxFrequencyShifterEffect::validate_left_direction(
  254. unsigned long ulLeftDirection)
  255. {
  256. eax_validate_range<EaxFrequencyShifterEffectException>(
  257. "Left Direction",
  258. ulLeftDirection,
  259. EAXFREQUENCYSHIFTER_MINLEFTDIRECTION,
  260. EAXFREQUENCYSHIFTER_MAXLEFTDIRECTION);
  261. }
  262. void EaxFrequencyShifterEffect::validate_right_direction(
  263. unsigned long ulRightDirection)
  264. {
  265. eax_validate_range<EaxFrequencyShifterEffectException>(
  266. "Right Direction",
  267. ulRightDirection,
  268. EAXFREQUENCYSHIFTER_MINRIGHTDIRECTION,
  269. EAXFREQUENCYSHIFTER_MAXRIGHTDIRECTION);
  270. }
  271. void EaxFrequencyShifterEffect::validate_all(
  272. const EAXFREQUENCYSHIFTERPROPERTIES& all)
  273. {
  274. validate_frequency(all.flFrequency);
  275. validate_left_direction(all.ulLeftDirection);
  276. validate_right_direction(all.ulRightDirection);
  277. }
  278. void EaxFrequencyShifterEffect::defer_frequency(
  279. float flFrequency)
  280. {
  281. eax_d_.flFrequency = flFrequency;
  282. eax_dirty_flags_.flFrequency = (eax_.flFrequency != eax_d_.flFrequency);
  283. }
  284. void EaxFrequencyShifterEffect::defer_left_direction(
  285. unsigned long ulLeftDirection)
  286. {
  287. eax_d_.ulLeftDirection = ulLeftDirection;
  288. eax_dirty_flags_.ulLeftDirection = (eax_.ulLeftDirection != eax_d_.ulLeftDirection);
  289. }
  290. void EaxFrequencyShifterEffect::defer_right_direction(
  291. unsigned long ulRightDirection)
  292. {
  293. eax_d_.ulRightDirection = ulRightDirection;
  294. eax_dirty_flags_.ulRightDirection = (eax_.ulRightDirection != eax_d_.ulRightDirection);
  295. }
  296. void EaxFrequencyShifterEffect::defer_all(
  297. const EAXFREQUENCYSHIFTERPROPERTIES& all)
  298. {
  299. defer_frequency(all.flFrequency);
  300. defer_left_direction(all.ulLeftDirection);
  301. defer_right_direction(all.ulRightDirection);
  302. }
  303. void EaxFrequencyShifterEffect::defer_frequency(
  304. const EaxEaxCall& eax_call)
  305. {
  306. const auto& frequency =
  307. eax_call.get_value<
  308. EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::flFrequency)>();
  309. validate_frequency(frequency);
  310. defer_frequency(frequency);
  311. }
  312. void EaxFrequencyShifterEffect::defer_left_direction(
  313. const EaxEaxCall& eax_call)
  314. {
  315. const auto& left_direction =
  316. eax_call.get_value<
  317. EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulLeftDirection)>();
  318. validate_left_direction(left_direction);
  319. defer_left_direction(left_direction);
  320. }
  321. void EaxFrequencyShifterEffect::defer_right_direction(
  322. const EaxEaxCall& eax_call)
  323. {
  324. const auto& right_direction =
  325. eax_call.get_value<
  326. EaxFrequencyShifterEffectException, const decltype(EAXFREQUENCYSHIFTERPROPERTIES::ulRightDirection)>();
  327. validate_right_direction(right_direction);
  328. defer_right_direction(right_direction);
  329. }
  330. void EaxFrequencyShifterEffect::defer_all(
  331. const EaxEaxCall& eax_call)
  332. {
  333. const auto& all =
  334. eax_call.get_value<
  335. EaxFrequencyShifterEffectException, const EAXFREQUENCYSHIFTERPROPERTIES>();
  336. validate_all(all);
  337. defer_all(all);
  338. }
  339. // [[nodiscard]]
  340. bool EaxFrequencyShifterEffect::apply_deferred()
  341. {
  342. if (eax_dirty_flags_ == EaxFrequencyShifterEffectDirtyFlags{})
  343. {
  344. return false;
  345. }
  346. eax_ = eax_d_;
  347. if (eax_dirty_flags_.flFrequency)
  348. {
  349. set_efx_frequency();
  350. }
  351. if (eax_dirty_flags_.ulLeftDirection)
  352. {
  353. set_efx_left_direction();
  354. }
  355. if (eax_dirty_flags_.ulRightDirection)
  356. {
  357. set_efx_right_direction();
  358. }
  359. eax_dirty_flags_ = EaxFrequencyShifterEffectDirtyFlags{};
  360. return true;
  361. }
  362. void EaxFrequencyShifterEffect::set(const EaxEaxCall& eax_call)
  363. {
  364. switch(eax_call.get_property_id())
  365. {
  366. case EAXFREQUENCYSHIFTER_NONE:
  367. break;
  368. case EAXFREQUENCYSHIFTER_ALLPARAMETERS:
  369. defer_all(eax_call);
  370. break;
  371. case EAXFREQUENCYSHIFTER_FREQUENCY:
  372. defer_frequency(eax_call);
  373. break;
  374. case EAXFREQUENCYSHIFTER_LEFTDIRECTION:
  375. defer_left_direction(eax_call);
  376. break;
  377. case EAXFREQUENCYSHIFTER_RIGHTDIRECTION:
  378. defer_right_direction(eax_call);
  379. break;
  380. default:
  381. throw EaxFrequencyShifterEffectException{"Unsupported property id."};
  382. }
  383. }
  384. } // namespace
  385. EaxEffectUPtr eax_create_eax_frequency_shifter_effect()
  386. {
  387. return std::make_unique<EaxFrequencyShifterEffect>();
  388. }
  389. #endif // ALSOFT_EAX