The Synthesis ToolKit in C++ (STK)

Home Information Classes Download Usage Mail List Requirements Links FAQ Tutorial

# LentPitShift.h

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

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