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
7namespace 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 ( delay_ > 1 && 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
stk::Delay
STK non-interpolating delay line class.
Definition Delay.h:25
stk::Delay::tapOut
StkFloat tapOut(unsigned long tapDelay)
Return the value at tapDelay samples from the delay-line input.
stk::Delay::addTo
StkFloat addTo(StkFloat value, unsigned long tapDelay)
Sum the provided value into the delay line at tapDelay samples from the input.
stk::Delay::tick
StkFloat tick(StkFloat input)
Input one sample to the filter and return one output.
Definition Delay.h:124
stk::Effect
STK abstract effects parent class.
Definition Effect.h:22
stk::LentPitShift
Pitch shifter effect class based on the Lent algorithm.
Definition LentPitShift.h:21
stk::LentPitShift::LentPitShift
LentPitShift(StkFloat periodRatio=1.0, int tMax=RT_BUFFER_SIZE)
Class constructor.
stk::LentPitShift::tick
StkFloat tick(StkFloat input)
Input one sample to the filter and return one output.
Definition LentPitShift.h:206
stk::LentPitShift::clear
void clear(void)
Reset and clear all internal state.
stk::LentPitShift::process
void process()
Apply the effect on the input samples and store it.
Definition LentPitShift.h:109
stk::LentPitShift::setShift
void setShift(StkFloat shift)
Set the pitch shift factor (1.0 produces no shift).
stk::StkFrames
An STK class to handle vectorized audio data.
Definition Stk.h:279
stk::StkFrames::channels
unsigned int channels(void) const
Return the number of channels represented by the data.
Definition Stk.h:416
stk::StkFrames::frames
unsigned int frames(void) const
Return the number of sample frames represented by the data.
Definition Stk.h:419
stk::StkFrames::size
size_t size() const
Returns the total number of audio samples represented by the object.
Definition Stk.h:374
stk
The STK namespace.
Definition ADSR.h:6

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