1 #ifndef STK_BRASS_H
2 #define STK_BRASS_H
3
4 #include "Instrmnt.h"
5 #include "DelayA.h"
6 #include "BiQuad.h"
7 #include "PoleZero.h"
8 #include "ADSR.h"
9 #include "SineWave.h"
10
11 namespace stk {
12
13 /***************************************************/
14 /*! \class Brass
15 \brief STK simple brass instrument class.
16
17 This class implements a simple brass instrument
18 waveguide model, a la Cook (TBone, HosePlayer).
19
20 This is a digital waveguide model, making its
21 use possibly subject to patents held by
22 Stanford University, Yamaha, and others.
23
24 Control Change Numbers:
25 - Lip Tension = 2
26 - Slide Length = 4
27 - Vibrato Frequency = 11
28 - Vibrato Gain = 1
29 - Volume = 128
30
31 by Perry R. Cook and Gary P. Scavone, 1995--2021.
32 */
33 /***************************************************/
34
35 class Brass: public Instrmnt
36 {
37 public:
38 //! Class constructor, taking the lowest desired playing frequency.
39 /*!
40 An StkError will be thrown if the rawwave path is incorrectly set.
41 */
42 Brass( StkFloat lowestFrequency = 8.0 );
43
44 //! Class destructor.
45 ~Brass( );
46
47 //! Reset and clear all internal state.
48 void clear( );
49
50 //! Set instrument parameters for a particular frequency.
51 void setFrequency( StkFloat frequency );
52
53 //! Set the lips frequency.
54 void setLip( StkFloat frequency );
55
56 //! Apply breath pressure to instrument with given amplitude and rate of increase.
57 void startBlowing( StkFloat amplitude, StkFloat rate );
58
59 //! Decrease breath pressure with given rate of decrease.
60 void stopBlowing( StkFloat rate );
61
62 //! Start a note with the given frequency and amplitude.
63 void noteOn( StkFloat frequency, StkFloat amplitude );
64
65 //! Stop a note with the given amplitude (speed of decay).
66 void noteOff( StkFloat amplitude );
67
68 //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
69 void controlChange( int number, StkFloat value );
70
71 //! Compute and return one output sample.
72 StkFloat tick( unsigned int channel = 0 );
73
74 //! Fill a channel of the StkFrames object with computed outputs.
75 /*!
76 The \c channel argument must be less than the number of
77 channels in the StkFrames argument (the first channel is specified
78 by 0). However, range checking is only performed if _STK_DEBUG_
79 is defined during compilation, in which case an out-of-range value
80 will trigger an StkError exception.
81 */
82 StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
83
84 protected:
85
86 DelayA delayLine_;
87 BiQuad lipFilter_;
88 PoleZero dcBlock_;
89 ADSR adsr_;
90 SineWave vibrato_;
91
92 StkFloat lipTarget_;
93 StkFloat slideTarget_;
94 StkFloat vibratoGain_;
95 StkFloat maxPressure_;
96
97 };
98
tick(unsigned int)99 inline StkFloat Brass :: tick( unsigned int )
100 {
101 StkFloat breathPressure = maxPressure_ * adsr_.tick();
102 breathPressure += vibratoGain_ * vibrato_.tick();
103
104 StkFloat mouthPressure = 0.3 * breathPressure;
105 StkFloat borePressure = 0.85 * delayLine_.lastOut();
106 StkFloat deltaPressure = mouthPressure - borePressure; // Differential pressure.
107 deltaPressure = lipFilter_.tick( deltaPressure ); // Force - > position.
108 deltaPressure *= deltaPressure; // Basic position to area mapping.
109 if ( deltaPressure > 1.0 ) deltaPressure = 1.0; // Non-linear saturation.
110
111 // The following input scattering assumes the mouthPressure = area.
112 lastFrame_[0] = deltaPressure * mouthPressure + ( 1.0 - deltaPressure) * borePressure;
113 lastFrame_[0] = delayLine_.tick( dcBlock_.tick( lastFrame_[0] ) );
114
115 return lastFrame_[0];
116 }
117
tick(StkFrames & frames,unsigned int channel)118 inline StkFrames& Brass :: tick( StkFrames& frames, unsigned int channel )
119 {
120 unsigned int nChannels = lastFrame_.channels();
121 #if defined(_STK_DEBUG_)
122 if ( channel > frames.channels() - nChannels ) {
123 oStream_ << "Brass::tick(): channel and StkFrames arguments are incompatible!";
124 handleError( StkError::FUNCTION_ARGUMENT );
125 }
126 #endif
127
128 StkFloat *samples = &frames[channel];
129 unsigned int j, hop = frames.channels() - nChannels;
130 if ( nChannels == 1 ) {
131 for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
132 *samples++ = tick();
133 }
134 else {
135 for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
136 *samples++ = tick();
137 for ( j=1; j<nChannels; j++ )
138 *samples++ = lastFrame_[j];
139 }
140 }
141
142 return frames;
143 }
144
145 } // stk namespace
146
147 #endif
148