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

578 lines
17 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<VMorpherPhenome> PhenomeFromEnum(ALenum val)
  16. {
  17. #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
  18. return al::make_optional(VMorpherPhenome::x)
  19. switch(val)
  20. {
  21. HANDLE_PHENOME(A);
  22. HANDLE_PHENOME(E);
  23. HANDLE_PHENOME(I);
  24. HANDLE_PHENOME(O);
  25. HANDLE_PHENOME(U);
  26. HANDLE_PHENOME(AA);
  27. HANDLE_PHENOME(AE);
  28. HANDLE_PHENOME(AH);
  29. HANDLE_PHENOME(AO);
  30. HANDLE_PHENOME(EH);
  31. HANDLE_PHENOME(ER);
  32. HANDLE_PHENOME(IH);
  33. HANDLE_PHENOME(IY);
  34. HANDLE_PHENOME(UH);
  35. HANDLE_PHENOME(UW);
  36. HANDLE_PHENOME(B);
  37. HANDLE_PHENOME(D);
  38. HANDLE_PHENOME(F);
  39. HANDLE_PHENOME(G);
  40. HANDLE_PHENOME(J);
  41. HANDLE_PHENOME(K);
  42. HANDLE_PHENOME(L);
  43. HANDLE_PHENOME(M);
  44. HANDLE_PHENOME(N);
  45. HANDLE_PHENOME(P);
  46. HANDLE_PHENOME(R);
  47. HANDLE_PHENOME(S);
  48. HANDLE_PHENOME(T);
  49. HANDLE_PHENOME(V);
  50. HANDLE_PHENOME(Z);
  51. }
  52. return al::nullopt;
  53. #undef HANDLE_PHENOME
  54. }
  55. ALenum EnumFromPhenome(VMorpherPhenome phenome)
  56. {
  57. #define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
  58. switch(phenome)
  59. {
  60. HANDLE_PHENOME(A);
  61. HANDLE_PHENOME(E);
  62. HANDLE_PHENOME(I);
  63. HANDLE_PHENOME(O);
  64. HANDLE_PHENOME(U);
  65. HANDLE_PHENOME(AA);
  66. HANDLE_PHENOME(AE);
  67. HANDLE_PHENOME(AH);
  68. HANDLE_PHENOME(AO);
  69. HANDLE_PHENOME(EH);
  70. HANDLE_PHENOME(ER);
  71. HANDLE_PHENOME(IH);
  72. HANDLE_PHENOME(IY);
  73. HANDLE_PHENOME(UH);
  74. HANDLE_PHENOME(UW);
  75. HANDLE_PHENOME(B);
  76. HANDLE_PHENOME(D);
  77. HANDLE_PHENOME(F);
  78. HANDLE_PHENOME(G);
  79. HANDLE_PHENOME(J);
  80. HANDLE_PHENOME(K);
  81. HANDLE_PHENOME(L);
  82. HANDLE_PHENOME(M);
  83. HANDLE_PHENOME(N);
  84. HANDLE_PHENOME(P);
  85. HANDLE_PHENOME(R);
  86. HANDLE_PHENOME(S);
  87. HANDLE_PHENOME(T);
  88. HANDLE_PHENOME(V);
  89. HANDLE_PHENOME(Z);
  90. }
  91. throw std::runtime_error{"Invalid phenome: "+std::to_string(static_cast<int>(phenome))};
  92. #undef HANDLE_PHENOME
  93. }
  94. al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
  95. {
  96. switch(value)
  97. {
  98. case AL_VOCAL_MORPHER_WAVEFORM_SINUSOID: return al::make_optional(VMorpherWaveform::Sinusoid);
  99. case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return al::make_optional(VMorpherWaveform::Triangle);
  100. case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return al::make_optional(VMorpherWaveform::Sawtooth);
  101. }
  102. return al::nullopt;
  103. }
  104. ALenum EnumFromWaveform(VMorpherWaveform type)
  105. {
  106. switch(type)
  107. {
  108. case VMorpherWaveform::Sinusoid: return AL_VOCAL_MORPHER_WAVEFORM_SINUSOID;
  109. case VMorpherWaveform::Triangle: return AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE;
  110. case VMorpherWaveform::Sawtooth: return AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH;
  111. }
  112. throw std::runtime_error{"Invalid vocal morpher waveform: " +
  113. std::to_string(static_cast<int>(type))};
  114. }
  115. void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
  116. {
  117. switch(param)
  118. {
  119. case AL_VOCAL_MORPHER_PHONEMEA:
  120. if(auto phenomeopt = PhenomeFromEnum(val))
  121. props->Vmorpher.PhonemeA = *phenomeopt;
  122. else
  123. throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
  124. break;
  125. case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
  126. if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
  127. throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a coarse tuning out of range"};
  128. props->Vmorpher.PhonemeACoarseTuning = val;
  129. break;
  130. case AL_VOCAL_MORPHER_PHONEMEB:
  131. if(auto phenomeopt = PhenomeFromEnum(val))
  132. props->Vmorpher.PhonemeB = *phenomeopt;
  133. else
  134. throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
  135. break;
  136. case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
  137. if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
  138. throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b coarse tuning out of range"};
  139. props->Vmorpher.PhonemeBCoarseTuning = val;
  140. break;
  141. case AL_VOCAL_MORPHER_WAVEFORM:
  142. if(auto formopt = WaveformFromEmum(val))
  143. props->Vmorpher.Waveform = *formopt;
  144. else
  145. throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
  146. break;
  147. default:
  148. throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
  149. param};
  150. }
  151. }
  152. void Vmorpher_setParamiv(EffectProps*, ALenum param, const int*)
  153. {
  154. throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
  155. param};
  156. }
  157. void Vmorpher_setParamf(EffectProps *props, ALenum param, float val)
  158. {
  159. switch(param)
  160. {
  161. case AL_VOCAL_MORPHER_RATE:
  162. if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
  163. throw effect_exception{AL_INVALID_VALUE, "Vocal morpher rate out of range"};
  164. props->Vmorpher.Rate = val;
  165. break;
  166. default:
  167. throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
  168. param};
  169. }
  170. }
  171. void Vmorpher_setParamfv(EffectProps *props, ALenum param, const float *vals)
  172. { Vmorpher_setParamf(props, param, vals[0]); }
  173. void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
  174. {
  175. switch(param)
  176. {
  177. case AL_VOCAL_MORPHER_PHONEMEA:
  178. *val = EnumFromPhenome(props->Vmorpher.PhonemeA);
  179. break;
  180. case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
  181. *val = props->Vmorpher.PhonemeACoarseTuning;
  182. break;
  183. case AL_VOCAL_MORPHER_PHONEMEB:
  184. *val = EnumFromPhenome(props->Vmorpher.PhonemeB);
  185. break;
  186. case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
  187. *val = props->Vmorpher.PhonemeBCoarseTuning;
  188. break;
  189. case AL_VOCAL_MORPHER_WAVEFORM:
  190. *val = EnumFromWaveform(props->Vmorpher.Waveform);
  191. break;
  192. default:
  193. throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
  194. param};
  195. }
  196. }
  197. void Vmorpher_getParamiv(const EffectProps*, ALenum param, int*)
  198. {
  199. throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
  200. param};
  201. }
  202. void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
  203. {
  204. switch(param)
  205. {
  206. case AL_VOCAL_MORPHER_RATE:
  207. *val = props->Vmorpher.Rate;
  208. break;
  209. default:
  210. throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
  211. param};
  212. }
  213. }
  214. void Vmorpher_getParamfv(const EffectProps *props, ALenum param, float *vals)
  215. { Vmorpher_getParamf(props, param, vals); }
  216. EffectProps genDefaultProps() noexcept
  217. {
  218. EffectProps props{};
  219. props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
  220. props.Vmorpher.PhonemeA = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA);
  221. props.Vmorpher.PhonemeB = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB);
  222. props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
  223. props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
  224. props.Vmorpher.Waveform = *WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM);
  225. return props;
  226. }
  227. } // namespace
  228. DEFINE_ALEFFECT_VTABLE(Vmorpher);
  229. const EffectProps VmorpherEffectProps{genDefaultProps()};
  230. #ifdef ALSOFT_EAX
  231. namespace {
  232. class EaxVocalMorpherEffectException : public EaxException {
  233. public:
  234. explicit EaxVocalMorpherEffectException(const char* message)
  235. : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
  236. {}
  237. }; // EaxVocalMorpherEffectException
  238. class EaxVocalMorpherEffect final : public EaxEffect4<EaxVocalMorpherEffectException, EAXVOCALMORPHERPROPERTIES> {
  239. public:
  240. EaxVocalMorpherEffect(const EaxCall& call);
  241. private:
  242. struct PhonemeAValidator {
  243. void operator()(unsigned long ulPhonemeA) const
  244. {
  245. eax_validate_range<Exception>(
  246. "Phoneme A",
  247. ulPhonemeA,
  248. EAXVOCALMORPHER_MINPHONEMEA,
  249. EAXVOCALMORPHER_MAXPHONEMEA);
  250. }
  251. }; // PhonemeAValidator
  252. struct PhonemeACoarseTuningValidator {
  253. void operator()(long lPhonemeACoarseTuning) const
  254. {
  255. eax_validate_range<Exception>(
  256. "Phoneme A Coarse Tuning",
  257. lPhonemeACoarseTuning,
  258. EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
  259. EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
  260. }
  261. }; // PhonemeACoarseTuningValidator
  262. struct PhonemeBValidator {
  263. void operator()(unsigned long ulPhonemeB) const
  264. {
  265. eax_validate_range<Exception>(
  266. "Phoneme B",
  267. ulPhonemeB,
  268. EAXVOCALMORPHER_MINPHONEMEB,
  269. EAXVOCALMORPHER_MAXPHONEMEB);
  270. }
  271. }; // PhonemeBValidator
  272. struct PhonemeBCoarseTuningValidator {
  273. void operator()(long lPhonemeBCoarseTuning) const
  274. {
  275. eax_validate_range<Exception>(
  276. "Phoneme B Coarse Tuning",
  277. lPhonemeBCoarseTuning,
  278. EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
  279. EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
  280. }
  281. }; // PhonemeBCoarseTuningValidator
  282. struct WaveformValidator {
  283. void operator()(unsigned long ulWaveform) const
  284. {
  285. eax_validate_range<Exception>(
  286. "Waveform",
  287. ulWaveform,
  288. EAXVOCALMORPHER_MINWAVEFORM,
  289. EAXVOCALMORPHER_MAXWAVEFORM);
  290. }
  291. }; // WaveformValidator
  292. struct RateValidator {
  293. void operator()(float flRate) const
  294. {
  295. eax_validate_range<Exception>(
  296. "Rate",
  297. flRate,
  298. EAXVOCALMORPHER_MINRATE,
  299. EAXVOCALMORPHER_MAXRATE);
  300. }
  301. }; // RateValidator
  302. struct AllValidator {
  303. void operator()(const Props& all) const
  304. {
  305. PhonemeAValidator{}(all.ulPhonemeA);
  306. PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning);
  307. PhonemeBValidator{}(all.ulPhonemeB);
  308. PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning);
  309. WaveformValidator{}(all.ulWaveform);
  310. RateValidator{}(all.flRate);
  311. }
  312. }; // AllValidator
  313. void set_defaults(Props& props) override;
  314. void set_efx_phoneme_a();
  315. void set_efx_phoneme_a_coarse_tuning() noexcept;
  316. void set_efx_phoneme_b();
  317. void set_efx_phoneme_b_coarse_tuning() noexcept;
  318. void set_efx_waveform();
  319. void set_efx_rate() noexcept;
  320. void set_efx_defaults() override;
  321. void get(const EaxCall& call, const Props& props) override;
  322. void set(const EaxCall& call, Props& props) override;
  323. bool commit_props(const Props& props) override;
  324. }; // EaxVocalMorpherEffect
  325. EaxVocalMorpherEffect::EaxVocalMorpherEffect(const EaxCall& call)
  326. : EaxEffect4{AL_EFFECT_VOCAL_MORPHER, call}
  327. {}
  328. void EaxVocalMorpherEffect::set_defaults(Props& props)
  329. {
  330. props.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
  331. props.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
  332. props.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
  333. props.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
  334. props.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
  335. props.flRate = EAXVOCALMORPHER_DEFAULTRATE;
  336. }
  337. void EaxVocalMorpherEffect::set_efx_phoneme_a()
  338. {
  339. const auto phoneme_a = clamp(
  340. static_cast<ALint>(props_.ulPhonemeA),
  341. AL_VOCAL_MORPHER_MIN_PHONEMEA,
  342. AL_VOCAL_MORPHER_MAX_PHONEMEA);
  343. const auto efx_phoneme_a = PhenomeFromEnum(phoneme_a);
  344. assert(efx_phoneme_a.has_value());
  345. al_effect_props_.Vmorpher.PhonemeA = *efx_phoneme_a;
  346. }
  347. void EaxVocalMorpherEffect::set_efx_phoneme_a_coarse_tuning() noexcept
  348. {
  349. const auto phoneme_a_coarse_tuning = clamp(
  350. static_cast<ALint>(props_.lPhonemeACoarseTuning),
  351. AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING,
  352. AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING);
  353. al_effect_props_.Vmorpher.PhonemeACoarseTuning = phoneme_a_coarse_tuning;
  354. }
  355. void EaxVocalMorpherEffect::set_efx_phoneme_b()
  356. {
  357. const auto phoneme_b = clamp(
  358. static_cast<ALint>(props_.ulPhonemeB),
  359. AL_VOCAL_MORPHER_MIN_PHONEMEB,
  360. AL_VOCAL_MORPHER_MAX_PHONEMEB);
  361. const auto efx_phoneme_b = PhenomeFromEnum(phoneme_b);
  362. assert(efx_phoneme_b.has_value());
  363. al_effect_props_.Vmorpher.PhonemeB = *efx_phoneme_b;
  364. }
  365. void EaxVocalMorpherEffect::set_efx_phoneme_b_coarse_tuning() noexcept
  366. {
  367. al_effect_props_.Vmorpher.PhonemeBCoarseTuning = clamp(
  368. static_cast<ALint>(props_.lPhonemeBCoarseTuning),
  369. AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING,
  370. AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING);
  371. }
  372. void EaxVocalMorpherEffect::set_efx_waveform()
  373. {
  374. const auto waveform = clamp(
  375. static_cast<ALint>(props_.ulWaveform),
  376. AL_VOCAL_MORPHER_MIN_WAVEFORM,
  377. AL_VOCAL_MORPHER_MAX_WAVEFORM);
  378. const auto wfx_waveform = WaveformFromEmum(waveform);
  379. assert(wfx_waveform.has_value());
  380. al_effect_props_.Vmorpher.Waveform = *wfx_waveform;
  381. }
  382. void EaxVocalMorpherEffect::set_efx_rate() noexcept
  383. {
  384. al_effect_props_.Vmorpher.Rate = clamp(
  385. props_.flRate,
  386. AL_VOCAL_MORPHER_MIN_RATE,
  387. AL_VOCAL_MORPHER_MAX_RATE);
  388. }
  389. void EaxVocalMorpherEffect::set_efx_defaults()
  390. {
  391. set_efx_phoneme_a();
  392. set_efx_phoneme_a_coarse_tuning();
  393. set_efx_phoneme_b();
  394. set_efx_phoneme_b_coarse_tuning();
  395. set_efx_waveform();
  396. set_efx_rate();
  397. }
  398. void EaxVocalMorpherEffect::get(const EaxCall& call, const Props& props)
  399. {
  400. switch(call.get_property_id())
  401. {
  402. case EAXVOCALMORPHER_NONE:
  403. break;
  404. case EAXVOCALMORPHER_ALLPARAMETERS:
  405. call.set_value<Exception>(props);
  406. break;
  407. case EAXVOCALMORPHER_PHONEMEA:
  408. call.set_value<Exception>(props.ulPhonemeA);
  409. break;
  410. case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
  411. call.set_value<Exception>(props.lPhonemeACoarseTuning);
  412. break;
  413. case EAXVOCALMORPHER_PHONEMEB:
  414. call.set_value<Exception>(props.ulPhonemeB);
  415. break;
  416. case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
  417. call.set_value<Exception>(props.lPhonemeBCoarseTuning);
  418. break;
  419. case EAXVOCALMORPHER_WAVEFORM:
  420. call.set_value<Exception>(props.ulWaveform);
  421. break;
  422. case EAXVOCALMORPHER_RATE:
  423. call.set_value<Exception>(props.flRate);
  424. break;
  425. default:
  426. fail_unknown_property_id();
  427. }
  428. }
  429. void EaxVocalMorpherEffect::set(const EaxCall& call, Props& props)
  430. {
  431. switch(call.get_property_id())
  432. {
  433. case EAXVOCALMORPHER_NONE:
  434. break;
  435. case EAXVOCALMORPHER_ALLPARAMETERS:
  436. defer<AllValidator>(call, props);
  437. break;
  438. case EAXVOCALMORPHER_PHONEMEA:
  439. defer<PhonemeAValidator>(call, props.ulPhonemeA);
  440. break;
  441. case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
  442. defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning);
  443. break;
  444. case EAXVOCALMORPHER_PHONEMEB:
  445. defer<PhonemeBValidator>(call, props.ulPhonemeB);
  446. break;
  447. case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
  448. defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning);
  449. break;
  450. case EAXVOCALMORPHER_WAVEFORM:
  451. defer<WaveformValidator>(call, props.ulWaveform);
  452. break;
  453. case EAXVOCALMORPHER_RATE:
  454. defer<RateValidator>(call, props.flRate);
  455. break;
  456. default:
  457. fail_unknown_property_id();
  458. }
  459. }
  460. bool EaxVocalMorpherEffect::commit_props(const Props& props)
  461. {
  462. auto is_dirty = false;
  463. if (props_.ulPhonemeA != props.ulPhonemeA)
  464. {
  465. is_dirty = true;
  466. set_efx_phoneme_a();
  467. }
  468. if (props_.lPhonemeACoarseTuning != props.lPhonemeACoarseTuning)
  469. {
  470. is_dirty = true;
  471. set_efx_phoneme_a_coarse_tuning();
  472. }
  473. if (props_.ulPhonemeB != props.ulPhonemeB)
  474. {
  475. is_dirty = true;
  476. set_efx_phoneme_b();
  477. }
  478. if (props_.lPhonemeBCoarseTuning != props.lPhonemeBCoarseTuning)
  479. {
  480. is_dirty = true;
  481. set_efx_phoneme_b_coarse_tuning();
  482. }
  483. if (props_.ulWaveform != props.ulWaveform)
  484. {
  485. is_dirty = true;
  486. set_efx_waveform();
  487. }
  488. if (props_.flRate != props.flRate)
  489. {
  490. is_dirty = true;
  491. set_efx_rate();
  492. }
  493. return is_dirty;
  494. }
  495. } // namespace
  496. EaxEffectUPtr eax_create_eax_vocal_morpher_effect(const EaxCall& call)
  497. {
  498. return eax_create_eax4_effect<EaxVocalMorpherEffect>(call);
  499. }
  500. #endif // ALSOFT_EAX