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