The Synthesis ToolKit in C++ (STK)

Home Information Classes Download Usage Mail List Requirements Links FAQ Tutorial

Shakers.h
1#ifndef STK_SHAKERS_H
2#define STK_SHAKERS_H
3
4#include "Instrmnt.h"
5#include <cmath>
6#include <stdlib.h>
7
8namespace stk {
9
10/***************************************************/
58/***************************************************/
59
60 class Shakers : public Instrmnt
61{
62 public:
64 Shakers( int type = 0 );
65
67
71 void noteOn( StkFloat instrument, StkFloat amplitude );
72
74 void noteOff( StkFloat amplitude );
75
77 void controlChange( int number, StkFloat value );
78
80 StkFloat tick( unsigned int channel = 0 );
81
83
90 StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
91
92 struct BiQuad {
93 StkFloat gain;
94 StkFloat b[3];
95 StkFloat a[3]; // a0 term assumed equal to 1.0
96 StkFloat inputs[3];
97 StkFloat outputs[3];
98
99 // Default constructor.
100 BiQuad()
101 {
102 gain = 0.0;
103 for ( int i=0; i<3; i++ ) {
104 b[i] = 0.0;
105 a[i] = 0.0;
106 inputs[i] = 0.0;
107 outputs[i] = 0.0;
108 }
109 }
110 };
111
112 protected:
113
114 void setType( int type );
115 void setResonance( BiQuad &filter, StkFloat frequency, StkFloat radius );
116 StkFloat tickResonance( BiQuad &filter, StkFloat input );
117 void setEqualization( StkFloat b0, StkFloat b1, StkFloat b2 );
118 StkFloat tickEqualize( StkFloat input );
119 int randomInt( int max );
120 StkFloat randomFloat( StkFloat max = 1.0 );
121 StkFloat noise( void );
122 void waterDrop( void );
123
124 int shakerType_;
125 unsigned int nResonances_;
126 StkFloat shakeEnergy_;
127 StkFloat soundDecay_;
128 StkFloat systemDecay_;
129 StkFloat nObjects_;
130 StkFloat sndLevel_;
131 StkFloat baseGain_;
132 StkFloat currentGain_;
133 StkFloat baseDecay_;
134 StkFloat baseObjects_;
135 StkFloat decayScale_;
136 BiQuad equalizer_;
137 StkFloat ratchetCount_;
138 StkFloat ratchetDelta_;
139 StkFloat baseRatchetDelta_;
140 int lastRatchetValue_;
141
142 std::vector< BiQuad > filters_;
143 std::vector< StkFloat > baseFrequencies_;
144 std::vector< StkFloat > baseRadii_;
145 std::vector< bool > doVaryFrequency_;
146 std::vector< StkFloat > tempFrequencies_;
147 StkFloat varyFactor_;
148};
149
150inline void Shakers :: setResonance( BiQuad &filter, StkFloat frequency, StkFloat radius )
151{
152 filter.a[1] = -2.0 * radius * cos( TWO_PI * frequency / Stk::sampleRate());
153 filter.a[2] = radius * radius;
154}
155
156inline StkFloat Shakers :: tickResonance( BiQuad &filter, StkFloat input )
157{
158 filter.outputs[0] = input * filter.gain * currentGain_;
159 filter.outputs[0] -= filter.a[1] * filter.outputs[1] + filter.a[2] * filter.outputs[2];
160 filter.outputs[2] = filter.outputs[1];
161 filter.outputs[1] = filter.outputs[0];
162 return filter.outputs[0];
163}
164
165inline void Shakers :: setEqualization( StkFloat b0, StkFloat b1, StkFloat b2 )
166{
167 equalizer_.b[0] = b0;
168 equalizer_.b[1] = b1;
169 equalizer_.b[2] = b2;
170}
171
172inline StkFloat Shakers :: tickEqualize( StkFloat input )
173{
174 equalizer_.inputs[0] = input;
175 equalizer_.outputs[0] = equalizer_.b[0] * equalizer_.inputs[0] + equalizer_.b[1] * equalizer_.inputs[1] + equalizer_.b[2] * equalizer_.inputs[2];
176 equalizer_.inputs[2] = equalizer_.inputs[1];
177 equalizer_.inputs[1] = equalizer_.inputs[0];
178 return equalizer_.outputs[0];
179}
180
181inline int Shakers :: randomInt( int max ) // Return random integer between 0 and max-1
182{
183 return (int) ((float)max * rand() / (RAND_MAX + 1.0) );
184}
185
186inline StkFloat Shakers :: randomFloat( StkFloat max ) // Return random float between 0.0 and max
187{
188 return (StkFloat) (max * rand() / (RAND_MAX + 1.0) );
189}
190
191inline StkFloat Shakers :: noise( void ) // Return random StkFloat float between -1.0 and 1.0
192{
193 return ( (StkFloat) ( 2.0 * rand() / (RAND_MAX + 1.0) ) - 1.0 );
194}
195
196const StkFloat MIN_ENERGY = 0.001;
197const StkFloat WATER_FREQ_SWEEP = 1.0001;
198
199inline void Shakers :: waterDrop( void )
200{
201 if ( randomInt( 32767 ) < nObjects_) {
202 sndLevel_ = shakeEnergy_;
203 unsigned int j = randomInt( 3 );
204 if ( j == 0 && filters_[0].gain == 0.0 ) { // don't change unless fully decayed
205 tempFrequencies_[0] = baseFrequencies_[1] * (0.75 + (0.25 * noise()));
206 filters_[0].gain = fabs( noise() );
207 }
208 else if (j == 1 && filters_[1].gain == 0.0) {
209 tempFrequencies_[1] = baseFrequencies_[1] * (1.0 + (0.25 * noise()));
210 filters_[1].gain = fabs( noise() );
211 }
212 else if ( filters_[2].gain == 0.0 ) {
213 tempFrequencies_[2] = baseFrequencies_[1] * (1.25 + (0.25 * noise()));
214 filters_[2].gain = fabs( noise() );
215 }
216 }
217
218 // Sweep center frequencies.
219 for ( unsigned int i=0; i<3; i++ ) { // WATER_RESONANCES = 3
220 filters_[i].gain *= baseRadii_[i];
221 if ( filters_[i].gain > 0.001 ) {
222 tempFrequencies_[i] *= WATER_FREQ_SWEEP;
223 filters_[i].a[1] = -2.0 * baseRadii_[i] * cos( TWO_PI * tempFrequencies_[i] / Stk::sampleRate() );
224 }
225 else
226 filters_[i].gain = 0.0;
227 }
228}
229
230 inline StkFloat Shakers :: tick( unsigned int )
231{
232 unsigned int iTube = 0;
233 StkFloat input = 0.0;
234 if ( shakerType_ == 19 || shakerType_ == 20 ) {
235 if ( ratchetCount_ <= 0 ) return lastFrame_[0] = 0.0;
236
237 shakeEnergy_ -= ( ratchetDelta_ + ( 0.002 * shakeEnergy_ ) );
238 if ( shakeEnergy_ < 0.0 ) {
239 shakeEnergy_ = 1.0;
240 ratchetCount_--;
241 }
242
243 if ( randomFloat( 1024 ) < nObjects_ )
244 sndLevel_ += shakeEnergy_ * shakeEnergy_;
245
246 // Sound is enveloped noise
247 input = sndLevel_ * noise() * shakeEnergy_;
248 }
249 else {
250 if ( shakeEnergy_ < MIN_ENERGY ) return lastFrame_[0] = 0.0;
251
252 // Exponential system decay
253 shakeEnergy_ *= systemDecay_;
254
255 // Random events
256 if ( shakerType_ == 21 ) {
257 waterDrop();
258 input = sndLevel_;
259 }
260 else {
261 if ( randomFloat( 1024.0 ) < nObjects_ ) {
262 sndLevel_ += shakeEnergy_;
263 input = sndLevel_;
264 // Vary resonance frequencies if specified.
265 for ( unsigned int i=0; i<nResonances_; i++ ) {
266 if ( doVaryFrequency_[i] ) {
267 StkFloat tempRand = baseFrequencies_[i] * ( 1.0 + ( varyFactor_ * noise() ) );
268 filters_[i].a[1] = -2.0 * baseRadii_[i] * cos( TWO_PI * tempRand / Stk::sampleRate() );
269 }
270 }
271 if ( shakerType_ == 22 ) iTube = randomInt( 7 ); // ANGKLUNG_RESONANCES
272 }
273 }
274 }
275
276 // Exponential sound decay
277 sndLevel_ *= soundDecay_;
278
279 // Do resonance filtering
280 lastFrame_[0] = 0.0;
281 if ( shakerType_ == 22 ) {
282 for ( unsigned int i=0; i<nResonances_; i++ ) {
283 if ( i == iTube )
284 lastFrame_[0] += tickResonance( filters_[i], input );
285 else
286 lastFrame_[0] += tickResonance( filters_[i], 0.0 );
287 }
288 }
289 else {
290 for ( unsigned int i=0; i<nResonances_; i++ )
291 lastFrame_[0] += tickResonance( filters_[i], input );
292 }
293
294 // Do final FIR filtering (lowpass or highpass)
295 lastFrame_[0] = tickEqualize( lastFrame_[0] );
296
297 //if ( std::abs(lastFrame_[0]) > 1.0 )
298 // std::cout << "lastOutput = " << lastFrame_[0] << std::endl;
299
300 return lastFrame_[0];
301}
302
303 inline StkFrames& Shakers :: tick( StkFrames& frames, unsigned int channel )
304{
305 unsigned int nChannels = lastFrame_.channels();
306#if defined(_STK_DEBUG_)
307 if ( channel > frames.channels() - nChannels ) {
308 oStream_ << "Shakers::tick(): channel and StkFrames arguments are incompatible!";
309 handleError( StkError::FUNCTION_ARGUMENT );
310 }
311#endif
312
313 StkFloat *samples = &frames[channel];
314 unsigned int j, hop = frames.channels() - nChannels;
315 if ( nChannels == 1 ) {
316 for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
317 *samples++ = tick();
318 }
319 else {
320 for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
321 *samples++ = tick();
322 for ( j=1; j<nChannels; j++ )
323 *samples++ = lastFrame_[j];
324 }
325 }
326
327 return frames;
328}
329
330} // stk namespace
331
332#endif
stk::Instrmnt
STK instrument abstract base class.
Definition Instrmnt.h:20
stk::Shakers
PhISEM and PhOLIES class.
Definition Shakers.h:61
stk::Shakers::Shakers
Shakers(int type=0)
Class constructor taking instrument type argument.
stk::Shakers::controlChange
void controlChange(int number, StkFloat value)
Perform the control change specified by number and value (0.0 - 128.0).
stk::Shakers::noteOn
void noteOn(StkFloat instrument, StkFloat amplitude)
Start a note with the given instrument and amplitude.
stk::Shakers::noteOff
void noteOff(StkFloat amplitude)
Stop a note with the given amplitude (speed of decay).
stk::Shakers::tick
StkFloat tick(unsigned int channel=0)
Compute and return one output sample.
Definition Shakers.h:230
stk::StkFrames
An STK class to handle vectorized audio data.
Definition Stk.h:279
stk::StkFrames::channels
unsigned int channels(void) const
Return the number of channels represented by the data.
Definition Stk.h:416
stk::StkFrames::frames
unsigned int frames(void) const
Return the number of sample frames represented by the data.
Definition Stk.h:419
stk::Stk::sampleRate
static StkFloat sampleRate(void)
Static method that returns the current STK sample rate.
Definition Stk.h:148
stk
The STK namespace.
Definition ADSR.h:6

The Synthesis ToolKit in C++ (STK)
©1995--2023 Perry R. Cook and Gary P. Scavone. All Rights Reserved.