mirror of
https://github.com/thestk/stk
synced 2026-01-11 20:11:52 +00:00
236 lines
6.7 KiB
C++
236 lines
6.7 KiB
C++
/*******************************************/
|
|
/* 4 Formant Synthesis Instrument */
|
|
/* by Perry R. Cook, 1995-96 */
|
|
/* 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. */
|
|
/* */
|
|
/* Measured Formant data (from me) is */
|
|
/* included, and enough data is there to */
|
|
/* support either parallel or cascade */
|
|
/* synthesis. In the floating point case */
|
|
/* cascade synthesis is the most natural */
|
|
/* so that's what you'll find here. */
|
|
/* */
|
|
/* For right now, there's a simple command*/
|
|
/* line score interface consisting of 3 */
|
|
/* letter symbols for the phonemes, =xx */
|
|
/* sets the pitch to x, + and - add and */
|
|
/* subtract a half step, and ... makes it */
|
|
/* keep doing what it's doing for longer. */
|
|
/*******************************************/
|
|
|
|
#include "VoicForm.h"
|
|
#include "SKINI11.msg"
|
|
|
|
VoicForm :: VoicForm() : Instrmnt()
|
|
{
|
|
voiced = new SingWave("rawwaves/impuls40.raw");
|
|
voiced->normalize();
|
|
voiced->setGainRate((MY_FLOAT) 0.001);
|
|
voiced->setGainTarget((MY_FLOAT) 0.0);
|
|
|
|
noise = new Noise;
|
|
|
|
filters[0] = new FormSwep;
|
|
filters[1] = new FormSwep;
|
|
filters[2] = new FormSwep;
|
|
filters[3] = new FormSwep;
|
|
filters[0]->setSweepRate((MY_FLOAT) 0.001);
|
|
filters[1]->setSweepRate((MY_FLOAT) 0.001);
|
|
filters[2]->setSweepRate((MY_FLOAT) 0.001);
|
|
filters[3]->setSweepRate((MY_FLOAT) 0.001);
|
|
|
|
onezero = new OneZero;
|
|
onezero->setCoeff((MY_FLOAT) -0.9);
|
|
onepole = new OnePole;
|
|
onepole->setPole((MY_FLOAT) 0.9);
|
|
|
|
noiseEnv = new Envelope;
|
|
noiseEnv->setRate((MY_FLOAT) 0.001);
|
|
noiseEnv->setTarget((MY_FLOAT) 0.0);
|
|
|
|
this->setPhoneme("eee");
|
|
this->clear();
|
|
}
|
|
|
|
VoicForm :: ~VoicForm()
|
|
{
|
|
delete voiced;
|
|
delete noise;
|
|
delete filters[0];
|
|
delete filters[1];
|
|
delete filters[2];
|
|
delete filters[3];
|
|
delete onezero;
|
|
delete onepole;
|
|
delete noiseEnv;
|
|
}
|
|
|
|
void VoicForm :: clear()
|
|
{
|
|
onezero->clear();
|
|
onepole->clear();
|
|
filters[0]->clear();
|
|
filters[1]->clear();
|
|
filters[2]->clear();
|
|
filters[3]->clear();
|
|
}
|
|
|
|
void VoicForm :: setFreq(MY_FLOAT frequency)
|
|
{
|
|
voiced->setFreq(frequency);
|
|
}
|
|
|
|
void VoicForm :: setFormantAll(int whichOne, MY_FLOAT freq,MY_FLOAT reson,MY_FLOAT gain)
|
|
{
|
|
filters[whichOne]->setTargets(freq,reson,gain);
|
|
}
|
|
|
|
#include "phontabl.h"
|
|
|
|
int VoicForm :: setPhoneme(char *phoneme)
|
|
{
|
|
int i=0,found=0;
|
|
|
|
while(i<32 && !found) {
|
|
if (!strcmp(phonemes[i],phoneme)) {
|
|
found = 1;
|
|
this->setFormantAll(0,(MY_FLOAT) phonParams[i][0][0],(MY_FLOAT) phonParams[i][0][1],(MY_FLOAT) pow(10.0,phonParams[i][0][2] / 20.0));
|
|
this->setFormantAll(1,(MY_FLOAT) phonParams[i][1][0],(MY_FLOAT) phonParams[i][1][1],(MY_FLOAT) 1.0);
|
|
this->setFormantAll(2,(MY_FLOAT) phonParams[i][2][0],(MY_FLOAT) phonParams[i][2][1],(MY_FLOAT) 1.0);
|
|
this->setFormantAll(3,(MY_FLOAT) phonParams[i][3][0],(MY_FLOAT) phonParams[i][3][1],(MY_FLOAT) 1.0);
|
|
this->setVoicedUnVoiced((MY_FLOAT) phonGains[i][0],(MY_FLOAT) phonGains[i][1]);
|
|
printf("Found Formant: %s (number %i)\n",phoneme,i);
|
|
}
|
|
i++;
|
|
}
|
|
if (!found) printf("Phoneme %s not found\n",phoneme);
|
|
return found;
|
|
}
|
|
|
|
void VoicForm :: setVoiced(MY_FLOAT vGain)
|
|
{
|
|
voiced->setGainTarget(vGain);
|
|
//voiced->setGainTarget(vGain*0.5);
|
|
}
|
|
|
|
void VoicForm :: setUnVoiced(MY_FLOAT nGain)
|
|
{
|
|
noiseEnv->setTarget(nGain);
|
|
//noiseEnv->setTarget(nGain*0.5);
|
|
}
|
|
|
|
void VoicForm :: setVoicedUnVoiced(MY_FLOAT vGain, MY_FLOAT nGain)
|
|
{
|
|
this->setVoiced(vGain);
|
|
//this->setVoiced(vGain*0.5);
|
|
this->setUnVoiced(nGain);
|
|
//this->setUnVoiced(nGain*0.5);
|
|
}
|
|
|
|
void VoicForm :: setFiltSweepRate(int whichOne,MY_FLOAT rate)
|
|
{
|
|
filters[whichOne]->setSweepRate(rate);
|
|
}
|
|
|
|
void VoicForm :: setPitchSweepRate(MY_FLOAT rate)
|
|
{
|
|
voiced->setSweepRate(rate);
|
|
}
|
|
|
|
void VoicForm :: speak()
|
|
{
|
|
voiced->noteOn();
|
|
}
|
|
|
|
void VoicForm :: quiet()
|
|
{
|
|
voiced->noteOff();
|
|
noiseEnv->setTarget((MY_FLOAT) 0.0);
|
|
}
|
|
|
|
void VoicForm :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
|
{
|
|
voiced->setGainTarget(amp);
|
|
//voiced->setGainTarget(amp*0.5);
|
|
onepole->setPole((MY_FLOAT) 0.95 - (amp * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2));
|
|
//onepole->setPole((MY_FLOAT) 0.9 - (amp * (MY_FLOAT) 0.2));
|
|
voiced->setFreq(freq);
|
|
}
|
|
|
|
void VoicForm :: noteOff(MY_FLOAT amp)
|
|
{
|
|
voiced->noteOff();
|
|
}
|
|
|
|
MY_FLOAT VoicForm :: tick()
|
|
{
|
|
MY_FLOAT temp;
|
|
temp = onepole->tick(onezero->tick(voiced->tick()));
|
|
temp += noiseEnv->tick() * noise->tick();
|
|
lastOutput = filters[0]->tick(temp);
|
|
lastOutput = filters[1]->tick(lastOutput);
|
|
lastOutput = filters[2]->tick(lastOutput);
|
|
lastOutput = filters[3]->tick(lastOutput);
|
|
//lastOutput *= (MY_FLOAT) 0.02;
|
|
lastOutput *= (MY_FLOAT) 0.005;
|
|
return lastOutput;
|
|
}
|
|
|
|
void VoicForm :: controlChange(int number, MY_FLOAT value)
|
|
{
|
|
MY_FLOAT temp;
|
|
int tempi;
|
|
|
|
#if defined(_debug_)
|
|
printf("VoicForm : ControlChange: Number=%i Value=%f\n",number,value);
|
|
#endif
|
|
if (number == __SK_Breath_) {
|
|
this->setVoiced((MY_FLOAT) 1.0 - (value *(MY_FLOAT) NORM_7));
|
|
this->setUnVoiced((MY_FLOAT) 0.01 * value * (MY_FLOAT) NORM_7);
|
|
}
|
|
else if (number == __SK_FootControl_) {
|
|
tempi = (int) (value / 2);
|
|
if (tempi < 16) {
|
|
tempi = tempi;
|
|
temp = (MY_FLOAT) 0.9;
|
|
}
|
|
else if (tempi < 32) {
|
|
tempi = tempi - 16;
|
|
temp = (MY_FLOAT) 1.0;
|
|
}
|
|
else if (tempi < 48) {
|
|
tempi = tempi - 32;
|
|
temp = (MY_FLOAT) 1.1;
|
|
}
|
|
else if (tempi <= 64) {
|
|
tempi = tempi - 48;
|
|
temp = (MY_FLOAT) 1.2;
|
|
}
|
|
this->setFormantAll(0,temp*(MY_FLOAT) phonParams[tempi][0][0],
|
|
(MY_FLOAT) phonParams[tempi][0][1],
|
|
(MY_FLOAT) pow(10.0,phonParams[tempi][0][2] / 20.0));
|
|
this->setFormantAll(1,temp*(MY_FLOAT) phonParams[tempi][1][0],
|
|
(MY_FLOAT) phonParams[tempi][1][1],(MY_FLOAT) 1.0);
|
|
this->setFormantAll(2,temp*(MY_FLOAT) phonParams[tempi][2][0],
|
|
(MY_FLOAT) phonParams[tempi][2][1],(MY_FLOAT) 1.0);
|
|
this->setFormantAll(3,temp*(MY_FLOAT) phonParams[tempi][3][0],
|
|
(MY_FLOAT) phonParams[tempi][3][1],(MY_FLOAT) 1.0);
|
|
}
|
|
else if (number == __SK_ModFrequency_)
|
|
voiced->setVibFreq(value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 12.0); /* 0 to 12 Hz */
|
|
else if (number == __SK_ModWheel_)
|
|
voiced->setVibAmt(value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2);
|
|
else if (number == __SK_AfterTouch_Cont_) {
|
|
this->setVoiced(value*NORM_7);
|
|
onepole->setPole((MY_FLOAT) 0.99 - (value *(MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2));
|
|
//onepole->setPole((MY_FLOAT) 0.5 - (value * (MY_FLOAT) NORM_7 * (MY_FLOAT) 0.2));
|
|
}
|
|
else {
|
|
printf("VoicForm : Undefined Control Number!!\n");
|
|
}
|
|
}
|