I wish to create a finite impulse response filter to decode a dolby digital matrix encoded 2 channel signal into 5 channels. These filters would then be used in a realtime pipeline on a Linux machine using jack and jconvolver to do the convolution.

The equation is as follows:


The reference for the above equation is: http://en.wikipedia.org/wiki/Matrix_decoder

It would seem this should be able to be done but I haven't the faintest how. Any help, and in particular working code that could generate the filters (Octave or other open source preferred) would be much appreciated!


Suppose that we had two channels encoded in some form in two signals according to a matrix. Recovering the original signals would be straightforward using the matrix inverse (or impossible, if the inverse did not exist). The situation is no different here, except that the matrix is not square, so you cannot use the conventional matrix inverse. You can, however, use a pseudoinverse or generalized inverse to reconstruct the original signals.

Other matrices which are not equal to an inverse may work also succeed, and may in fact sound better. I don't know the psychoacoustic situation, but it may more sense to do some transform based on the position of speakers for example. Certainly, the inverse seems like a good place to start.

I rewrote your encoder table as a 2x5 input matrix $ E $, and used Wolfram Alpha to determine the inverse, $ D = E^{-1} $. Here is the 5x2 result it provided, using $ i $ as the imaginary unit, with $ j = i $ and $ k = -i $.

$$ D = \frac{1}{18(46+6\sqrt{2})} \begin{bmatrix} 405 & -3(27 - 36\sqrt{2}) \\ -3(27 - 36\sqrt{2}) & 405 \\ 6(18+27\sqrt{2}) & 6(18+27\sqrt{2}) \\ -i(27\sqrt{3} + 99\sqrt{6}) & i(63\sqrt{3} + 27\sqrt{6}) \\ -i(63\sqrt{3} + 27\sqrt{6}) & i(27\sqrt{3} + 99\sqrt{6}) \end{bmatrix} $$

As one would expect, the decoding matrix shows left/right symmetry.

Now we can express the encoding/decoding operations as: $$ \begin{bmatrix} L_{encoded} \\ R_{encoded} \end{bmatrix} = E \space{} \begin{bmatrix} L \\ R \\ C \\ L_{rear} \\ R_{rear} \\ \end{bmatrix} $$ $$ \begin{bmatrix} L' \\ R' \\ C' \\ L_{rear}' \\ R_{rear}' \\ \end{bmatrix} = D \space{} \begin{bmatrix} L_{encoded} \\ R_{encoded} \end{bmatrix} $$

Now you can easily obtain formulas to express the three front components as functions of the encoded left and right signals. For the two rear components, you have an equation in the time domain with a complex component.

Looking at the left rear component, and converting constants from the matrix $ D $ to numeric form: $$ L_{rear}'[n] = -i0.2949 L_{encoded}[n] + i0.1787 R_{encoded}[n] $$

The Hilbert transform can be used to remove the imaginary unit, because this has the same effect on the frequency domain of performing a ±90º phase shift. The Hilbert transform only needs to be applied once, since convolution ($ * $) is distributive and commutative and all other good things. $$ L_{rear}'[n] = (-0.2949 L_{encoded}[n] + 0.1787 R_{encoded}[n]) * H[n] $$

The operating principle, then, is that the encoding technique functions in part by encoding the left/right rear components in quadrature.

The Hilbert transform is infinitely long, so it must be truncated and expressed as either a FIR filter, or depending on your circumstances, a FFT-IFFT operation. A causal Hilbert transform will delay the rear channels, so your other filters will need to be delayed by some amount to compensate.

For example, if $ k $ is the group delay of a causal approximation of a Hilbert filter $ H_k[n] $ then you delay must delay the three front channels by $ k $ as well: $$ C'[n] = (0.3437L_{encoded}[n] + 0.3437R_{encoded}[n]) * \delta[n-k] $$

In practice, all of the output signals depend on the two input signals. That is, you take two input channels and produce one output channel five times. Your JACK pipeline will need to accommodate this.

  • $\begingroup$ Thank you very much for the thorough answer, its much appreciated! So if I understand correctly, to get the Rear Left channel I would 1) convolve the Left channel with a dirac pulse of gain -0.2949, the Right channel with a dirac pulse of gain 0.1787, and 2) convolve the combined output from (1) with a hilbert transform impulse response while ensuring the hilbert and dirac pulses have the same delay? Sorry if this is a very basic question and thanks in advance! $\endgroup$
    – psandersen
    Oct 31 '12 at 19:59
  • $\begingroup$ You're welcome. I hope my clarification explains it. The issue is that the Hilbert delays the rear channels, so you must insert an equivalent for the front channels to resynchronize the channels. There's no need to introduce a Dirac pulse in the rear channels – they are just a weighted sum of the left/right channels convolved with Hilbert. $\endgroup$
    – jbarlow
    Nov 2 '12 at 22:42

Jbarlow's answer is excellently derived but misses a major issue: Almost all of the "better" surround sound decoders such as Dolby Prologic, DTS Neo 6, Lexicon, Bose Videostage are "dynmaic", i.e. they looks constantly at the signal conditions and adjust the decoding matrix in the fly based on an estimate what the original signals may have been.

The main problem here is that the encoder is "lossy", i.e. a lot of information is lost during the encoding process and you can't fully recover the original signal. A simple example: let's say you start a "left" signal. That encodes to Lt = 1 and Rt = 0. Decoding this again then leads to signal in all five channels and not just in the left like the original condition. The only way around this is to dynamically look at correlation and panning of the input signals and adjust the decoder matrix on the fly.

Finally, while jbarlow's equations are mathematically correct, it's typically not done this way, even if it's only a static decoder. The main issue is that this creates side to side cross talk, i.e. signals that where original in the left front can end up partially in the right front which highly undesirable from a perceptual point of view. What's typically used is roughly something like this (properly normalized that is)

L= Lt, R = Rt;
C = .707*Lt + .707Rt;
Ls = .6*Lt - .3*Rt;
Rs = .6*Rt - 0.3 *Lt;

In practice most people also don't bother with the Hilbert Transformer since most encoders that do a real time downmix (such as Blu ray players, set top boxes, or TVs) don't implement it in anyway.


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.