diff -pur openal-soft.orig/Alc/ALc.c openal-soft/Alc/ALc.c
--- openal-soft.orig/Alc/ALc.c	2009-01-18 10:30:25.000000000 +0000
+++ openal-soft/Alc/ALc.c	2009-01-18 13:29:38.000000000 +0000
@@ -37,6 +37,7 @@
 #include "alExtension.h"
 #include "alAuxEffectSlot.h"
 #include "bs2b.h"
+#include "alu.h"
 
 ///////////////////////////////////////////////////////
 // DEBUG INFORMATION
@@ -1280,6 +1281,12 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDev
                 break;
             }
         }
+
+        if (bDeviceFound)
+        {
+            aluInitPanning(device->Format);
+        }
+
         ProcessContext(NULL);
 
         if (!bDeviceFound)
diff -pur openal-soft.orig/Alc/ALu.c openal-soft/Alc/ALu.c
--- openal-soft.orig/Alc/ALu.c	2009-01-18 10:30:25.000000000 +0000
+++ openal-soft/Alc/ALu.c	2009-01-18 13:39:03.000000000 +0000
@@ -23,6 +23,8 @@
 #include "config.h"
 
 #include <math.h>
+#include <stdlib.h>
+#include <string.h>
 #include "alMain.h"
 #include "AL/al.h"
 #include "AL/alc.h"
@@ -62,6 +64,18 @@ typedef long long ALint64;
 #define aluAcos(x) ((ALfloat)acos((double)(x)))
 #endif
 
+#ifdef HAVE_ATANF
+#define aluAtan(x) ((ALfloat)atanf((float)(x)))MAX_SPEAKER
+#else
+#define aluAtan(x) ((ALfloat)atan((double)(x)))
+#endif
+
+#ifdef HAVE_FABSF
+#define aluFabs(x) ((ALfloat)fabsf((float)(x)))
+#else
+#define aluFabs(x) ((ALfloat)fabs((double)(x)))
+#endif
+
 // fixes for mingw32.
 #if defined(max) && !defined(__max)
 #define __max max
@@ -75,11 +89,20 @@ typedef long long ALint64;
 #define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
 #define MAX_PITCH 65536
 
+#define MAX_SPEAKER 8
+#define QUADRANT_NUM 128
+#define LUT_NUM (4 * QUADRANT_NUM)
+
 /* Minimum ramp length in milliseconds. The value below was chosen to
  * adequately reduce clicks and pops from harsh gain changes. */
 #define MIN_RAMP_LENGTH  16
 
 ALboolean DuplicateStereo = AL_FALSE;
+ALfloat PanningLUT[MAX_SPEAKER * LUT_NUM];
+ALfloat SpeakerAngle[MAX_SPEAKER];
+ALint Speaker2Chan[MAX_SPEAKER];
+ALint NumChan = 2;
+ALfloat MaxAmbientGain = 1.0;
 
 /* NOTE: The AL_FORMAT_REAR* enums aren't handled here be cause they're
  *       converted to AL_FORMAT_QUAD* when loaded */
@@ -240,6 +263,34 @@ static __inline ALvoid aluMatrixVector(A
     memcpy(vector, result, sizeof(result));
 }
 
+static __inline ALfloat aluLUTpos2Angle(ALint pos)
+{
+    if (pos < QUADRANT_NUM)
+    {
+        return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
+    }
+    else if (pos < 2 * QUADRANT_NUM)
+    {
+        return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
+    }
+    else if (pos < 3 * QUADRANT_NUM)
+    {
+        return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
+    }
+    return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
+}
+
+static __inline ALint aluCart2LUTpos(ALfloat re, ALfloat im)
+{
+    ALint pos;
+
+    pos = round(QUADRANT_NUM * aluFabs(im) / (aluFabs(re) + aluFabs(im)));
+    if (re < 0.0)
+        pos = 2 * QUADRANT_NUM - pos;
+    if (im < 0.0)
+        pos = LUT_NUM - pos;
+    return pos % LUT_NUM;
+}
 
 static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
                                ALenum isMono, ALenum OutputFormat,
@@ -250,7 +301,7 @@ static ALvoid CalcSourceParams(ALCcontex
     ALfloat InnerAngle,OuterAngle,Angle,Distance,DryMix,WetMix=0.0f;
     ALfloat Direction[3],Position[3],SourceToListener[3];
     ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
-    ALfloat ConeVolume,SourceVolume,PanningFB,PanningLR,ListenerGain;
+    ALfloat ConeVolume,SourceVolume,PanningLR,ListenerGain;
     ALfloat U[3],V[3],N[3];
     ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound, flMaxVelocity;
     ALfloat Matrix[3][3];
@@ -260,6 +311,9 @@ static ALvoid CalcSourceParams(ALCcontex
     ALfloat RoomRolloff;
     ALfloat DryGainHF = 1.0f;
     ALfloat WetGainHF = 1.0f;
+    ALfloat SpeakerGain[8];
+    ALfloat DirGain, AmbientGain;
+    ALint pos, s;
     ALfloat cw, a, g;
 
     //Get context properties
@@ -519,9 +573,9 @@ static ALvoid CalcSourceParams(ALCcontex
         DryMix *= ListenerGain;
         WetMix *= ListenerGain;
 
-        //6. Convert normalized position into pannings, then into channel volumes
+        //6. Use energy-preserving panning algorithm for multi-speaker playback
         aluNormalize(Position);
-        switch(aluChannelsFromFormat(OutputFormat))
+        switch(NumChan)
         {
             case 1:
             case 2:
@@ -534,48 +588,30 @@ static ALvoid CalcSourceParams(ALCcontex
                 drysend[SIDE_RIGHT]  = 0.0f;
                 break;
             case 4:
-            /* TODO: Add center/lfe channel in spatial calculations? */
+            case 5:
             case 6:
-                // Apply a scalar so each individual speaker has more weight
-                PanningLR = 0.5f + (0.5f*Position[0]*1.41421356f);
-                PanningLR = __min(1.0f, PanningLR);
-                PanningLR = __max(0.0f, PanningLR);
-                PanningFB = 0.5f + (0.5f*Position[2]*1.41421356f);
-                PanningFB = __min(1.0f, PanningFB);
-                PanningFB = __max(0.0f, PanningFB);
-                drysend[FRONT_LEFT]  = DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
-                drysend[FRONT_RIGHT] = DryMix * aluSqrt((     PanningLR)*(1.0f-PanningFB));
-                drysend[BACK_LEFT]   = DryMix * aluSqrt((1.0f-PanningLR)*(     PanningFB));
-                drysend[BACK_RIGHT]  = DryMix * aluSqrt((     PanningLR)*(     PanningFB));
-                drysend[SIDE_LEFT]   = 0.0f;
-                drysend[SIDE_RIGHT]  = 0.0f;
-                break;
             case 7:
             case 8:
-                PanningFB = 1.0f - fabs(Position[2]*1.15470054f);
-                PanningFB = __min(1.0f, PanningFB);
-                PanningFB = __max(0.0f, PanningFB);
-                PanningLR = 0.5f + (0.5*Position[0]*((1.0f-PanningFB)*2.0f));
-                PanningLR = __min(1.0f, PanningLR);
-                PanningLR = __max(0.0f, PanningLR);
-                if(Position[2] > 0.0f)
-                {
-                    drysend[BACK_LEFT]   = DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
-                    drysend[BACK_RIGHT]  = DryMix * aluSqrt((     PanningLR)*(1.0f-PanningFB));
-                    drysend[SIDE_LEFT]   = DryMix * aluSqrt((1.0f-PanningLR)*(     PanningFB));
-                    drysend[SIDE_RIGHT]  = DryMix * aluSqrt((     PanningLR)*(     PanningFB));
-                    drysend[FRONT_LEFT]  = 0.0f;
-                    drysend[FRONT_RIGHT] = 0.0f;
-                }
-                else
+                // set directional gain
+                pos = aluCart2LUTpos(-Position[2], Position[0]);
+                memcpy(SpeakerGain, &PanningLUT[MAX_SPEAKER * pos], MAX_SPEAKER * sizeof(ALfloat));
+
+                // elevation adjustment for directional gain
+                DirGain = aluSqrt(Position[0] * Position[0] + Position[2] * Position[2]);
+                for (s = 0; s < MAX_SPEAKER; s++)
+                    SpeakerGain[s] *= DirGain;
+
+                // increase gain for sound sources above/below listener
+                AmbientGain = MaxAmbientGain * (1.0 - DirGain);   // this sucks, but has low complexity
+                for (s = 0; s < NumChan; s++)
+                    SpeakerGain[Speaker2Chan[s]] += AmbientGain;
+
+                // set "drysend" levels
+                for (s = 0; s < MAX_SPEAKER; s++)
                 {
-                    drysend[FRONT_LEFT]  = DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
-                    drysend[FRONT_RIGHT] = DryMix * aluSqrt((     PanningLR)*(1.0f-PanningFB));
-                    drysend[SIDE_LEFT]   = DryMix * aluSqrt((1.0f-PanningLR)*(     PanningFB));
-                    drysend[SIDE_RIGHT]  = DryMix * aluSqrt((     PanningLR)*(     PanningFB));
-                    drysend[BACK_LEFT]   = 0.0f;
-                    drysend[BACK_RIGHT]  = 0.0f;
+                    drysend[s] = DryMix * SpeakerGain[s];
                 }
+                break;
             default:
                 break;
         }
@@ -646,6 +682,122 @@ static __inline ALshort lerp(ALshort val
     return val1 + (((val2-val1)*frac)>>FRACTIONBITS);
 }
 
+ALvoid aluInitPanning(ALenum OutputFormat)
+{
+    ALint pos, offset, s;
+    ALfloat Alpha, Theta;
+
+    // Shall the user configure this in alsoft.conf ?!
+    switch(OutputFormat)
+    {
+        case AL_FORMAT_QUAD8_LOKI:
+        case AL_FORMAT_QUAD8:
+        case AL_FORMAT_QUAD16_LOKI:
+        case AL_FORMAT_QUAD16:
+        case AL_FORMAT_QUAD32:
+            NumChan = 4;
+            Speaker2Chan[0] = BACK_LEFT;
+            Speaker2Chan[1] = FRONT_LEFT;
+            Speaker2Chan[2] = FRONT_RIGHT;
+            Speaker2Chan[3] = BACK_RIGHT;
+            SpeakerAngle[0] = -135.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  -45.0f * M_PI/180.0f;
+            SpeakerAngle[2] =   45.0f * M_PI/180.0f;
+            SpeakerAngle[3] =  135.0f * M_PI/180.0f;
+            break;
+
+        case AL_FORMAT_51CHN8:
+        case AL_FORMAT_51CHN16:
+        case AL_FORMAT_51CHN32:
+            NumChan = 5;
+            Speaker2Chan[0] = BACK_LEFT;
+            Speaker2Chan[1] = FRONT_LEFT;
+            Speaker2Chan[2] = CENTER;
+            Speaker2Chan[3] = FRONT_RIGHT;
+            Speaker2Chan[4] = BACK_RIGHT;
+            SpeakerAngle[0] = -110.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  -30.0f * M_PI/180.0f;
+            SpeakerAngle[2] =    0.0f * M_PI/180.0f;
+            SpeakerAngle[3] =   30.0f * M_PI/180.0f;
+            SpeakerAngle[4] =  110.0f * M_PI/180.0f;
+            break;
+
+        case AL_FORMAT_61CHN8:
+        case AL_FORMAT_61CHN16:
+        case AL_FORMAT_61CHN32:
+            NumChan = 6;
+            Speaker2Chan[0] = BACK_LEFT;
+            Speaker2Chan[1] = SIDE_LEFT;
+            Speaker2Chan[2] = FRONT_LEFT;
+            Speaker2Chan[3] = FRONT_RIGHT;
+            Speaker2Chan[4] = SIDE_RIGHT;
+            Speaker2Chan[5] = BACK_RIGHT;
+            SpeakerAngle[0] = -150.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  -90.0f * M_PI/180.0f;
+            SpeakerAngle[2] =  -30.0f * M_PI/180.0f;
+            SpeakerAngle[3] =   30.0f * M_PI/180.0f;
+            SpeakerAngle[4] =   90.0f * M_PI/180.0f;
+            SpeakerAngle[5] =  150.0f * M_PI/180.0f;
+            break;
+
+        case AL_FORMAT_71CHN8:
+        case AL_FORMAT_71CHN16:
+        case AL_FORMAT_71CHN32:
+            NumChan = 7;
+            Speaker2Chan[0] = BACK_LEFT;
+            Speaker2Chan[1] = SIDE_LEFT;
+            Speaker2Chan[2] = FRONT_LEFT;
+            Speaker2Chan[3] = CENTER;
+            Speaker2Chan[4] = FRONT_RIGHT;
+            Speaker2Chan[5] = SIDE_RIGHT;
+            Speaker2Chan[6] = BACK_RIGHT;
+            SpeakerAngle[0] = -150.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  -90.0f * M_PI/180.0f;
+            SpeakerAngle[2] =  -30.0f * M_PI/180.0f;
+            SpeakerAngle[3] =    0.0f * M_PI/180.0f;
+            SpeakerAngle[4] =   30.0f * M_PI/180.0f;
+            SpeakerAngle[5] =   90.0f * M_PI/180.0f;
+            SpeakerAngle[6] =  150.0f * M_PI/180.0f;
+            break;
+
+        default:
+            NumChan = 2;
+            return;
+    }
+    MaxAmbientGain = 1.0 / aluSqrt(NumChan);
+
+    for (pos = 0; pos < LUT_NUM; pos++)
+    {
+        // source angle
+        Theta = aluLUTpos2Angle(pos);
+
+        // clear all values
+        offset = MAX_SPEAKER * pos;
+        for (s = 0; s < MAX_SPEAKER; s++)
+            PanningLUT[offset+s] = 0;
+
+        // set panning values
+        for (s = 0; s < NumChan - 1; s++)
+        {
+            if (Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
+            {   // source between speaker s and speaker s+1
+                Alpha = M_PI_2 * (Theta - SpeakerAngle[s]) / (SpeakerAngle[s+1]-SpeakerAngle[s]);
+                PanningLUT[offset + Speaker2Chan[s]]   = cos(Alpha);
+                PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
+                break;
+            }
+        }
+        if (s == NumChan - 1)   // source between last and first speaker
+        {
+            if (Theta < SpeakerAngle[0])
+                Theta += 2.0f * M_PI;
+            Alpha = M_PI_2 * (Theta - SpeakerAngle[s]) / (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
+            PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
+            PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);
+        }
+    }
+}
+
 ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum format)
 {
     static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS];
@@ -847,6 +999,7 @@ ALvoid aluMixData(ALCcontext *ALContext,
                             DryBuffer[j][SIDE_RIGHT]  += outsamp*DrySend[SIDE_RIGHT];
                             DryBuffer[j][BACK_LEFT]   += outsamp*DrySend[BACK_LEFT];
                             DryBuffer[j][BACK_RIGHT]  += outsamp*DrySend[BACK_RIGHT];
+                            DryBuffer[j][CENTER]      += outsamp*DrySend[CENTER];
                             //Room path final mix buffer and panning
                             outsamp = lpFilter(WetFilter, sample);
                             WetBuffer[j] += outsamp*(*WetSend);
diff -pur openal-soft.orig/CMakeLists.txt openal-soft/CMakeLists.txt
--- openal-soft.orig/CMakeLists.txt	2009-01-18 10:30:25.000000000 +0000
+++ openal-soft/CMakeLists.txt	2009-01-18 11:05:29.000000000 +0000
@@ -122,10 +122,12 @@ CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H)
 
 CHECK_LIBRARY_EXISTS(m  sqrtf  "" HAVE_SQRTF)
 CHECK_LIBRARY_EXISTS(m  acosf  "" HAVE_ACOSF)
+CHECK_LIBRARY_EXISTS(m  atanf  "" HAVE_ATANF)
+CHECK_LIBRARY_EXISTS(m  fabsf  "" HAVE_FABSF)
 IF(HAVE_FENV_H)
     CHECK_LIBRARY_EXISTS(m  fesetround  "" HAVE_FESETROUND)
 ENDIF()
-IF(HAVE_SQRTF OR HAVE_ACOSF OR HAVE_FESETROUND)
+IF(HAVE_SQRTF OR HAVE_ACOSF OR HAVE_ATANF OR HAVE_FABSF OR HAVE_FESETROUND)
     SET(EXTRA_LIBS m ${EXTRA_LIBS})
 ENDIF()
 CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
diff -pur openal-soft.orig/OpenAL32/Include/alu.h openal-soft/OpenAL32/Include/alu.h
--- openal-soft.orig/OpenAL32/Include/alu.h	2009-01-18 10:30:25.000000000 +0000
+++ openal-soft/OpenAL32/Include/alu.h	2009-01-18 11:00:01.000000000 +0000
@@ -25,6 +25,7 @@ extern ALboolean DuplicateStereo;
 
 __inline ALuint aluBytesFromFormat(ALenum format);
 __inline ALuint aluChannelsFromFormat(ALenum format);
+ALvoid aluInitPanning(ALenum OutputFormat);
 ALvoid aluMixData(ALCcontext *context,ALvoid *buffer,ALsizei size,ALenum format);
 
 #ifdef __cplusplus

