]> git.tdb.fi Git - ext/openal.git/blob - al/effects/vmorpher.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / al / effects / vmorpher.cpp
1
2 #include "config.h"
3
4 #include <stdexcept>
5
6 #include "AL/al.h"
7 #include "AL/efx.h"
8
9 #include "alc/effects/base.h"
10 #include "aloptional.h"
11 #include "effects.h"
12
13 #ifdef ALSOFT_EAX
14 #include <cassert>
15 #include "alnumeric.h"
16 #include "al/eax/exception.h"
17 #include "al/eax/utils.h"
18 #endif // ALSOFT_EAX
19
20
21 namespace {
22
23 al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val)
24 {
25 #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x:                \
26     return VMorpherPhenome::x
27     switch(val)
28     {
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);
59     }
60     return al::nullopt;
61 #undef HANDLE_PHENOME
62 }
63 ALenum EnumFromPhenome(VMorpherPhenome phenome)
64 {
65 #define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
66     switch(phenome)
67     {
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);
98     }
99     throw std::runtime_error{"Invalid phenome: "+std::to_string(static_cast<int>(phenome))};
100 #undef HANDLE_PHENOME
101 }
102
103 al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
104 {
105     switch(value)
106     {
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;
110     }
111     return al::nullopt;
112 }
113 ALenum EnumFromWaveform(VMorpherWaveform type)
114 {
115     switch(type)
116     {
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;
120     }
121     throw std::runtime_error{"Invalid vocal morpher waveform: " +
122         std::to_string(static_cast<int>(type))};
123 }
124
125 void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
126 {
127     switch(param)
128     {
129     case AL_VOCAL_MORPHER_PHONEMEA:
130         if(auto phenomeopt = PhenomeFromEnum(val))
131             props->Vmorpher.PhonemeA = *phenomeopt;
132         else
133             throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
134         break;
135
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;
140         break;
141
142     case AL_VOCAL_MORPHER_PHONEMEB:
143         if(auto phenomeopt = PhenomeFromEnum(val))
144             props->Vmorpher.PhonemeB = *phenomeopt;
145         else
146             throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
147         break;
148
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;
153         break;
154
155     case AL_VOCAL_MORPHER_WAVEFORM:
156         if(auto formopt = WaveformFromEmum(val))
157             props->Vmorpher.Waveform = *formopt;
158         else
159             throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
160         break;
161
162     default:
163         throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
164             param};
165     }
166 }
167 void Vmorpher_setParamiv(EffectProps*, ALenum param, const int*)
168 {
169     throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
170         param};
171 }
172 void Vmorpher_setParamf(EffectProps *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             throw effect_exception{AL_INVALID_VALUE, "Vocal morpher rate out of range"};
179         props->Vmorpher.Rate = val;
180         break;
181
182     default:
183         throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
184             param};
185     }
186 }
187 void Vmorpher_setParamfv(EffectProps *props, ALenum param, const float *vals)
188 { Vmorpher_setParamf(props, param, vals[0]); }
189
190 void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
191 {
192     switch(param)
193     {
194     case AL_VOCAL_MORPHER_PHONEMEA:
195         *val = EnumFromPhenome(props->Vmorpher.PhonemeA);
196         break;
197
198     case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
199         *val = props->Vmorpher.PhonemeACoarseTuning;
200         break;
201
202     case AL_VOCAL_MORPHER_PHONEMEB:
203         *val = EnumFromPhenome(props->Vmorpher.PhonemeB);
204         break;
205
206     case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
207         *val = props->Vmorpher.PhonemeBCoarseTuning;
208         break;
209
210     case AL_VOCAL_MORPHER_WAVEFORM:
211         *val = EnumFromWaveform(props->Vmorpher.Waveform);
212         break;
213
214     default:
215         throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
216             param};
217     }
218 }
219 void Vmorpher_getParamiv(const EffectProps*, ALenum param, int*)
220 {
221     throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer-vector property 0x%04x",
222         param};
223 }
224 void Vmorpher_getParamf(const EffectProps *props, ALenum param, float *val)
225 {
226     switch(param)
227     {
228     case AL_VOCAL_MORPHER_RATE:
229         *val = props->Vmorpher.Rate;
230         break;
231
232     default:
233         throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher float property 0x%04x",
234             param};
235     }
236 }
237 void Vmorpher_getParamfv(const EffectProps *props, ALenum param, float *vals)
238 { Vmorpher_getParamf(props, param, vals); }
239
240 EffectProps genDefaultProps() noexcept
241 {
242     EffectProps props{};
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);
249     return props;
250 }
251
252 } // namespace
253
254 DEFINE_ALEFFECT_VTABLE(Vmorpher);
255
256 const EffectProps VmorpherEffectProps{genDefaultProps()};
257
258 #ifdef ALSOFT_EAX
259 namespace {
260
261 using VocalMorpherCommitter = EaxCommitter<EaxVocalMorpherCommitter>;
262
263 struct PhonemeAValidator {
264     void operator()(unsigned long ulPhonemeA) const
265     {
266         eax_validate_range<VocalMorpherCommitter::Exception>(
267             "Phoneme A",
268             ulPhonemeA,
269             EAXVOCALMORPHER_MINPHONEMEA,
270             EAXVOCALMORPHER_MAXPHONEMEA);
271     }
272 }; // PhonemeAValidator
273
274 struct PhonemeACoarseTuningValidator {
275     void operator()(long lPhonemeACoarseTuning) const
276     {
277         eax_validate_range<VocalMorpherCommitter::Exception>(
278             "Phoneme A Coarse Tuning",
279             lPhonemeACoarseTuning,
280             EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
281             EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
282     }
283 }; // PhonemeACoarseTuningValidator
284
285 struct PhonemeBValidator {
286     void operator()(unsigned long ulPhonemeB) const
287     {
288         eax_validate_range<VocalMorpherCommitter::Exception>(
289             "Phoneme B",
290             ulPhonemeB,
291             EAXVOCALMORPHER_MINPHONEMEB,
292             EAXVOCALMORPHER_MAXPHONEMEB);
293     }
294 }; // PhonemeBValidator
295
296 struct PhonemeBCoarseTuningValidator {
297     void operator()(long lPhonemeBCoarseTuning) const
298     {
299         eax_validate_range<VocalMorpherCommitter::Exception>(
300             "Phoneme B Coarse Tuning",
301             lPhonemeBCoarseTuning,
302             EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
303             EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
304     }
305 }; // PhonemeBCoarseTuningValidator
306
307 struct WaveformValidator {
308     void operator()(unsigned long ulWaveform) const
309     {
310         eax_validate_range<VocalMorpherCommitter::Exception>(
311             "Waveform",
312             ulWaveform,
313             EAXVOCALMORPHER_MINWAVEFORM,
314             EAXVOCALMORPHER_MAXWAVEFORM);
315     }
316 }; // WaveformValidator
317
318 struct RateValidator {
319     void operator()(float flRate) const
320     {
321         eax_validate_range<VocalMorpherCommitter::Exception>(
322             "Rate",
323             flRate,
324             EAXVOCALMORPHER_MINRATE,
325             EAXVOCALMORPHER_MAXRATE);
326     }
327 }; // RateValidator
328
329 struct AllValidator {
330     void operator()(const EAXVOCALMORPHERPROPERTIES& all) const
331     {
332         PhonemeAValidator{}(all.ulPhonemeA);
333         PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning);
334         PhonemeBValidator{}(all.ulPhonemeB);
335         PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning);
336         WaveformValidator{}(all.ulWaveform);
337         RateValidator{}(all.flRate);
338     }
339 }; // AllValidator
340
341 } // namespace
342
343 template<>
344 struct VocalMorpherCommitter::Exception : public EaxException {
345     explicit Exception(const char *message) : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
346     { }
347 };
348
349 template<>
350 [[noreturn]] void VocalMorpherCommitter::fail(const char *message)
351 {
352     throw Exception{message};
353 }
354
355 template<>
356 bool VocalMorpherCommitter::commit(const EaxEffectProps &props)
357 {
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)
365         return false;
366
367     mEaxProps = props;
368
369     auto get_phoneme = [](unsigned long phoneme) noexcept
370     {
371 #define HANDLE_PHENOME(x) case x: return VMorpherPhenome::x
372         switch(phoneme)
373         {
374         HANDLE_PHENOME(A);
375         HANDLE_PHENOME(E);
376         HANDLE_PHENOME(I);
377         HANDLE_PHENOME(O);
378         HANDLE_PHENOME(U);
379         HANDLE_PHENOME(AA);
380         HANDLE_PHENOME(AE);
381         HANDLE_PHENOME(AH);
382         HANDLE_PHENOME(AO);
383         HANDLE_PHENOME(EH);
384         HANDLE_PHENOME(ER);
385         HANDLE_PHENOME(IH);
386         HANDLE_PHENOME(IY);
387         HANDLE_PHENOME(UH);
388         HANDLE_PHENOME(UW);
389         HANDLE_PHENOME(B);
390         HANDLE_PHENOME(D);
391         HANDLE_PHENOME(F);
392         HANDLE_PHENOME(G);
393         HANDLE_PHENOME(J);
394         HANDLE_PHENOME(K);
395         HANDLE_PHENOME(L);
396         HANDLE_PHENOME(M);
397         HANDLE_PHENOME(N);
398         HANDLE_PHENOME(P);
399         HANDLE_PHENOME(R);
400         HANDLE_PHENOME(S);
401         HANDLE_PHENOME(T);
402         HANDLE_PHENOME(V);
403         HANDLE_PHENOME(Z);
404         }
405         return VMorpherPhenome::A;
406 #undef HANDLE_PHENOME
407     };
408     auto get_waveform = [](unsigned long form) noexcept
409     {
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;
414     };
415
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;
422
423     return true;
424 }
425
426 template<>
427 void VocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
428 {
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;
436 }
437
438 template<>
439 void VocalMorpherCommitter::Get(const EaxCall &call, const EaxEffectProps &props)
440 {
441     switch(call.get_property_id())
442     {
443     case EAXVOCALMORPHER_NONE:
444         break;
445
446     case EAXVOCALMORPHER_ALLPARAMETERS:
447         call.set_value<Exception>(props.mVocalMorpher);
448         break;
449
450     case EAXVOCALMORPHER_PHONEMEA:
451         call.set_value<Exception>(props.mVocalMorpher.ulPhonemeA);
452         break;
453
454     case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
455         call.set_value<Exception>(props.mVocalMorpher.lPhonemeACoarseTuning);
456         break;
457
458     case EAXVOCALMORPHER_PHONEMEB:
459         call.set_value<Exception>(props.mVocalMorpher.ulPhonemeB);
460         break;
461
462     case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
463         call.set_value<Exception>(props.mVocalMorpher.lPhonemeBCoarseTuning);
464         break;
465
466     case EAXVOCALMORPHER_WAVEFORM:
467         call.set_value<Exception>(props.mVocalMorpher.ulWaveform);
468         break;
469
470     case EAXVOCALMORPHER_RATE:
471         call.set_value<Exception>(props.mVocalMorpher.flRate);
472         break;
473
474     default:
475         fail_unknown_property_id();
476     }
477 }
478
479 template<>
480 void VocalMorpherCommitter::Set(const EaxCall &call, EaxEffectProps &props)
481 {
482     switch(call.get_property_id())
483     {
484     case EAXVOCALMORPHER_NONE:
485         break;
486
487     case EAXVOCALMORPHER_ALLPARAMETERS:
488         defer<AllValidator>(call, props.mVocalMorpher);
489         break;
490
491     case EAXVOCALMORPHER_PHONEMEA:
492         defer<PhonemeAValidator>(call, props.mVocalMorpher.ulPhonemeA);
493         break;
494
495     case EAXVOCALMORPHER_PHONEMEACOARSETUNING:
496         defer<PhonemeACoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeACoarseTuning);
497         break;
498
499     case EAXVOCALMORPHER_PHONEMEB:
500         defer<PhonemeBValidator>(call, props.mVocalMorpher.ulPhonemeB);
501         break;
502
503     case EAXVOCALMORPHER_PHONEMEBCOARSETUNING:
504         defer<PhonemeBCoarseTuningValidator>(call, props.mVocalMorpher.lPhonemeBCoarseTuning);
505         break;
506
507     case EAXVOCALMORPHER_WAVEFORM:
508         defer<WaveformValidator>(call, props.mVocalMorpher.ulWaveform);
509         break;
510
511     case EAXVOCALMORPHER_RATE:
512         defer<RateValidator>(call, props.mVocalMorpher.flRate);
513         break;
514
515     default:
516         fail_unknown_property_id();
517     }
518 }
519
520 #endif // ALSOFT_EAX