Check for unsigned underflow
[openal-soft.git] / al / effects / vmorpher.cpp
blob09bd73d9c4fbca382d868796c48eb602a7eb62ba
2 #include "config.h"
4 #include <optional>
5 #include <stdexcept>
7 #include "AL/al.h"
8 #include "AL/efx.h"
10 #include "core/effects/base.h"
11 #include "effects.h"
13 #if ALSOFT_EAX
14 #include <cassert>
15 #include "al/eax/effect.h"
16 #include "al/eax/exception.h"
17 #include "al/eax/utils.h"
18 #endif // ALSOFT_EAX
21 namespace {
23 constexpr std::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val) noexcept
25 #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
26 return VMorpherPhenome::x
27 switch(val)
29 HANDLE_PHENOME(A);
30 HANDLE_PHENOME(E);
31 HANDLE_PHENOME(I);
32 HANDLE_PHENOME(O);
33 HANDLE_PHENOME(U);
34 HANDLE_PHENOME(AA);
35 HANDLE_PHENOME(AE);
36 HANDLE_PHENOME(AH);
37 HANDLE_PHENOME(AO);
38 HANDLE_PHENOME(EH);
39 HANDLE_PHENOME(ER);
40 HANDLE_PHENOME(IH);
41 HANDLE_PHENOME(IY);
42 HANDLE_PHENOME(UH);
43 HANDLE_PHENOME(UW);
44 HANDLE_PHENOME(B);
45 HANDLE_PHENOME(D);
46 HANDLE_PHENOME(F);
47 HANDLE_PHENOME(G);
48 HANDLE_PHENOME(J);
49 HANDLE_PHENOME(K);
50 HANDLE_PHENOME(L);
51 HANDLE_PHENOME(M);
52 HANDLE_PHENOME(N);
53 HANDLE_PHENOME(P);
54 HANDLE_PHENOME(R);
55 HANDLE_PHENOME(S);
56 HANDLE_PHENOME(T);
57 HANDLE_PHENOME(V);
58 HANDLE_PHENOME(Z);
60 return std::nullopt;
61 #undef HANDLE_PHENOME
63 constexpr ALenum EnumFromPhenome(VMorpherPhenome phenome)
65 #define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
66 switch(phenome)
68 HANDLE_PHENOME(A);
69 HANDLE_PHENOME(E);
70 HANDLE_PHENOME(I);
71 HANDLE_PHENOME(O);
72 HANDLE_PHENOME(U);
73 HANDLE_PHENOME(AA);
74 HANDLE_PHENOME(AE);
75 HANDLE_PHENOME(AH);
76 HANDLE_PHENOME(AO);
77 HANDLE_PHENOME(EH);
78 HANDLE_PHENOME(ER);
79 HANDLE_PHENOME(IH);
80 HANDLE_PHENOME(IY);
81 HANDLE_PHENOME(UH);
82 HANDLE_PHENOME(UW);
83 HANDLE_PHENOME(B);
84 HANDLE_PHENOME(D);
85 HANDLE_PHENOME(F);
86 HANDLE_PHENOME(G);
87 HANDLE_PHENOME(J);
88 HANDLE_PHENOME(K);
89 HANDLE_PHENOME(L);
90 HANDLE_PHENOME(M);
91 HANDLE_PHENOME(N);
92 HANDLE_PHENOME(P);
93 HANDLE_PHENOME(R);
94 HANDLE_PHENOME(S);
95 HANDLE_PHENOME(T);
96 HANDLE_PHENOME(V);
97 HANDLE_PHENOME(Z);
99 throw std::runtime_error{"Invalid phenome: "+std::to_string(static_cast<int>(phenome))};
100 #undef HANDLE_PHENOME
103 constexpr std::optional<VMorpherWaveform> WaveformFromEmum(ALenum value) noexcept
105 switch(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;
111 return std::nullopt;
113 constexpr ALenum EnumFromWaveform(VMorpherWaveform type)
115 switch(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 constexpr EffectProps genDefaultProps() noexcept
127 VmorpherProps props{};
128 props.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
129 props.PhonemeA = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA).value();
130 props.PhonemeB = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB).value();
131 props.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
132 props.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
133 props.Waveform = WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM).value();
134 return props;
137 } // namespace
139 const EffectProps VmorpherEffectProps{genDefaultProps()};
141 void VmorpherEffectHandler::SetParami(VmorpherProps &props, ALenum param, int val)
143 switch(param)
145 case AL_VOCAL_MORPHER_PHONEMEA:
146 if(auto phenomeopt = PhenomeFromEnum(val))
147 props.PhonemeA = *phenomeopt;
148 else
149 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
150 break;
152 case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
153 if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
154 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a coarse tuning out of range"};
155 props.PhonemeACoarseTuning = val;
156 break;
158 case AL_VOCAL_MORPHER_PHONEMEB:
159 if(auto phenomeopt = PhenomeFromEnum(val))
160 props.PhonemeB = *phenomeopt;
161 else
162 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
163 break;
165 case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
166 if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
167 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b coarse tuning out of range"};
168 props.PhonemeBCoarseTuning = val;
169 break;
171 case AL_VOCAL_MORPHER_WAVEFORM:
172 if(auto formopt = WaveformFromEmum(val))
173 props.Waveform = *formopt;
174 else
175 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
176 break;
178 default:
179 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
180 param};
183 void VmorpherEffectHandler::SetParamiv(VmorpherProps&, ALenum param, const int*)
185 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
186 param};
188 void VmorpherEffectHandler::SetParamf(VmorpherProps &props, ALenum param, float val)
190 switch(param)
192 case AL_VOCAL_MORPHER_RATE:
193 if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
194 throw effect_exception{AL_INVALID_VALUE, "Vocal morpher rate out of range"};
195 props.Rate = val;
196 break;
198 default:
199 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
200 param};
203 void VmorpherEffectHandler::SetParamfv(VmorpherProps &props, ALenum param, const float *vals)
204 { SetParamf(props, param, *vals); }
206 void VmorpherEffectHandler::GetParami(const VmorpherProps &props, ALenum param, int* val)
208 switch(param)
210 case AL_VOCAL_MORPHER_PHONEMEA: *val = EnumFromPhenome(props.PhonemeA); break;
211 case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: *val = props.PhonemeACoarseTuning; break;
212 case AL_VOCAL_MORPHER_PHONEMEB: *val = EnumFromPhenome(props.PhonemeB); break;
213 case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: *val = props.PhonemeBCoarseTuning; break;
214 case AL_VOCAL_MORPHER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); break;
216 default:
217 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
218 param};
221 void VmorpherEffectHandler::GetParamiv(const VmorpherProps&, ALenum param, int*)
223 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
224 param};
226 void VmorpherEffectHandler::GetParamf(const VmorpherProps &props, ALenum param, float *val)
228 switch(param)
230 case AL_VOCAL_MORPHER_RATE:
231 *val = props.Rate;
232 break;
234 default:
235 throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
236 param};
239 void VmorpherEffectHandler::GetParamfv(const VmorpherProps &props, ALenum param, float *vals)
240 { GetParamf(props, param, vals); }
243 #if ALSOFT_EAX
244 namespace {
246 using VocalMorpherCommitter = EaxCommitter<EaxVocalMorpherCommitter>;
248 struct PhonemeAValidator {
249 void operator()(unsigned long ulPhonemeA) const
251 eax_validate_range<VocalMorpherCommitter::Exception>(
252 "Phoneme A",
253 ulPhonemeA,
254 EAXVOCALMORPHER_MINPHONEMEA,
255 EAXVOCALMORPHER_MAXPHONEMEA);
257 }; // PhonemeAValidator
259 struct PhonemeACoarseTuningValidator {
260 void operator()(long lPhonemeACoarseTuning) const
262 eax_validate_range<VocalMorpherCommitter::Exception>(
263 "Phoneme A Coarse Tuning",
264 lPhonemeACoarseTuning,
265 EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
266 EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
268 }; // PhonemeACoarseTuningValidator
270 struct PhonemeBValidator {
271 void operator()(unsigned long ulPhonemeB) const
273 eax_validate_range<VocalMorpherCommitter::Exception>(
274 "Phoneme B",
275 ulPhonemeB,
276 EAXVOCALMORPHER_MINPHONEMEB,
277 EAXVOCALMORPHER_MAXPHONEMEB);
279 }; // PhonemeBValidator
281 struct PhonemeBCoarseTuningValidator {
282 void operator()(long lPhonemeBCoarseTuning) const
284 eax_validate_range<VocalMorpherCommitter::Exception>(
285 "Phoneme B Coarse Tuning",
286 lPhonemeBCoarseTuning,
287 EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
288 EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
290 }; // PhonemeBCoarseTuningValidator
292 struct WaveformValidator {
293 void operator()(unsigned long ulWaveform) const
295 eax_validate_range<VocalMorpherCommitter::Exception>(
296 "Waveform",
297 ulWaveform,
298 EAXVOCALMORPHER_MINWAVEFORM,
299 EAXVOCALMORPHER_MAXWAVEFORM);
301 }; // WaveformValidator
303 struct RateValidator {
304 void operator()(float flRate) const
306 eax_validate_range<VocalMorpherCommitter::Exception>(
307 "Rate",
308 flRate,
309 EAXVOCALMORPHER_MINRATE,
310 EAXVOCALMORPHER_MAXRATE);
312 }; // RateValidator
314 struct AllValidator {
315 void operator()(const EAXVOCALMORPHERPROPERTIES& all) const
317 PhonemeAValidator{}(all.ulPhonemeA);
318 PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning);
319 PhonemeBValidator{}(all.ulPhonemeB);
320 PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning);
321 WaveformValidator{}(all.ulWaveform);
322 RateValidator{}(all.flRate);
324 }; // AllValidator
326 } // namespace
328 template<>
329 struct VocalMorpherCommitter::Exception : public EaxException {
330 explicit Exception(const char *message) : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
334 template<>
335 [[noreturn]] void VocalMorpherCommitter::fail(const char *message)
337 throw Exception{message};
340 bool EaxVocalMorpherCommitter::commit(const EAXVOCALMORPHERPROPERTIES &props)
342 if(auto *cur = std::get_if<EAXVOCALMORPHERPROPERTIES>(&mEaxProps); cur && *cur == props)
343 return false;
345 mEaxProps = props;
347 auto get_phoneme = [](unsigned long phoneme) noexcept
349 #define HANDLE_PHENOME(x) case x: return VMorpherPhenome::x
350 switch(phoneme)
352 HANDLE_PHENOME(A);
353 HANDLE_PHENOME(E);
354 HANDLE_PHENOME(I);
355 HANDLE_PHENOME(O);
356 HANDLE_PHENOME(U);
357 HANDLE_PHENOME(AA);
358 HANDLE_PHENOME(AE);
359 HANDLE_PHENOME(AH);
360 HANDLE_PHENOME(AO);
361 HANDLE_PHENOME(EH);
362 HANDLE_PHENOME(ER);
363 HANDLE_PHENOME(IH);
364 HANDLE_PHENOME(IY);
365 HANDLE_PHENOME(UH);
366 HANDLE_PHENOME(UW);
367 HANDLE_PHENOME(B);
368 HANDLE_PHENOME(D);
369 HANDLE_PHENOME(F);
370 HANDLE_PHENOME(G);
371 HANDLE_PHENOME(J);
372 HANDLE_PHENOME(K);
373 HANDLE_PHENOME(L);
374 HANDLE_PHENOME(M);
375 HANDLE_PHENOME(N);
376 HANDLE_PHENOME(P);
377 HANDLE_PHENOME(R);
378 HANDLE_PHENOME(S);
379 HANDLE_PHENOME(T);
380 HANDLE_PHENOME(V);
381 HANDLE_PHENOME(Z);
383 return VMorpherPhenome::A;
384 #undef HANDLE_PHENOME
386 auto get_waveform = [](unsigned long form) noexcept
388 if(form == EAX_VOCALMORPHER_SINUSOID) return VMorpherWaveform::Sinusoid;
389 if(form == EAX_VOCALMORPHER_TRIANGLE) return VMorpherWaveform::Triangle;
390 if(form == EAX_VOCALMORPHER_SAWTOOTH) return VMorpherWaveform::Sawtooth;
391 return VMorpherWaveform::Sinusoid;
394 mAlProps = [&]{
395 VmorpherProps ret{};
396 ret.PhonemeA = get_phoneme(props.ulPhonemeA);
397 ret.PhonemeACoarseTuning = static_cast<int>(props.lPhonemeACoarseTuning);
398 ret.PhonemeB = get_phoneme(props.ulPhonemeB);
399 ret.PhonemeBCoarseTuning = static_cast<int>(props.lPhonemeBCoarseTuning);
400 ret.Waveform = get_waveform(props.ulWaveform);
401 ret.Rate = props.flRate;
402 return ret;
403 }();
405 return true;
408 void EaxVocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
410 static constexpr EAXVOCALMORPHERPROPERTIES defprops{[]
412 EAXVOCALMORPHERPROPERTIES ret{};
413 ret.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
414 ret.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
415 ret.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
416 ret.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
417 ret.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
418 ret.flRate = EAXVOCALMORPHER_DEFAULTRATE;
419 return ret;
420 }()};
421 props = defprops;
424 void EaxVocalMorpherCommitter::Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props)
426 switch(call.get_property_id())
428 case EAXVOCALMORPHER_NONE: break;
429 case EAXVOCALMORPHER_ALLPARAMETERS: call.set_value<Exception>(props); break;
430 case EAXVOCALMORPHER_PHONEMEA: call.set_value<Exception>(props.ulPhonemeA); break;
431 case EAXVOCALMORPHER_PHONEMEACOARSETUNING: call.set_value<Exception>(props.lPhonemeACoarseTuning); break;
432 case EAXVOCALMORPHER_PHONEMEB: call.set_value<Exception>(props.ulPhonemeB); break;
433 case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: call.set_value<Exception>(props.lPhonemeBCoarseTuning); break;
434 case EAXVOCALMORPHER_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
435 case EAXVOCALMORPHER_RATE: call.set_value<Exception>(props.flRate); break;
436 default: fail_unknown_property_id();
440 void EaxVocalMorpherCommitter::Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props)
442 switch(call.get_property_id())
444 case EAXVOCALMORPHER_NONE: break;
445 case EAXVOCALMORPHER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
446 case EAXVOCALMORPHER_PHONEMEA: defer<PhonemeAValidator>(call, props.ulPhonemeA); break;
447 case EAXVOCALMORPHER_PHONEMEACOARSETUNING: defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning); break;
448 case EAXVOCALMORPHER_PHONEMEB: defer<PhonemeBValidator>(call, props.ulPhonemeB); break;
449 case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning); break;
450 case EAXVOCALMORPHER_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
451 case EAXVOCALMORPHER_RATE: defer<RateValidator>(call, props.flRate); break;
452 default: fail_unknown_property_id();
456 #endif // ALSOFT_EAX