Home Information Classes Download Usage Mail List Requirements Links FAQ Tutorial
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. |