declare name "Voice Formant"; declare description "Voice Formant Instrument"; declare author "Romain Michon (rmichon@ccrma.stanford.edu)"; declare copyright "Romain Michon"; declare version "1.0"; declare licence "STK-4.3"; // Synthesis Tool Kit 4.3 (MIT style license); declare description "This instrument contains an excitation singing wavetable (looping wave with random and periodic vibrato, smoothing on frequency, etc.), excitation noise, and four sweepable complex resonances. Phoneme preset numbers: 0->eee (beet), 1->ihh (bit), 2->ehh (bet), 3->aaa (bat), 4->ahh (father), 5->aww (bought), 6->ohh (bone), 7->uhh (but), 8->uuu (foot), 9->ooo (boot), 10->rrr (bird), 11->lll (lull), 12->mmm (mom), 13->nnn (nun), 14->nng (sang), 15->ngg (bong), 16->fff, 17->sss, 18->thh, 19->shh, 20->xxx, 21->hee (beet), 22->hoo (boot), 23->hah (father), 24->bbb, 25->ddd, 26->jjj, 27->ggg, 28->vvv, 29->zzz, 30->thz, 31->zhh"; import("music.lib"); import("oscillator.lib"); import("instrument.lib"); //==================== GUI SPECIFICATION ================ freq = nentry("h:Basic_Parameters/freq [1][unit:Hz] [tooltip:Tone frequency]",440,20,20000,1); gain = nentry("h:Basic_Parameters/gain [1][tooltip:Gain (value between 0 and 1)]",1,0,1,0.01); gate = button("h:Basic_Parameters/gate [1][tooltip:noteOn = 1, noteOff = 0]"); phoneme = hslider("v:Physical_Parameters/Phoneme [2][tooltip:0->eee, 1->ihh, 2->ehh, 3->aaa, 4->ahh, 5->aww, 6->ohh, 7->uhh, 8->uuu, 9->ooo, 10->rrr, 11->lll, 12->mmm, 13->nnn, 14->nng, 15->ngg, 16->fff, 17->sss, 18->thh, 19->shh, 20->xxx, 21->hee, 22->hoo, 23->hah, 24->bbb, 25->ddd, 26->jjj, 27->ggg, 28->vvv, 29->zzz, 30->thz, 31->zhh]",4,0,31,1); vibratoFreq = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Freq [3][unit:Hz]",6,1,15,0.1); vibratoGain = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Gain [3][tooltip:A value between 0 and 1]",0.05,0,1,0.01); vibratoBegin = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Begin [3][unit:s][tooltip:Vibrato silence duration before attack]",0.05,0,2,0.01); vibratoAttack = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Attack [3][unit:s][tooltip:Vibrato attack duration]",0.5,0,2,0.01); vibratoRelease = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Release [3][unit:s][tooltip:Vibrato release duration]",0.1,0,2,0.01); voicedEnvelopeAttack = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Voiced_Attack [4][unit:s][tooltip:Voiced sounds attack duration]",0.01,0,2,0.01); voicedEnvelopeRelease = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Voiced_Release [4][unit:s][tooltip:Voiced sounds release duration]",0.01,0,2,0.01); noiseEnvelopeAttack = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Noised_Attack [4][unit:s][tooltip:Noised sounds attack duration]",0.001,0,2,0.001); noiseEnvelopeRelease = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Noised_Release [4][unit:s][tooltip:Noised sounds release duration]",0.001,0,2,0.001); //==================== SIGNAL PROCESSING ================ //----------------------- Synthesis parameters computing and functions declaration ---------------------------- //stereoizer is declared in instrument.lib and implement a stereo spacialisation in function of //the frequency period in number of samples stereo = stereoizer(SR/freq); //exitation filters (declared in instrument.lib) onePoleFilter = onePole(b0,a1) with{ pole = 0.97 - (gain*0.2); b0 = 1 - pole; a1 = -pole; }; oneZeroFilter = oneZero1(b0,b1) with{ zero = -0.9; b0 = 1/(1 - zero); b1 = -zero*b0; }; //implements a formant (resonance) which can be "swept" over time from one frequency setting to another formSwep(frequency,radius,filterGain) = *(gain_) : bandPass(frequency_,radius) with{ //filter's radius, gain and frequency are interpolated radius_ = radius : smooth(0.999); frequency_ = frequency : smooth(0.999); gain_ = filterGain : smooth(0.999); }; //formants parameters are countained in a C++ file phonemeGains = ffunction(float loadPhonemeGains(int,int), ,""); phonemeParameters = ffunction(float loadPhonemeParameters(int,int,int), ,""); //formants frequencies ffreq0 = phonemeParameters(phoneme,0,0); ffreq1 = phonemeParameters(phoneme,1,0); ffreq2 = phonemeParameters(phoneme,2,0); ffreq3 = phonemeParameters(phoneme,3,0); //formants radius frad0 = phonemeParameters(phoneme,0,1); frad1 = phonemeParameters(phoneme,1,1); frad2 = phonemeParameters(phoneme,2,1); frad3 = phonemeParameters(phoneme,3,1); //formants gains fgain0 = phonemeParameters(phoneme,0,2) : pow(10,(_/20)); fgain1 = phonemeParameters(phoneme,1,2) : pow(10,(_/20)); fgain2 = phonemeParameters(phoneme,2,2) : pow(10,(_/20)); fgain3 = phonemeParameters(phoneme,3,2) : pow(10,(_/20)); //gain of the voiced part od the sound voiceGain = phonemeGains(phoneme,0) : smooth(0.999); //gain of the fricative part of the sound noiseGain = phonemeGains(phoneme,1) : smooth(0.999); //formants filters filter0 = formSwep(ffreq0,frad0,fgain0); filter1 = formSwep(ffreq1,frad1,fgain1); filter2 = formSwep(ffreq2,frad2,fgain2); filter3 = formSwep(ffreq3,frad3,fgain3); //----------------------- Algorithm implementation ---------------------------- //envelopes (declared in instrument.lib) and vibrato vibratoEnvelope = envVibrato(vibratoBegin,vibratoAttack,100,vibratoRelease,gate); voicedEnvelope = asr(voicedEnvelopeAttack,100,voicedEnvelopeRelease,gate); noiseEnvelope = asr(noiseEnvelopeAttack,100,noiseEnvelopeRelease,gate); vibrato = osc(vibratoFreq)*vibratoGain*100*vibratoEnvelope; //the voice source is generated by an impulse train //(imptrain defined in oscillator.lib) that is lowpass filtered voiced = imptrain(freq+vibrato) : lowpass3e(3300) : *(voiceGain*voicedEnvelope); //ficative sounds are produced by a noise generator frica = noise*noiseEnvelope*noiseGain; process = voiced : oneZeroFilter : onePoleFilter : +(frica) <: filter0,filter1,filter2,filter3 :> + : stereo : instrReverb;