1 #ifndef STK_FORMSWEP_H
2 #define STK_FORMSWEP_H
3
4 #include "Filter.h"
5
6 namespace stk {
7
8 /***************************************************/
9 /*! \class FormSwep
10 \brief STK sweepable formant filter class.
11
12 This class implements a formant (resonance) which can be "swept"
13 over time from one frequency setting to another. It provides
14 methods for controlling the sweep rate and target frequency.
15
16 by Perry R. Cook and Gary P. Scavone, 1995--2021.
17 */
18 /***************************************************/
19
20 class FormSwep : public Filter
21 {
22 public:
23
24 //! Default constructor creates a second-order pass-through filter.
25 FormSwep( void );
26
27 //! Class destructor.
28 ~FormSwep();
29
30 //! A function to enable/disable the automatic updating of class data when the STK sample rate changes.
31 void ignoreSampleRateChange( bool ignore = true ) { ignoreSampleRateChange_ = ignore; };
32
33 //! Sets the filter coefficients for a resonance at \e frequency (in Hz).
34 /*!
35 This method determines the filter coefficients corresponding to
36 two complex-conjugate poles with the given \e frequency (in Hz)
37 and \e radius from the z-plane origin. The filter zeros are
38 placed at z = 1, z = -1, and the coefficients are then normalized
39 to produce a constant unity gain (independent of the filter \e
40 gain parameter). The resulting filter frequency response has a
41 resonance at the given \e frequency. The closer the poles are to
42 the unit-circle (\e radius close to one), the narrower the
43 resulting resonance width. An unstable filter will result for \e
44 radius >= 1.0. The \e frequency value should be between zero and
45 half the sample rate.
46 */
47 void setResonance( StkFloat frequency, StkFloat radius );
48
49 //! Set both the current and target resonance parameters.
50 void setStates( StkFloat frequency, StkFloat radius, StkFloat gain = 1.0 );
51
52 //! Set target resonance parameters.
53 void setTargets( StkFloat frequency, StkFloat radius, StkFloat gain = 1.0 );
54
55 //! Set the sweep rate (between 0.0 - 1.0).
56 /*!
57 The formant parameters are varied in increments of the
58 sweep rate between their current and target values.
59 A sweep rate of 1.0 will produce an immediate change in
60 resonance parameters from their current values to the
61 target values. A sweep rate of 0.0 will produce no
62 change in resonance parameters.
63 */
64 void setSweepRate( StkFloat rate );
65
66 //! Set the sweep rate in terms of a time value in seconds.
67 /*!
68 This method adjusts the sweep rate based on a
69 given time for the formant parameters to reach
70 their target values.
71 */
72 void setSweepTime( StkFloat time );
73
74 //! Return the last computed output value.
lastOut(void)75 StkFloat lastOut( void ) const { return lastFrame_[0]; };
76
77 //! Input one sample to the filter and return a reference to one output.
78 StkFloat tick( StkFloat input );
79
80 //! Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
81 /*!
82 The StkFrames argument reference is returned. The \c channel
83 argument must be less than the number of channels in the
84 StkFrames argument (the first channel is specified by 0).
85 However, range checking is only performed if _STK_DEBUG_ is
86 defined during compilation, in which case an out-of-range value
87 will trigger an StkError exception.
88 */
89 StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
90
91 //! Take a channel of the \c iFrames object as inputs to the filter and write outputs to the \c oFrames object.
92 /*!
93 The \c iFrames object reference is returned. Each channel
94 argument must be less than the number of channels in the
95 corresponding StkFrames argument (the first channel is specified
96 by 0). However, range checking is only performed if _STK_DEBUG_
97 is defined during compilation, in which case an out-of-range value
98 will trigger an StkError exception.
99 */
100 StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
101
102 protected:
103
104 virtual void sampleRateChanged( StkFloat newRate, StkFloat oldRate );
105
106 bool dirty_;
107 StkFloat frequency_;
108 StkFloat radius_;
109 StkFloat startFrequency_;
110 StkFloat startRadius_;
111 StkFloat startGain_;
112 StkFloat targetFrequency_;
113 StkFloat targetRadius_;
114 StkFloat targetGain_;
115 StkFloat deltaFrequency_;
116 StkFloat deltaRadius_;
117 StkFloat deltaGain_;
118 StkFloat sweepState_;
119 StkFloat sweepRate_;
120
121 };
122
tick(StkFloat input)123 inline StkFloat FormSwep :: tick( StkFloat input )
124 {
125 if ( dirty_ ) {
126 sweepState_ += sweepRate_;
127 if ( sweepState_ >= 1.0 ) {
128 sweepState_ = 1.0;
129 dirty_ = false;
130 radius_ = targetRadius_;
131 frequency_ = targetFrequency_;
132 gain_ = targetGain_;
133 }
134 else {
135 radius_ = startRadius_ + (deltaRadius_ * sweepState_);
136 frequency_ = startFrequency_ + (deltaFrequency_ * sweepState_);
137 gain_ = startGain_ + (deltaGain_ * sweepState_);
138 }
139 this->setResonance( frequency_, radius_ );
140 }
141
142 inputs_[0] = gain_ * input;
143 lastFrame_[0] = b_[0] * inputs_[0] + b_[1] * inputs_[1] + b_[2] * inputs_[2];
144 lastFrame_[0] -= a_[2] * outputs_[2] + a_[1] * outputs_[1];
145 inputs_[2] = inputs_[1];
146 inputs_[1] = inputs_[0];
147 outputs_[2] = outputs_[1];
148 outputs_[1] = lastFrame_[0];
149
150 return lastFrame_[0];
151 }
152
tick(StkFrames & frames,unsigned int channel)153 inline StkFrames& FormSwep :: tick( StkFrames& frames, unsigned int channel )
154 {
155 #if defined(_STK_DEBUG_)
156 if ( channel >= frames.channels() ) {
157 oStream_ << "FormSwep::tick(): channel and StkFrames arguments are incompatible!";
158 handleError( StkError::FUNCTION_ARGUMENT );
159 }
160 #endif
161
162 StkFloat *samples = &frames[channel];
163 unsigned int hop = frames.channels();
164 for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
165 *samples = tick( *samples );
166
167 return frames;
168 }
169
tick(StkFrames & iFrames,StkFrames & oFrames,unsigned int iChannel,unsigned int oChannel)170 inline StkFrames& FormSwep :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
171 {
172 #if defined(_STK_DEBUG_)
173 if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
174 oStream_ << "FormSwep::tick(): channel and StkFrames arguments are incompatible!";
175 handleError( StkError::FUNCTION_ARGUMENT );
176 }
177 #endif
178
179 StkFloat *iSamples = &iFrames[iChannel];
180 StkFloat *oSamples = &oFrames[oChannel];
181 unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
182 for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop )
183 *oSamples = tick( *iSamples );
184
185 return iFrames;
186 }
187
188 } // stk namespace
189
190 #endif
191