90° Phase Shift

How would I apply a 90° phase shift to a buffer of floating point audio samples?

It’s not something silly like a delay, or inversion, is it? Would it be time-consuming?


EDIT: this is why: http://en.wikipedia.org/wiki/Dolby_Pro_Logic#Dolby_encoding_matrices

1 Like

You want a perfect 90 degree shift for all frequencies? I don’t know of any such technique other than using a Fourier transform (but admittedly my knowledge is limited).

If you’re ok with frequency-dependent phase shifts you can muck around with an all-pass filter.

Bruce, I haven’t tried this yet, but besides FFT you should look at the Hilbert transform. The ICST DSP library has an implementation (based on allpass filters as it happens).

Delay is only OK for phase shifting a single frequency waveform. Generic audio is composed of waves at many frequencies and any arbitrary delay would result in different phase shifts according to frequency.

OK, thanks. Those thoughts sent me the right direction on some web searching. What I found is:

Often the 90 degree shifts possibly needed will be in the material,
There’s a only a few cases where the shifts come into play,
a trivial mix-down will yield acceptable results,

Any actual implementation will require a fair amount of CPU and then delay of all other channels.

So I’m leaving it alone. If I was making a sound tool, not a video tool…


My recommendation is to look up Hilbert networks, and phase differencing networks.

An efficient Hilbert network can be created by using 2 parallel chains of allpass filters, where the phase difference between the 2 parallel chains is 90 degrees, plus or minus a small amount of phase error, over a given frequency range. I put some code into Csound in 1999 to do this (look up the hilbert ugen), but there were some errors in it. I think I got sine and cosine mixed up. :oops: Anyway, the code is fixed now, and you are welcome to use it if you like.

A more efficient version of the code would be to use the biquad filters of your choice (built into Juce, IPP, whatever), and translate the 1st order allpass coefficients into 2nd order allpasses. Somewhere in the Supercollider mailing list archives I described how to do this, around 2002 or 2003.

Another alternative is to use the half-band elliptic filter code that is floating around out there, as this is generated with 2 parallel allpass chains that have a 90 degree phase relationship. MATLAB can generate the coefficients for these filters, which usually are based around z^-2 (2-sample unit delays) as opposed to the single sample unit delays found in most digital filters.

All of these allpass based Hilbert networks will create phase lag. In order to equalize the lag between channels, you will want to use the “cosine” allpass cascade for all channels that are supposed to be at 0 degrees. So, for all the channels in the Pro Logic matrices that have the “j” in their gains, you would use the “imaginary” or sine allpass cascade, while all other channels used the “real” or cosine allpass cascade.

The allpass based Hilbert networks can be VERY efficient - far more so than FFT or FIR based Hilbert networks. A standard phase differencing network that covers the audio range of 20 Hz to 20 KHz can be made with two parallel 6th order allpass cascades, or with 6 biquads total. For the Pro Logic implementations, each channel would use 6 1st order allpasses, or 3 biquads (or 2nd order allpasses if you want to save a few multiplies).

Wow, a question that I can actually answer on this forum! It’s kinda refreshing. Anyway, back to figuring out why my GUI just disappeared on my Windows VST.

Sean Costello


Sorry to hijack a thread purely for my ignorance.

What does phase-shifting audio 90 degrees sound like?

It’s the sound of one hand clapping :wink:

Actually - just the same as before the shift, ideally. It’s in reference or conjunction with other non-shifted signals that it makes sense, in my case coming from other speakers.


I’m guessing that rotating the speakers is not a possible solution…


The first derivative in time is shifted 90° in all frequencies.

Use a 1 pole allpass IIR for a phase shift of 90° at given frequency. What I don’t understand about this dolby table is that there’s no indication of the frequency the phase shift occurs at.

For the Dolby Pro Logic stuff it’s 90° at ALL frequencies not around a specific frequency (as with a simple allpass).


On encode, the centre channel (C) is mixed into both L+R (reduced by -3dB) and the surround (S) is 90° phase-shifted then fed into L and R in opposite polarities (also down by -3dB).

On decode the L and R channels feed the main speakers while the difference between L and R feeds the surround speakers (there could even be a centre speaker mixing L and R since the entire S signal would be cancelled out). Of course the derived S signals is not the originally encoded signal but I guess the idea is that it’s close enough to give the impression of spatiality.

[code]You want a perfect 90 degree shift for all frequencies? I don’t know of any such technique other than using a Fourier transform (but admittedly my knowledge is limited).

If you’re ok with frequency-dependent phase shifts you can muck around with an all-pass filter.[/code]
Has a 90 degree shift not always frequency-dependent phase shifts (because 90 degrees is a different wavelength for all frequencies), or do you mean delay?


I think Vinn was talking about phase shifts that are not always 90° at all frequencies?

You could create a +90° phase shifter impulse response and apply it to your signal with convolution. (It's a long time I did not use Juce maybe convolution has been added)

Here is how I would do the filter that shifts of +90° the signal in Matlab / Scilab.

% ------------------------------
% create a +90° shift FIR filter
% ------------------------------

fs = 44100;
n = 10;
xx = zeros(2^n + 1, 1);
% put a delta in the middle of the signal
xx(ceil(length(xx)/2)) = 1;
% hilber transform
analytic_signal = hilbert(xx);
% get the IR of the +90° phase response (imag component oh analytic signal)
% and window to reduce leakage
ww = window(@tukeywin, length(analytic_signal), .25);
phase_shift_IR = imag(analytic_signal).*ww;
% write IR to file
wavwrite(phase_shift_IR, fs, 32, '90_degree_phase_shift.wav');

A wavfile containig the filter is stored as "90_degree_phase_shift.wav".

Remember to apply a delay of

delay = ceil(length(xx)/2);

samples to the non filtered signal to compensate for the delay added by the 90° phase shift FIR filter.

The amplitude response is not perfectly flat due to the non infinite response but it should sound good anyway.

Good luck!