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