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.
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 }
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.
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 }
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.
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 }
The Synthesis ToolKit in C++ (STK) |
©1995-2012 Perry R. Cook and Gary P. Scavone. All Rights Reserved. |