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--2021.
22 */
23 /***************************************************/
24
25 #include "Clarinet.h"
26 #include "SKINImsg.h"
27
28 namespace stk {
29
Clarinet(StkFloat lowestFrequency)30 Clarinet :: Clarinet( StkFloat lowestFrequency )
31 {
32 if ( lowestFrequency <= 0.0 ) {
33 oStream_ << "Clarinet::Clarinet: argument is less than or equal to zero!";
34 handleError( StkError::FUNCTION_ARGUMENT );
35 }
36
37 unsigned long nDelays = (unsigned long) ( 0.5 * Stk::sampleRate() / lowestFrequency );
38 delayLine_.setMaximumDelay( nDelays + 1 );
39
40 reedTable_.setOffset( 0.7 );
41 reedTable_.setSlope( -0.3 );
42
43 vibrato_.setFrequency( 5.735 );
44 outputGain_ = 1.0;
45 noiseGain_ = 0.2;
46 vibratoGain_ = 0.1;
47
48 this->setFrequency( 220.0 );
49 this->clear();
50 }
51
~Clarinet(void)52 Clarinet :: ~Clarinet( void )
53 {
54 }
55
clear(void)56 void Clarinet :: clear( void )
57 {
58 delayLine_.clear();
59 filter_.tick( 0.0 );
60 }
61
setFrequency(StkFloat frequency)62 void Clarinet :: setFrequency( StkFloat frequency )
63 {
64 #if defined(_STK_DEBUG_)
65 if ( frequency <= 0.0 ) {
66 oStream_ << "Clarinet::setFrequency: argument is less than or equal to zero!";
67 handleError( StkError::WARNING ); return;
68 }
69 #endif
70
71 // Account for filter delay and one sample "lastOut" delay.
72 StkFloat delay = ( Stk::sampleRate() / frequency ) * 0.5 - filter_.phaseDelay( frequency ) - 1.0;
73 delayLine_.setDelay( delay );
74 }
75
startBlowing(StkFloat amplitude,StkFloat rate)76 void Clarinet :: startBlowing( StkFloat amplitude, StkFloat rate )
77 {
78 if ( amplitude <= 0.0 || rate <= 0.0 ) {
79 oStream_ << "Clarinet::startBlowing: one or more arguments is less than or equal to zero!";
80 handleError( StkError::WARNING ); return;
81 }
82
83 envelope_.setRate( rate );
84 envelope_.setTarget( amplitude );
85 }
86
stopBlowing(StkFloat rate)87 void Clarinet :: stopBlowing( StkFloat rate )
88 {
89 if ( rate <= 0.0 ) {
90 oStream_ << "Clarinet::stopBlowing: argument is less than or equal to zero!";
91 handleError( StkError::WARNING ); return;
92 }
93
94 envelope_.setRate( rate );
95 envelope_.setTarget( 0.0 );
96 }
97
noteOn(StkFloat frequency,StkFloat amplitude)98 void Clarinet :: noteOn( StkFloat frequency, StkFloat amplitude )
99 {
100 this->setFrequency( frequency );
101 this->startBlowing( 0.55 + (amplitude * 0.30), amplitude * 0.005 );
102 outputGain_ = amplitude + 0.001;
103 }
104
noteOff(StkFloat amplitude)105 void Clarinet :: noteOff( StkFloat amplitude )
106 {
107 this->stopBlowing( amplitude * 0.01 );
108 }
109
controlChange(int number,StkFloat value)110 void Clarinet :: controlChange( int number, StkFloat value )
111 {
112 #if defined(_STK_DEBUG_)
113 if ( Stk::inRange( value, 0.0, 128.0 ) == false ) {
114 oStream_ << "Clarinet::controlChange: value (" << value << ") is out of range!";
115 handleError( StkError::WARNING ); return;
116 }
117 #endif
118
119 StkFloat normalizedValue = value * ONE_OVER_128;
120 if ( number == __SK_ReedStiffness_ ) // 2
121 reedTable_.setSlope( -0.44 + ( 0.26 * normalizedValue ) );
122 else if ( number == __SK_NoiseLevel_ ) // 4
123 noiseGain_ = ( normalizedValue * 0.4 );
124 else if ( number == __SK_ModFrequency_ ) // 11
125 vibrato_.setFrequency( normalizedValue * 12.0 );
126 else if ( number == __SK_ModWheel_ ) // 1
127 vibratoGain_ = ( normalizedValue * 0.5 );
128 else if ( number == __SK_AfterTouch_Cont_ ) // 128
129 envelope_.setValue( normalizedValue );
130 #if defined(_STK_DEBUG_)
131 else {
132 oStream_ << "Clarinet::controlChange: undefined control number (" << number << ")!";
133 handleError( StkError::WARNING );
134 }
135 #endif
136 }
137
138 } // stk namespace
139