1
$\begingroup$

I'm coding a phase vocoder in C for time-stretching audio signals. The only piece that is currently not working is the phase propagation.

  1. I take overlapping frames from an input signal, apply a window function, and perform FFT.
  2. Then i calculate the phase propagation (the one I'm stuck with)
  3. Finally I perform iFFT and overlap-add the output frames with a different hop size.

If I skip step 2, the phase propagation, the output sound is correctly time-stretched but I can hear a phaser effect. My assumption is that the missing piece will correct this. However when I apply my current implementation the sound is terribly distorted.

I appreciate if anyone can give some good pointers on how the phase correction can be implemented.

It might be too much to ask, but this is my current implementation should you see something weird.

// _prevPhaseX[] = FFT phases from previous frame (n-1) (propagation input)
// _prevPhaseY[] = FFT phases from previous frame (n-1) (propagation output)
// _phase[] has the FFT phase information from current frame
static int first = 1;
if (first)
{
    first = 0;
    for (int k=0; k<half; k++)          // half = window length/2 = number of bins
    {
        _prevPhaseX[k] = _phase[k];
        _prevPhaseY[k] = _phase[k];
    }
}
else
{
    // int length = window length - e.g. 1024 
    // float Ra = analysis hop size - e.g. 256
    // float Rs = synthesis hop size - e.g. 512
    // float PI = PI
    // float DPI = 2*PI
    for (int k=1; k<half; k++)
    {
        // compute Delta Phi(k)
        float phase = _phase[k];
        float omega = DPI*(float)k/(float)length;  // length vs length/2?
        float phasediff = phase - _prevPhaseX[k] - Ra*omega;
        _prevPhaseX[k] = phase;   // Save value for next frame

        // get principal argument
        while (phasediff>PI) phasediff -=DPI;
        while (phasediff<-PI) phasediff +=DPI;

        float freq = omega + (phasediff)/Ra;
        _phase[k] = _prevPhaseY[k] + Rs*freq;
        _prevPhaseY[k] = _phase[k];   // Save value for next frame
    }
} 
// the _phase[] vector (and magnitude[]) goes to IFFT (after conv. to rectangluar)

Thanks!

$\endgroup$
4
+50
$\begingroup$

you don't wanna do this on a bin-by-bin basis. here's a paper by Miller Puckette that is seminal regarding this issue. what you want to do is identify specific frequency components (perhaps each lobe in the spectrum would be a specific frequency component) and multiply that entire $n$th lobe by $e^{j \phi_n}$ where $\phi_n = \omega_n \ T_n$ and $\omega_n$ is the frequency of the $n$th component and $T_n$ is the time adjustment to that component to match its phase to the corresponding component in the previous frame.

each bin gets multiplied by $e^{j \phi_n}$, but for most bins that factor is the same as for an adjacent bin.

$\endgroup$
  • $\begingroup$ in your code, the problem is that $\tt{freq}$ is a function of $\tt{k}$ because $\tt{phasediff}$ is recomputed for every $\tt{k}$. $\tt{phasediff}$ and $\tt{freq}$ should be computed only for specific frequency components. and the same value used for all $\tt{k}$ within that component. $\endgroup$ – robert bristow-johnson Mar 9 '14 at 2:16
  • $\begingroup$ Thanks for your kind reply. I'm going to study that paper and come back to let you know if it helped. $\endgroup$ – Merlevede Mar 9 '14 at 22:14
  • $\begingroup$ The paper you describe seems to be an enhancement for the classical phase vocoder algorithm (this classic algorithm is the one I'm trying to implement and the formulas I used are agreed upon in many papers I've read, so I'd like to have this working before moving on with enhancements such as phase-locking). $\endgroup$ – Merlevede Mar 10 '14 at 7:19
  • 1
    $\begingroup$ @merle, the "classic" algorithm is fundamentally flawed because the whole purpose of the phase adjustments on the frequency domain is to align frequency-components which are derived from the bins of the DFT. if a single component is dispersed or diffused because the various bins that comprise that component are shifted by different amounts, that contradicts the very purpose of this phase adjustment. that is what this Miller Puckette paper is all about. it changed the definition of the basic phase vocoder. Puckette is correct and Portnoff or Flanagan are incorrect. $\endgroup$ – robert bristow-johnson Mar 10 '14 at 17:12
  • $\begingroup$ if you look up phase vocoder in Wikipedia, it appears that they credit Jean Laroche with this phase coherence discovery, but Laroche credits Puckette (i was there at IEEE Mohonk when Jean first presented this). i'm gonna try to correct that credit problem in Wikipedia. i have also published a paper in this area, if you want i can send you a copy of it or some old MATLAB code that implements this basic phase-locked vocoder. $\endgroup$ – robert bristow-johnson Mar 10 '14 at 17:17
1
$\begingroup$

I think one problem with your code is that $\tt{\_phase[k]}$ is the phase of the current input frame, whereas $\tt{\_prevPhase[k]}$ refers to the previous output frame. However, I think you should compute the phase difference by comparing the current and the previous input frames, and not the current input and the previous output frame. So you need two variables for past phases, one for the input phase and one for the output phase.

One more thing: you should increase your FFT size. For $R_s=512$ you should probably have an FFT size of at least $2048$.

It would also be helpful if you posted links to a short segment of an input signal, and the two corresponding output signals, one with and one without phase modification. Then it might be easier to judge what the problem is.

$\endgroup$
  • $\begingroup$ Thanks for your reply. I'm confused (I'm assuming that by input you mean before this calculation and output means after). Isn't the input phase of the previous frame useless? After all that's why we're correcting it. $\endgroup$ – Merlevede Mar 8 '14 at 17:51
  • $\begingroup$ I guess that for determining the instantaneous frequency you need the phase difference between two input frames. The method I'm talking about is this one: hci.rwth-aachen.de/materials/publications/karrer2006a.pdf Have a look at equation (1). $\endgroup$ – Matt L. Mar 8 '14 at 21:40
  • $\begingroup$ Hmmm, I see your point, and it makes sense. I'm going to experiment with this to see if this works. $\endgroup$ – Merlevede Mar 8 '14 at 21:46
  • $\begingroup$ I changed the code with your suggestion (I updated code in my question) and the sound improved, less distortion (but still distorted). The quality is still better without the phase correction, and in both cases (with/without) I can hear the phaser effect. $\endgroup$ – Merlevede Mar 8 '14 at 22:03
  • $\begingroup$ Now that you've changed the code, it seems to me that the remaining problem is not in that part of the code. As long as you reconstruct with _phase, and as long as _phase is overwritten with the phase of the next frame, everything should be fine. Maybe something is going wrong in the reconstruction stage? In general, it is very helpful to implement such an algorithm first in Matlab/Octave (or something similar). Then you always have a reference for a later implementation in C. $\endgroup$ – Matt L. Mar 11 '14 at 8:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.