On Wednesday 21 January 2009 1:02:02 am Christian Borss wrote:
> >Though as "luck" would have it, I started implementing a Phonon backend
> > just before this patch was brought up, and I've been fighting with it
> > trying to get it not to crash.
>
> Good luck. ;-)
Well, the Phonon backend didn't work out as I hoped. Doesn't seem as though
I'll be able to use it for ALURE to load files either, for the time being. Oh
well.
In either case, I've been playing around with this code. I've simplified the
code setting the drysends a bit, but it should be functionally the same. I've
also made it so stereo will use it too, since it's possible they may not be at
the sides (like with quad+, they could be at 30~45 degree angles.. or they
could be at +/-90, eg. with headphones; this allows them to be configurable as
such).
I didn't change the positioning of the speakers yet, but I'll do that after
the initial change is committed. Attached is a patch that I have now.. does it
work good for you?
[new-pan-algo.diff]
diff --git a/Alc/ALc.c b/Alc/ALc.c
index 7f393c7..7290229 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -37,6 +37,7 @@
#include "alExtension.h"
#include "alAuxEffectSlot.h"
#include "bs2b.h"
+#include "alu.h"
///////////////////////////////////////////////////////
// DEBUG INFORMATION
@@ -487,6 +488,8 @@ static ALvoid InitContext(ALCcontext *pContext)
bs2b_set_srate(pContext->bs2b, pContext->Frequency);
bs2b_set_level(pContext->bs2b, level);
}
+
+ aluInitPanning(pContext);
}
diff --git a/Alc/ALu.c b/Alc/ALu.c
index a6be6ae..1ffdc0c 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -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)))
+#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
@@ -240,17 +254,158 @@ static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3])
memcpy(vector, result, sizeof(result));
}
+static __inline ALfloat aluLUTpos2Angle(ALint pos)
+{
+ if(pos < QUADRANT_NUM)
+ return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
+ if(pos < 2 * QUADRANT_NUM)
+ return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
+ 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;
+}
+
+ALvoid aluInitPanning(ALCcontext *Context)
+{
+ ALint pos, offset, s;
+ ALfloat Alpha, Theta;
+ ALfloat SpeakerAngle[OUTPUTCHANNELS];
+ ALint Speaker2Chan[OUTPUTCHANNELS];
+
+ // Shall the user configure this in alsoft.conf ?!
+ switch(Context->Device->Format)
+ {
+ case AL_FORMAT_QUAD8:
+ case AL_FORMAT_QUAD16:
+ case AL_FORMAT_QUAD32:
+ Context->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:
+ Context->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:
+ Context->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:
+ Context->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:
+ Context->NumChan = 2;
+ Speaker2Chan[0] = FRONT_LEFT;
+ Speaker2Chan[1] = FRONT_RIGHT;
+ SpeakerAngle[0] = -90.0f * M_PI/180.0f;
+ SpeakerAngle[1] = 90.0f * M_PI/180.0f;
+ }
+
+ for(pos = 0; pos < LUT_NUM; pos++)
+ {
+ // source angle
+ Theta = aluLUTpos2Angle(pos);
+
+ // clear all values
+ offset = OUTPUTCHANNELS * pos;
+ for(s = 0; s < OUTPUTCHANNELS; s++)
+ Context->PanningLUT[offset+s] = 0.0f;
+
+ // set panning values
+ for(s = 0; s < Context->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]);
+ Context->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
+ Context->PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
+ break;
+ }
+ }
+ if(s == Context->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]);
+ Context->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
+ Context->PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);
+ }
+ }
+}
+
+static __inline ALint aluCart2LUTpos(ALfloat re, ALfloat im)
+{
+ ALint pos = 0;
+ ALfloat denom = aluFabs(re) + aluFabs(im);
+ if(denom > 0.0f)
+ pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
+
+ 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,
- ALfloat *drysend, ALfloat *wetsend,
- ALfloat *pitch, ALfloat *drygainhf,
- ALfloat *wetgainhf)
+ ALenum isMono, ALfloat *drysend,
+ ALfloat *wetsend, ALfloat *pitch,
+ ALfloat *drygainhf, ALfloat *wetgainhf)
{
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,ListenerGain;
ALfloat U[3],V[3],N[3];
ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound, flMaxVelocity;
ALfloat Matrix[3][3];
@@ -260,6 +415,9 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
ALfloat RoomRolloff;
ALfloat DryGainHF = 1.0f;
ALfloat WetGainHF = 1.0f;
+ ALfloat DirGain, AmbientGain;
+ const ALfloat *SpeakerGain;
+ ALint pos, s;
ALfloat cw, a, g;
//Get context properties
@@ -519,65 +677,20 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
DryMix *= ListenerGain;
WetMix *= ListenerGain;
- //6. Convert normalized position into pannings, then into channel volumes
+ // Use energy-preserving panning algorithm for multi-speaker playback
aluNormalize(Position);
- switch(aluChannelsFromFormat(OutputFormat))
+
+ pos = aluCart2LUTpos(-Position[2], Position[0]);
+ SpeakerGain = &ALContext->PanningLUT[OUTPUTCHANNELS * pos];
+
+ DirGain = aluSqrt(Position[0] * Position[0] + Position[2] * Position[2]);
+ // elevation adjustment for directional gain. this sucks, but
+ // has low complexity
+ AmbientGain = 1.0/aluSqrt(ALContext->NumChan) * (1.0-DirGain);
+ for (s = 0; s < OUTPUTCHANNELS; s++)
{
- case 1:
- case 2:
- PanningLR = 0.5f + 0.5f*Position[0];
- drysend[FRONT_LEFT] = DryMix * aluSqrt(1.0f-PanningLR); //L Direct
- drysend[FRONT_RIGHT] = DryMix * aluSqrt( PanningLR); //R Direct
- drysend[BACK_LEFT] = 0.0f;
- drysend[BACK_RIGHT] = 0.0f;
- drysend[SIDE_LEFT] = 0.0f;
- drysend[SIDE_RIGHT] = 0.0f;
- break;
- case 4:
- /* TODO: Add center/lfe channel in spatial calculations? */
- 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
- {
- 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;
- }
- default:
- break;
+ ALfloat gain = SpeakerGain[s]*DirGain + AmbientGain;
+ drysend[s] = DryMix * gain;
}
*wetsend = WetMix;
@@ -748,7 +861,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
CalcSourceParams(ALContext, ALSource,
(Channels==1) ? AL_TRUE : AL_FALSE,
- format, newDrySend, &newWetSend, &Pitch,
+ newDrySend, &newWetSend, &Pitch,
&DryGainHF, &WetGainHF);
Pitch = (Pitch*Frequency) / ALContext->Frequency;
@@ -847,6 +960,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
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 --git a/CMakeLists.txt b/CMakeLists.txt
index 2862217..845442c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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 --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 042ab77..de53b07 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -129,6 +129,9 @@ extern char _alDebug[256];
#define LOWPASSFREQCUTOFF (5000)
+#define QUADRANT_NUM 128
+#define LUT_NUM (4 * QUADRANT_NUM)
+
typedef struct {
ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*);
@@ -206,6 +209,9 @@ struct ALCcontext_struct
ALint lNumMonoSources;
ALint lNumStereoSources;
+ ALfloat PanningLUT[OUTPUTCHANNELS * LUT_NUM];
+ ALint NumChan;
+
ALCdevice *Device;
const ALCchar *ExtensionList;
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index b14180b..f307ea0 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -25,6 +25,7 @@ extern ALboolean DuplicateStereo;
__inline ALuint aluBytesFromFormat(ALenum format);
__inline ALuint aluChannelsFromFormat(ALenum format);
+ALvoid aluInitPanning(ALCcontext *Context);
ALvoid aluMixData(ALCcontext *context,ALvoid *buffer,ALsizei size,ALenum format);
#ifdef __cplusplus
diff --git a/config.h.in b/config.h.in
index 45df515..0c8ef40 100644
--- a/config.h.in
+++ b/config.h.in
@@ -31,6 +31,12 @@
/* Define if we have the acosf function */
#cmakedefine HAVE_ACOSF
+/* Define if we have the atanf function */
+#cmakedefine HAVE_ATANF
+
+/* Define if we have the fabsf function */
+#cmakedefine HAVE_FABSF
+
/* Define if we have the strtof function */
#cmakedefine HAVE_STRTOF
_______________________________________________
Openal-devel mailing list
Openal-devel@...
http://opensource.creative.com/mailman/listinfo/openal-devel