The Synthesis ToolKit in C++ (STK)

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
109 inline void LentPitShift::process()
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--2017 Perry R. Cook and Gary P. Scavone. All Rights Reserved.