1 #ifndef STK_BOWED_H
2 #define STK_BOWED_H
3
4 #include "Instrmnt.h"
5 #include "DelayL.h"
6 #include "BowTable.h"
7 #include "OnePole.h"
8 #include "BiQuad.h"
9 #include "SineWave.h"
10 #include "ADSR.h"
11
12 namespace stk {
13
14 /***************************************************/
15 /*! \class Bowed
16 \brief STK bowed string instrument class.
17
18 This class implements a bowed string model, a
19 la Smith (1986), after McIntyre, Schumacher,
20 Woodhouse (1983).
21
22 This is a digital waveguide model, making its
23 use possibly subject to patents held by
24 Stanford University, Yamaha, and others.
25
26 Control Change Numbers:
27 - Bow Pressure = 2
28 - Bow Position = 4
29 - Vibrato Frequency = 11
30 - Vibrato Gain = 1
31 - Bow Velocity = 100
32 - Frequency = 101
33 - Volume = 128
34
35 by Perry R. Cook and Gary P. Scavone, 1995--2021.
36 Contributions by Esteban Maestre, 2011.
37 */
38 /***************************************************/
39
40 class Bowed : public Instrmnt
41 {
42 public:
43 //! Class constructor, taking the lowest desired playing frequency.
44 Bowed( StkFloat lowestFrequency = 8.0 );
45
46 //! Class destructor.
47 ~Bowed( void );
48
49 //! Reset and clear all internal state.
50 void clear( void );
51
52 //! Set instrument parameters for a particular frequency.
53 void setFrequency( StkFloat frequency );
54
55 //! Set vibrato gain.
setVibrato(StkFloat gain)56 void setVibrato( StkFloat gain ) { vibratoGain_ = gain; };
57
58 //! Apply breath pressure to instrument with given amplitude and rate of increase.
59 void startBowing( StkFloat amplitude, StkFloat rate );
60
61 //! Decrease breath pressure with given rate of decrease.
62 void stopBowing( StkFloat rate );
63
64 //! Start a note with the given frequency and amplitude.
65 void noteOn( StkFloat frequency, StkFloat amplitude );
66
67 //! Stop a note with the given amplitude (speed of decay).
68 void noteOff( StkFloat amplitude );
69
70 //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
71 void controlChange( int number, StkFloat value );
72
73 //! Compute and return one output sample.
74 StkFloat tick( unsigned int channel = 0 );
75
76 //! Fill a channel of the StkFrames object with computed outputs.
77 /*!
78 The \c channel argument must be less than the number of
79 channels in the StkFrames argument (the first channel is specified
80 by 0). However, range checking is only performed if _STK_DEBUG_
81 is defined during compilation, in which case an out-of-range value
82 will trigger an StkError exception.
83 */
84 StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
85
86 protected:
87
88 DelayL neckDelay_;
89 DelayL bridgeDelay_;
90 BowTable bowTable_;
91 OnePole stringFilter_;
92 BiQuad bodyFilters_[6];
93 SineWave vibrato_;
94 ADSR adsr_;
95
96 bool bowDown_;
97 StkFloat maxVelocity_;
98 StkFloat baseDelay_;
99 StkFloat vibratoGain_;
100 StkFloat betaRatio_;
101
102 };
103
tick(unsigned int)104 inline StkFloat Bowed :: tick( unsigned int )
105 {
106 StkFloat bowVelocity = maxVelocity_ * adsr_.tick();
107 StkFloat bridgeReflection = -stringFilter_.tick( bridgeDelay_.lastOut() );
108 StkFloat nutReflection = -neckDelay_.lastOut();
109 StkFloat stringVelocity = bridgeReflection + nutReflection;
110 StkFloat deltaV = bowVelocity - stringVelocity; // Differential velocity
111
112 StkFloat newVelocity = 0.0;
113 if ( bowDown_ )
114 newVelocity = deltaV * bowTable_.tick( deltaV ); // Non-Linear bow function
115 neckDelay_.tick( bridgeReflection + newVelocity); // Do string propagations
116 bridgeDelay_.tick(nutReflection + newVelocity);
117
118 if ( vibratoGain_ > 0.0 ) {
119 neckDelay_.setDelay( (baseDelay_ * (1.0 - betaRatio_) ) +
120 (baseDelay_ * vibratoGain_ * vibrato_.tick()) );
121 }
122
123 lastFrame_[0] = 0.1248 * bodyFilters_[5].tick( bodyFilters_[4].tick( bodyFilters_[3].tick( bodyFilters_[2].tick( bodyFilters_[1].tick( bodyFilters_[0].tick( bridgeDelay_.lastOut() ) ) ) ) ) );
124
125 return lastFrame_[0];
126 }
127
tick(StkFrames & frames,unsigned int channel)128 inline StkFrames& Bowed :: tick( StkFrames& frames, unsigned int channel )
129 {
130 unsigned int nChannels = lastFrame_.channels();
131 #if defined(_STK_DEBUG_)
132 if ( channel > frames.channels() - nChannels ) {
133 oStream_ << "Bowed::tick(): channel and StkFrames arguments are incompatible!";
134 handleError( StkError::FUNCTION_ARGUMENT );
135 }
136 #endif
137
138 StkFloat *samples = &frames[channel];
139 unsigned int j, hop = frames.channels() - nChannels;
140 if ( nChannels == 1 ) {
141 for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
142 *samples++ = tick();
143 }
144 else {
145 for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
146 *samples++ = tick();
147 for ( j=1; j<nChannels; j++ )
148 *samples++ = lastFrame_[j];
149 }
150 }
151
152 return frames;
153 }
154
155 } // stk namespace
156
157 #endif
158