diff options
Diffstat (limited to 'Alc/effects/vmorpher.cpp')
-rw-r--r-- | Alc/effects/vmorpher.cpp | 208 |
1 files changed, 66 insertions, 142 deletions
diff --git a/Alc/effects/vmorpher.cpp b/Alc/effects/vmorpher.cpp index 5fb7a269..dc402aaf 100644 --- a/Alc/effects/vmorpher.cpp +++ b/Alc/effects/vmorpher.cpp @@ -80,6 +80,14 @@ void Oscillate(ALfloat *RESTRICT dst, ALsizei index, const ALsizei step, ALsizei struct FormantFilter { + ALfloat f0norm{0.0f}; + ALfloat fGain{1.0f}; + ALfloat s1{0.0f}; + ALfloat s2{0.0f}; + + FormantFilter() = default; + FormantFilter(ALfloat f0norm_, ALfloat gain) : f0norm{f0norm_}, fGain{gain} { } + inline void process(const ALfloat* samplesIn, ALfloat* samplesOut, const ALsizei numInput) { /* A state variable filter from a topology-preserving transform. @@ -107,11 +115,6 @@ struct FormantFilter s1 = 0.0f; s2 = 0.0f; } - - ALfloat f0norm; - ALfloat fGain; - ALfloat s1; - ALfloat s2; }; @@ -138,9 +141,60 @@ struct VmorpherState final : public EffectState { void update(const ALCcontext *context, const ALeffectslot *slot, const EffectProps *props, const EffectTarget target) override; void process(const ALsizei samplesToDo, const FloatBufferLine *RESTRICT samplesIn, const ALsizei numInput, const al::span<FloatBufferLine> samplesOut) override; + static std::array<FormantFilter,4> getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch); + DEF_NEWDEL(VmorpherState) }; +std::array<FormantFilter,4> VmorpherState::getFiltersByPhoneme(ALenum phoneme, ALfloat frequency, ALfloat pitch) +{ + /* Using soprano formant set of values to + * better match mid-range frequency space. + * + * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html + */ + switch(phoneme) + { + case AL_VOCAL_MORPHER_PHONEME_A: + return {{ + {( 800 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(1150 * pitch) / frequency, 0.501187f}, /* std::pow(10.0f, -6 / 20.0f); */ + {(2900 * pitch) / frequency, 0.025118f}, /* std::pow(10.0f, -32 / 20.0f); */ + {(3900 * pitch) / frequency, 0.100000f} /* std::pow(10.0f, -20 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_E: + return {{ + {( 350 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2000 * pitch) / frequency, 0.100000f}, /* std::pow(10.0f, -20 / 20.0f); */ + {(2800 * pitch) / frequency, 0.177827f}, /* std::pow(10.0f, -15 / 20.0f); */ + {(3600 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_I: + return {{ + {( 270 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {(2140 * pitch) / frequency, 0.251188f}, /* std::pow(10.0f, -12 / 20.0f); */ + {(2950 * pitch) / frequency, 0.050118f}, /* std::pow(10.0f, -26 / 20.0f); */ + {(3900 * pitch) / frequency, 0.050118f} /* std::pow(10.0f, -26 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_O: + return {{ + {( 450 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 800 * pitch) / frequency, 0.281838f}, /* std::pow(10.0f, -11 / 20.0f); */ + {(2830 * pitch) / frequency, 0.079432f}, /* std::pow(10.0f, -22 / 20.0f); */ + {(3800 * pitch) / frequency, 0.079432f} /* std::pow(10.0f, -22 / 20.0f); */ + }}; + case AL_VOCAL_MORPHER_PHONEME_U: + return {{ + {( 325 * pitch) / frequency, 1.000000f}, /* std::pow(10.0f, 0 / 20.0f); */ + {( 700 * pitch) / frequency, 0.158489f}, /* std::pow(10.0f, -16 / 20.0f); */ + {(2700 * pitch) / frequency, 0.017782f}, /* std::pow(10.0f, -35 / 20.0f); */ + {(3800 * pitch) / frequency, 0.009999f} /* std::pow(10.0f, -40 / 20.0f); */ + }}; + } + return {}; +} + + ALboolean VmorpherState::deviceUpdate(const ALCdevice* /*device*/) { for(auto &e : mChans) @@ -171,151 +225,21 @@ void VmorpherState::update(const ALCcontext *context, const ALeffectslot *slot, else /*if(props->Vmorpher.Waveform == AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE)*/ mGetSamples = Oscillate<Triangle>; - auto& vowelA = mChans[0].Formants[VOWEL_A_INDEX]; - auto& vowelB = mChans[0].Formants[VOWEL_B_INDEX]; - const ALfloat pitchA{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeACoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; const ALfloat pitchB{fastf2i(std::pow(2.0f, props->Vmorpher.PhonemeBCoarseTuning*100.0f / 2400.0f)*FRACTIONONE) * (1.0f/FRACTIONONE)}; - /* Using soprano formant set of values to - * better match mid-range frequency space. - * - * See: https://www.classes.cs.uchicago.edu/archive/1999/spring/CS295/Computing_Resources/Csound/CsManual3.48b1.HTML/Appendices/table3.html - */ - switch(props->Vmorpher.PhonemeA) - { - case AL_VOCAL_MORPHER_PHONEME_A: - vowelA[0].f0norm = (800 * pitchA) / frequency; - vowelA[1].f0norm = (1150 * pitchA) / frequency; - vowelA[2].f0norm = (2900 * pitchA) / frequency; - vowelA[3].f0norm = (3900 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ - vowelA[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ - vowelA[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_E: - vowelA[0].f0norm = (350 * pitchA) / frequency; - vowelA[1].f0norm = (2000 * pitchA) / frequency; - vowelA[2].f0norm = (2800 * pitchA) / frequency; - vowelA[3].f0norm = (3600 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - vowelA[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ - vowelA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_I: - vowelA[0].f0norm = (270 * pitchA) / frequency; - vowelA[1].f0norm = (2140 * pitchA) / frequency; - vowelA[2].f0norm = (2950 * pitchA) / frequency; - vowelA[3].f0norm = (3900 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ - vowelA[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - vowelA[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_O: - vowelA[0].f0norm = (450 * pitchA) / frequency; - vowelA[1].f0norm = (800 * pitchA) / frequency; - vowelA[2].f0norm = (2830 * pitchA) / frequency; - vowelA[3].f0norm = (3800 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ - vowelA[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - vowelA[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_U: - vowelA[0].f0norm = (325 * pitchA) / frequency; - vowelA[1].f0norm = (700 * pitchA) / frequency; - vowelA[2].f0norm = (2700 * pitchA) / frequency; - vowelA[3].f0norm = (3800 * pitchA) / frequency; - - vowelA[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelA[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ - vowelA[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ - vowelA[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - } - - switch(props->Vmorpher.PhonemeB) - { - case AL_VOCAL_MORPHER_PHONEME_A: - vowelB[0].f0norm = (800 * pitchB) / frequency; - vowelB[1].f0norm = (1150 * pitchB) / frequency; - vowelB[2].f0norm = (2900 * pitchB) / frequency; - vowelB[3].f0norm = (3900 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.501187f; /* std::pow(10.0f, -6 / 20.0f); */ - vowelB[2].fGain = 0.025118f; /* std::pow(10.0f, -32 / 20.0f); */ - vowelB[3].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_E: - vowelB[0].f0norm = (350 * pitchB) / frequency; - vowelB[1].f0norm = (2000 * pitchB) / frequency; - vowelB[2].f0norm = (2800 * pitchB) / frequency; - vowelB[3].f0norm = (3600 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.100000f; /* std::pow(10.0f, -20 / 20.0f); */ - vowelB[2].fGain = 0.177827f; /* std::pow(10.0f, -15 / 20.0f); */ - vowelB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_I: - vowelB[0].f0norm = (270 * pitchB) / frequency; - vowelB[1].f0norm = (2140 * pitchB) / frequency; - vowelB[2].f0norm = (2950 * pitchB) / frequency; - vowelB[3].f0norm = (3900 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.251188f; /* std::pow(10.0f, -12 / 20.0f); */ - vowelB[2].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - vowelB[3].fGain = 0.050118f; /* std::pow(10.0f, -26 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_O: - vowelB[0].f0norm = (450 * pitchB) / frequency; - vowelB[1].f0norm = (800 * pitchB) / frequency; - vowelB[2].f0norm = (2830 * pitchB) / frequency; - vowelB[3].f0norm = (3800 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.281838f; /* std::pow(10.0f, -11 / 20.0f); */ - vowelB[2].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - vowelB[3].fGain = 0.079432f; /* std::pow(10.0f, -22 / 20.0f); */ - break; - case AL_VOCAL_MORPHER_PHONEME_U: - vowelB[0].f0norm = (325 * pitchB) / frequency; - vowelB[1].f0norm = (700 * pitchB) / frequency; - vowelB[2].f0norm = (2700 * pitchB) / frequency; - vowelB[3].f0norm = (3800 * pitchB) / frequency; - - vowelB[0].fGain = 1.000000f; /* std::pow(10.0f, 0 / 20.0f); */ - vowelB[1].fGain = 0.158489f; /* std::pow(10.0f, -16 / 20.0f); */ - vowelB[2].fGain = 0.017782f; /* std::pow(10.0f, -35 / 20.0f); */ - vowelB[3].fGain = 0.009999f; /* std::pow(10.0f, -40 / 20.0f); */ - break; - } + auto vowelA = getFiltersByPhoneme(props->Vmorpher.PhonemeA, frequency, pitchA); + auto vowelB = getFiltersByPhoneme(props->Vmorpher.PhonemeB, frequency, pitchB); - /* Copy the filter coefficients for the other input channels. */ - for(ALuint i{1u};i < slot->Wet.Buffer.size();++i) + /* Copy the filter coefficients to the input channels. */ + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { - mChans[i].Formants[VOWEL_A_INDEX][0] = vowelA[0]; - mChans[i].Formants[VOWEL_A_INDEX][1] = vowelA[1]; - mChans[i].Formants[VOWEL_A_INDEX][2] = vowelA[2]; - mChans[i].Formants[VOWEL_A_INDEX][3] = vowelA[3]; - - mChans[i].Formants[VOWEL_B_INDEX][0] = vowelB[0]; - mChans[i].Formants[VOWEL_B_INDEX][1] = vowelB[1]; - mChans[i].Formants[VOWEL_B_INDEX][2] = vowelB[2]; - mChans[i].Formants[VOWEL_B_INDEX][3] = vowelB[3]; + std::copy(vowelA.begin(), vowelA.end(), std::begin(mChans[i].Formants[VOWEL_A_INDEX])); + std::copy(vowelB.begin(), vowelB.end(), std::begin(mChans[i].Formants[VOWEL_B_INDEX])); } mOutTarget = target.Main->Buffer; - for(ALuint i{0u};i < slot->Wet.Buffer.size();++i) + for(size_t i{0u};i < slot->Wet.Buffer.size();++i) { auto coeffs = GetAmbiIdentityRow(i); ComputePanGains(target.Main, coeffs.data(), slot->Params.Gain, mChans[i].TargetGains); |