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