How do stereo panning knobs work?

So far the panning algorithm I’ve used is this (dealing with mono sources):

Gain L = cos(θ), Gain R = sin(θ)

With θ ranging from 0° (hard left) to 90° (hard right).

How would one extend this to work with stereo sources, and how is it handled in DAW mixers for example? I see there must be coefficients for L->L, R->R, L->R and R->L but I’m not sure how to calculate them.

Any insight appreciated!


why can’t you just apply those formulas to the left and right channels of the stereo wave form (treat it as a pair of mono wave forms)?

Because if we just look at the left channel, panned centrally, the coefficients are L=1 and R=0. If it were a mono source the coefficients would be L=1 and R=1. No?

did you try it out though? perhaps 45deg = center?

a mono signal duplicated and panned hard left/hard right will appear centered.

Haven’t researched into it, but making something up just based on sense, how about: pan(leftChannel, min(hardLeft, hardLeft+degrees)) + pan(rightChannel, max(hardRight, hardRight+degrees))

If you treat a stereo source as two mono sources and apply the formula in my original post to them, it will have the same effect as summing the two channels together, then panning them as a single mono source, this is not how it should work.

@yairadix I don’t understand your suggestion, why would you need to use min and max?

I’ve just been doing some research and apparently some “pan” knobs are actually balance knobs, meaning they only adjust the L->L and R->R coefficients, L->R and R->L are always 0.

I’m now looking for formulas for both pan and balance so I can try them myself.

If you think of the input left channel as a mono channel already panned to hard-left, and same for right, and of the stereo panning as modifying this panning - you use min because you can’t pan further than hard-left.

There are several options to choose from:

a) simple panning (similar to what you posted):

float pan;  // [-1;+1]

leftOut  = leftIn  * min (1 - pan, 1.0);  // max gain = 1.0, pan = 0: left and right unchanged)
rightOut = rightIn * min (1 + pan, 1.0);

b) M/S panning:

mSignal = 0.5 * (left + right);
sSignal = left - right;

float pan; // [-1; +1]
left  = 0.5 * (1.0 + pan) * mSignal + sSignal;
right = 0.5 * (1.0 - pan) * mSignal - sSignal;

The beauty of the M/S approach is, that you can also adapt the stereo width of the input signal simply by attenuating the sSignal.

HTH, happy new year!


Most DAWs implement several different pan laws. Scroll down for the details, the top bit is background.

The algorithm you’re using is called constant power pan law. It’s the most common. Your issue is that you’re using incorrect angles. If you pan it at the center your angle is 45 degrees, so the gains are .707, or added together for a mono signal would give you a total gain of 1.414 or a gain of 3dB at center.


Thanks for the link, that was very insightful.

I understood the question, how to pan a stereo signal to a stereo output.
If you copy the mono input and feed it to a stereo -> stereo panner, you can’t really blame the panning algorithm, that the power is different…
If you copy a mono signal into a stereo bus, you should apply the factor .707 on both channels, if you want to keep the power constant. If you do so, there is no issue, or did I understand that wrong?

EDIT: actually having thought about it again, the M/S variant could indeed take profit from your thought:

mSignal = 0.5 * (left + right);
sSignal = left - right;

float pan; // [-1; +1]
left  = cos (0.25 * M_PI * (1.0 + pan) * mSignal + sSignal;  // mSignal is sent to both channels * cos (45º)
right = cos (0.25 * M_PI * (1.0 - pan) * mSignal - sSignal;
1 Like

Formulas + curves + explanations :

1 Like

has anyone ever really tested if the “equal power” panning method is actually valid for the majority of cases?

In my experience, it usually gave bad results. I always just go with a dj crossfader style approach, so that at centre pan, both L and R are 100%.

For stereo to stereo panning, i also do a similar super simple approach. At mid pan, both L and R come through 100% (as you’d expect!), and then you just cut the left as you go from 0.5->0, and cut the right as you go from 0.5->1.

I really think too many people over-think this one, and actually end up with badly attenuated signals even, as a result.

1 Like

Hey @mashu
Is this what you mean ??
Assume level is a float between 0 and 1

         if (level < 0.5) { // cut right
         right = level;
         left = 0.5;  }
         if (level >= 0.5) { // cut left
         right = 0.5;
         left = 1 - level;