9 #include "alc/effects/base.h"
10 #include "aloptional.h"
15 #include "alnumeric.h"
16 #include "al/eax/exception.h"
17 #include "al/eax/utils.h"
23 al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val)
25 #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
26 return VMorpherPhenome::x
63 ALenum EnumFromPhenome(VMorpherPhenome phenome)
65 #define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
99 throw std::runtime_error{"Invalid phenome: "+std::to_string(static_cast<int>(phenome))};
100 #undef HANDLE_PHENOME
103 al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
107 case AL_VOCAL_MORPHER_WAVEFORM_SINUSOID: return VMorpherWaveform::Sinusoid;
108 case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return VMorpherWaveform::Triangle;
109 case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return VMorpherWaveform::Sawtooth;
113 ALenum EnumFromWaveform(VMorpherWaveform type)
117 case VMorpherWaveform::Sinusoid: return AL_VOCAL_MORPHER_WAVEFORM_SINUSOID;
118 case VMorpherWaveform::Triangle: return AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE;
119 case VMorpherWaveform::Sawtooth: return AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH;
121 throw std::runtime_error{"Invalid vocal morpher waveform: " +
122 std::to_string(static_cast<int>(type))};
125 void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
129 case AL_VOCAL_MORPHER_PHONEMEA:
130 if(auto phenomeopt = PhenomeFromEnum(val))
131 props->Vmorpher.PhonemeA = *phenomeopt;
133 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
136 case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
137 if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
138 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a coarse tuning out of range"};
139 props->Vmorpher.PhonemeACoarseTuning = val;
142 case AL_VOCAL_MORPHER_PHONEMEB:
143 if(auto phenomeopt = PhenomeFromEnum(val))
144 props->Vmorpher.PhonemeB = *phenomeopt;
146 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
149 case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
150 if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
151 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b coarse tuning out of range"};
152 props->Vmorpher.PhonemeBCoarseTuning = val;
155 case AL_VOCAL_MORPHER_WAVEFORM:
156 if(auto formopt = WaveformFromEmum(val))
157 props->Vmorpher.Waveform = *formopt;
159 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
163 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
167 void Vmorpher_setParamiv(EffectProps*, ALenum param, const int*)
169 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
172 void Vmorpher_setParamf(EffectProps *props, ALenum param, float val)
176 case AL_VOCAL_MORPHER_RATE:
177 if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
178 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher rate out of range"};
179 props->Vmorpher.Rate = val;
183 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
187 void Vmorpher_setParamfv(EffectProps *props, ALenum param, const float *vals)
188 { Vmorpher_setParamf(props, param, vals[0]); }
190 void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
194 case AL_VOCAL_MORPHER_PHONEMEA:
195 *val = EnumFromPhenome(props->Vmorpher.PhonemeA);
198 case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
199 *val = props->Vmorpher.PhonemeACoarseTuning;
202 case AL_VOCAL_MORPHER_PHONEMEB:
203 *val = EnumFromPhenome(props->Vmorpher.PhonemeB);
206 case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
207 *val = props->Vmorpher.PhonemeBCoarseTuning;
210 case AL_VOCAL_MORPHER_WAVEFORM:
211 *val = EnumFromWaveform(props->Vmorpher.Waveform);
215 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
219 void Vmorpher_getParamiv(const EffectProps*, ALenum param, int*)
221 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
224 void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
228 case AL_VOCAL_MORPHER_RATE:
229 *val = props->Vmorpher.Rate;
233 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
237 void Vmorpher_getParamfv(const EffectProps *props, ALenum param, float *vals)
238 { Vmorpher_getParamf(props, param, vals); }
240 EffectProps genDefaultProps() noexcept
243 props.Vmorpher.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
244 props.Vmorpher.PhonemeA = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA);
245 props.Vmorpher.PhonemeB = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB);
246 props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
247 props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
248 props.Vmorpher.Waveform = *WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM);
254 DEFINE_ALEFFECT_VTABLE(Vmorpher);
256 const EffectProps VmorpherEffectProps{genDefaultProps()};
261 using VocalMorpherCommitter = EaxCommitter<EaxVocalMorpherCommitter>;
263 struct PhonemeAValidator {
264 void operator()(unsigned long ulPhonemeA) const
266 eax_validate_range<VocalMorpherCommitter::Exception>(
269 EAXVOCALMORPHER_MINPHONEMEA,
270 EAXVOCALMORPHER_MAXPHONEMEA);
272 }; // PhonemeAValidator
274 struct PhonemeACoarseTuningValidator {
275 void operator()(long lPhonemeACoarseTuning) const
277 eax_validate_range<VocalMorpherCommitter::Exception>(
278 "Phoneme A Coarse Tuning",
279 lPhonemeACoarseTuning,
280 EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
281 EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
283 }; // PhonemeACoarseTuningValidator
285 struct PhonemeBValidator {
286 void operator()(unsigned long ulPhonemeB) const
288 eax_validate_range<VocalMorpherCommitter::Exception>(
291 EAXVOCALMORPHER_MINPHONEMEB,
292 EAXVOCALMORPHER_MAXPHONEMEB);
294 }; // PhonemeBValidator
296 struct PhonemeBCoarseTuningValidator {
297 void operator()(long lPhonemeBCoarseTuning) const
299 eax_validate_range<VocalMorpherCommitter::Exception>(
300 "Phoneme B Coarse Tuning",
301 lPhonemeBCoarseTuning,
302 EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
303 EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
305 }; // PhonemeBCoarseTuningValidator
307 struct WaveformValidator {
308 void operator()(unsigned long ulWaveform) const
310 eax_validate_range<VocalMorpherCommitter::Exception>(
313 EAXVOCALMORPHER_MINWAVEFORM,
314 EAXVOCALMORPHER_MAXWAVEFORM);
316 }; // WaveformValidator
318 struct RateValidator {
319 void operator()(float flRate) const
321 eax_validate_range<VocalMorpherCommitter::Exception>(
324 EAXVOCALMORPHER_MINRATE,
325 EAXVOCALMORPHER_MAXRATE);
329 struct AllValidator {
330 void operator()(const EAXVOCALMORPHERPROPERTIES& all) const
332 PhonemeAValidator{}(all.ulPhonemeA);
333 PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning);
334 PhonemeBValidator{}(all.ulPhonemeB);
335 PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning);
336 WaveformValidator{}(all.ulWaveform);
337 RateValidator{}(all.flRate);
344 struct VocalMorpherCommitter::Exception : public EaxException {
345 explicit Exception(const char *message) : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
350 [[noreturn]] void VocalMorpherCommitter::fail(const char *message)
352 throw Exception{message};
356 bool VocalMorpherCommitter::commit(const EaxEffectProps &props)
358 if(props.mType == mEaxProps.mType
359 && mEaxProps.mVocalMorpher.ulPhonemeA == props.mVocalMorpher.ulPhonemeA
360 && mEaxProps.mVocalMorpher.lPhonemeACoarseTuning == props.mVocalMorpher.lPhonemeACoarseTuning
361 && mEaxProps.mVocalMorpher.ulPhonemeB == props.mVocalMorpher.ulPhonemeB
362 && mEaxProps.mVocalMorpher.lPhonemeBCoarseTuning == props.mVocalMorpher.lPhonemeBCoarseTuning
363 && mEaxProps.mVocalMorpher.ulWaveform == props.mVocalMorpher.ulWaveform
364 && mEaxProps.mVocalMorpher.flRate == props.mVocalMorpher.flRate)
369 auto get_phoneme = [](unsigned long phoneme) noexcept
371 #define HANDLE_PHENOME(x) case x: return VMorpherPhenome::x
405 return VMorpherPhenome::A;
406 #undef HANDLE_PHENOME
408 auto get_waveform = [](unsigned long form) noexcept
410 if(form == EAX_VOCALMORPHER_SINUSOID) return VMorpherWaveform::Sinusoid;
411 if(form == EAX_VOCALMORPHER_TRIANGLE) return VMorpherWaveform::Triangle;
412 if(form == EAX_VOCALMORPHER_SAWTOOTH) return VMorpherWaveform::Sawtooth;
413 return VMorpherWaveform::Sinusoid;
416 mAlProps.Vmorpher.PhonemeA = get_phoneme(props.mVocalMorpher.ulPhonemeA);
417 mAlProps.Vmorpher.PhonemeACoarseTuning = static_cast<int>(props.mVocalMorpher.lPhonemeACoarseTuning);
418 mAlProps.Vmorpher.PhonemeB = get_phoneme(props.mVocalMorpher.ulPhonemeB);
419 mAlProps.Vmorpher.PhonemeBCoarseTuning = static_cast<int>(props.mVocalMorpher.lPhonemeBCoarseTuning);
420 mAlProps.Vmorpher.Waveform = get_waveform(props.mVocalMorpher.ulWaveform);
421 mAlProps.Vmorpher.Rate = props.mVocalMorpher.flRate;
427 void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
429 props.mType = EaxEffectType::VocalMorpher;
430 props.mVocalMorpher.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
431 props.mVocalMorpher.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
432 props.mVocalMorpher.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
433 props.mVocalMorpher.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
434 props.mVocalMorpher.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
435 props.mVocalMorpher.flRate = EAXVOCALMORPHER_DEFAULTRATE;
439 void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
441 switch(call.get_property_id())
443 case EAXVOCALMORPHER_NONE:
446 case EAXVOCALMORPHER_ALLPARAMETERS:
447 call.set_value<Exception>(props.mVocalMorpher);
450 case EAXVOCALMORPHER_PHONEMEA:
451 call.set_value<Exception>(props.mVocalMorpher.ulPhonemeA);
454 case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
455 call.set_value<Exception>(props.mVocalMorpher.lPhonemeACoarseTuning);
458 case EAXVOCALMORPHER_PHONEMEB:
459 call.set_value<Exception>(props.mVocalMorpher.ulPhonemeB);
462 case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
463 call.set_value<Exception>(props.mVocalMorpher.lPhonemeBCoarseTuning);
466 case EAXVOCALMORPHER_WAVEFORM:
467 call.set_value<Exception>(props.mVocalMorpher.ulWaveform);
470 case EAXVOCALMORPHER_RATE:
471 call.set_value<Exception>(props.mVocalMorpher.flRate);
475 fail_unknown_property_id();
480 void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props)
482 switch(call.get_property_id())
484 case EAXVOCALMORPHER_NONE:
487 case EAXVOCALMORPHER_ALLPARAMETERS:
488 defer<AllValidator>(call, props.mVocalMorpher);
491 case EAXVOCALMORPHER_PHONEMEA:
492 defer<PhonemeAValidator>(call, props.mVocalMorpher.ulPhonemeA);
495 case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
496 defer<PhonemeACoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeACoarseTuning);
499 case EAXVOCALMORPHER_PHONEMEB:
500 defer<PhonemeBValidator>(call, props.mVocalMorpher.ulPhonemeB);
503 case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
504 defer<PhonemeBCoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeBCoarseTuning);
507 case EAXVOCALMORPHER_WAVEFORM:
508 defer<WaveformValidator>(call, props.mVocalMorpher.ulWaveform);
511 case EAXVOCALMORPHER_RATE:
512 defer<RateValidator>(call, props.mVocalMorpher.flRate);
516 fail_unknown_property_id();