1 /***************************************************/
2 /*! \class Clarinet
3     \brief STK clarinet physical model class.
4 
5     This class implements a simple clarinet
6     physical model, as discussed by Smith (1986),
7     McIntyre, Schumacher, Woodhouse (1983), and
8     others.
9 
10     This is a digital waveguide model, making its
11     use possibly subject to patents held by Stanford
12     University, Yamaha, and others.
13 
14     Control Change Numbers:
15        - Reed Stiffness = 2
16        - Noise Gain = 4
17        - Vibrato Frequency = 11
18        - Vibrato Gain = 1
19        - Breath Pressure = 128
20 
21     by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
22 */
23 /***************************************************/
24 
25 #include "Clarinet.h"
26 #include "SKINI.msg"
27 
28 using namespace Nyq;
29 
Clarinet(StkFloat lowestFrequency)30 Clarinet :: Clarinet(StkFloat lowestFrequency)
31 {
32   length_ = (long) (Stk::sampleRate() / lowestFrequency + 1);
33   delayLine_.setMaximumDelay( length_ );
34   delayLine_.setDelay( length_ / 2.0 );
35   reedTable_.setOffset((StkFloat) 0.7);
36   reedTable_.setSlope((StkFloat) -0.3);
37 
38   vibrato_.setFrequency((StkFloat) 5.735);
39   outputGain_ = (StkFloat) 1.0;
40   noiseGain_ = (StkFloat) 0.2;
41   vibratoGain_ = (StkFloat) 0.1;
42 }
43 
~Clarinet()44 Clarinet :: ~Clarinet()
45 {
46 }
47 
clear()48 void Clarinet :: clear()
49 {
50   delayLine_.clear();
51   filter_.tick((StkFloat) 0.0);
52 }
53 
setFrequency(StkFloat frequency)54 void Clarinet :: setFrequency(StkFloat frequency)
55 {
56   StkFloat freakency = frequency;
57   if ( frequency <= 0.0 ) {
58     errorString_ << "Clarinet::setFrequency: parameter is less than or equal to zero!";
59     handleError( StkError::WARNING );
60     freakency = 220.0;
61   }
62 
63   // Delay = length - approximate filter delay.
64   StkFloat delay = (Stk::sampleRate() / freakency) * 0.5 - 1.5;
65   if (delay <= 0.0) delay = 0.3;
66   else if (delay > length_) delay = length_;
67   delayLine_.setDelay(delay);
68 }
69 
startBlowing(StkFloat amplitude,StkFloat rate)70 void Clarinet :: startBlowing(StkFloat amplitude, StkFloat rate)
71 {
72   envelope_.setRate(rate);
73   envelope_.setTarget(amplitude);
74 }
75 
stopBlowing(StkFloat rate)76 void Clarinet :: stopBlowing(StkFloat rate)
77 {
78   envelope_.setRate(rate);
79   envelope_.setTarget((StkFloat) 0.0);
80 }
81 
noteOn(StkFloat frequency,StkFloat amplitude)82 void Clarinet :: noteOn(StkFloat frequency, StkFloat amplitude)
83 {
84   this->setFrequency(frequency);
85   this->startBlowing((StkFloat) 0.55 + (amplitude * (StkFloat) 0.30), amplitude * (StkFloat) 0.005);
86   outputGain_ = amplitude + (StkFloat) 0.001;
87 
88 #if defined(_STK_DEBUG_)
89   errorString_ << "Clarinet::NoteOn: frequency = " << frequency << ", amplitude = " << amplitude << '.';
90   handleError( StkError::DEBUG_WARNING );
91 #endif
92 }
93 
noteOff(StkFloat amplitude)94 void Clarinet :: noteOff(StkFloat amplitude)
95 {
96   this->stopBlowing( amplitude * 0.01 );
97 
98 #if defined(_STK_DEBUG_)
99   errorString_ << "Clarinet::NoteOff: amplitude = " << amplitude << '.';
100   handleError( StkError::DEBUG_WARNING );
101 #endif
102 }
103 
computeSample()104 StkFloat Clarinet :: computeSample()
105 {
106   StkFloat pressureDiff;
107   StkFloat breathPressure;
108 
109   // Calculate the breath pressure (envelope + noise + vibrato)
110   breathPressure = envelope_.tick();
111   breathPressure += breathPressure * noiseGain_ * noise_.tick();
112   breathPressure += breathPressure * vibratoGain_ * vibrato_.tick();
113 
114   // Perform commuted loss filtering.
115   pressureDiff = -0.95 * filter_.tick(delayLine_.lastOut());
116 
117   // Calculate pressure difference of reflected and mouthpiece pressures.
118   pressureDiff = pressureDiff - breathPressure;
119 
120   // Perform non-linear scattering using pressure difference in reed function.
121   lastOutput_ = delayLine_.tick(breathPressure + pressureDiff * reedTable_.tick(pressureDiff));
122 
123   // Apply output gain.
124   lastOutput_ *= outputGain_;
125 
126   return lastOutput_;
127 }
128 
controlChange(int number,StkFloat value)129 void Clarinet :: controlChange(int number, StkFloat value)
130 {
131   StkFloat norm = value * ONE_OVER_128;
132   if ( norm < 0 ) {
133     norm = 0.0;
134     errorString_ << "Clarinet::controlChange: control value less than zero ... setting to zero!";
135     handleError( StkError::WARNING );
136   }
137   else if ( norm > 1.0 ) {
138     norm = 1.0;
139     errorString_ << "Clarinet::controlChange: control value greater than 128.0 ... setting to 128.0!";
140     handleError( StkError::WARNING );
141   }
142 
143   if (number == __SK_ReedStiffness_) // 2
144     reedTable_.setSlope((StkFloat) -0.44 + ( (StkFloat) 0.26 * norm ));
145   else if (number == __SK_NoiseLevel_) // 4
146     noiseGain_ = (norm * (StkFloat) 0.4);
147   else if (number == __SK_ModFrequency_) // 11
148     vibrato_.setFrequency((norm * (StkFloat) 12.0));
149   else if (number == __SK_ModWheel_) // 1
150     vibratoGain_ = (norm * (StkFloat) 0.5);
151   else if (number == __SK_AfterTouch_Cont_) // 128
152     envelope_.setValue(norm);
153   else {
154     errorString_ << "Clarinet::controlChange: undefined control number (" << number << ")!";
155     handleError( StkError::WARNING );
156   }
157 
158 #if defined(_STK_DEBUG_)
159     errorString_ << "Clarinet::controlChange: number = " << number << ", value = " << value << '.';
160     handleError( StkError::DEBUG_WARNING );
161 #endif
162 }
163