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.