1 /***************************************************/
2 /*! \class FMVoices
3 \brief STK singing FM synthesis instrument.
4
5 This class implements 3 carriers and a common
6 modulator, also referred to as algorithm 6 of
7 the TX81Z.
8
9 \code
10 Algorithm 6 is :
11 /->1 -\
12 4-|-->2 - +-> Out
13 \->3 -/
14 \endcode
15
16 Control Change Numbers:
17 - Vowel = 2
18 - Spectral Tilt = 4
19 - LFO Speed = 11
20 - LFO Depth = 1
21 - ADSR 2 & 4 Target = 128
22
23 The basic Chowning/Stanford FM patent expired
24 in 1995, but there exist follow-on patents,
25 mostly assigned to Yamaha. If you are of the
26 type who should worry about this (making
27 money) worry away.
28
29 by Perry R. Cook and Gary P. Scavone, 1995--2021.
30 */
31 /***************************************************/
32
33 #include "FMVoices.h"
34 #include "SKINImsg.h"
35 #include "Phonemes.h"
36
37 namespace stk {
38
FMVoices(void)39 FMVoices :: FMVoices( void )
40 : FM()
41 {
42 // Concatenate the STK rawwave path to the rawwave files
43 for ( unsigned int i=0; i<3; i++ )
44 waves_[i] = new FileLoop( (Stk::rawwavePath() + "sinewave.raw").c_str(), true );
45 waves_[3] = new FileLoop( (Stk::rawwavePath() + "fwavblnk.raw").c_str(), true );
46
47 this->setRatio(0, 2.00);
48 this->setRatio(1, 4.00);
49 this->setRatio(2, 12.0);
50 this->setRatio(3, 1.00);
51
52 gains_[3] = fmGains_[80];
53
54 adsr_[0]->setAllTimes( 0.05, 0.05, fmSusLevels_[15], 0.05);
55 adsr_[1]->setAllTimes( 0.05, 0.05, fmSusLevels_[15], 0.05);
56 adsr_[2]->setAllTimes( 0.05, 0.05, fmSusLevels_[15], 0.05);
57 adsr_[3]->setAllTimes( 0.01, 0.01, fmSusLevels_[15], 0.5);
58
59 twozero_.setGain( 0.0 );
60 modDepth_ = (StkFloat) 0.005;
61 currentVowel_ = 0;
62 tilt_[0] = 1.0;
63 tilt_[1] = 0.5;
64 tilt_[2] = 0.2;
65 mods_[0] = 1.0;
66 mods_[1] = 1.1;
67 mods_[2] = 1.1;
68 baseFrequency_ = 110.0;
69 this->setFrequency( 110.0 );
70 }
71
~FMVoices(void)72 FMVoices :: ~FMVoices( void )
73 {
74 }
75
setFrequency(StkFloat frequency)76 void FMVoices :: setFrequency( StkFloat frequency )
77 {
78 #if defined(_STK_DEBUG_)
79 if ( frequency <= 0.0 ) {
80 oStream_ << "FMVoices::setFrequency: argument is less than or equal to zero!";
81 handleError( StkError::WARNING ); return;
82 }
83 #endif
84
85 StkFloat temp, temp2 = 0.0;
86 int tempi = 0;
87 unsigned int i = 0;
88
89 if (currentVowel_ < 32) {
90 i = currentVowel_;
91 temp2 = 0.9;
92 }
93 else if (currentVowel_ < 64) {
94 i = currentVowel_ - 32;
95 temp2 = 1.0;
96 }
97 else if (currentVowel_ < 96) {
98 i = currentVowel_ - 64;
99 temp2 = 1.1;
100 }
101 else if (currentVowel_ < 128) {
102 i = currentVowel_ - 96;
103 temp2 = 1.2;
104 }
105 else return;
106
107 baseFrequency_ = frequency;
108 temp = (temp2 * Phonemes::formantFrequency(i, 0) / baseFrequency_) + 0.5;
109 tempi = (int) temp;
110 this->setRatio( 0, (StkFloat) tempi );
111 temp = (temp2 * Phonemes::formantFrequency(i, 1) / baseFrequency_) + 0.5;
112 tempi = (int) temp;
113 this->setRatio( 1, (StkFloat) tempi );
114 temp = (temp2 * Phonemes::formantFrequency(i, 2) / baseFrequency_) + 0.5;
115 tempi = (int) temp;
116 this->setRatio( 2, (StkFloat) tempi );
117 gains_[0] = 1.0;
118 gains_[1] = 1.0;
119 gains_[2] = 1.0;
120 }
121
noteOn(StkFloat frequency,StkFloat amplitude)122 void FMVoices :: noteOn( StkFloat frequency, StkFloat amplitude )
123 {
124 this->setFrequency( frequency );
125 tilt_[0] = amplitude;
126 tilt_[1] = amplitude * amplitude;
127 tilt_[2] = tilt_[1] * amplitude;
128 this->keyOn();
129 }
130
controlChange(int number,StkFloat value)131 void FMVoices :: controlChange( int number, StkFloat value )
132 {
133 #if defined(_STK_DEBUG_)
134 if ( Stk::inRange( value, 0.0, 128.0 ) == false ) {
135 oStream_ << "FMVoices::controlChange: value (" << value << ") is out of range!";
136 handleError( StkError::WARNING ); return;
137 }
138 #endif
139
140 StkFloat normalizedValue = value * ONE_OVER_128;
141 if (number == __SK_Breath_) // 2
142 gains_[3] = fmGains_[(int) ( normalizedValue * 99.9 )];
143 else if (number == __SK_FootControl_) { // 4
144 currentVowel_ = (int) (normalizedValue * 127.0);
145 this->setFrequency(baseFrequency_);
146 }
147 else if (number == __SK_ModFrequency_) // 11
148 this->setModulationSpeed( normalizedValue * 12.0);
149 else if (number == __SK_ModWheel_) // 1
150 this->setModulationDepth( normalizedValue );
151 else if (number == __SK_AfterTouch_Cont_) { // 128
152 tilt_[0] = normalizedValue;
153 tilt_[1] = normalizedValue * normalizedValue;
154 tilt_[2] = tilt_[1] * normalizedValue;
155 }
156 #if defined(_STK_DEBUG_)
157 else {
158 oStream_ << "FMVoices::controlChange: undefined control number (" << number << ")!";
159 handleError( StkError::WARNING );
160 }
161 #endif
162 }
163
164 } // stk namespace
165