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.