| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- #include "config.h"
- #include <optional>
- #include <stdexcept>
- #include "AL/al.h"
- #include "AL/efx.h"
- #include "alc/context.h"
- #include "alnumeric.h"
- #include "effects.h"
- #if ALSOFT_EAX
- #include <cassert>
- #include "al/eax/effect.h"
- #include "al/eax/exception.h"
- #include "al/eax/utils.h"
- #endif // ALSOFT_EAX
- namespace {
- constexpr std::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val) noexcept
- {
- #define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x: \
- return VMorpherPhenome::x
- switch(val)
- {
- HANDLE_PHENOME(A);
- HANDLE_PHENOME(E);
- HANDLE_PHENOME(I);
- HANDLE_PHENOME(O);
- HANDLE_PHENOME(U);
- HANDLE_PHENOME(AA);
- HANDLE_PHENOME(AE);
- HANDLE_PHENOME(AH);
- HANDLE_PHENOME(AO);
- HANDLE_PHENOME(EH);
- HANDLE_PHENOME(ER);
- HANDLE_PHENOME(IH);
- HANDLE_PHENOME(IY);
- HANDLE_PHENOME(UH);
- HANDLE_PHENOME(UW);
- HANDLE_PHENOME(B);
- HANDLE_PHENOME(D);
- HANDLE_PHENOME(F);
- HANDLE_PHENOME(G);
- HANDLE_PHENOME(J);
- HANDLE_PHENOME(K);
- HANDLE_PHENOME(L);
- HANDLE_PHENOME(M);
- HANDLE_PHENOME(N);
- HANDLE_PHENOME(P);
- HANDLE_PHENOME(R);
- HANDLE_PHENOME(S);
- HANDLE_PHENOME(T);
- HANDLE_PHENOME(V);
- HANDLE_PHENOME(Z);
- }
- return std::nullopt;
- #undef HANDLE_PHENOME
- }
- constexpr ALenum EnumFromPhenome(VMorpherPhenome phenome)
- {
- #define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
- switch(phenome)
- {
- HANDLE_PHENOME(A);
- HANDLE_PHENOME(E);
- HANDLE_PHENOME(I);
- HANDLE_PHENOME(O);
- HANDLE_PHENOME(U);
- HANDLE_PHENOME(AA);
- HANDLE_PHENOME(AE);
- HANDLE_PHENOME(AH);
- HANDLE_PHENOME(AO);
- HANDLE_PHENOME(EH);
- HANDLE_PHENOME(ER);
- HANDLE_PHENOME(IH);
- HANDLE_PHENOME(IY);
- HANDLE_PHENOME(UH);
- HANDLE_PHENOME(UW);
- HANDLE_PHENOME(B);
- HANDLE_PHENOME(D);
- HANDLE_PHENOME(F);
- HANDLE_PHENOME(G);
- HANDLE_PHENOME(J);
- HANDLE_PHENOME(K);
- HANDLE_PHENOME(L);
- HANDLE_PHENOME(M);
- HANDLE_PHENOME(N);
- HANDLE_PHENOME(P);
- HANDLE_PHENOME(R);
- HANDLE_PHENOME(S);
- HANDLE_PHENOME(T);
- HANDLE_PHENOME(V);
- HANDLE_PHENOME(Z);
- }
- throw std::runtime_error{fmt::format("Invalid phenome: {}", int{al::to_underlying(phenome)})};
- #undef HANDLE_PHENOME
- }
- constexpr std::optional<VMorpherWaveform> WaveformFromEmum(ALenum value) noexcept
- {
- switch(value)
- {
- case AL_VOCAL_MORPHER_WAVEFORM_SINUSOID: return VMorpherWaveform::Sinusoid;
- case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return VMorpherWaveform::Triangle;
- case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return VMorpherWaveform::Sawtooth;
- }
- return std::nullopt;
- }
- constexpr ALenum EnumFromWaveform(VMorpherWaveform type)
- {
- switch(type)
- {
- case VMorpherWaveform::Sinusoid: return AL_VOCAL_MORPHER_WAVEFORM_SINUSOID;
- case VMorpherWaveform::Triangle: return AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE;
- case VMorpherWaveform::Sawtooth: return AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH;
- }
- throw std::runtime_error{fmt::format("Invalid vocal morpher waveform: {}",
- int{al::to_underlying(type)})};
- }
- constexpr EffectProps genDefaultProps() noexcept
- {
- VmorpherProps props{};
- props.Rate = AL_VOCAL_MORPHER_DEFAULT_RATE;
- props.PhonemeA = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA).value();
- props.PhonemeB = PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB).value();
- props.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
- props.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
- props.Waveform = WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM).value();
- return props;
- }
- } // namespace
- const EffectProps VmorpherEffectProps{genDefaultProps()};
- void VmorpherEffectHandler::SetParami(ALCcontext *context, VmorpherProps &props, ALenum param, int val)
- {
- switch(param)
- {
- case AL_VOCAL_MORPHER_PHONEMEA:
- if(auto phenomeopt = PhenomeFromEnum(val))
- props.PhonemeA = *phenomeopt;
- else
- context->throw_error(AL_INVALID_VALUE,
- "Vocal morpher phoneme-a out of range: {:#04x}", as_unsigned(val));
- return;
- case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
- if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING))
- context->throw_error(AL_INVALID_VALUE,
- "Vocal morpher phoneme-a coarse tuning out of range");
- props.PhonemeACoarseTuning = val;
- return;
- case AL_VOCAL_MORPHER_PHONEMEB:
- if(auto phenomeopt = PhenomeFromEnum(val))
- props.PhonemeB = *phenomeopt;
- else
- context->throw_error(AL_INVALID_VALUE,
- "Vocal morpher phoneme-b out of range: {:#04x}", as_unsigned(val));
- return;
- case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
- if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
- context->throw_error(AL_INVALID_VALUE,
- "Vocal morpher phoneme-b coarse tuning out of range");
- props.PhonemeBCoarseTuning = val;
- return;
- case AL_VOCAL_MORPHER_WAVEFORM:
- if(auto formopt = WaveformFromEmum(val))
- props.Waveform = *formopt;
- else
- context->throw_error(AL_INVALID_VALUE, "Vocal morpher waveform out of range: {:#04x}",
- as_unsigned(val));
- return;
- }
- context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher integer property {:#04x}",
- as_unsigned(param));
- }
- void VmorpherEffectHandler::SetParamiv(ALCcontext *context, VmorpherProps &props, ALenum param, const int *vals)
- { SetParami(context, props, param, *vals); }
- void VmorpherEffectHandler::SetParamf(ALCcontext *context, VmorpherProps &props, ALenum param, float val)
- {
- switch(param)
- {
- case AL_VOCAL_MORPHER_RATE:
- if(!(val >= AL_VOCAL_MORPHER_MIN_RATE && val <= AL_VOCAL_MORPHER_MAX_RATE))
- context->throw_error(AL_INVALID_VALUE, "Vocal morpher rate out of range");
- props.Rate = val;
- return;
- }
- context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher float property {:#04x}",
- as_unsigned(param));
- }
- void VmorpherEffectHandler::SetParamfv(ALCcontext *context, VmorpherProps &props, ALenum param, const float *vals)
- { SetParamf(context, props, param, *vals); }
- void VmorpherEffectHandler::GetParami(ALCcontext *context, const VmorpherProps &props, ALenum param, int* val)
- {
- switch(param)
- {
- case AL_VOCAL_MORPHER_PHONEMEA: *val = EnumFromPhenome(props.PhonemeA); return;
- case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING: *val = props.PhonemeACoarseTuning; return;
- case AL_VOCAL_MORPHER_PHONEMEB: *val = EnumFromPhenome(props.PhonemeB); return;
- case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING: *val = props.PhonemeBCoarseTuning; return;
- case AL_VOCAL_MORPHER_WAVEFORM: *val = EnumFromWaveform(props.Waveform); return;
- }
- context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher integer property {:#04x}",
- as_unsigned(param));
- }
- void VmorpherEffectHandler::GetParamiv(ALCcontext *context, const VmorpherProps &props, ALenum param, int *vals)
- { GetParami(context, props, param, vals); }
- void VmorpherEffectHandler::GetParamf(ALCcontext *context, const VmorpherProps &props, ALenum param, float *val)
- {
- switch(param)
- {
- case AL_VOCAL_MORPHER_RATE: *val = props.Rate; return;
- }
- context->throw_error(AL_INVALID_ENUM, "Invalid vocal morpher float property {:#04x}",
- as_unsigned(param));
- }
- void VmorpherEffectHandler::GetParamfv(ALCcontext *context, const VmorpherProps &props, ALenum param, float *vals)
- { GetParamf(context, props, param, vals); }
- #if ALSOFT_EAX
- namespace {
- using VocalMorpherCommitter = EaxCommitter<EaxVocalMorpherCommitter>;
- struct PhonemeAValidator {
- void operator()(unsigned long ulPhonemeA) const
- {
- eax_validate_range<VocalMorpherCommitter::Exception>(
- "Phoneme A",
- ulPhonemeA,
- EAXVOCALMORPHER_MINPHONEMEA,
- EAXVOCALMORPHER_MAXPHONEMEA);
- }
- }; // PhonemeAValidator
- struct PhonemeACoarseTuningValidator {
- void operator()(long lPhonemeACoarseTuning) const
- {
- eax_validate_range<VocalMorpherCommitter::Exception>(
- "Phoneme A Coarse Tuning",
- lPhonemeACoarseTuning,
- EAXVOCALMORPHER_MINPHONEMEACOARSETUNING,
- EAXVOCALMORPHER_MAXPHONEMEACOARSETUNING);
- }
- }; // PhonemeACoarseTuningValidator
- struct PhonemeBValidator {
- void operator()(unsigned long ulPhonemeB) const
- {
- eax_validate_range<VocalMorpherCommitter::Exception>(
- "Phoneme B",
- ulPhonemeB,
- EAXVOCALMORPHER_MINPHONEMEB,
- EAXVOCALMORPHER_MAXPHONEMEB);
- }
- }; // PhonemeBValidator
- struct PhonemeBCoarseTuningValidator {
- void operator()(long lPhonemeBCoarseTuning) const
- {
- eax_validate_range<VocalMorpherCommitter::Exception>(
- "Phoneme B Coarse Tuning",
- lPhonemeBCoarseTuning,
- EAXVOCALMORPHER_MINPHONEMEBCOARSETUNING,
- EAXVOCALMORPHER_MAXPHONEMEBCOARSETUNING);
- }
- }; // PhonemeBCoarseTuningValidator
- struct WaveformValidator {
- void operator()(unsigned long ulWaveform) const
- {
- eax_validate_range<VocalMorpherCommitter::Exception>(
- "Waveform",
- ulWaveform,
- EAXVOCALMORPHER_MINWAVEFORM,
- EAXVOCALMORPHER_MAXWAVEFORM);
- }
- }; // WaveformValidator
- struct RateValidator {
- void operator()(float flRate) const
- {
- eax_validate_range<VocalMorpherCommitter::Exception>(
- "Rate",
- flRate,
- EAXVOCALMORPHER_MINRATE,
- EAXVOCALMORPHER_MAXRATE);
- }
- }; // RateValidator
- struct AllValidator {
- void operator()(const EAXVOCALMORPHERPROPERTIES& all) const
- {
- PhonemeAValidator{}(all.ulPhonemeA);
- PhonemeACoarseTuningValidator{}(all.lPhonemeACoarseTuning);
- PhonemeBValidator{}(all.ulPhonemeB);
- PhonemeBCoarseTuningValidator{}(all.lPhonemeBCoarseTuning);
- WaveformValidator{}(all.ulWaveform);
- RateValidator{}(all.flRate);
- }
- }; // AllValidator
- } // namespace
- template<>
- struct VocalMorpherCommitter::Exception : public EaxException {
- explicit Exception(const char *message) : EaxException{"EAX_VOCAL_MORPHER_EFFECT", message}
- { }
- };
- template<>
- [[noreturn]] void VocalMorpherCommitter::fail(const char *message)
- {
- throw Exception{message};
- }
- bool EaxVocalMorpherCommitter::commit(const EAXVOCALMORPHERPROPERTIES &props)
- {
- if(auto *cur = std::get_if<EAXVOCALMORPHERPROPERTIES>(&mEaxProps); cur && *cur == props)
- return false;
- mEaxProps = props;
- auto get_phoneme = [](unsigned long phoneme) noexcept
- {
- #define HANDLE_PHENOME(x) case x: return VMorpherPhenome::x
- switch(phoneme)
- {
- HANDLE_PHENOME(A);
- HANDLE_PHENOME(E);
- HANDLE_PHENOME(I);
- HANDLE_PHENOME(O);
- HANDLE_PHENOME(U);
- HANDLE_PHENOME(AA);
- HANDLE_PHENOME(AE);
- HANDLE_PHENOME(AH);
- HANDLE_PHENOME(AO);
- HANDLE_PHENOME(EH);
- HANDLE_PHENOME(ER);
- HANDLE_PHENOME(IH);
- HANDLE_PHENOME(IY);
- HANDLE_PHENOME(UH);
- HANDLE_PHENOME(UW);
- HANDLE_PHENOME(B);
- HANDLE_PHENOME(D);
- HANDLE_PHENOME(F);
- HANDLE_PHENOME(G);
- HANDLE_PHENOME(J);
- HANDLE_PHENOME(K);
- HANDLE_PHENOME(L);
- HANDLE_PHENOME(M);
- HANDLE_PHENOME(N);
- HANDLE_PHENOME(P);
- HANDLE_PHENOME(R);
- HANDLE_PHENOME(S);
- HANDLE_PHENOME(T);
- HANDLE_PHENOME(V);
- HANDLE_PHENOME(Z);
- }
- return VMorpherPhenome::A;
- #undef HANDLE_PHENOME
- };
- auto get_waveform = [](unsigned long form) noexcept
- {
- if(form == EAX_VOCALMORPHER_SINUSOID) return VMorpherWaveform::Sinusoid;
- if(form == EAX_VOCALMORPHER_TRIANGLE) return VMorpherWaveform::Triangle;
- if(form == EAX_VOCALMORPHER_SAWTOOTH) return VMorpherWaveform::Sawtooth;
- return VMorpherWaveform::Sinusoid;
- };
- mAlProps = [&]{
- VmorpherProps ret{};
- ret.PhonemeA = get_phoneme(props.ulPhonemeA);
- ret.PhonemeACoarseTuning = static_cast<int>(props.lPhonemeACoarseTuning);
- ret.PhonemeB = get_phoneme(props.ulPhonemeB);
- ret.PhonemeBCoarseTuning = static_cast<int>(props.lPhonemeBCoarseTuning);
- ret.Waveform = get_waveform(props.ulWaveform);
- ret.Rate = props.flRate;
- return ret;
- }();
- return true;
- }
- void EaxVocalMorpherCommitter::SetDefaults(EaxEffectProps &props)
- {
- static constexpr EAXVOCALMORPHERPROPERTIES defprops{[]
- {
- EAXVOCALMORPHERPROPERTIES ret{};
- ret.ulPhonemeA = EAXVOCALMORPHER_DEFAULTPHONEMEA;
- ret.lPhonemeACoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEACOARSETUNING;
- ret.ulPhonemeB = EAXVOCALMORPHER_DEFAULTPHONEMEB;
- ret.lPhonemeBCoarseTuning = EAXVOCALMORPHER_DEFAULTPHONEMEBCOARSETUNING;
- ret.ulWaveform = EAXVOCALMORPHER_DEFAULTWAVEFORM;
- ret.flRate = EAXVOCALMORPHER_DEFAULTRATE;
- return ret;
- }()};
- props = defprops;
- }
- void EaxVocalMorpherCommitter::Get(const EaxCall &call, const EAXVOCALMORPHERPROPERTIES &props)
- {
- switch(call.get_property_id())
- {
- case EAXVOCALMORPHER_NONE: break;
- case EAXVOCALMORPHER_ALLPARAMETERS: call.set_value<Exception>(props); break;
- case EAXVOCALMORPHER_PHONEMEA: call.set_value<Exception>(props.ulPhonemeA); break;
- case EAXVOCALMORPHER_PHONEMEACOARSETUNING: call.set_value<Exception>(props.lPhonemeACoarseTuning); break;
- case EAXVOCALMORPHER_PHONEMEB: call.set_value<Exception>(props.ulPhonemeB); break;
- case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: call.set_value<Exception>(props.lPhonemeBCoarseTuning); break;
- case EAXVOCALMORPHER_WAVEFORM: call.set_value<Exception>(props.ulWaveform); break;
- case EAXVOCALMORPHER_RATE: call.set_value<Exception>(props.flRate); break;
- default: fail_unknown_property_id();
- }
- }
- void EaxVocalMorpherCommitter::Set(const EaxCall &call, EAXVOCALMORPHERPROPERTIES &props)
- {
- switch(call.get_property_id())
- {
- case EAXVOCALMORPHER_NONE: break;
- case EAXVOCALMORPHER_ALLPARAMETERS: defer<AllValidator>(call, props); break;
- case EAXVOCALMORPHER_PHONEMEA: defer<PhonemeAValidator>(call, props.ulPhonemeA); break;
- case EAXVOCALMORPHER_PHONEMEACOARSETUNING: defer<PhonemeACoarseTuningValidator>(call, props.lPhonemeACoarseTuning); break;
- case EAXVOCALMORPHER_PHONEMEB: defer<PhonemeBValidator>(call, props.ulPhonemeB); break;
- case EAXVOCALMORPHER_PHONEMEBCOARSETUNING: defer<PhonemeBCoarseTuningValidator>(call, props.lPhonemeBCoarseTuning); break;
- case EAXVOCALMORPHER_WAVEFORM: defer<WaveformValidator>(call, props.ulWaveform); break;
- case EAXVOCALMORPHER_RATE: defer<RateValidator>(call, props.flRate); break;
- default: fail_unknown_property_id();
- }
- }
- #endif // ALSOFT_EAX
|