1 /***************************************************/
2 /*! \class VoicForm
3     \brief Four formant synthesis instrument.
4 
5     This instrument contains an excitation singing
6     wavetable (looping wave with random and
7     periodic vibrato, smoothing on frequency,
8     etc.), excitation noise, and four sweepable
9     complex resonances.
10 
11     Measured formant data is included, and enough
12     data is there to support either parallel or
13     cascade synthesis.  In the floating point case
14     cascade synthesis is the most natural so
15     that's what you'll find here.
16 
17     Control Change Numbers:
18        - Voiced/Unvoiced Mix = 2
19        - Vowel/Phoneme Selection = 4
20        - Vibrato Frequency = 11
21        - Vibrato Gain = 1
22        - Loudness (Spectral Tilt) = 128
23 
24     by Perry R. Cook and Gary P. Scavone, 1995--2021.
25 */
26 /***************************************************/
27 
28 #include "VoicForm.h"
29 #include "Phonemes.h"
30 #include "SKINImsg.h"
31 #include <cstring>
32 #include <cmath>
33 
34 namespace stk {
35 
VoicForm(void)36 VoicForm :: VoicForm( void ) : Instrmnt()
37 {
38   // Concatenate the STK rawwave path to the rawwave file
39   voiced_ = new SingWave( (Stk::rawwavePath() + "impuls20.raw").c_str(), true );
40   voiced_->setGainRate( 0.001 );
41   voiced_->setGainTarget( 0.0 );
42 
43   for ( int i=0; i<4; i++ )
44     filters_[i].setSweepRate( 0.001 );
45 
46   onezero_.setZero( -0.9 );
47   onepole_.setPole( 0.9 );
48 
49   noiseEnv_.setRate( 0.001 );
50   noiseEnv_.setTarget( 0.0 );
51 
52   this->setPhoneme( "eee" );
53   this->clear();
54 }
55 
~VoicForm(void)56 VoicForm :: ~VoicForm( void )
57 {
58   delete voiced_;
59 }
60 
clear(void)61 void VoicForm :: clear( void )
62 {
63   onezero_.clear();
64   onepole_.clear();
65   for ( int i=0; i<4; i++ ) {
66     filters_[i].clear();
67   }
68 }
69 
setFrequency(StkFloat frequency)70 void VoicForm :: setFrequency( StkFloat frequency )
71 {
72 #if defined(_STK_DEBUG_)
73   if ( frequency <= 0.0 ) {
74     oStream_ << "VoicForm::setFrequency: parameter is less than or equal to zero!";
75     handleError( StkError::WARNING ); return;
76   }
77 #endif
78 
79   voiced_->setFrequency( frequency );
80 }
81 
setPhoneme(const char * phoneme)82 bool VoicForm :: setPhoneme( const char *phoneme )
83 {
84   bool found = false;
85   unsigned int i = 0;
86   while( i < 32 && !found ) {
87     if ( !strcmp( Phonemes::name(i), phoneme ) ) {
88       found = true;
89       filters_[0].setTargets( Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
90       filters_[1].setTargets( Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
91       filters_[2].setTargets( Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
92       filters_[3].setTargets( Phonemes::formantFrequency(i, 3), Phonemes::formantRadius(i, 3), pow(10.0, Phonemes::formantGain(i, 3 ) / 20.0) );
93       this->setVoiced( Phonemes::voiceGain( i ) );
94       this->setUnVoiced( Phonemes::noiseGain( i ) );
95     }
96     i++;
97   }
98 
99   if ( !found ) {
100     oStream_ << "VoicForm::setPhoneme: phoneme " << phoneme << " not found!";
101     handleError( StkError::WARNING );
102   }
103 
104   return found;
105 }
106 
setFilterSweepRate(unsigned int whichOne,StkFloat rate)107 void VoicForm :: setFilterSweepRate( unsigned int whichOne, StkFloat rate )
108 {
109   if ( whichOne > 3 ) {
110     oStream_ << "VoicForm::setFilterSweepRate: filter select argument outside range 0-3!";
111     handleError( StkError::WARNING ); return;
112   }
113 
114   filters_[whichOne].setSweepRate(rate);
115 }
116 
quiet(void)117 void VoicForm :: quiet( void )
118 {
119   voiced_->noteOff();
120   noiseEnv_.setTarget( 0.0 );
121 }
122 
noteOn(StkFloat frequency,StkFloat amplitude)123 void VoicForm :: noteOn( StkFloat frequency, StkFloat amplitude )
124 {
125   this->setFrequency( frequency );
126   voiced_->setGainTarget( amplitude );
127   onepole_.setPole( 0.97 - (amplitude * 0.2) );
128 }
129 
controlChange(int number,StkFloat value)130 void VoicForm :: controlChange( int number, StkFloat value )
131 {
132 #if defined(_STK_DEBUG_)
133   if ( Stk::inRange( value, 0.0, 128.0 ) == false ) {
134     oStream_ << "VoicForm::controlChange: value (" << value << ") is out of range!";
135     handleError( StkError::WARNING ); return;
136   }
137 #endif
138 
139   StkFloat normalizedValue = value * ONE_OVER_128;
140   if (number == __SK_Breath_)	{ // 2
141     this->setVoiced( 1.0 - normalizedValue );
142     this->setUnVoiced( 0.01 * normalizedValue );
143   }
144   else if (number == __SK_FootControl_)	{ // 4
145     StkFloat temp = 0.0;
146     unsigned int i = (int) value;
147     if (i < 32)	{
148       temp = 0.9;
149     }
150     else if (i < 64)	{
151       i -= 32;
152       temp = 1.0;
153     }
154     else if (i < 96)	{
155       i -= 64;
156       temp = 1.1;
157     }
158     else if (i < 128)	{
159       i -= 96;
160       temp = 1.2;
161     }
162     else if (i == 128)	{
163       i = 0;
164       temp = 1.4;
165     }
166     filters_[0].setTargets( temp * Phonemes::formantFrequency(i, 0), Phonemes::formantRadius(i, 0), pow(10.0, Phonemes::formantGain(i, 0 ) / 20.0) );
167     filters_[1].setTargets( temp * Phonemes::formantFrequency(i, 1), Phonemes::formantRadius(i, 1), pow(10.0, Phonemes::formantGain(i, 1 ) / 20.0) );
168     filters_[2].setTargets( temp * Phonemes::formantFrequency(i, 2), Phonemes::formantRadius(i, 2), pow(10.0, Phonemes::formantGain(i, 2 ) / 20.0) );
169     filters_[3].setTargets( temp * Phonemes::formantFrequency(i, 3), Phonemes::formantRadius(i, 3), pow(10.0, Phonemes::formantGain(i, 3 ) / 20.0) );
170     this->setVoiced( Phonemes::voiceGain( i ) );
171     this->setUnVoiced( Phonemes::noiseGain( i ) );
172   }
173   else if (number == __SK_ModFrequency_) // 11
174     voiced_->setVibratoRate( normalizedValue * 12.0);  // 0 to 12 Hz
175   else if (number == __SK_ModWheel_) // 1
176     voiced_->setVibratoGain( normalizedValue * 0.2);
177   else if (number == __SK_AfterTouch_Cont_)	{ // 128
178     this->setVoiced( normalizedValue );
179     onepole_.setPole( 0.97 - ( normalizedValue * 0.2) );
180   }
181 #if defined(_STK_DEBUG_)
182   else {
183     oStream_ << "VoicForm::controlChange: undefined control number (" << number << ")!";
184     handleError( StkError::WARNING );
185   }
186 #endif
187 }
188 
189 } // stk namespace
190