Home Information Classes Download Usage Mail List Requirements Links FAQ Tutorial
Pitch shifter effect class based on the Lent algorithm. More...
#include <LentPitShift.h>
Public Member Functions | |
LentPitShift (StkFloat periodRatio=1.0, int tMax=RT_BUFFER_SIZE) | |
Class constructor. | |
void | clear (void) |
Reset and clear all internal state. | |
void | setShift (StkFloat shift) |
Set the pitch shift factor (1.0 produces no shift). | |
StkFloat | tick (StkFloat input) |
Input one sample to the filter and return one output. | |
StkFrames & | tick (StkFrames &frames, unsigned int channel=0) |
Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs. | |
StkFrames & | tick (StkFrames &iFrames, StkFrames &oFrames, unsigned int iChannel=0, unsigned int oChannel=0) |
Take a channel of the iFrames object as inputs to the filter and write outputs to the oFrames object. | |
Protected Member Functions | |
void | process () |
Apply the effect on the input samples and store it. |
Pitch shifter effect class based on the Lent algorithm.
This class implements a pitch shifter using pitch tracking and sample windowing and shifting.
by Francois Germain, 2009.
Take a channel of the StkFrames object as inputs to the filter and replace with corresponding outputs.
The StkFrames argument reference is returned. The channel
argument must be less than the number of channels in the StkFrames argument (the first channel is specified by 0). However, range checking is only performed if _STK_DEBUG_ is defined during compilation, in which case an out-of-range value will trigger an StkError exception.
00228 { 00229 #if defined(_STK_DEBUG_) 00230 if ( channel >= frames.channels() ) { 00231 oStream_ << "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 }
StkFrames & stk::LentPitShift::tick | ( | StkFrames & | iFrames, | |
StkFrames & | oFrames, | |||
unsigned int | iChannel = 0 , |
|||
unsigned int | oChannel = 0 | |||
) | [inline] |
Take a channel of the iFrames
object as inputs to the filter and write outputs to the oFrames
object.
The iFrames
object reference is returned. Each channel argument must be less than the number of channels in the corresponding StkFrames argument (the first channel is specified by 0). However, range checking is only performed if _STK_DEBUG_ is defined during compilation, in which case an out-of-range value will trigger an StkError exception.
00246 { 00247 #if defined(_STK_DEBUG_) 00248 if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) { 00249 oStream_ << "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 }
void stk::LentPitShift::process | ( | ) | [inline, protected] |
Apply the effect on the input samples and store it.
The samples stored in the input frame vector are processed and the delayed result are stored in the output frame vector
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_.tapOut( 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_.tapOut(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 }
The Synthesis ToolKit in C++ (STK) |
©1995-2011 Perry R. Cook and Gary P. Scavone. All Rights Reserved. |