Check for a minimum PipeWire version
[openal-soft.git] / al / effects / vmorpher.cpp
blob8c0b3adba79d036b3d1af421edae25a0505c6555
2 #include "config.h"
4 #include <stdexcept>
6 #include "AL/al.h"
7 #include "AL/efx.h"
9 #include "alc/effects/base.h"
10 #include "aloptional.h"
11 #include "effects.h"
13 #ifdef ALSOFT_EAX
14 #include <cassert>
16 #include "alnumeric.h"
18 #include "al/eax_exception.h"
19 #include "al/eax_utils.h"
20 #endif // ALSOFT_EAX
23 namespace {
25 al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val)
27 #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
28 return al::make_optional(VMorpherPhenome::x)
29 switch(val)
31 HANDLE_PHENOME(A);
32 HANDLE_PHENOME(E);
33 HANDLE_PHENOME(I);
34 HANDLE_PHENOME(O);
35 HANDLE_PHENOME(U);
36 HANDLE_PHENOME(AA);
37 HANDLE_PHENOME(AE);
38 HANDLE_PHENOME(AH);
39 HANDLE_PHENOME(AO);
40 HANDLE_PHENOME(EH);
41 HANDLE_PHENOME(ER);
42 HANDLE_PHENOME(IH);
43 HANDLE_PHENOME(IY);
44 HANDLE_PHENOME(UH);
45 HANDLE_PHENOME(UW);
46 HANDLE_PHENOME(B);
47 HANDLE_PHENOME(D);
48 HANDLE_PHENOME(F);
49 HANDLE_PHENOME(G);
50 HANDLE_PHENOME(J);
51 HANDLE_PHENOME(K);
52 HANDLE_PHENOME(L);
53 HANDLE_PHENOME(M);
54 HANDLE_PHENOME(N);
55 HANDLE_PHENOME(P);
56 HANDLE_PHENOME(R);
57 HANDLE_PHENOME(S);
58 HANDLE_PHENOME(T);
59 HANDLE_PHENOME(V);
60 HANDLE_PHENOME(Z);
62 return al::nullopt;
63 #undef HANDLE_PHENOME
65 ALenum EnumFromPhenome(VMorpherPhenome phenome)
67 #define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
68 switch(phenome)
70 HANDLE_PHENOME(A);
71 HANDLE_PHENOME(E);
72 HANDLE_PHENOME(I);
73 HANDLE_PHENOME(O);
74 HANDLE_PHENOME(U);
75 HANDLE_PHENOME(AA);
76 HANDLE_PHENOME(AE);
77 HANDLE_PHENOME(AH);
78 HANDLE_PHENOME(AO);
79 HANDLE_PHENOME(EH);
80 HANDLE_PHENOME(ER);
81 HANDLE_PHENOME(IH);
82 HANDLE_PHENOME(IY);
83 HANDLE_PHENOME(UH);
84 HANDLE_PHENOME(UW);
85 HANDLE_PHENOME(B);
86 HANDLE_PHENOME(D);
87 HANDLE_PHENOME(F);
88 HANDLE_PHENOME(G);
89 HANDLE_PHENOME(J);
90 HANDLE_PHENOME(K);
91 HANDLE_PHENOME(L);
92 HANDLE_PHENOME(M);
93 HANDLE_PHENOME(N);
94 HANDLE_PHENOME(P);
95 HANDLE_PHENOME(R);
96 HANDLE_PHENOME(S);
97 HANDLE_PHENOME(T);
98 HANDLE_PHENOME(V);
99 HANDLE_PHENOME(Z);
101 throw std::runtime_error{"Invalid phenome: "+std::to_string(static_cast<int>(phenome))};
102 #undef HANDLE_PHENOME
105 al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
107 switch(value)
109 case AL_VOCAL_MORPHER_WAVEFORM_SINUSOID: return al::make_optional(VMorpherWaveform::Sinusoid);
110 case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return al::make_optional(VMorpherWaveform::Triangle);
111 case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return al::make_optional(VMorpherWaveform::Sawtooth);
113 return al::nullopt;
115 ALenum EnumFromWaveform(VMorpherWaveform type)
117 switch(type)
119 case VMorpherWaveform::Sinusoid: return AL_VOCAL_MORPHER_WAVEFORM_SINUSOID;
120 case VMorpherWaveform::Triangle: return AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE;
121 case VMorpherWaveform::Sawtooth: return AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH;
123 throw std::runtime_error{"Invalid vocal morpher waveform: " +
124 std::to_string(static_cast<int>(type))};
127 void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
129 switch(param)
131 case AL_VOCAL_MORPHER_PHONEMEA:
132 if(auto phenomeopt = PhenomeFromEnum(val))
133 props->Vmorpher.PhonemeA = *phenomeopt;
134 else
135 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
136 break;
138 case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
139 if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
140 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a coarse tuning out of range"};
141 props->Vmorpher.PhonemeACoarseTuning = val;
142 break;
144 case AL_VOCAL_MORPHER_PHONEMEB:
145 if(auto phenomeopt = PhenomeFromEnum(val))
146 props->Vmorpher.PhonemeB = *phenomeopt;
147 else
148 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
149 break;
151 case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
152 if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
153 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b coarse tuning out of range"};
154 props->Vmorpher.PhonemeBCoarseTuning = val;
155 break;
157 case AL_VOCAL_MORPHER_WAVEFORM:
158 if(auto formopt = WaveformFromEmum(val))
159 props->Vmorpher.Waveform = *formopt;
160 else
161 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
162 break;
164 default:
165 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
166 param};
169 void Vmorpher_setParamiv(EffectProps*, ALenum param, const int*)
171 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
172 param};
174 void Vmorpher_setParamf(EffectProps *props, ALenum param, float val)
176 switch(param)
178 case AL_VOCAL_MORPHER_RATE:
179 if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
180 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher rate out of range"};
181 props->Vmorpher.Rate = val;
182 break;
184 default:
185 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
186 param};
189 void Vmorpher_setParamfv(EffectProps *props, ALenum param, const float *vals)
190 { Vmorpher_setParamf(props, param, vals[0]); }
192 void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
194 switch(param)
196 case AL_VOCAL_MORPHER_PHONEMEA:
197 *val = EnumFromPhenome(props->Vmorpher.PhonemeA);
198 break;
200 case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
201 *val = props->Vmorpher.PhonemeACoarseTuning;
202 break;
204 case AL_VOCAL_MORPHER_PHONEMEB:
205 *val = EnumFromPhenome(props->Vmorpher.PhonemeB);
206 break;
208 case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
209 *val = props->Vmorpher.PhonemeBCoarseTuning;
210 break;
212 case AL_VOCAL_MORPHER_WAVEFORM:
213 *val = EnumFromWaveform(props->Vmorpher.Waveform);
214 break;
216 default:
217 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
218 param};
221 void Vmorpher_getParamiv(const EffectProps*, ALenum param, int*)
223 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
224 param};
226 void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
228 switch(param)
230 case AL_VOCAL_MORPHER_RATE:
231 *val = props->Vmorpher.Rate;
232 break;
234 default:
235 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
236 param};
239 void Vmorpher_getParamfv(const EffectProps *props, ALenum param, float *vals)
240 { Vmorpher_getParamf(props, param, vals); }
242 EffectProps genDefaultProps() noexcept
244 EffectProps props{};
245 props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
246 props.Vmorpher.PhonemeA = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA);
247 props.Vmorpher.PhonemeB = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB);
248 props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
249 props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
250 props.Vmorpher.Waveform = *WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM);
251 return props;
254 } // namespace
256 DEFINE_ALEFFECT_VTABLE(Vmorpher);
258 const EffectProps VmorpherEffectProps{genDefaultProps()};
260 #ifdef ALSOFT_EAX
261 namespace {
263 using EaxVocalMorpherEffectDirtyFlagsValue = std::uint_least8_t;
265 struct EaxVocalMorpherEffectDirtyFlags
267 using EaxIsBitFieldStruct = bool;
269 EaxVocalMorpherEffectDirtyFlagsValue ulPhonemeA : 1;
270 EaxVocalMorpherEffectDirtyFlagsValue lPhonemeACoarseTuning : 1;
271 EaxVocalMorpherEffectDirtyFlagsValue ulPhonemeB : 1;
272 EaxVocalMorpherEffectDirtyFlagsValue lPhonemeBCoarseTuning : 1;
273 EaxVocalMorpherEffectDirtyFlagsValue ulWaveform : 1;
274 EaxVocalMorpherEffectDirtyFlagsValue flRate : 1;
275 }; // EaxPitchShifterEffectDirtyFlags
278 class EaxVocalMorpherEffect final :
279 public EaxEffect
281 public:
282 EaxVocalMorpherEffect();
284 void dispatch(const EaxEaxCall& eax_call) override;
286 // [[nodiscard]]
287 bool apply_deferred() override;
289 private:
290 EAXVOCALMORPHERPROPERTIES eax_{};
291 EAXVOCALMORPHERPROPERTIES eax_d_{};
292 EaxVocalMorpherEffectDirtyFlags eax_dirty_flags_{};
294 void set_eax_defaults();
296 void set_efx_phoneme_a();
297 void set_efx_phoneme_a_coarse_tuning();
298 void set_efx_phoneme_b();
299 void set_efx_phoneme_b_coarse_tuning();
300 void set_efx_waveform();
301 void set_efx_rate();
302 void set_efx_defaults();
304 void get(const EaxEaxCall& eax_call);
306 void validate_phoneme_a(unsigned long ulPhonemeA);
307 void validate_phoneme_a_coarse_tuning(long lPhonemeACoarseTuning);
308 void validate_phoneme_b(unsigned long ulPhonemeB);
309 void validate_phoneme_b_coarse_tuning(long lPhonemeBCoarseTuning);
310 void validate_waveform(unsigned long ulWaveform);
311 void validate_rate(float flRate);
312 void validate_all(const EAXVOCALMORPHERPROPERTIES& all);
314 void defer_phoneme_a(unsigned long ulPhonemeA);
315 void defer_phoneme_a_coarse_tuning(long lPhonemeACoarseTuning);
316 void defer_phoneme_b(unsigned long ulPhonemeB);
317 void defer_phoneme_b_coarse_tuning(long lPhonemeBCoarseTuning);
318 void defer_waveform(unsigned long ulWaveform);
319 void defer_rate(float flRate);
320 void defer_all(const EAXVOCALMORPHERPROPERTIES& all);
322 void defer_phoneme_a(const EaxEaxCall& eax_call);
323 void defer_phoneme_a_coarse_tuning(const EaxEaxCall& eax_call);
324 void defer_phoneme_b(const EaxEaxCall& eax_call);
325 void defer_phoneme_b_coarse_tuning(const EaxEaxCall& eax_call);
326 void defer_waveform(const EaxEaxCall& eax_call);
327 void defer_rate(const EaxEaxCall& eax_call);
328 void defer_all(const EaxEaxCall& eax_call);
330 void set(const EaxEaxCall& eax_call);
331 }; // EaxVocalMorpherEffect
334 class EaxVocalMorpherEffectException :
335 public EaxException
337 public:
338 explicit EaxVocalMorpherEffectException(
339 const char* message)
341 EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
344 }; // EaxVocalMorpherEffectException
347 EaxVocalMorpherEffect::EaxVocalMorpherEffect()
348 : EaxEffect{AL_EFFECT_VOCAL_MORPHER}
350 set_eax_defaults();
351 set_efx_defaults();
354 void EaxVocalMorpherEffect::dispatch(const EaxEaxCall& eax_call)
356 eax_call.is_get() ? get(eax_call) : set(eax_call);
359 void EaxVocalMorpherEffect::set_eax_defaults()
361 eax_.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
362 eax_.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
363 eax_.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
364 eax_.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
365 eax_.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
366 eax_.flRate = EAXVOCALMORPHER_DEFAULTRATE;
368 eax_d_ = eax_;
371 void EaxVocalMorpherEffect::set_efx_phoneme_a()
373 const auto phoneme_a = clamp(
374 static_cast<ALint>(eax_.ulPhonemeA),
375 AL_VOCAL_MORPHER_MIN_PHONEMEA,
376 AL_VOCAL_MORPHER_MAX_PHONEMEA);
378 const auto efx_phoneme_a = PhenomeFromEnum(phoneme_a);
379 assert(efx_phoneme_a.has_value());
380 al_effect_props_.Vmorpher.PhonemeA = *efx_phoneme_a;
383 void EaxVocalMorpherEffect::set_efx_phoneme_a_coarse_tuning()
385 const auto phoneme_a_coarse_tuning = clamp(
386 static_cast<ALint>(eax_.lPhonemeACoarseTuning),
387 AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING,
388 AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING);
390 al_effect_props_.Vmorpher.PhonemeACoarseTuning = phoneme_a_coarse_tuning;
393 void EaxVocalMorpherEffect::set_efx_phoneme_b()
395 const auto phoneme_b = clamp(
396 static_cast<ALint>(eax_.ulPhonemeB),
397 AL_VOCAL_MORPHER_MIN_PHONEMEB,
398 AL_VOCAL_MORPHER_MAX_PHONEMEB);
400 const auto efx_phoneme_b = PhenomeFromEnum(phoneme_b);
401 assert(efx_phoneme_b.has_value());
402 al_effect_props_.Vmorpher.PhonemeB = *efx_phoneme_b;
405 void EaxVocalMorpherEffect::set_efx_phoneme_b_coarse_tuning()
407 const auto phoneme_b_coarse_tuning = clamp(
408 static_cast<ALint>(eax_.lPhonemeBCoarseTuning),
409 AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING,
410 AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING);
412 al_effect_props_.Vmorpher.PhonemeBCoarseTuning = phoneme_b_coarse_tuning;
415 void EaxVocalMorpherEffect::set_efx_waveform()
417 const auto waveform = clamp(
418 static_cast<ALint>(eax_.ulWaveform),
419 AL_VOCAL_MORPHER_MIN_WAVEFORM,
420 AL_VOCAL_MORPHER_MAX_WAVEFORM);
422 const auto wfx_waveform = WaveformFromEmum(waveform);
423 assert(wfx_waveform.has_value());
424 al_effect_props_.Vmorpher.Waveform = *wfx_waveform;
427 void EaxVocalMorpherEffect::set_efx_rate()
429 const auto rate = clamp(
430 eax_.flRate,
431 AL_VOCAL_MORPHER_MIN_RATE,
432 AL_VOCAL_MORPHER_MAX_RATE);
434 al_effect_props_.Vmorpher.Rate = rate;
437 void EaxVocalMorpherEffect::set_efx_defaults()
439 set_efx_phoneme_a();
440 set_efx_phoneme_a_coarse_tuning();
441 set_efx_phoneme_b();
442 set_efx_phoneme_b_coarse_tuning();
443 set_efx_waveform();
444 set_efx_rate();
447 void EaxVocalMorpherEffect::get(const EaxEaxCall& eax_call)
449 switch(eax_call.get_property_id())
451 case EAXVOCALMORPHER_NONE:
452 break;
454 case EAXVOCALMORPHER_ALLPARAMETERS:
455 eax_call.set_value<EaxVocalMorpherEffectException>(eax_);
456 break;
458 case EAXVOCALMORPHER_PHONEMEA:
459 eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulPhonemeA);
460 break;
462 case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
463 eax_call.set_value<EaxVocalMorpherEffectException>(eax_.lPhonemeACoarseTuning);
464 break;
466 case EAXVOCALMORPHER_PHONEMEB:
467 eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulPhonemeB);
468 break;
470 case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
471 eax_call.set_value<EaxVocalMorpherEffectException>(eax_.lPhonemeBCoarseTuning);
472 break;
474 case EAXVOCALMORPHER_WAVEFORM:
475 eax_call.set_value<EaxVocalMorpherEffectException>(eax_.ulWaveform);
476 break;
478 case EAXVOCALMORPHER_RATE:
479 eax_call.set_value<EaxVocalMorpherEffectException>(eax_.flRate);
480 break;
482 default:
483 throw EaxVocalMorpherEffectException{"Unsupported property id."};
487 void EaxVocalMorpherEffect::validate_phoneme_a(
488 unsigned long ulPhonemeA)
490 eax_validate_range<EaxVocalMorpherEffectException>(
491 "Phoneme A",
492 ulPhonemeA,
493 EAXVOCALMORPHER_MINPHONEMEA,
494 EAXVOCALMORPHER_MAXPHONEMEA);
497 void EaxVocalMorpherEffect::validate_phoneme_a_coarse_tuning(
498 long lPhonemeACoarseTuning)
500 eax_validate_range<EaxVocalMorpherEffectException>(
501 "Phoneme A Coarse Tuning",
502 lPhonemeACoarseTuning,
503 EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
504 EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
507 void EaxVocalMorpherEffect::validate_phoneme_b(
508 unsigned long ulPhonemeB)
510 eax_validate_range<EaxVocalMorpherEffectException>(
511 "Phoneme B",
512 ulPhonemeB,
513 EAXVOCALMORPHER_MINPHONEMEB,
514 EAXVOCALMORPHER_MAXPHONEMEB);
517 void EaxVocalMorpherEffect::validate_phoneme_b_coarse_tuning(
518 long lPhonemeBCoarseTuning)
520 eax_validate_range<EaxVocalMorpherEffectException>(
521 "Phoneme B Coarse Tuning",
522 lPhonemeBCoarseTuning,
523 EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
524 EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
527 void EaxVocalMorpherEffect::validate_waveform(
528 unsigned long ulWaveform)
530 eax_validate_range<EaxVocalMorpherEffectException>(
531 "Waveform",
532 ulWaveform,
533 EAXVOCALMORPHER_MINWAVEFORM,
534 EAXVOCALMORPHER_MAXWAVEFORM);
537 void EaxVocalMorpherEffect::validate_rate(
538 float flRate)
540 eax_validate_range<EaxVocalMorpherEffectException>(
541 "Rate",
542 flRate,
543 EAXVOCALMORPHER_MINRATE,
544 EAXVOCALMORPHER_MAXRATE);
547 void EaxVocalMorpherEffect::validate_all(
548 const EAXVOCALMORPHERPROPERTIES& all)
550 validate_phoneme_a(all.ulPhonemeA);
551 validate_phoneme_a_coarse_tuning(all.lPhonemeACoarseTuning);
552 validate_phoneme_b(all.ulPhonemeB);
553 validate_phoneme_b_coarse_tuning(all.lPhonemeBCoarseTuning);
554 validate_waveform(all.ulWaveform);
555 validate_rate(all.flRate);
558 void EaxVocalMorpherEffect::defer_phoneme_a(
559 unsigned long ulPhonemeA)
561 eax_d_.ulPhonemeA = ulPhonemeA;
562 eax_dirty_flags_.ulPhonemeA = (eax_.ulPhonemeA != eax_d_.ulPhonemeA);
565 void EaxVocalMorpherEffect::defer_phoneme_a_coarse_tuning(
566 long lPhonemeACoarseTuning)
568 eax_d_.lPhonemeACoarseTuning = lPhonemeACoarseTuning;
569 eax_dirty_flags_.lPhonemeACoarseTuning = (eax_.lPhonemeACoarseTuning != eax_d_.lPhonemeACoarseTuning);
572 void EaxVocalMorpherEffect::defer_phoneme_b(
573 unsigned long ulPhonemeB)
575 eax_d_.ulPhonemeB = ulPhonemeB;
576 eax_dirty_flags_.ulPhonemeB = (eax_.ulPhonemeB != eax_d_.ulPhonemeB);
579 void EaxVocalMorpherEffect::defer_phoneme_b_coarse_tuning(
580 long lPhonemeBCoarseTuning)
582 eax_d_.lPhonemeBCoarseTuning = lPhonemeBCoarseTuning;
583 eax_dirty_flags_.lPhonemeBCoarseTuning = (eax_.lPhonemeBCoarseTuning != eax_d_.lPhonemeBCoarseTuning);
586 void EaxVocalMorpherEffect::defer_waveform(
587 unsigned long ulWaveform)
589 eax_d_.ulWaveform = ulWaveform;
590 eax_dirty_flags_.ulWaveform = (eax_.ulWaveform != eax_d_.ulWaveform);
593 void EaxVocalMorpherEffect::defer_rate(
594 float flRate)
596 eax_d_.flRate = flRate;
597 eax_dirty_flags_.flRate = (eax_.flRate != eax_d_.flRate);
600 void EaxVocalMorpherEffect::defer_all(
601 const EAXVOCALMORPHERPROPERTIES& all)
603 defer_phoneme_a(all.ulPhonemeA);
604 defer_phoneme_a_coarse_tuning(all.lPhonemeACoarseTuning);
605 defer_phoneme_b(all.ulPhonemeB);
606 defer_phoneme_b_coarse_tuning(all.lPhonemeBCoarseTuning);
607 defer_waveform(all.ulWaveform);
608 defer_rate(all.flRate);
611 void EaxVocalMorpherEffect::defer_phoneme_a(
612 const EaxEaxCall& eax_call)
614 const auto& phoneme_a = eax_call.get_value<EaxVocalMorpherEffectException,
615 const decltype(EAXVOCALMORPHERPROPERTIES::ulPhonemeA)>();
617 validate_phoneme_a(phoneme_a);
618 defer_phoneme_a(phoneme_a);
621 void EaxVocalMorpherEffect::defer_phoneme_a_coarse_tuning(
622 const EaxEaxCall& eax_call)
624 const auto& phoneme_a_coarse_tuning = eax_call.get_value<
625 EaxVocalMorpherEffectException,
626 const decltype(EAXVOCALMORPHERPROPERTIES::lPhonemeACoarseTuning)
627 >();
629 validate_phoneme_a_coarse_tuning(phoneme_a_coarse_tuning);
630 defer_phoneme_a_coarse_tuning(phoneme_a_coarse_tuning);
633 void EaxVocalMorpherEffect::defer_phoneme_b(
634 const EaxEaxCall& eax_call)
636 const auto& phoneme_b = eax_call.get_value<
637 EaxVocalMorpherEffectException,
638 const decltype(EAXVOCALMORPHERPROPERTIES::ulPhonemeB)
639 >();
641 validate_phoneme_b(phoneme_b);
642 defer_phoneme_b(phoneme_b);
645 void EaxVocalMorpherEffect::defer_phoneme_b_coarse_tuning(
646 const EaxEaxCall& eax_call)
648 const auto& phoneme_b_coarse_tuning = eax_call.get_value<
649 EaxVocalMorpherEffectException,
650 const decltype(EAXVOCALMORPHERPROPERTIES::lPhonemeBCoarseTuning)
651 >();
653 validate_phoneme_b_coarse_tuning(phoneme_b_coarse_tuning);
654 defer_phoneme_b_coarse_tuning(phoneme_b_coarse_tuning);
657 void EaxVocalMorpherEffect::defer_waveform(
658 const EaxEaxCall& eax_call)
660 const auto& waveform = eax_call.get_value<
661 EaxVocalMorpherEffectException,
662 const decltype(EAXVOCALMORPHERPROPERTIES::ulWaveform)
663 >();
665 validate_waveform(waveform);
666 defer_waveform(waveform);
669 void EaxVocalMorpherEffect::defer_rate(
670 const EaxEaxCall& eax_call)
672 const auto& rate = eax_call.get_value<
673 EaxVocalMorpherEffectException,
674 const decltype(EAXVOCALMORPHERPROPERTIES::flRate)
675 >();
677 validate_rate(rate);
678 defer_rate(rate);
681 void EaxVocalMorpherEffect::defer_all(
682 const EaxEaxCall& eax_call)
684 const auto& all = eax_call.get_value<
685 EaxVocalMorpherEffectException,
686 const EAXVOCALMORPHERPROPERTIES
687 >();
689 validate_all(all);
690 defer_all(all);
693 // [[nodiscard]]
694 bool EaxVocalMorpherEffect::apply_deferred()
696 if (eax_dirty_flags_ == EaxVocalMorpherEffectDirtyFlags{})
698 return false;
701 eax_ = eax_d_;
703 if (eax_dirty_flags_.ulPhonemeA)
705 set_efx_phoneme_a();
708 if (eax_dirty_flags_.lPhonemeACoarseTuning)
710 set_efx_phoneme_a_coarse_tuning();
713 if (eax_dirty_flags_.ulPhonemeB)
715 set_efx_phoneme_b();
718 if (eax_dirty_flags_.lPhonemeBCoarseTuning)
720 set_efx_phoneme_b_coarse_tuning();
723 if (eax_dirty_flags_.ulWaveform)
725 set_efx_waveform();
728 if (eax_dirty_flags_.flRate)
730 set_efx_rate();
733 eax_dirty_flags_ = EaxVocalMorpherEffectDirtyFlags{};
735 return true;
738 void EaxVocalMorpherEffect::set(const EaxEaxCall& eax_call)
740 switch(eax_call.get_property_id())
742 case EAXVOCALMORPHER_NONE:
743 break;
745 case EAXVOCALMORPHER_ALLPARAMETERS:
746 defer_all(eax_call);
747 break;
749 case EAXVOCALMORPHER_PHONEMEA:
750 defer_phoneme_a(eax_call);
751 break;
753 case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
754 defer_phoneme_a_coarse_tuning(eax_call);
755 break;
757 case EAXVOCALMORPHER_PHONEMEB:
758 defer_phoneme_b(eax_call);
759 break;
761 case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
762 defer_phoneme_b_coarse_tuning(eax_call);
763 break;
765 case EAXVOCALMORPHER_WAVEFORM:
766 defer_waveform(eax_call);
767 break;
769 case EAXVOCALMORPHER_RATE:
770 defer_rate(eax_call);
771 break;
773 default:
774 throw EaxVocalMorpherEffectException{"Unsupported property id."};
778 } // namespace
781 EaxEffectUPtr eax_create_eax_vocal_morpher_effect()
783 return std::make_unique<EaxVocalMorpherEffect>();
786 #endif // ALSOFT_EAX