1 #ifndef STK_RESONATE_H
2 #define STK_RESONATE_H
3 
4 #include "Instrmnt.h"
5 #include "ADSR.h"
6 #include "BiQuad.h"
7 #include "Noise.h"
8 
9 namespace stk {
10 
11 /***************************************************/
12 /*! \class Resonate
13     \brief STK noise driven formant filter.
14 
15     This instrument contains a noise source, which
16     excites a biquad resonance filter, with volume
17     controlled by an ADSR.
18 
19     Control Change Numbers:
20        - Resonance Frequency (0-Nyquist) = 2
21        - Pole Radii = 4
22        - Notch Frequency (0-Nyquist) = 11
23        - Zero Radii = 1
24        - Envelope Gain = 128
25 
26     by Perry R. Cook and Gary P. Scavone, 1995--2021.
27 */
28 /***************************************************/
29 
30 class Resonate : public Instrmnt
31 {
32  public:
33   //! Class constructor.
34   Resonate( void );
35 
36   //! Class destructor.
37   ~Resonate( void );
38 
39   //! Set the filter for a resonance at the given frequency (Hz) and radius.
40   void setResonance( StkFloat frequency, StkFloat radius );
41 
42   //! Set the filter for a notch at the given frequency (Hz) and radius.
43   void setNotch( StkFloat frequency, StkFloat radius );
44 
45   //! Set the filter zero coefficients for contant resonance gain.
setEqualGainZeroes(void)46   void setEqualGainZeroes( void ) { filter_.setEqualGainZeroes(); };
47 
48   //! Initiate the envelope with a key-on event.
keyOn(void)49   void keyOn( void ) { adsr_.keyOn(); };
50 
51   //! Signal a key-off event to the envelope.
keyOff(void)52   void keyOff( void ) { adsr_.keyOff(); };
53 
54   //! Start a note with the given frequency and amplitude.
55   void noteOn( StkFloat frequency, StkFloat amplitude );
56 
57   //! Stop a note with the given amplitude (speed of decay).
58   void noteOff( StkFloat amplitude );
59 
60   //! Perform the control change specified by \e number and \e value (0.0 - 128.0).
61   void controlChange( int number, StkFloat value );
62 
63   //! Compute and return one output sample.
64   StkFloat tick( unsigned int channel = 0 );
65 
66   //! Fill a channel of the StkFrames object with computed outputs.
67   /*!
68     The \c channel argument must be less than the number of
69     channels in the StkFrames argument (the first channel is specified
70     by 0).  However, range checking is only performed if _STK_DEBUG_
71     is defined during compilation, in which case an out-of-range value
72     will trigger an StkError exception.
73   */
74   StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
75 
76  protected:
77 
78   ADSR     adsr_;
79   BiQuad   filter_;
80   Noise    noise_;
81   StkFloat poleFrequency_;
82   StkFloat poleRadius_;
83   StkFloat zeroFrequency_;
84   StkFloat zeroRadius_;
85 
86 };
87 
tick(unsigned int)88 inline StkFloat Resonate :: tick( unsigned int )
89 {
90   lastFrame_[0] = filter_.tick( noise_.tick() );
91   lastFrame_[0] *= adsr_.tick();
92   return lastFrame_[0];
93 }
94 
tick(StkFrames & frames,unsigned int channel)95 inline StkFrames& Resonate :: tick( StkFrames& frames, unsigned int channel )
96 {
97   unsigned int nChannels = lastFrame_.channels();
98 #if defined(_STK_DEBUG_)
99   if ( channel > frames.channels() - nChannels ) {
100     oStream_ << "Resonate::tick(): channel and StkFrames arguments are incompatible!";
101     handleError( StkError::FUNCTION_ARGUMENT );
102   }
103 #endif
104 
105   StkFloat *samples = &frames[channel];
106   unsigned int j, hop = frames.channels() - nChannels;
107   if ( nChannels == 1 ) {
108     for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
109       *samples++ = tick();
110   }
111   else {
112     for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
113       *samples++ = tick();
114       for ( j=1; j<nChannels; j++ )
115         *samples++ = lastFrame_[j];
116     }
117   }
118 
119   return frames;
120 }
121 
122 } // stk namespace
123 
124 #endif
125