Home   Information   Classes   Download   Usage   Mail List   Requirements   Links   FAQ   Tutorial


LentPitShift.h

00001 #ifndef STK_LENLentPitShift_H
00002 #define STK_LENLentPitShift_H
00003 
00004 #include "Effect.h"
00005 #include "Delay.h"
00006 
00007 namespace stk {
00008 
00009 /***************************************************/
00018 /***************************************************/
00019 
00020 class LentPitShift : public Effect
00021 {
00022  public:
00024   LentPitShift( StkFloat periodRatio = 1.0, int tMax = RT_BUFFER_SIZE );
00025 
00026   ~LentPitShift( void ) {
00027     delete window;
00028     window = NULL;
00029     delete dt;
00030     dt = NULL;
00031     delete dpt;
00032     dpt = NULL;
00033     delete cumDt;
00034     cumDt = NULL;
00035   }
00036 
00038   void clear( void );
00039 
00041   void setShift( StkFloat shift );
00042 
00044   StkFloat tick( StkFloat input );
00045 
00047 
00055   StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
00056 
00058 
00066   StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
00067 
00068  protected:
00069 
00071 
00075   void process( );
00076 
00077   // Frame storage vectors for process function
00078   StkFrames inputFrames;
00079   StkFrames outputFrames;
00080   int ptrFrames;          // writing pointer
00081 
00082   // Input delay line
00083   Delay inputLine_;
00084   int inputPtr;
00085 
00086   // Output delay line
00087   Delay outputLine_;
00088   double outputPtr;
00089 
00090   // Pitch tracker variables
00091   unsigned long tMax_;    // Maximal period measurable by the pitch tracker.
00092   // It is also the size of the window used by the pitch tracker and
00093   // the size of the frames that can be computed by the tick function
00094 
00095   StkFloat threshold_; // Threshold of detection for the pitch tracker
00096   unsigned long lastPeriod_;    // Result of the last pitch tracking loop
00097   StkFloat* dt;        // Array containing the euclidian distance coefficients
00098   StkFloat* cumDt;     // Array containing the cumulative sum of the coefficients in dt
00099   StkFloat* dpt;       // Array containing the pitch tracking function coefficients
00100 
00101   // Pitch shifter variables
00102   StkFloat env[2];     // Coefficients for the linear interpolation when modifying the output samples
00103   StkFloat* window;    // Hamming window used for the input portion extraction
00104   double periodRatio_; // Ratio of modification of the signal period
00105   StkFrames zeroFrame; // Frame of tMax_ zero samples
00106 
00107 
00108   // Coefficient delay line that could be used for a dynamic calculation of the pitch
00109   //Delay* coeffLine_;
00110 
00111 };
00112 
00113 inline void LentPitShift::process()
00114 {
00115   StkFloat x_t;    // input coefficient
00116   StkFloat x_t_T;  // previous input coefficient at T samples
00117   StkFloat coeff;  // new coefficient for the difference function
00118 
00119   int alternativePitch = tMax_;  // Global minimum storage
00120   lastPeriod_ = tMax_+1;         // Storage of the lowest local minimum under the threshold
00121 
00122   // Loop variables
00123   unsigned long delay_;
00124   unsigned int n;
00125 
00126   // Initialization of the dt coefficients.  Since the
00127   // frames are of tMax_ length, there is no overlapping
00128   // between the successive windows where pitch tracking
00129   // is performed.
00130   for ( delay_=1; delay_<=tMax_; delay_++ )
00131     dt[delay_] = 0.;
00132 
00133   // Calculation of the dt coefficients and update of the input delay line.
00134   for ( n=0; n<inputFrames.size(); n++ ) {
00135     x_t = inputLine_.tick( inputFrames[ n ] );
00136     for ( delay_=1; delay_<= tMax_; delay_++ ) {
00137       x_t_T = inputLine_.contentsAt( delay_ );
00138       coeff = x_t - x_t_T;
00139       dt[delay_] += coeff * coeff;
00140     }
00141   }
00142 
00143   // Calculation of the pitch tracking function and test for the minima.
00144   for ( delay_=1; delay_<=tMax_; delay_++ ) {
00145     cumDt[delay_] = dt[delay_] + cumDt[delay_-1];
00146     dpt[delay_] = dt[delay_] * delay_ / cumDt[delay_];
00147 
00148     // Look for a minimum
00149     if ( dpt[delay_-1]-dpt[delay_-2] < 0 && dpt[delay_]-dpt[delay_-1] > 0 ) {
00150       // Check if the minimum is under the threshold
00151       if ( dpt[delay_-1] < threshold_ ){
00152         lastPeriod_ = delay_-1;
00153         // If a minimum is found, we can stop the loop
00154         break;
00155       }
00156       else if ( dpt[alternativePitch] > dpt[delay_-1] )
00157         // Otherwise we store it if it is the current global minimum
00158         alternativePitch = delay_-1;
00159     }
00160   }
00161 
00162   // Test for the last period length.
00163   if ( dpt[delay_]-dpt[delay_-1] < 0 ) {
00164     if ( dpt[delay_] < threshold_ )
00165       lastPeriod_ = delay_;
00166     else if ( dpt[alternativePitch] > dpt[delay_] )
00167       alternativePitch = delay_;
00168   }
00169 
00170   if ( lastPeriod_ == tMax_+1 )
00171     // No period has been under the threshold so we used the global minimum
00172     lastPeriod_ = alternativePitch;
00173 
00174   // We put the new zero output coefficients in the output delay line and 
00175   // we get the previous calculated coefficients
00176   outputLine_.tick( zeroFrame, outputFrames );
00177 
00178   // Initialization of the Hamming window used in the algorithm
00179   for ( int n=-(int)lastPeriod_; n<(int)lastPeriod_; n++ )
00180     window[n+lastPeriod_] = (1 + cos(PI*n/lastPeriod_)) / 2    ;
00181 
00182   int M;  // Index of reading in the input delay line
00183   int N;  // Index of writing in the output delay line
00184   double sample;  // Temporary storage for the new coefficient
00185 
00186   // We loop for all the frames of length lastPeriod_ presents between inputPtr and tMax_
00187   for ( ; inputPtr<(int)(tMax_-lastPeriod_); inputPtr+=lastPeriod_ ) {
00188     // Test for the decision of compression/expansion
00189     while ( outputPtr < inputPtr ) {
00190       // Coefficients for the linear interpolation
00191       env[1] = fmod( outputPtr + tMax_, 1.0 );
00192       env[0] = 1.0 - env[1];
00193       M = tMax_ - inputPtr + lastPeriod_ - 1; // New reading pointer
00194       N = 2*tMax_ - (unsigned long)floor(outputPtr + tMax_) + lastPeriod_ - 1; // New writing pointer
00195       for ( unsigned int j=0; j<2*lastPeriod_; j++,M--,N-- ) {
00196         sample = inputLine_.contentsAt(M) * window[j] / 2.;
00197         // Linear interpolation
00198         outputLine_.addTo(N, env[0] * sample);
00199         outputLine_.addTo(N-1, env[1] * sample);
00200       }
00201       outputPtr = outputPtr + lastPeriod_ * periodRatio_; // new output pointer
00202     }
00203   }
00204   // Shifting of the pointers waiting for the new frame of length tMax_.
00205   outputPtr -= tMax_;
00206   inputPtr  -= tMax_;
00207 }
00208 
00209 
00210 inline StkFloat LentPitShift :: tick( StkFloat input )
00211 {
00212   StkFloat sample;
00213 
00214   inputFrames[ptrFrames] = input;
00215 
00216   sample = outputFrames[ptrFrames++];
00217 
00218   // Check for end condition
00219   if ( ptrFrames == (int) inputFrames.size() ){
00220     ptrFrames = 0;
00221     process( );
00222   }
00223 
00224   return sample;
00225 }
00226 
00227 inline StkFrames& LentPitShift :: tick( StkFrames& frames, unsigned int channel )
00228 {
00229 #if defined(_STK_DEBUG_)
00230   if ( channel >= frames.channels() ) {
00231     errorString_ << "LentPitShift::tick(): channel and StkFrames arguments are incompatible!";
00232     handleError( StkError::FUNCTION_ARGUMENT );
00233   }
00234 #endif
00235 
00236   StkFloat *samples = &frames[channel];
00237   unsigned int hop = frames.channels();
00238   for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
00239     *samples = tick( *samples );
00240   }
00241 
00242   return frames;
00243 }
00244 
00245 inline StkFrames& LentPitShift :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
00246 {
00247 #if defined(_STK_DEBUG_)
00248   if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
00249     errorString_ << "LentPitShift::tick(): channel and StkFrames arguments are incompatible!";
00250     handleError( StkError::FUNCTION_ARGUMENT );
00251   }
00252 #endif
00253 
00254   StkFloat *iSamples = &iFrames[iChannel];
00255   StkFloat *oSamples = &oFrames[oChannel];
00256   unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
00257   for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
00258     *oSamples = tick( *iSamples );
00259   }
00260 
00261   return iFrames;
00262 }
00263 
00264 } // stk namespace
00265 
00266 #endif
00267 

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