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