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