Home   Information   Classes   Download   Usage   Mail List   Requirements   Links   FAQ   Tutorial


Shakers.h

00001 #ifndef STK_SHAKERS_H
00002 #define STK_SHAKERS_H
00003 
00004 #include "Instrmnt.h"
00005 #include <cmath>
00006 #include <stdlib.h>
00007 
00008 namespace stk {
00009 
00010 /***************************************************/
00058 /***************************************************/
00059 
00060 class Shakers : public Instrmnt
00061 {
00062  public:
00064   Shakers( int type = 0 );
00065 
00067 
00071   void noteOn( StkFloat instrument, StkFloat amplitude );
00072 
00074   void noteOff( StkFloat amplitude );
00075 
00077   void controlChange( int number, StkFloat value );
00078 
00080   StkFloat tick( unsigned int channel = 0 );
00081 
00083 
00090   StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
00091 
00092   struct BiQuad {
00093     StkFloat gain;
00094     StkFloat b[3];
00095     StkFloat a[3]; // a0 term assumed equal to 1.0
00096     StkFloat inputs[3];
00097     StkFloat outputs[3];
00098 
00099     // Default constructor.
00100     BiQuad()
00101     {
00102       gain = 0.0;
00103       for ( int i=0; i<3; i++ ) {
00104         b[i] = 0.0;
00105         a[i] = 0.0;
00106         inputs[i] = 0.0;
00107         outputs[i] = 0.0;
00108       }
00109     }
00110   };
00111 
00112  protected:
00113 
00114   void setType( int type );
00115   void setResonance( BiQuad &filter, StkFloat frequency, StkFloat radius );
00116   StkFloat tickResonance( BiQuad &filter, StkFloat input );
00117   void setEqualization( StkFloat b0, StkFloat b1, StkFloat b2 );
00118   StkFloat tickEqualize( StkFloat input );
00119   int randomInt( int max );
00120   StkFloat randomFloat( StkFloat max = 1.0 );
00121   StkFloat noise( void );
00122   void waterDrop( void );
00123 
00124   int shakerType_;
00125   unsigned int nResonances_;
00126   StkFloat shakeEnergy_;
00127   StkFloat soundDecay_;
00128   StkFloat systemDecay_;
00129   StkFloat nObjects_;
00130   StkFloat sndLevel_;
00131   StkFloat baseGain_;
00132   StkFloat currentGain_;
00133   StkFloat baseDecay_;
00134   StkFloat baseObjects_;
00135   StkFloat decayScale_;
00136   BiQuad equalizer_;
00137   StkFloat ratchetCount_;
00138   StkFloat ratchetDelta_;
00139   StkFloat baseRatchetDelta_;
00140   int lastRatchetValue_;
00141 
00142   std::vector< BiQuad > filters_;
00143   std::vector< StkFloat > baseFrequencies_;
00144   std::vector< StkFloat > baseRadii_;
00145   std::vector< bool > doVaryFrequency_;
00146   std::vector< StkFloat > tempFrequencies_;
00147   StkFloat varyFactor_;
00148 };
00149 
00150 inline void Shakers :: setResonance( BiQuad &filter, StkFloat frequency, StkFloat radius )
00151 {
00152   filter.a[1] = -2.0 * radius * cos( TWO_PI * frequency / Stk::sampleRate());
00153   filter.a[2] = radius * radius;
00154 }
00155 
00156 inline StkFloat Shakers :: tickResonance( BiQuad &filter, StkFloat input )
00157 {
00158   filter.outputs[0] = input * filter.gain * currentGain_;
00159   filter.outputs[0] -= filter.a[1] * filter.outputs[1] + filter.a[2] * filter.outputs[2];
00160   filter.outputs[2] = filter.outputs[1];
00161   filter.outputs[1] = filter.outputs[0];
00162   return filter.outputs[0];
00163 }
00164 
00165 inline void Shakers :: setEqualization( StkFloat b0, StkFloat b1, StkFloat b2 )
00166 {
00167   equalizer_.b[0] = b0;
00168   equalizer_.b[1] = b1;
00169   equalizer_.b[2] = b2;
00170 }
00171 
00172 inline StkFloat Shakers :: tickEqualize( StkFloat input )
00173 {
00174   equalizer_.inputs[0] = input;
00175   equalizer_.outputs[0] = equalizer_.b[0] * equalizer_.inputs[0] + equalizer_.b[1] * equalizer_.inputs[1] + equalizer_.b[2] * equalizer_.inputs[2];
00176   equalizer_.inputs[2] = equalizer_.inputs[1];
00177   equalizer_.inputs[1] = equalizer_.inputs[0];
00178   return equalizer_.outputs[0];
00179 }
00180 
00181 inline int Shakers :: randomInt( int max ) //  Return random integer between 0 and max-1
00182 {
00183   return (int) ((float)max * rand() / (RAND_MAX + 1.0) );
00184 }
00185 
00186 inline StkFloat Shakers :: randomFloat( StkFloat max ) // Return random float between 0.0 and max
00187 {        
00188   return (StkFloat) (max * rand() / (RAND_MAX + 1.0) );
00189 }
00190 
00191 inline StkFloat Shakers :: noise( void ) //  Return random StkFloat float between -1.0 and 1.0
00192 {
00193   return ( (StkFloat) ( 2.0 * rand() / (RAND_MAX + 1.0) ) - 1.0 );
00194 }
00195 
00196 const StkFloat MIN_ENERGY = 0.001;
00197 const StkFloat WATER_FREQ_SWEEP = 1.0001;
00198 
00199 inline void Shakers :: waterDrop( void )
00200 {
00201   if ( randomInt( 32767 ) < nObjects_) {
00202     sndLevel_ = shakeEnergy_;   
00203     unsigned int j = randomInt( 3 );
00204     if ( j == 0 && filters_[0].gain == 0.0 ) { // don't change unless fully decayed
00205       tempFrequencies_[0] = baseFrequencies_[1] * (0.75 + (0.25 * noise()));
00206       filters_[0].gain = fabs( noise() );
00207     }
00208     else if (j == 1 && filters_[1].gain == 0.0) {
00209       tempFrequencies_[1] = baseFrequencies_[1] * (1.0 + (0.25 * noise()));
00210       filters_[1].gain = fabs( noise() );
00211     }
00212     else if ( filters_[2].gain == 0.0 ) {
00213       tempFrequencies_[2] = baseFrequencies_[1] * (1.25 + (0.25 * noise()));
00214       filters_[2].gain = fabs( noise() );
00215     }
00216   }
00217 
00218   // Sweep center frequencies.
00219   for ( unsigned int i=0; i<3; i++ ) { // WATER_RESONANCES = 3
00220     filters_[i].gain *= baseRadii_[i];
00221     if ( filters_[i].gain > 0.001 ) {
00222       tempFrequencies_[i] *= WATER_FREQ_SWEEP;
00223       filters_[i].a[1] = -2.0 * baseRadii_[i] * cos( TWO_PI * tempFrequencies_[i] / Stk::sampleRate() );
00224     }
00225     else
00226       filters_[i].gain = 0.0;
00227   }
00228 }
00229 
00230 inline StkFloat Shakers :: tick( unsigned int )
00231 {
00232   unsigned int iTube = 0;
00233   StkFloat input = 0.0;
00234   if ( shakerType_ == 19 || shakerType_ == 20 ) {
00235     if ( ratchetCount_ <= 0 ) return lastFrame_[0] = 0.0;
00236 
00237     shakeEnergy_ -= ( ratchetDelta_ + ( 0.002 * shakeEnergy_ ) );
00238     if ( shakeEnergy_ < 0.0 ) {
00239       shakeEnergy_ = 1.0;
00240       ratchetCount_--;
00241     }
00242 
00243     if ( randomFloat( 1024 ) < nObjects_ )
00244       sndLevel_ += shakeEnergy_ * shakeEnergy_;
00245 
00246     // Sound is enveloped noise
00247     input = sndLevel_ * noise() * shakeEnergy_;
00248   }
00249   else { 
00250     if ( shakeEnergy_ < MIN_ENERGY ) return lastFrame_[0] = 0.0;
00251 
00252     // Exponential system decay
00253     shakeEnergy_ *= systemDecay_;
00254 
00255     // Random events
00256     if ( shakerType_ == 21 ) {
00257       waterDrop();
00258       input = sndLevel_;
00259     }
00260     else {
00261       if ( randomFloat( 1024.0 ) < nObjects_ ) {
00262         sndLevel_ += shakeEnergy_;
00263         input = sndLevel_;
00264         // Vary resonance frequencies if specified.
00265         for ( unsigned int i=0; i<nResonances_; i++ ) {
00266           if ( doVaryFrequency_[i] ) {
00267             StkFloat tempRand = baseFrequencies_[i] * ( 1.0 + ( varyFactor_ * noise() ) );
00268             filters_[i].a[1] = -2.0 * baseRadii_[i] * cos( TWO_PI * tempRand / Stk::sampleRate() );
00269           }
00270         }
00271         if ( shakerType_ == 22 ) iTube = randomInt( 7 ); // ANGKLUNG_RESONANCES
00272       }
00273     }
00274   }
00275 
00276   // Exponential sound decay
00277   sndLevel_ *= soundDecay_;
00278 
00279   // Do resonance filtering
00280   lastFrame_[0] = 0.0;
00281   if ( shakerType_ == 22 ) {
00282     for ( unsigned int i=0; i<nResonances_; i++ ) {
00283       if ( i == iTube )
00284         lastFrame_[0] += tickResonance( filters_[i], input );
00285       else
00286         lastFrame_[0] += tickResonance( filters_[i], 0.0 );
00287     }
00288   }
00289   else {
00290     for ( unsigned int i=0; i<nResonances_; i++ )
00291       lastFrame_[0] += tickResonance( filters_[i], input );
00292   }
00293 
00294   // Do final FIR filtering (lowpass or highpass)
00295   lastFrame_[0] = tickEqualize( lastFrame_[0] );
00296 
00297   //if ( std::abs(lastFrame_[0]) > 1.0 )
00298   //  std::cout << "lastOutput = " << lastFrame_[0] << std::endl;
00299 
00300   return lastFrame_[0];
00301 }
00302 
00303 inline StkFrames& Shakers :: tick( StkFrames& frames, unsigned int channel )
00304 {
00305   unsigned int nChannels = lastFrame_.channels();
00306 #if defined(_STK_DEBUG_)
00307   if ( channel > frames.channels() - nChannels ) {
00308     oStream_ << "Shakers::tick(): channel and StkFrames arguments are incompatible!";
00309     handleError( StkError::FUNCTION_ARGUMENT );
00310   }
00311 #endif
00312 
00313   StkFloat *samples = &frames[channel];
00314   unsigned int j, hop = frames.channels() - nChannels;
00315   if ( nChannels == 1 ) {
00316     for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
00317       *samples++ = tick();
00318   }
00319   else {
00320     for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
00321       *samples++ = tick();
00322       for ( j=1; j<nChannels; j++ )
00323         *samples++ = lastFrame_[j];
00324     }
00325   }
00326 
00327   return frames;
00328 }
00329 
00330 } // stk namespace
00331 
00332 #endif

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