Home   Information   Classes   Download   Usage   Mail List   Requirements   Links   FAQ   Tutorial


BlitSaw.h

00001 #ifndef STK_BLITSAW_H
00002 #define STK_BLITSAW_H
00003 
00004 #include "Generator.h"
00005 #include <cmath>
00006 #include <limits>
00007 
00008 namespace stk {
00009 
00010 /***************************************************/
00029 /***************************************************/
00030 
00031 class BlitSaw: public Generator
00032 {
00033  public:
00035   BlitSaw( StkFloat frequency = 220.0 );
00036 
00038   ~BlitSaw();
00039 
00041   void reset();
00042 
00044   void setFrequency( StkFloat frequency );
00045 
00047 
00059   void setHarmonics( unsigned int nHarmonics = 0 );
00060 
00062   StkFloat lastOut( void ) const { return lastFrame_[0]; };
00063 
00065   StkFloat tick( void );
00066 
00068 
00075   StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
00076 
00077  protected:
00078 
00079   void updateHarmonics( void );
00080 
00081   unsigned int nHarmonics_;
00082   unsigned int m_;
00083   StkFloat rate_;
00084   StkFloat phase_;
00085   StkFloat p_;
00086   StkFloat C2_;
00087   StkFloat a_;
00088   StkFloat state_;
00089 
00090 };
00091 
00092 inline StkFloat BlitSaw :: tick( void )
00093 {
00094   // The code below implements the BLIT algorithm of Stilson and
00095   // Smith, followed by a summation and filtering operation to produce
00096   // a sawtooth waveform.  After experimenting with various approaches
00097   // to calculate the average value of the BLIT over one period, I
00098   // found that an estimate of C2_ = 1.0 / period (in samples) worked
00099   // most consistently.  A "leaky integrator" is then applied to the
00100   // difference of the BLIT output and C2_. (GPS - 1 October 2005)
00101 
00102   // A fully  optimized version of this code would replace the two sin 
00103   // calls with a pair of fast sin oscillators, for which stable fast 
00104   // two-multiply algorithms are well known. In the spirit of STK,
00105   // which favors clarity over performance, the optimization has 
00106   // not been made here.
00107 
00108   // Avoid a divide by zero, or use of a denormalized divisor 
00109   // at the sinc peak, which has a limiting value of m_ / p_.
00110   StkFloat tmp, denominator = sin( phase_ );
00111   if ( fabs(denominator) <= std::numeric_limits<StkFloat>::epsilon() )
00112     tmp = a_;
00113   else {
00114     tmp =  sin( m_ * phase_ );
00115     tmp /= p_ * denominator;
00116   }
00117 
00118   tmp += state_ - C2_;
00119   state_ = tmp * 0.995;
00120 
00121   phase_ += rate_;
00122   if ( phase_ >= PI ) phase_ -= PI;
00123     
00124   lastFrame_[0] = tmp;
00125          return lastFrame_[0];
00126 }
00127 
00128 inline StkFrames& BlitSaw :: tick( StkFrames& frames, unsigned int channel )
00129 {
00130 #if defined(_STK_DEBUG_)
00131   if ( channel >= frames.channels() ) {
00132     oStream_ << "BlitSaw::tick(): channel and StkFrames arguments are incompatible!";
00133     handleError( StkError::FUNCTION_ARGUMENT );
00134   }
00135 #endif
00136 
00137 
00138   StkFloat *samples = &frames[channel];
00139   unsigned int hop = frames.channels();
00140   for ( unsigned int i=0; i<frames.frames(); i++, samples += hop )
00141     *samples = BlitSaw::tick();
00142 
00143   return frames;
00144 }
00145 
00146 } // stk namespace
00147 
00148 #endif

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