@@ -207,11 +207,7 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) {
207207
208208 // For frames other than the first frame, we'll need to perform phase computation.
209209 else {
210- bool phaseLock = false ;
211- if (IN0 (4 ) != 0 .f ) {
212- phaseLock = true ;
213- // std::cout << "Phase lock\n";
214- }
210+ size_t phaseLock = sc_clip (static_cast <size_t >(IN0 (4 )), 0 , 2 );
215211 SCPolarBuf *p = ToPolarApx (buf);
216212 size_t roundedPos = static_cast <size_t >(std::round (newPos));
217213 // std::cout << "New pos: " << intPos << "\n";
@@ -223,15 +219,27 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) {
223219 fillPolarBuf (stftData + (roundedPos * stftBufFftSize), unit->m_frameNext , stftBufFftSize);
224220 fillPolarBuf (stftData + (lastPos * stftBufFftSize), unit->m_framePrev1 , stftBufFftSize);
225221 // Render the output FFT frame
226- Stretch2 (
227- unit->m_frameNext ,
228- unit->m_framePrev1 ,
229- p,
230- unit->m_outFramePrev ,
231- stftBufFftSize,
232- stftBufHopSize,
233- phaseLock
234- );
222+ switch (phaseLock) {
223+ case 1 :
224+ Stretch2Puckette (
225+ unit->m_frameNext ,
226+ unit->m_framePrev1 ,
227+ p,
228+ unit->m_outFramePrev ,
229+ stftBufFftSize,
230+ stftBufHopSize
231+ );
232+ break ;
233+ default :
234+ Stretch2 (
235+ unit->m_frameNext ,
236+ unit->m_framePrev1 ,
237+ p,
238+ unit->m_outFramePrev ,
239+ stftBufFftSize,
240+ stftBufHopSize
241+ );
242+ }
235243 } else {
236244 // Otherwise we're between two FFT frames, and we're going to have to
237245 // interpolate magnitude and frequency data.
@@ -243,17 +251,31 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) {
243251 // This is the frame right before that. It's needed to compute the previous instantaneous frequencies.
244252 fillPolarBuf (stftData + ((lo-1 ) * stftBufFftSize), unit->m_framePrev2 , stftBufFftSize);
245253 // Render the output FFT frame
246- Stretch3 (
247- unit->m_frameNext ,
248- unit->m_framePrev1 ,
249- unit->m_framePrev2 ,
250- p,
251- unit->m_outFramePrev ,
252- newPos-static_cast <float >(lo),
253- stftBufFftSize,
254- stftBufHopSize,
255- phaseLock
256- );
254+ switch (phaseLock) {
255+ case 1 :
256+ Stretch3Puckette (
257+ unit->m_frameNext ,
258+ unit->m_framePrev1 ,
259+ unit->m_framePrev2 ,
260+ p,
261+ unit->m_outFramePrev ,
262+ newPos-static_cast <float >(lo),
263+ stftBufFftSize,
264+ stftBufHopSize
265+ );
266+ break ;
267+ default :
268+ Stretch3 (
269+ unit->m_frameNext ,
270+ unit->m_framePrev1 ,
271+ unit->m_framePrev2 ,
272+ p,
273+ unit->m_outFramePrev ,
274+ newPos-static_cast <float >(lo),
275+ stftBufFftSize,
276+ stftBufHopSize
277+ );
278+ }
257279 }
258280 // We always need to store the resultant FFT frame in the UGen.
259281 // It is used in the next call to PV_PlayBufStretch_next, for
@@ -276,59 +298,78 @@ void PV_PlayBufStretch_next(PV_PlayBufStretch *unit, int inNumSamples) {
276298// / \param outFramePrev The previously computed output STFT frame
277299// / \param fftSize The FFT size
278300// / \param hopSize The hop size
279- // / \param phaseLock Whether or not to apply phase locking
280301void Stretch2 (
281302 const SCPolarBuf *frame,
282303 const SCPolarBuf *framePrev,
283304 SCPolarBuf *outFrame,
284305 const SCPolarBuf *outFramePrev,
285306 size_t fftSize,
286- size_t hopSize,
287- bool phaseLock) {
307+ size_t hopSize) {
288308 outFrame->dc = frame->dc ;
289309 outFrame->nyq = frame->nyq ;
290310 for (size_t xxk = 0 ; xxk < fftSize/2 -1 ; xxk++) {
291311 outFrame->bin [xxk].mag = frame->bin [xxk].mag ;
292312
293- // Puckette-style phase locking
294- if (phaseLock) {
295- // Compute the instantaneous frequency
296- float omegaK = twopi * (xxk+1 ) / fftSize;
297- float phaseInc = frame->bin [xxk].phase - framePrev->bin [xxk].phase - hopSize * omegaK;
298- phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
299- float instantaneousFreq = omegaK + phaseInc/hopSize;
300-
301- // In Puckette-style phase locking, we make a substitution for the previous phase,
302- // in order to "lock" phases of adjacent bins together.
303- float prevPhase = 0.0 ;
304- if (xxk == 0 ) {
305- std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->dc , 0 .f );
306- std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
307- std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
308- prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
309- } else if (xxk == fftSize/2 -2 ) {
310- std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
311- std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
312- std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->nyq , 0 .f );
313- prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
314- } else {
315- std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
316- std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
317- std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
318- prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
319- }
320-
321- // Compute the new phase
322- outFrame->bin [xxk].phase = prevPhase + hopSize * instantaneousFreq;
313+ // Compute the instantaneous frequency
314+ float omegaK = twopi * (xxk+1 ) / fftSize;
315+ float phaseInc = frame->bin [xxk].phase - framePrev->bin [xxk].phase - hopSize * omegaK;
316+ phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
317+ float instantaneousFreq = omegaK + phaseInc/hopSize;
318+
319+ // Compute the new phase
320+ outFrame->bin [xxk].phase = outFramePrev->bin [xxk].phase + hopSize * instantaneousFreq;
321+ }
322+ }
323+
324+ // / Computes a single frame of STFT data for time stretching.
325+ // / The assumption is that we are positioned exactly at `frame`, and we therefore
326+ // / just need framePrev to compute the instantaneous frequency. We also do not
327+ // / need to perform any magnitude or frequency interpolation.
328+ // /
329+ // / This version uses Miller Puckette's phase locking.
330+ // /
331+ // / \param frame The current STFT frame
332+ // / \param framePrev The previous STFT frame
333+ // / \param [out] outFrame The output STFT frame
334+ // / \param outFramePrev The previously computed output STFT frame
335+ // / \param fftSize The FFT size
336+ // / \param hopSize The hop size
337+ void Stretch2Puckette (
338+ const SCPolarBuf *frame,
339+ const SCPolarBuf *framePrev,
340+ SCPolarBuf *outFrame,
341+ const SCPolarBuf *outFramePrev,
342+ size_t fftSize,
343+ size_t hopSize) {
344+ outFrame->dc = frame->dc ;
345+ outFrame->nyq = frame->nyq ;
346+ for (size_t xxk = 0 ; xxk < fftSize/2 -1 ; xxk++) {
347+ outFrame->bin [xxk].mag = frame->bin [xxk].mag ;
348+
349+ // Compute the instantaneous frequency
350+ float omegaK = twopi * (xxk+1 ) / fftSize;
351+ float phaseInc = frame->bin [xxk].phase - framePrev->bin [xxk].phase - hopSize * omegaK;
352+ phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
353+ float instantaneousFreq = omegaK + phaseInc/hopSize;
354+
355+ // In Puckette-style phase locking, we make a substitution for the previous phase,
356+ // in order to "lock" phases of adjacent bins together.
357+ float prevPhase = 0.0 ;
358+ if (xxk == 0 ) {
359+ std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->dc , 0 .f );
360+ std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
361+ std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
362+ prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
363+ } else if (xxk == fftSize/2 -2 ) {
364+ std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
365+ std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
366+ std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->nyq , 0 .f );
367+ prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
323368 } else {
324- // Compute the instantaneous frequency
325- float omegaK = twopi * (xxk+1 ) / fftSize;
326- float phaseInc = frame->bin [xxk].phase - framePrev->bin [xxk].phase - hopSize * omegaK;
327- phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
328- float instantaneousFreq = omegaK + phaseInc/hopSize;
329-
330- // Compute the new phase
331- outFrame->bin [xxk].phase = outFramePrev->bin [xxk].phase + hopSize * instantaneousFreq;
369+ std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
370+ std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
371+ std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
372+ prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
332373 }
333374 }
334375}
@@ -346,7 +387,6 @@ void Stretch2(
346387// / \param pos The position between framePrev1 and frameNext (0 < pos < 1)
347388// / \param fftSize The FFT size
348389// / \param hopSize The hop size
349- // / \param phaseLock Whether or not to apply phase locking
350390void Stretch3 (
351391 const SCPolarBuf *frameNext,
352392 const SCPolarBuf *framePrev1,
@@ -355,71 +395,98 @@ void Stretch3(
355395 const SCPolarBuf *outFramePrev,
356396 float pos,
357397 size_t fftSize,
358- size_t hopSize,
359- bool phaseLock) {
398+ size_t hopSize) {
360399 outFrame->dc = INTERP (framePrev1->dc , frameNext->dc , pos);
361400 outFrame->nyq = INTERP (framePrev1->nyq , frameNext->nyq , pos);
362401 for (size_t xxk = 0 ; xxk < fftSize/2 -1 ; xxk++) {
363402 outFrame->bin [xxk].mag = INTERP (framePrev1->bin [xxk].mag , frameNext->bin [xxk].mag , pos);
364403
365- // Puckette-style phase locking
366- if (phaseLock) {
367- float omegaK = twopi * (xxk+1 ) / fftSize;
368-
369- // Compute the next instantaneous frequency
370- float phaseInc = frameNext->bin [xxk].phase - framePrev1->bin [xxk].phase - hopSize * omegaK;
371- phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
372- float instantaneousFreqNext = omegaK + phaseInc/hopSize;
373-
374- // Compute the previous instantaneous frequency
375- phaseInc = framePrev1->bin [xxk].phase - framePrev2->bin [xxk].phase - hopSize * omegaK;
376- phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
377- float instantaneousFreqPrev = omegaK + phaseInc/hopSize;
378-
379- // Interpolate the instantaneous frequency
380- float instantaneousFreq = INTERP (instantaneousFreqPrev, instantaneousFreqNext, pos);
381-
382- // In Puckette-style phase locking, we make a substitution for the previous phase,
383- // in order to "lock" phases of adjacent bins together.
384- float prevPhase = 0.0 ;
385- if (xxk == 0 ) {
386- std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->dc , 0 .f );
387- std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
388- std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
389- prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
390- } else if (xxk == fftSize/2 -2 ) {
391- std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
392- std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
393- std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->nyq , 0 .f );
394- prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
395- } else {
396- std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
397- std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
398- std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
399- prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
400- }
401-
402- // Compute the new phase
403- outFrame->bin [xxk].phase = prevPhase + hopSize * instantaneousFreq;
404+ float omegaK = twopi * (xxk+1 ) / fftSize;
405+
406+ // Compute the next instantaneous frequency
407+ float phaseInc = frameNext->bin [xxk].phase - framePrev1->bin [xxk].phase - hopSize * omegaK;
408+ phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
409+ float instantaneousFreqNext = omegaK + phaseInc/hopSize;
410+
411+ // Compute the previous instantaneous frequency
412+ phaseInc = framePrev1->bin [xxk].phase - framePrev2->bin [xxk].phase - hopSize * omegaK;
413+ phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
414+ float instantaneousFreqPrev = omegaK + phaseInc/hopSize;
415+
416+ // Interpolate the instantaneous frequency
417+ float instantaneousFreq = INTERP (instantaneousFreqPrev, instantaneousFreqNext, pos);
418+
419+ // Compute the new phase
420+ outFrame->bin [xxk].phase = outFramePrev->bin [xxk].phase + hopSize * instantaneousFreq;
421+ }
422+ }
423+
424+ // / Computes a single frame of STFT data for time stretching.
425+ // / The assumption is that we are positioned between framePrev1 and frameNext.
426+ // / This means we will need to interpolate frequency data. So we will need to
427+ // / compute two frequencies for each bin, and that means we need three STFT frames.
428+ // /
429+ // / This version uses Miller Puckette's phase locking.
430+ // /
431+ // / \param frameNext The next STFT frame
432+ // / \param framePrev1 The previous STFT frame
433+ // / \param framePrev2 The previous STFT frame before that (required for instantaneous frequency interpolation)
434+ // / \param [out] outFrame The output STFT frame
435+ // / \param outFramePrev The previously computed output STFT frame
436+ // / \param pos The position between framePrev1 and frameNext (0 < pos < 1)
437+ // / \param fftSize The FFT size
438+ // / \param hopSize The hop size
439+ void Stretch3Puckette (
440+ const SCPolarBuf *frameNext,
441+ const SCPolarBuf *framePrev1,
442+ const SCPolarBuf *framePrev2,
443+ SCPolarBuf *outFrame,
444+ const SCPolarBuf *outFramePrev,
445+ float pos,
446+ size_t fftSize,
447+ size_t hopSize) {
448+ outFrame->dc = INTERP (framePrev1->dc , frameNext->dc , pos);
449+ outFrame->nyq = INTERP (framePrev1->nyq , frameNext->nyq , pos);
450+ for (size_t xxk = 0 ; xxk < fftSize/2 -1 ; xxk++) {
451+ outFrame->bin [xxk].mag = INTERP (framePrev1->bin [xxk].mag , frameNext->bin [xxk].mag , pos);
452+
453+ float omegaK = twopi * (xxk+1 ) / fftSize;
454+
455+ // Compute the next instantaneous frequency
456+ float phaseInc = frameNext->bin [xxk].phase - framePrev1->bin [xxk].phase - hopSize * omegaK;
457+ phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
458+ float instantaneousFreqNext = omegaK + phaseInc/hopSize;
459+
460+ // Compute the previous instantaneous frequency
461+ phaseInc = framePrev1->bin [xxk].phase - framePrev2->bin [xxk].phase - hopSize * omegaK;
462+ phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
463+ float instantaneousFreqPrev = omegaK + phaseInc/hopSize;
464+
465+ // Interpolate the instantaneous frequency
466+ float instantaneousFreq = INTERP (instantaneousFreqPrev, instantaneousFreqNext, pos);
467+
468+ // In Puckette-style phase locking, we make a substitution for the previous phase,
469+ // in order to "lock" phases of adjacent bins together.
470+ float prevPhase = 0.0 ;
471+ if (xxk == 0 ) {
472+ std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->dc , 0 .f );
473+ std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
474+ std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
475+ prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
476+ } else if (xxk == fftSize/2 -2 ) {
477+ std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
478+ std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
479+ std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->nyq , 0 .f );
480+ prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
404481 } else {
405- float omegaK = twopi * (xxk+1 ) / fftSize;
406-
407- // Compute the next instantaneous frequency
408- float phaseInc = frameNext->bin [xxk].phase - framePrev1->bin [xxk].phase - hopSize * omegaK;
409- phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
410- float instantaneousFreqNext = omegaK + phaseInc/hopSize;
411-
412- // Compute the previous instantaneous frequency
413- phaseInc = framePrev1->bin [xxk].phase - framePrev2->bin [xxk].phase - hopSize * omegaK;
414- phaseInc = std::fmod (phaseInc + pi, twopi) - pi;
415- float instantaneousFreqPrev = omegaK + phaseInc/hopSize;
416-
417- // Interpolate the instantaneous frequency
418- float instantaneousFreq = INTERP (instantaneousFreqPrev, instantaneousFreqNext, pos);
419-
420- // Compute the new phase
421- outFrame->bin [xxk].phase = outFramePrev->bin [xxk].phase + hopSize * instantaneousFreq;
482+ std::complex <float > prevBinKMinus1 = std::polar<float >(outFramePrev->bin [xxk-1 ].mag , outFramePrev->bin [xxk-1 ].phase );
483+ std::complex <float > prevBinK = std::polar<float >(outFramePrev->bin [xxk].mag , outFramePrev->bin [xxk].phase );
484+ std::complex <float > prevBinKPlus1 = std::polar<float >(outFramePrev->bin [xxk+1 ].mag , outFramePrev->bin [xxk+1 ].phase );
485+ prevPhase = std::arg (prevBinK - prevBinKMinus1 - prevBinKPlus1);
422486 }
487+
488+ // Compute the new phase
489+ outFrame->bin [xxk].phase = prevPhase + hopSize * instantaneousFreq;
423490 }
424491}
425492
0 commit comments