Panning

Panning refers to moving the apparent spatial position of a sound. As each sample value is generated and written to the output buffer, we can pan the value to left or right by setting a different volume level for left and right channels. The simplest way to implement panning is to provide a different level setting for left and right volume. However, if we want to alter the overall volume level of a mixer input, we have to change both values and keep their ratio the same. Usually we would prefer to set panning independently of the volume level so that we can move the spatial location of the sound by varying only one parameter.

Suppose we let the pan value range from 0 to +1. A value of 0 indicates a value all in the left. A value of +1 represents a value all in the right. We could then calculate the left and right values as follows.

left = value * (1 - pan);
right = value * pan;

The resulting outputs for different settings are shown in the following table.

Pan Value

Left Multiplier

Right Multiplier

1.000

0.000

1.000

0.750

0.250

0.750

0.625

0.375

0.625

0.500

0.500

0.500

0.375

0.625

0.375

0.250

0.750

0.250

0.000

1.000

0.000

Note how the amplitudes change from 0 to 1 in each channel. The overall amplitude remains constant at 1, but is split between the two channels. With the pan value set to 0.5, we have split the amplitude equally between the two output channels. When the pan value is non-zero one channel will sound louder than the other and we will hear this as a spatial movement of the sound.

Although simple and efficient, this calculation produces the well-known "hole in the middle" effect. As the sound intensity increases in the left and right channel it appears to move forward and backward as well as side to side. We can compensate for this by using a non-linear calculation for the left and right values. One common way to do this is to consider the pan position an angle from the center and take the sine of the position:

left = value * sin((1 - pan) * PI/2);
right = value * sin(pan * PI/2);

This produces the following values for each channel:

Pan Value

Left Multiplier

Right Multiplier

1.000

0.000

1.000

0.750

0.383

0.924

0.625

0.556

0.831

0.500

0.707

0.707

0.375

0.831

0.556

0.250

0.924

0.383

0.000

1.000

0.000

Alternatively, we can take the square root of the pan settings:

left = value * sqrt(1 - pan);
right = value * sqrt(pan);

This produces the following values for each channel:

Pan Value

Left Multiplier

Right Multiplier

1.000

0.000

1.000

0.750

0.500

0.866

0.625

0.612

0.791

0.500

0.707

0.707

0.375

0.791

0.612

0.250

0.866

0.500

0.000

1.000

0.000

Notice that for the non-linear methods the resulting amplitude at center setting is now 1.414 rather than 1.0. We can compensate for this by multiplying each channel by 0.707. This will produce settings that are 0.5 for each channel at a pan setting of 0.5.

Links:

Dan Mitchell's Personal Website