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