vmorpher.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. #include "config.h"
  2. #include <optional>
  3. #include <stdexcept>
  4. #include "AL/al.h"
  5. #include "AL/efx.h"
  6. #include "alc/context.h"
  7. #include "alnumeric.h"
  8. #include "effects.h"
  9. #if ALSOFT_EAX
  10. #include <cassert>
  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<VMorpherPhenome> PhenomeFromEnum(ALenum val) noexcept
  17. {
  18. #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
  19. return VMorpherPhenome::x
  20. switch(val)
  21. {
  22. HANDLE_PHENOME(A);
  23. HANDLE_PHENOME(E);
  24. HANDLE_PHENOME(I);
  25. HANDLE_PHENOME(O);
  26. HANDLE_PHENOME(U);
  27. HANDLE_PHENOME(AA);
  28. HANDLE_PHENOME(AE);
  29. HANDLE_PHENOME(AH);
  30. HANDLE_PHENOME(AO);
  31. HANDLE_PHENOME(EH);
  32. HANDLE_PHENOME(ER);
  33. HANDLE_PHENOME(IH);
  34. HANDLE_PHENOME(IY);
  35. HANDLE_PHENOME(UH);
  36. HANDLE_PHENOME(UW);
  37. HANDLE_PHENOME(B);
  38. HANDLE_PHENOME(D);
  39. HANDLE_PHENOME(F);
  40. HANDLE_PHENOME(G);
  41. HANDLE_PHENOME(J);
  42. HANDLE_PHENOME(K);
  43. HANDLE_PHENOME(L);
  44. HANDLE_PHENOME(M);
  45. HANDLE_PHENOME(N);
  46. HANDLE_PHENOME(P);
  47. HANDLE_PHENOME(R);
  48. HANDLE_PHENOME(S);
  49. HANDLE_PHENOME(T);
  50. HANDLE_PHENOME(V);
  51. HANDLE_PHENOME(Z);
  52. }
  53. return std::nullopt;
  54. #undef HANDLE_PHENOME
  55. }
  56. constexpr ALenum EnumFromPhenome(VMorpherPhenome phenome)
  57. {
  58. #define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
  59. switch(phenome)
  60. {
  61. HANDLE_PHENOME(A);
  62. HANDLE_PHENOME(E);
  63. HANDLE_PHENOME(I);
  64. HANDLE_PHENOME(O);
  65. HANDLE_PHENOME(U);
  66. HANDLE_PHENOME(AA);
  67. HANDLE_PHENOME(AE);
  68. HANDLE_PHENOME(AH);
  69. HANDLE_PHENOME(AO);
  70. HANDLE_PHENOME(EH);
  71. HANDLE_PHENOME(ER);
  72. HANDLE_PHENOME(IH);
  73. HANDLE_PHENOME(IY);
  74. HANDLE_PHENOME(UH);
  75. HANDLE_PHENOME(UW);
  76. HANDLE_PHENOME(B);
  77. HANDLE_PHENOME(D);
  78. HANDLE_PHENOME(F);
  79. HANDLE_PHENOME(G);
  80. HANDLE_PHENOME(J);
  81. HANDLE_PHENOME(K);
  82. HANDLE_PHENOME(L);
  83. HANDLE_PHENOME(M);
  84. HANDLE_PHENOME(N);
  85. HANDLE_PHENOME(P);
  86. HANDLE_PHENOME(R);
  87. HANDLE_PHENOME(S);
  88. HANDLE_PHENOME(T);
  89. HANDLE_PHENOME(V);
  90. HANDLE_PHENOME(Z);
  91. }
  92. throw std::runtime_error{fmt::format("Invalid phenome: {}", int{al::to_underlying(phenome)})};
  93. #undef HANDLE_PHENOME
  94. }
  95. constexpr std::optional<VMorpherWaveform> WaveformFromEmum(ALenum value) noexcept
  96. {
  97. switch(value)
  98. {
  99. case AL_VOCAL_MORPHER_WAVEFORM_SINUSOID: return VMorpherWaveform::Sinusoid;
  100. case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return VMorpherWaveform::Triangle;
  101. case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return VMorpherWaveform::Sawtooth;
  102. }
  103. return std::nullopt;
  104. }
  105. constexpr ALenum EnumFromWaveform(VMorpherWaveform type)
  106. {
  107. switch(type)
  108. {
  109. case VMorpherWaveform::Sinusoid: return AL_VOCAL_MORPHER_WAVEFORM_SINUSOID;
  110. case VMorpherWaveform::Triangle: return AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE;
  111. case VMorpherWaveform::Sawtooth: return AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH;
  112. }
  113. throw std::runtime_error{fmt::format("Invalid vocal morpher waveform: {}",
  114. int{al::to_underlying(type)})};
  115. }
  116. constexpr EffectProps genDefaultProps() noexcept
  117. {
  118. VmorpherProps props{};
  119. props.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
  120. props.PhonemeA = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA).value();
  121. props.PhonemeB = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB).value();
  122. props.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
  123. props.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
  124. props.Waveform = WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM).value();
  125. return props;
  126. }
  127. } // namespace
  128. const EffectProps VmorpherEffectProps{genDefaultProps()};
  129. void VmorpherEffectHandler::SetParami(ALCcontext *context, VmorpherProps &props, ALenum param, int val)
  130. {
  131. switch(param)
  132. {
  133. case AL_VOCAL_MORPHER_PHONEMEA:
  134. if(auto phenomeopt = PhenomeFromEnum(val))
  135. props.PhonemeA = *phenomeopt;
  136. else
  137. context->throw_error(AL_INVALID_VALUE,
  138. "Vocal morpher phoneme-a out of range: {:#04x}", as_unsigned(val));
  139. return;
  140. case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
  141. if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
  142. context->throw_error(AL_INVALID_VALUE,
  143. "Vocal morpher phoneme-a coarse tuning out of range");
  144. props.PhonemeACoarseTuning = val;
  145. return;
  146. case AL_VOCAL_MORPHER_PHONEMEB:
  147. if(auto phenomeopt = PhenomeFromEnum(val))
  148. props.PhonemeB = *phenomeopt;
  149. else
  150. context->throw_error(AL_INVALID_VALUE,
  151. "Vocal morpher phoneme-b out of range: {:#04x}", as_unsigned(val));
  152. return;
  153. case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
  154. if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
  155. context->throw_error(AL_INVALID_VALUE,
  156. "Vocal morpher phoneme-b coarse tuning out of range");
  157. props.PhonemeBCoarseTuning = val;
  158. return;
  159. case AL_VOCAL_MORPHER_WAVEFORM:
  160. if(auto formopt = WaveformFromEmum(val))
  161. props.Waveform = *formopt;
  162. else
  163. context->throw_error(AL_INVALID_VALUE, "Vocal morpher waveform out of range: {:#04x}",
  164. as_unsigned(val));
  165. return;
  166. }
  167. context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher integer property {:#04x}",
  168. as_unsigned(param));
  169. }
  170. void VmorpherEffectHandler::SetParamiv(ALCcontext *context, VmorpherProps &props, ALenum param, const int *vals)
  171. { SetParami(context, props, param, *vals); }
  172. void VmorpherEffectHandler::SetParamf(ALCcontext *context, VmorpherProps &props, ALenum param, float val)
  173. {
  174. switch(param)
  175. {
  176. case AL_VOCAL_MORPHER_RATE:
  177. if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
  178. context->throw_error(AL_INVALID_VALUE, "Vocal morpher rate out of range");
  179. props.Rate = val;
  180. return;
  181. }
  182. context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher float property {:#04x}",
  183. as_unsigned(param));
  184. }
  185. void VmorpherEffectHandler::SetParamfv(ALCcontext *context, VmorpherProps &props, ALenum param, const float *vals)
  186. { SetParamf(context, props, param, *vals); }
  187. void VmorpherEffectHandler::GetParami(ALCcontext *context, const VmorpherProps &props, ALenum param, int* val)
  188. {
  189. switch(param)
  190. {
  191. case AL_VOCAL_MORPHER_PHONEMEA: *val = EnumFromPhenome(props.PhonemeA); return;
  192. case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: *val = props.PhonemeACoarseTuning; return;
  193. case AL_VOCAL_MORPHER_PHONEMEB: *val = EnumFromPhenome(props.PhonemeB); return;
  194. case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: *val = props.PhonemeBCoarseTuning; return;
  195. case AL_VOCAL_MORPHER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); return;
  196. }
  197. context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher integer property {:#04x}",
  198. as_unsigned(param));
  199. }
  200. void VmorpherEffectHandler::GetParamiv(ALCcontext *context, const VmorpherProps &props, ALenum param, int *vals)
  201. { GetParami(context, props, param, vals); }
  202. void VmorpherEffectHandler::GetParamf(ALCcontext *context, const VmorpherProps &props, ALenum param, float *val)
  203. {
  204. switch(param)
  205. {
  206. case AL_VOCAL_MORPHER_RATE: *val = props.Rate; return;
  207. }
  208. context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher float property {:#04x}",
  209. as_unsigned(param));
  210. }
  211. void VmorpherEffectHandler::GetParamfv(ALCcontext *context, const VmorpherProps &props, ALenum param, float *vals)
  212. { GetParamf(context, props, param, vals); }
  213. #if ALSOFT_EAX
  214. namespace {
  215. using VocalMorpherCommitter = EaxCommitter<EaxVocalMorpherCommitter>;
  216. struct PhonemeAValidator {
  217. void operator()(unsigned long ulPhonemeA) const
  218. {
  219. eax_validate_range<VocalMorpherCommitter::Exception>(
  220. "Phoneme A",
  221. ulPhonemeA,
  222. EAXVOCALMORPHER_MINPHONEMEA,
  223. EAXVOCALMORPHER_MAXPHONEMEA);
  224. }
  225. }; // PhonemeAValidator
  226. struct PhonemeACoarseTuningValidator {
  227. void operator()(long lPhonemeACoarseTuning) const
  228. {
  229. eax_validate_range<VocalMorpherCommitter::Exception>(
  230. "Phoneme A Coarse Tuning",
  231. lPhonemeACoarseTuning,
  232. EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
  233. EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
  234. }
  235. }; // PhonemeACoarseTuningValidator
  236. struct PhonemeBValidator {
  237. void operator()(unsigned long ulPhonemeB) const
  238. {
  239. eax_validate_range<VocalMorpherCommitter::Exception>(
  240. "Phoneme B",
  241. ulPhonemeB,
  242. EAXVOCALMORPHER_MINPHONEMEB,
  243. EAXVOCALMORPHER_MAXPHONEMEB);
  244. }
  245. }; // PhonemeBValidator
  246. struct PhonemeBCoarseTuningValidator {
  247. void operator()(long lPhonemeBCoarseTuning) const
  248. {
  249. eax_validate_range<VocalMorpherCommitter::Exception>(
  250. "Phoneme B Coarse Tuning",
  251. lPhonemeBCoarseTuning,
  252. EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
  253. EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
  254. }
  255. }; // PhonemeBCoarseTuningValidator
  256. struct WaveformValidator {
  257. void operator()(unsigned long ulWaveform) const
  258. {
  259. eax_validate_range<VocalMorpherCommitter::Exception>(
  260. "Waveform",
  261. ulWaveform,
  262. EAXVOCALMORPHER_MINWAVEFORM,
  263. EAXVOCALMORPHER_MAXWAVEFORM);
  264. }
  265. }; // WaveformValidator
  266. struct RateValidator {
  267. void operator()(float flRate) const
  268. {
  269. eax_validate_range<VocalMorpherCommitter::Exception>(
  270. "Rate",
  271. flRate,
  272. EAXVOCALMORPHER_MINRATE,
  273. EAXVOCALMORPHER_MAXRATE);
  274. }
  275. }; // RateValidator
  276. struct AllValidator {
  277. void operator()(const EAXVOCALMORPHERPROPERTIES& all) const
  278. {
  279. PhonemeAValidator{}(all.ulPhonemeA);
  280. PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning);
  281. PhonemeBValidator{}(all.ulPhonemeB);
  282. PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning);
  283. WaveformValidator{}(all.ulWaveform);
  284. RateValidator{}(all.flRate);
  285. }
  286. }; // AllValidator
  287. } // namespace
  288. template<>
  289. struct VocalMorpherCommitter::Exception : public EaxException {
  290. explicit Exception(const char *message) : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
  291. { }
  292. };
  293. template<>
  294. [[noreturn]] void VocalMorpherCommitter::fail(const char *message)
  295. {
  296. throw Exception{message};
  297. }
  298. bool EaxVocalMorpherCommitter::commit(const EAXVOCALMORPHERPROPERTIES &props)
  299. {
  300. if(auto *cur = std::get_if<EAXVOCALMORPHERPROPERTIES>(&mEaxProps); cur && *cur == props)
  301. return false;
  302. mEaxProps = props;
  303. auto get_phoneme = [](unsigned long phoneme) noexcept
  304. {
  305. #define HANDLE_PHENOME(x) case x: return VMorpherPhenome::x
  306. switch(phoneme)
  307. {
  308. HANDLE_PHENOME(A);
  309. HANDLE_PHENOME(E);
  310. HANDLE_PHENOME(I);
  311. HANDLE_PHENOME(O);
  312. HANDLE_PHENOME(U);
  313. HANDLE_PHENOME(AA);
  314. HANDLE_PHENOME(AE);
  315. HANDLE_PHENOME(AH);
  316. HANDLE_PHENOME(AO);
  317. HANDLE_PHENOME(EH);
  318. HANDLE_PHENOME(ER);
  319. HANDLE_PHENOME(IH);
  320. HANDLE_PHENOME(IY);
  321. HANDLE_PHENOME(UH);
  322. HANDLE_PHENOME(UW);
  323. HANDLE_PHENOME(B);
  324. HANDLE_PHENOME(D);
  325. HANDLE_PHENOME(F);
  326. HANDLE_PHENOME(G);
  327. HANDLE_PHENOME(J);
  328. HANDLE_PHENOME(K);
  329. HANDLE_PHENOME(L);
  330. HANDLE_PHENOME(M);
  331. HANDLE_PHENOME(N);
  332. HANDLE_PHENOME(P);
  333. HANDLE_PHENOME(R);
  334. HANDLE_PHENOME(S);
  335. HANDLE_PHENOME(T);
  336. HANDLE_PHENOME(V);
  337. HANDLE_PHENOME(Z);
  338. }
  339. return VMorpherPhenome::A;
  340. #undef HANDLE_PHENOME
  341. };
  342. auto get_waveform = [](unsigned long form) noexcept
  343. {
  344. if(form == EAX_VOCALMORPHER_SINUSOID) return VMorpherWaveform::Sinusoid;
  345. if(form == EAX_VOCALMORPHER_TRIANGLE) return VMorpherWaveform::Triangle;
  346. if(form == EAX_VOCALMORPHER_SAWTOOTH) return VMorpherWaveform::Sawtooth;
  347. return VMorpherWaveform::Sinusoid;
  348. };
  349. mAlProps = [&]{
  350. VmorpherProps ret{};
  351. ret.PhonemeA = get_phoneme(props.ulPhonemeA);
  352. ret.PhonemeACoarseTuning = static_cast<int>(props.lPhonemeACoarseTuning);
  353. ret.PhonemeB = get_phoneme(props.ulPhonemeB);
  354. ret.PhonemeBCoarseTuning = static_cast<int>(props.lPhonemeBCoarseTuning);
  355. ret.Waveform = get_waveform(props.ulWaveform);
  356. ret.Rate = props.flRate;
  357. return ret;
  358. }();
  359. return true;
  360. }
  361. void EaxVocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
  362. {
  363. static constexpr EAXVOCALMORPHERPROPERTIES defprops{[]
  364. {
  365. EAXVOCALMORPHERPROPERTIES ret{};
  366. ret.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
  367. ret.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
  368. ret.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
  369. ret.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
  370. ret.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
  371. ret.flRate = EAXVOCALMORPHER_DEFAULTRATE;
  372. return ret;
  373. }()};
  374. props = defprops;
  375. }
  376. void EaxVocalMorpherCommitter::Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props)
  377. {
  378. switch(call.get_property_id())
  379. {
  380. case EAXVOCALMORPHER_NONE: break;
  381. case EAXVOCALMORPHER_ALLPARAMETERS: call.set_value<Exception>(props); break;
  382. case EAXVOCALMORPHER_PHONEMEA: call.set_value<Exception>(props.ulPhonemeA); break;
  383. case EAXVOCALMORPHER_PHONEMEACOARSETUNING: call.set_value<Exception>(props.lPhonemeACoarseTuning); break;
  384. case EAXVOCALMORPHER_PHONEMEB: call.set_value<Exception>(props.ulPhonemeB); break;
  385. case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: call.set_value<Exception>(props.lPhonemeBCoarseTuning); break;
  386. case EAXVOCALMORPHER_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
  387. case EAXVOCALMORPHER_RATE: call.set_value<Exception>(props.flRate); break;
  388. default: fail_unknown_property_id();
  389. }
  390. }
  391. void EaxVocalMorpherCommitter::Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props)
  392. {
  393. switch(call.get_property_id())
  394. {
  395. case EAXVOCALMORPHER_NONE: break;
  396. case EAXVOCALMORPHER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
  397. case EAXVOCALMORPHER_PHONEMEA: defer<PhonemeAValidator>(call, props.ulPhonemeA); break;
  398. case EAXVOCALMORPHER_PHONEMEACOARSETUNING: defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning); break;
  399. case EAXVOCALMORPHER_PHONEMEB: defer<PhonemeBValidator>(call, props.ulPhonemeB); break;
  400. case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning); break;
  401. case EAXVOCALMORPHER_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
  402. case EAXVOCALMORPHER_RATE: defer<RateValidator>(call, props.flRate); break;
  403. default: fail_unknown_property_id();
  404. }
  405. }
  406. #endif // ALSOFT_EAX