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