Home   Information   Classes   Download   Usage   Mail List   Requirements   Links   FAQ   Tutorial


LentPitShift.h
1 #ifndef STK_LENTPITSHIFT_H
2 #define STK_LENTPITSHIFT_H
3 
4 #include "Effect.h"
5 #include "Delay.h"
6 
7 namespace stk {
8 
9 /***************************************************/
18 /***************************************************/
19 
20 class LentPitShift : public Effect
21 {
22  public:
24  LentPitShift( StkFloat periodRatio = 1.0, int tMax = RT_BUFFER_SIZE );
25 
26  ~LentPitShift( void ) {
27  delete window;
28  delete dt;
29  delete dpt;
30  delete cumDt;
31  }
32 
34  void clear( void );
35 
37  void setShift( StkFloat shift );
38 
40  StkFloat tick( StkFloat input );
41 
43 
51  StkFrames& tick( StkFrames& frames, unsigned int channel = 0 );
52 
54 
62  StkFrames& tick( StkFrames& iFrames, StkFrames &oFrames, unsigned int iChannel = 0, unsigned int oChannel = 0 );
63 
64  protected:
65 
67 
71  void process( );
72 
73  // Frame storage vectors for process function
74  StkFrames inputFrames;
75  StkFrames outputFrames;
76  int ptrFrames; // writing pointer
77 
78  // Input delay line
79  Delay inputLine_;
80  int inputPtr;
81 
82  // Output delay line
83  Delay outputLine_;
84  double outputPtr;
85 
86  // Pitch tracker variables
87  unsigned long tMax_; // Maximal period measurable by the pitch tracker.
88  // It is also the size of the window used by the pitch tracker and
89  // the size of the frames that can be computed by the tick function
90 
91  StkFloat threshold_; // Threshold of detection for the pitch tracker
92  unsigned long lastPeriod_; // Result of the last pitch tracking loop
93  StkFloat* dt; // Array containing the euclidian distance coefficients
94  StkFloat* cumDt; // Array containing the cumulative sum of the coefficients in dt
95  StkFloat* dpt; // Array containing the pitch tracking function coefficients
96 
97  // Pitch shifter variables
98  StkFloat env[2]; // Coefficients for the linear interpolation when modifying the output samples
99  StkFloat* window; // Hamming window used for the input portion extraction
100  double periodRatio_; // Ratio of modification of the signal period
101  StkFrames zeroFrame; // Frame of tMax_ zero samples
102 
103 
104  // Coefficient delay line that could be used for a dynamic calculation of the pitch
105  //Delay* coeffLine_;
106 
107 };
108 
110 {
111  StkFloat x_t; // input coefficient
112  StkFloat x_t_T; // previous input coefficient at T samples
113  StkFloat coeff; // new coefficient for the difference function
114 
115  unsigned long alternativePitch = tMax_; // Global minimum storage
116  lastPeriod_ = tMax_+1; // Storage of the lowest local minimum under the threshold
117 
118  // Loop variables
119  unsigned long delay_;
120  unsigned int n;
121 
122  // Initialization of the dt coefficients. Since the
123  // frames are of tMax_ length, there is no overlapping
124  // between the successive windows where pitch tracking
125  // is performed.
126  for ( delay_=1; delay_<=tMax_; delay_++ )
127  dt[delay_] = 0.;
128 
129  // Calculation of the dt coefficients and update of the input delay line.
130  for ( n=0; n<inputFrames.size(); n++ ) {
131  x_t = inputLine_.tick( inputFrames[ n ] );
132  for ( delay_=1; delay_<= tMax_; delay_++ ) {
133  x_t_T = inputLine_.tapOut( delay_ );
134  coeff = x_t - x_t_T;
135  dt[delay_] += coeff * coeff;
136  }
137  }
138 
139  // Calculation of the pitch tracking function and test for the minima.
140  for ( delay_=1; delay_<=tMax_; delay_++ ) {
141  cumDt[delay_] = dt[delay_] + cumDt[delay_-1];
142  dpt[delay_] = dt[delay_] * delay_ / cumDt[delay_];
143 
144  // Look for a minimum
145  if ( dpt[delay_-1]-dpt[delay_-2] < 0 && dpt[delay_]-dpt[delay_-1] > 0 ) {
146  // Check if the minimum is under the threshold
147  if ( dpt[delay_-1] < threshold_ ){
148  lastPeriod_ = delay_-1;
149  // If a minimum is found, we can stop the loop
150  break;
151  }
152  else if ( dpt[alternativePitch] > dpt[delay_-1] )
153  // Otherwise we store it if it is the current global minimum
154  alternativePitch = delay_-1;
155  }
156  }
157 
158  // Test for the last period length.
159  if ( dpt[delay_]-dpt[delay_-1] < 0 ) {
160  if ( dpt[delay_] < threshold_ )
161  lastPeriod_ = delay_;
162  else if ( dpt[alternativePitch] > dpt[delay_] )
163  alternativePitch = delay_;
164  }
165 
166  if ( lastPeriod_ == tMax_+1 )
167  // No period has been under the threshold so we used the global minimum
168  lastPeriod_ = alternativePitch;
169 
170  // We put the new zero output coefficients in the output delay line and
171  // we get the previous calculated coefficients
172  outputLine_.tick( zeroFrame, outputFrames );
173 
174  // Initialization of the Hamming window used in the algorithm
175  for ( int n=-(int)lastPeriod_; n<(int)lastPeriod_; n++ )
176  window[n+lastPeriod_] = (1 + cos(PI*n/lastPeriod_)) / 2 ;
177 
178  long M; // Index of reading in the input delay line
179  long N; // Index of writing in the output delay line
180  double sample; // Temporary storage for the new coefficient
181 
182  // We loop for all the frames of length lastPeriod_ presents between inputPtr and tMax_
183  for ( ; inputPtr<(int)(tMax_-lastPeriod_); inputPtr+=lastPeriod_ ) {
184  // Test for the decision of compression/expansion
185  while ( outputPtr < inputPtr ) {
186  // Coefficients for the linear interpolation
187  env[1] = fmod( outputPtr + tMax_, 1.0 );
188  env[0] = 1.0 - env[1];
189  M = tMax_ - inputPtr + lastPeriod_ - 1; // New reading pointer
190  N = 2*tMax_ - (unsigned long)floor(outputPtr + tMax_) + lastPeriod_ - 1; // New writing pointer
191  for ( unsigned int j=0; j<2*lastPeriod_; j++,M--,N-- ) {
192  sample = inputLine_.tapOut(M) * window[j] / 2.;
193  // Linear interpolation
194  outputLine_.addTo(env[0] * sample, N);
195  outputLine_.addTo(env[1] * sample, N-1);
196  }
197  outputPtr = outputPtr + lastPeriod_ * periodRatio_; // new output pointer
198  }
199  }
200  // Shifting of the pointers waiting for the new frame of length tMax_.
201  outputPtr -= tMax_;
202  inputPtr -= tMax_;
203 }
204 
205 
206 inline StkFloat LentPitShift :: tick( StkFloat input )
207 {
208  StkFloat sample;
209 
210  inputFrames[ptrFrames] = input;
211 
212  sample = outputFrames[ptrFrames++];
213 
214  // Check for end condition
215  if ( ptrFrames == (int) inputFrames.size() ){
216  ptrFrames = 0;
217  process( );
218  }
219 
220  return sample;
221 }
222 
223 inline StkFrames& LentPitShift :: tick( StkFrames& frames, unsigned int channel )
224 {
225 #if defined(_STK_DEBUG_)
226  if ( channel >= frames.channels() ) {
227  oStream_ << "LentPitShift::tick(): channel and StkFrames arguments are incompatible!";
228  handleError( StkError::FUNCTION_ARGUMENT );
229  }
230 #endif
231 
232  StkFloat *samples = &frames[channel];
233  unsigned int hop = frames.channels();
234  for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
235  *samples = tick( *samples );
236  }
237 
238  return frames;
239 }
240 
241 inline StkFrames& LentPitShift :: tick( StkFrames& iFrames, StkFrames& oFrames, unsigned int iChannel, unsigned int oChannel )
242 {
243 #if defined(_STK_DEBUG_)
244  if ( iChannel >= iFrames.channels() || oChannel >= oFrames.channels() ) {
245  oStream_ << "LentPitShift::tick(): channel and StkFrames arguments are incompatible!";
246  handleError( StkError::FUNCTION_ARGUMENT );
247  }
248 #endif
249 
250  StkFloat *iSamples = &iFrames[iChannel];
251  StkFloat *oSamples = &oFrames[oChannel];
252  unsigned int iHop = iFrames.channels(), oHop = oFrames.channels();
253  for ( unsigned int i=0; i<iFrames.frames(); i++, iSamples += iHop, oSamples += oHop ) {
254  *oSamples = tick( *iSamples );
255  }
256 
257  return iFrames;
258 }
259 
260 } // stk namespace
261 
262 #endif
263 

The Synthesis ToolKit in C++ (STK)
©1995--2014 Perry R. Cook and Gary P. Scavone. All Rights Reserved.