Compare commits

...

39 Commits

Author SHA1 Message Date
Chris Robinson 61122a5093 Release 1.7.411 2009-03-14 22:24:59 -07:00
Chris Robinson a8a4ff8af1 Constify some parameters 2009-03-13 23:08:15 -07:00
Chris Robinson 8a857c35ee Calculate filter coefficients in aluMixData 2009-03-13 22:58:54 -07:00
Chris Robinson 89ddd7d8e5 Don't modify the device struct until playback succesfully starts 2009-03-13 22:16:01 -07:00
Chris Robinson 8d0c4ccb3b The room rolloff factor can go up to 10 2009-03-13 02:12:45 -07:00
Chris Robinson 8ee47d5573 Dynamically load dsound when possible 2009-03-10 02:46:42 -07:00
Chris Robinson 9e88011417 Add a cast for setting a dummy pointer value 2009-03-10 02:20:05 -07:00
Chris Robinson f8949ee7a1 Always add the default ALSA device even if no cards are present 2009-03-10 01:46:51 -07:00
Chris Robinson 62aa2d0ba7 Only expose the default ALSA device in standard enumeration 2009-03-10 01:28:01 -07:00
Chris Robinson ace047d625 Append the card and device indices to the ALSA device strings 2009-03-10 01:21:42 -07:00
Chris Robinson d6277db209 Fix alsoftrc configuration sample comments 2009-03-10 01:08:03 -07:00
Chris Robinson 7ebb28327f Remove the SDL backend 2009-03-10 01:03:39 -07:00
Chris Robinson 86931cbde4 Add a PortAudio backend 2009-03-10 00:55:29 -07:00
Chris Robinson 6d7be151dc Remove the unneeded path from the cross-compiler commands 2009-03-06 20:09:44 -08:00
Chris Robinson 07227b9806 Use a modified reverb model that obeys the reverb parameters better 2009-03-02 18:48:23 -08:00
Chris Robinson 8348d719cd Clamp gain of multichannel sources 2009-02-10 15:15:49 -08:00
Chris Robinson 0fcefd865b Install the pkgconfig file to the correct directory 2009-02-10 14:39:48 -08:00
Chris Robinson 57c2e9b5f8 Include assert.h for assert() 2009-02-02 11:18:33 -08:00
Chris Robinson 7d7fc39035 Use calculated distance from reference for air absorption 2009-01-30 10:56:25 -08:00
Chris Robinson 351105b3df Fix incorrect comment 2009-01-30 10:53:09 -08:00
Chris Robinson cbfc33215b Use M_PI since it is sure to be defined 2009-01-27 07:11:58 -08:00
Chris Robinson 5a93b56673 Fix ignored return value warning 2009-01-26 08:10:05 -08:00
Chris Robinson 1f4c69c17a Use a matrix for up- and down-mixing channels 2009-01-25 22:11:07 -08:00
Chris Robinson f5b19fad20 Duplicate stereo onto the side channels as well as the back 2009-01-25 19:54:50 -08:00
Chris Robinson bc60818e9a Don't read stereo layout when output is mono 2009-01-25 19:33:52 -08:00
Chris Robinson f82c88f016 Add options for user-configurable speaker arrangements 2009-01-25 19:20:47 -08:00
Chris Robinson 98e86decad 6.1 uses front- and back-center, not left- and right-back channels 2009-01-24 15:13:14 -08:00
Chris Robinson aaf2c0ebd4 Seperate mixing loops depending on source channel configuration 2009-01-24 13:57:01 -08:00
Chris Robinson 778b74cae1 Reimplement panning using lookup tables, based on a patch by Christian Borss
This allows speaker positions to be specified by discrete angles around the
listener, providing more flexibility and configurability in placement.
Additional patches to take advantage of this are forthcoming.
2009-01-24 10:38:04 -08:00
Chris Robinson 43ee1edd97 Properly capitalize the libname in Win32 2009-01-10 21:23:53 -08:00
Chris Robinson dd7e23740b Remove XCOMPILEWIN32 option in favor of CMake 2.6's cross-compiling caps 2008-12-12 11:19:38 -08:00
Chris Robinson 1acd6da745 Search for SDL.h in addition to SDL/SDL.h 2008-12-12 11:09:23 -08:00
Chris Robinson 3056f91ec5 Apply the dry filter to multi-channel sources
Unlike mono sources, they use 2 chained one-pole filters instead of 4
2008-12-10 11:54:13 -08:00
Chris Robinson ed03570e1a Fix some CMake checks 2008-12-07 02:20:17 -08:00
Chris Robinson 2ec0e48d06 Protect playback device opening with a mutex lock 2008-12-07 01:07:54 -08:00
Chris Robinson 8b54d59b8c Add an SDL backend 2008-12-07 01:05:39 -08:00
Chris Robinson f6a4dbabdd Add cast for setting a dummy pointer value 2008-12-06 12:17:29 -08:00
Chris Robinson a71c291bcb Let CMAKE_DEBUG_POSTFIX be exposed for graphical CMake front-ends 2008-12-02 02:37:51 -08:00
Chris Robinson 55b9ccc2de Implement AL_EXTX_source_distance_model
As with other EXTX extensions, this is subject to change and removal as the
spec gets worked on
2008-11-25 18:56:10 -08:00
18 changed files with 1360 additions and 505 deletions
+9 -3
View File
@@ -37,6 +37,7 @@
#include "alExtension.h"
#include "alAuxEffectSlot.h"
#include "bs2b.h"
#include "alu.h"
///////////////////////////////////////////////////////
// DEBUG INFORMATION
@@ -67,6 +68,9 @@ static struct {
#ifdef HAVE_WINMM
{ "winmm", alcWinMMInit, EmptyFuncs },
#endif
#ifdef HAVE_PORTAUDIO
{ "port", alc_pa_init, EmptyFuncs },
#endif
{ "wave", alc_wave_init, EmptyFuncs },
@@ -475,7 +479,7 @@ static ALvoid InitContext(ALCcontext *pContext)
pContext->lNumStereoSources = 1;
pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources;
pContext->ExtensionList = "AL_EXTX_buffer_sub_data AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic";
pContext->ExtensionList = "AL_EXTX_buffer_sub_data AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_EXTX_source_distance_model AL_LOKI_quadriphonic";
level = GetConfigValueInt(NULL, "cf_level", 0);
if(level > 0 && level <= 6)
@@ -484,6 +488,8 @@ static ALvoid InitContext(ALCcontext *pContext)
bs2b_set_srate(pContext->bs2b, pContext->Frequency);
bs2b_set_level(pContext->bs2b, level);
}
aluInitPanning(pContext);
}
@@ -1263,21 +1269,21 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
device->MaxNoOfSources = 256;
// Find a playback device to open
SuspendContext(NULL);
for(i = 0;BackendList[i].Init;i++)
{
device->Funcs = &BackendList[i].Funcs;
if(ALCdevice_OpenPlayback(device, deviceName))
{
SuspendContext(NULL);
device->next = g_pDeviceList;
g_pDeviceList = device;
g_ulDeviceCount++;
ProcessContext(NULL);
bDeviceFound = AL_TRUE;
break;
}
}
ProcessContext(NULL);
if (!bDeviceFound)
{
+563 -202
View File
@@ -23,6 +23,11 @@
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
@@ -39,6 +44,11 @@
#include <float.h>
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#define M_PI_2 1.57079632679489661923 /* pi/2 */
#endif
#if defined(HAVE_STDINT_H)
#include <stdint.h>
typedef int64_t ALint64;
@@ -62,6 +72,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
@@ -178,6 +200,20 @@ static __inline ALfloat lpFilter(FILTER *iir, ALfloat input)
return output;
}
static __inline ALfloat lpFilterMC(FILTER *iir, ALuint chan, ALfloat input)
{
ALfloat *history = &iir->history[chan*2];
ALfloat a = iir->coeff;
ALfloat output = input;
output = output + (history[0]-output)*a;
history[0] = output;
output = output + (history[1]-output)*a;
history[1] = output;
return output;
}
static __inline ALshort aluF2S(ALfloat Value)
{
@@ -189,14 +225,14 @@ static __inline ALshort aluF2S(ALfloat Value)
return ((ALshort)i);
}
static __inline ALvoid aluCrossproduct(ALfloat *inVector1,ALfloat *inVector2,ALfloat *outVector)
static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
{
outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
}
static __inline ALfloat aluDotproduct(ALfloat *inVector1,ALfloat *inVector2)
static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
{
return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
inVector1[2]*inVector2[2];
@@ -226,9 +262,300 @@ static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3])
memcpy(vector, result, sizeof(result));
}
static ALvoid SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[OUTPUTCHANNELS],
ALint Speaker2Chan[OUTPUTCHANNELS], ALint chans)
{
const char *confkey;
const char *next;
const char *sep;
const char *end;
int i, val;
static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
ALenum isMono, ALenum OutputFormat,
confkey = GetConfigValue(NULL, name, "");
next = confkey;
while(next && *next)
{
confkey = next;
next = strchr(confkey, ',');
if(next)
{
do {
next++;
} while(isspace(*next));
}
sep = strchr(confkey, '=');
if(!sep || confkey == sep)
continue;
end = sep - 1;
while(isspace(*end) && end != confkey)
end--;
if(strncmp(confkey, "fl", end-confkey) == 0)
val = FRONT_LEFT;
else if(strncmp(confkey, "fr", end-confkey) == 0)
val = FRONT_RIGHT;
else if(strncmp(confkey, "fc", end-confkey) == 0)
val = FRONT_CENTER;
else if(strncmp(confkey, "bl", end-confkey) == 0)
val = BACK_LEFT;
else if(strncmp(confkey, "br", end-confkey) == 0)
val = BACK_RIGHT;
else if(strncmp(confkey, "bc", end-confkey) == 0)
val = BACK_CENTER;
else if(strncmp(confkey, "sl", end-confkey) == 0)
val = SIDE_LEFT;
else if(strncmp(confkey, "sr", end-confkey) == 0)
val = SIDE_RIGHT;
else
{
AL_PRINT("Unknown speaker for %s: \"%c%c\"\n", name, confkey[0], confkey[1]);
continue;
}
sep++;
while(isspace(*sep))
sep++;
for(i = 0;i < chans;i++)
{
if(Speaker2Chan[i] == val)
{
val = strtol(sep, NULL, 10);
if(val >= -180 && val <= 180)
SpeakerAngle[i] = val * M_PI/180.0f;
else
AL_PRINT("Invalid angle for speaker \"%c%c\": %d\n", confkey[0], confkey[1], val);
break;
}
}
}
for(i = 1;i < chans;i++)
{
if(SpeakerAngle[i] <= SpeakerAngle[i-1])
{
AL_PRINT("Speaker %d of %d does not follow previous: %f > %f\n", i, chans,
SpeakerAngle[i-1] * 180.0f/M_PI, SpeakerAngle[i] * 180.0f/M_PI);
SpeakerAngle[i] = SpeakerAngle[i-1] + 1 * 180.0f/M_PI;
}
}
}
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];
for(s = 0;s < OUTPUTCHANNELS;s++)
{
int s2;
for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
Context->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
}
switch(Context->Device->Format)
{
/* Mono is rendered as stereo, then downmixed during post-process */
case AL_FORMAT_MONO8:
case AL_FORMAT_MONO16:
case AL_FORMAT_MONO_FLOAT32:
Context->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = 1.0f;
Context->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f;
Context->ChannelMatrix[BACK_LEFT][FRONT_LEFT] = 1.0f;
Context->ChannelMatrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f;
Context->ChannelMatrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
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;
break;
case AL_FORMAT_STEREO8:
case AL_FORMAT_STEREO16:
case AL_FORMAT_STEREO_FLOAT32:
Context->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = 1.0f;
Context->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f;
Context->ChannelMatrix[BACK_LEFT][FRONT_LEFT] = 1.0f;
Context->ChannelMatrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f;
Context->ChannelMatrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
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;
SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Context->NumChan);
break;
case AL_FORMAT_QUAD8:
case AL_FORMAT_QUAD16:
case AL_FORMAT_QUAD32:
Context->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
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;
SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Context->NumChan);
break;
case AL_FORMAT_51CHN8:
case AL_FORMAT_51CHN16:
case AL_FORMAT_51CHN32:
Context->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
Context->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
Context->NumChan = 5;
Speaker2Chan[0] = BACK_LEFT;
Speaker2Chan[1] = FRONT_LEFT;
Speaker2Chan[2] = FRONT_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;
SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Context->NumChan);
break;
case AL_FORMAT_61CHN8:
case AL_FORMAT_61CHN16:
case AL_FORMAT_61CHN32:
Context->ChannelMatrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5);
Context->NumChan = 6;
Speaker2Chan[0] = SIDE_LEFT;
Speaker2Chan[1] = FRONT_LEFT;
Speaker2Chan[2] = FRONT_CENTER;
Speaker2Chan[3] = FRONT_RIGHT;
Speaker2Chan[4] = SIDE_RIGHT;
Speaker2Chan[5] = BACK_CENTER;
SpeakerAngle[0] = -90.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] = 90.0f * M_PI/180.0f;
SpeakerAngle[5] = 180.0f * M_PI/180.0f;
SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Context->NumChan);
break;
case AL_FORMAT_71CHN8:
case AL_FORMAT_71CHN16:
case AL_FORMAT_71CHN32:
Context->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
Context->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
Context->NumChan = 7;
Speaker2Chan[0] = BACK_LEFT;
Speaker2Chan[1] = SIDE_LEFT;
Speaker2Chan[2] = FRONT_LEFT;
Speaker2Chan[3] = FRONT_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;
SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Context->NumChan);
break;
default:
assert(0);
}
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(const ALCcontext *ALContext,
const ALsource *ALSource, ALenum isMono,
ALfloat *drysend, ALfloat *wetsend,
ALfloat *pitch, ALfloat *drygainhf,
ALfloat *wetgainhf)
@@ -236,7 +563,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
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];
@@ -246,7 +573,9 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
ALfloat RoomRolloff;
ALfloat DryGainHF = 1.0f;
ALfloat WetGainHF = 1.0f;
ALfloat cw, a, g;
ALfloat DirGain, AmbientGain;
const ALfloat *SpeakerGain;
ALint pos, s;
//Get context properties
DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
@@ -301,7 +630,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
SourceToListener[1] = -Position[1];
SourceToListener[2] = -Position[2];
// Transform source position and direction into listener space
// Transform source position into listener space
aluMatrixVector(Position, Matrix);
}
else
@@ -324,7 +653,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
flAttenuation = 1.0f;
RoomAttenuation = 1.0f;
switch (ALContext->DistanceModel)
switch (ALSource->DistanceModel)
{
case AL_INVERSE_DISTANCE_CLAMPED:
Distance=__max(Distance,MinDist);
@@ -386,7 +715,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
if(dist < 0.0f) dist = 0.0f;
// Absorption calculation is done in dB
absorb = (ALSource->AirAbsorptionFactor*AIRABSORBGAINDBHF) *
(Distance*MetersPerUnit);
(dist*MetersPerUnit);
// Convert dB to linear gain before applying
absorb = pow(10.0, absorb/20.0);
DryGainHF *= absorb;
@@ -403,8 +732,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
WetMix = __max(WetMix,MinVolume);
//3. Apply directional soundcones
Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f /
3.141592654f;
Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
if(Angle >= InnerAngle && Angle <= OuterAngle)
{
ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
@@ -505,87 +833,23 @@ 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;
// Update filter coefficients. Calculations based on the I3DL2 spec.
cw = cos(2.0f*3.141592654f * LOWPASSFREQCUTOFF / ALContext->Frequency);
// We use four chained one-pole filters, so we need to take the fourth
// root of the squared gain, which is the same as the square root of
// the base gain.
// Be careful with gains < 0.0001, as that causes the coefficient to
// head towards 1, which will flatten the signal
g = aluSqrt(__max(DryGainHF, 0.0001f));
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
ALSource->iirFilter.coeff = a;
g = aluSqrt(__max(WetGainHF, 0.0001f));
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
ALSource->Send[0].iirFilter.coeff = a;
*drygainhf = DryGainHF;
*wetgainhf = WetGainHF;
}
@@ -594,16 +858,28 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
//1. Multi-channel buffers always play "normal"
pitch[0] = ALSource->flPitch;
drysend[FRONT_LEFT] = SourceVolume * ListenerGain;
drysend[FRONT_RIGHT] = SourceVolume * ListenerGain;
drysend[SIDE_LEFT] = SourceVolume * ListenerGain;
drysend[SIDE_RIGHT] = SourceVolume * ListenerGain;
drysend[BACK_LEFT] = SourceVolume * ListenerGain;
drysend[BACK_RIGHT] = SourceVolume * ListenerGain;
drysend[CENTER] = SourceVolume * ListenerGain;
drysend[LFE] = SourceVolume * ListenerGain;
*wetsend = 0.0f;
WetGainHF = 1.0f;
DryMix = SourceVolume;
DryMix = __min(DryMix,MaxVolume);
DryMix = __max(DryMix,MinVolume);
switch(ALSource->DirectFilter.type)
{
case AL_FILTER_LOWPASS:
DryMix *= ALSource->DirectFilter.Gain;
DryGainHF *= ALSource->DirectFilter.GainHF;
break;
}
drysend[FRONT_LEFT] = DryMix * ListenerGain;
drysend[FRONT_RIGHT] = DryMix * ListenerGain;
drysend[SIDE_LEFT] = DryMix * ListenerGain;
drysend[SIDE_RIGHT] = DryMix * ListenerGain;
drysend[BACK_LEFT] = DryMix * ListenerGain;
drysend[BACK_RIGHT] = DryMix * ListenerGain;
drysend[FRONT_CENTER] = DryMix * ListenerGain;
drysend[BACK_CENTER] = DryMix * ListenerGain;
drysend[LFE] = DryMix * ListenerGain;
*wetsend = 0.0f;
*drygainhf = DryGainHF;
*wetgainhf = WetGainHF;
@@ -619,6 +895,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
{
static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS];
static float WetBuffer[BUFFERSIZE];
ALfloat (*Matrix)[OUTPUTCHANNELS] = ALContext->ChannelMatrix;
ALfloat newDrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
ALfloat newWetSend = 0.0f;
ALfloat DryGainHF = 0.0f;
@@ -639,9 +916,11 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
ALsource *ALSource;
ALbuffer *ALBuffer;
ALeffectslot *ALEffectSlot;
ALfloat values[OUTPUTCHANNELS];
ALfloat value;
ALshort *Data;
ALuint i,j,k;
ALuint i,j,k,out;
ALfloat cw, a, g;
ALbufferlistitem *BufferListItem;
ALuint loop;
ALint64 DataSize64,DataPos64;
@@ -715,19 +994,70 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
if(DataPosInt >= DataSize)
goto skipmix;
CalcSourceParams(ALContext, ALSource,
(Channels==1) ? AL_TRUE : AL_FALSE,
format, newDrySend, &newWetSend, &Pitch,
&DryGainHF, &WetGainHF);
Pitch = (Pitch*Frequency) / ALContext->Frequency;
//Get source info
DryFilter = &ALSource->iirFilter;
WetFilter = &ALSource->Send[0].iirFilter;
DrySend = ALSource->DryGains;
WetSend = &ALSource->WetGain;
CalcSourceParams(ALContext, ALSource,
(Channels==1) ? AL_TRUE : AL_FALSE,
newDrySend, &newWetSend, &Pitch,
&DryGainHF, &WetGainHF);
Pitch = (Pitch*Frequency) / ALContext->Frequency;
if(Channels == 1)
{
// Update filter coefficients. Calculations based on
// the I3DL2 spec.
cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / ALContext->Frequency);
// We use four chained one-pole filters, so we need to
// take the fourth root of the squared gain, which is
// the same as the square root of the base gain.
// Be careful with gains < 0.0001, as that causes the
// coefficient to head towards 1, which will flatten
// the signal
g = aluSqrt(__max(DryGainHF, 0.0001f));
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
DryFilter->coeff = a;
g = aluSqrt(__max(WetGainHF, 0.0001f));
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
WetFilter->coeff = a;
}
else
{
// Multi-channel sources use two chained one-pole
// filters, so take the base gain (square root of the
// squared gain)
cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / ALContext->Frequency);
g = __max(DryGainHF, 0.01f);
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
DryFilter->coeff = a;
WetFilter->coeff = 0.0f;
if(DuplicateStereo && Channels == 2)
{
Matrix[FRONT_LEFT][SIDE_LEFT] = 1.0f;
Matrix[FRONT_RIGHT][SIDE_RIGHT] = 1.0f;
Matrix[FRONT_LEFT][BACK_LEFT] = 1.0f;
Matrix[FRONT_RIGHT][BACK_RIGHT] = 1.0f;
}
else if(DuplicateStereo)
{
Matrix[FRONT_LEFT][SIDE_LEFT] = 0.0f;
Matrix[FRONT_RIGHT][SIDE_RIGHT] = 0.0f;
Matrix[FRONT_LEFT][BACK_LEFT] = 0.0f;
Matrix[FRONT_RIGHT][BACK_RIGHT] = 0.0f;
}
}
//Compute the gain steps for each output channel
if(ALSource->FirstStart && DataPosInt == 0 && DataPosFrac == 0)
{
@@ -796,87 +1126,130 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
//Actual sample mixing loop
k = 0;
Data += DataPosInt*Channels;
while(BufferSize--)
{
for(i = 0;i < OUTPUTCHANNELS;i++)
DrySend[i] += dryGainStep[i];
*WetSend += wetGainStep;
if(Channels==1)
if(Channels == 1) /* Mono */
{
ALfloat outsamp;
while(BufferSize--)
{
ALfloat sample, outsamp;
for(i = 0;i < OUTPUTCHANNELS;i++)
DrySend[i] += dryGainStep[i];
*WetSend += wetGainStep;
//First order interpolator
sample = lerp(Data[k], Data[k+1], DataPosFrac);
value = lerp(Data[k], Data[k+1], DataPosFrac);
//Direct path final mix buffer and panning
outsamp = lpFilter(DryFilter, sample);
DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT];
DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT];
DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT];
DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT];
DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT];
DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT];
outsamp = lpFilter(DryFilter, value);
DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT];
DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT];
DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT];
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][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER];
DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER];
//Room path final mix buffer and panning
outsamp = lpFilter(WetFilter, sample);
outsamp = lpFilter(WetFilter, value);
WetBuffer[j] += outsamp*(*WetSend);
DataPosFrac += increment;
k += DataPosFrac>>FRACTIONBITS;
DataPosFrac &= FRACTIONMASK;
j++;
}
else
}
else if(Channels == 2) /* Stereo */
{
const int chans[] = {
FRONT_LEFT, FRONT_RIGHT
};
#define DO_MIX() do { \
*WetSend += wetGainStep*BufferSize; \
while(BufferSize--) \
{ \
for(i = 0;i < OUTPUTCHANNELS;i++) \
DrySend[i] += dryGainStep[i]; \
\
for(i = 0;i < Channels;i++) \
{ \
value = lerp(Data[k*Channels + i], Data[(k+1)*Channels + i], DataPosFrac); \
values[i] = lpFilterMC(DryFilter, chans[i], value)*DrySend[chans[i]]; \
} \
for(out = 0;out < OUTPUTCHANNELS;out++) \
{ \
ALfloat sum = 0.0f; \
for(i = 0;i < Channels;i++) \
sum += values[i]*Matrix[chans[i]][out]; \
DryBuffer[j][out] += sum; \
} \
\
DataPosFrac += increment; \
k += DataPosFrac>>FRACTIONBITS; \
DataPosFrac &= FRACTIONMASK; \
j++; \
} \
} while(0)
DO_MIX();
}
else if(Channels == 4) /* Quad */
{
const int chans[] = {
FRONT_LEFT, FRONT_RIGHT,
BACK_LEFT, BACK_RIGHT
};
DO_MIX();
}
else if(Channels == 6) /* 5.1 */
{
const int chans[] = {
FRONT_LEFT, FRONT_RIGHT,
FRONT_CENTER, LFE,
BACK_LEFT, BACK_RIGHT
};
DO_MIX();
}
else if(Channels == 7) /* 6.1 */
{
const int chans[] = {
FRONT_LEFT, FRONT_RIGHT,
FRONT_CENTER, LFE,
BACK_CENTER,
SIDE_LEFT, SIDE_RIGHT
};
DO_MIX();
}
else if(Channels == 8) /* 7.1 */
{
const int chans[] = {
FRONT_LEFT, FRONT_RIGHT,
FRONT_CENTER, LFE,
BACK_LEFT, BACK_RIGHT,
SIDE_LEFT, SIDE_RIGHT
};
DO_MIX();
#undef DO_MIX
}
else /* Unknown? */
{
*WetSend += wetGainStep*BufferSize;
for(i = 0;i < OUTPUTCHANNELS;i++)
DrySend[i] += dryGainStep[i]*BufferSize;
while(BufferSize--)
{
ALfloat samp1, samp2;
//First order interpolator (front left)
samp1 = lerp(Data[k*Channels], Data[(k+1)*Channels], DataPosFrac);
DryBuffer[j][FRONT_LEFT] += samp1*DrySend[FRONT_LEFT];
//First order interpolator (front right)
samp2 = lerp(Data[k*Channels+1], Data[(k+1)*Channels+1], DataPosFrac);
DryBuffer[j][FRONT_RIGHT] += samp2*DrySend[FRONT_RIGHT];
if(Channels >= 4)
{
int i = 2;
if(Channels >= 6)
{
if(Channels != 7)
{
//First order interpolator (center)
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][CENTER] += value*DrySend[CENTER];
i++;
}
//First order interpolator (lfe)
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][LFE] += value*DrySend[LFE];
i++;
}
//First order interpolator (back left)
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT];
i++;
//First order interpolator (back right)
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT];
i++;
if(Channels >= 7)
{
//First order interpolator (side left)
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT];
i++;
//First order interpolator (side right)
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT];
i++;
}
}
else if(DuplicateStereo)
{
//Duplicate stereo channels on the back speakers
DryBuffer[j][BACK_LEFT] += samp1*DrySend[BACK_LEFT];
DryBuffer[j][BACK_RIGHT] += samp2*DrySend[BACK_RIGHT];
}
DataPosFrac += increment;
k += DataPosFrac>>FRACTIONBITS;
DataPosFrac &= FRACTIONMASK;
j++;
}
DataPosFrac += increment;
k += DataPosFrac>>FRACTIONBITS;
DataPosFrac &= FRACTIONMASK;
j++;
}
DataPosInt += k;
@@ -1021,14 +1394,14 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
#ifdef _WIN32 /* Of course, Windows can't use the same ordering... */
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
#else
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
#endif
buffer = ((ALubyte*)buffer) + 6;
@@ -1039,15 +1412,9 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
{
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
#ifdef _WIN32
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
#else
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
#endif
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_CENTER])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT])>>8)+128);
((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_RIGHT])>>8)+128);
buffer = ((ALubyte*)buffer) + 7;
@@ -1059,14 +1426,14 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
#ifdef _WIN32
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
#else
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
#endif
((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT])>>8)+128);
@@ -1122,14 +1489,14 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
#ifdef _WIN32
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][FRONT_CENTER]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT]);
#else
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][FRONT_CENTER]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE]);
#endif
buffer = ((ALshort*)buffer) + 6;
@@ -1140,15 +1507,9 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
{
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
#ifdef _WIN32
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][LFE]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_RIGHT]);
#else
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][LFE]);
#endif
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][FRONT_CENTER]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_CENTER]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][SIDE_LEFT]);
((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_RIGHT]);
buffer = ((ALshort*)buffer) + 7;
@@ -1160,14 +1521,14 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
#ifdef _WIN32
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][FRONT_CENTER]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT]);
#else
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][FRONT_CENTER]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE]);
#endif
((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_LEFT]);
+316 -215
View File
@@ -1,6 +1,6 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2008 by Christopher Fitzgerald.
* Reverb for the OpenAL cross platform audio library
* Copyright (C) 2008-2009 by Christopher Fitzgerald.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
@@ -46,8 +46,8 @@
typedef struct DelayLine
{
// The delay lines use lengths that are powers of 2 to allow bitmasking
// instead of modulus wrapping.
// The delay lines use sample lengths that are powers of 2 to allow
// bitmasking instead of modulus wrapping.
ALuint Mask;
ALfloat *Line;
} DelayLine;
@@ -55,15 +55,15 @@ typedef struct DelayLine
struct ALverbState
{
// All delay lines are allocated as a single buffer to reduce memory
// fragmentation and teardown code.
// fragmentation and management code.
ALfloat *SampleBuffer;
// Master reverb gain.
// Master effect gain.
ALfloat Gain;
// Initial reverb delay.
// Initial effect delay and decorrelation.
DelayLine Delay;
// The tap points for the initial delay. First tap goes to early
// reflections, the second to late reverb.
ALuint Tap[2];
// reflections, the last four decorrelate to late reverb.
ALuint Tap[5];
struct {
// Gain for early reflections.
ALfloat Gain;
@@ -75,42 +75,64 @@ struct ALverbState
struct {
// Gain for late reverb.
ALfloat Gain;
// Diffusion of late reverb.
ALfloat Diffusion;
// Late reverb is done with 8 delay lines.
ALfloat Coeff[8];
DelayLine Delay[8];
ALuint Offset[8];
// The input and last 4 delay lines are low-pass filtered.
ALfloat LpCoeff[5];
ALfloat LpSample[5];
// Attenuation to compensate for modal density and decay rate.
ALfloat DensityGain;
// The feed-back and feed-forward all-pass coefficient.
ALfloat ApFeedCoeff;
// Mixing matrix coefficient.
ALfloat MixCoeff;
// Late reverb has 4 parallel all-pass filters.
ALfloat ApCoeff[4];
DelayLine ApDelay[4];
ALuint ApOffset[4];
// In addition to 4 cyclical delay lines.
ALfloat Coeff[4];
DelayLine Delay[4];
ALuint Offset[4];
// The cyclical delay lines are low-pass filtered.
ALfloat LpCoeff[4][2];
ALfloat LpSample[4];
} Late;
// The current read offset for all delay lines.
ALuint Offset;
};
// All delay line lengths are specified in seconds.
// The length of the initial delay line (a sum of the maximum delay before
// early reflections and late reverb; 0.3 + 0.1).
static const ALfloat MASTER_LINE_LENGTH = 0.4000f;
// The lengths of the early delay lines.
static const ALfloat EARLY_LINE_LENGTH[4] =
{
0.0015f, 0.0045f, 0.0135f, 0.0405f
};
// The lengths of the late delay lines.
static const ALfloat LATE_LINE_LENGTH[8] =
// The lengths of the late all-pass delay lines.
static const ALfloat ALLPASS_LINE_LENGTH[4] =
{
0.0015f, 0.0037f, 0.0093f, 0.0234f,
0.0100f, 0.0150f, 0.0225f, 0.0337f
0.0151f, 0.0167f, 0.0183f, 0.0200f,
};
// The last 4 late delay lines have a variable length dependent on the effect
// density parameter and this multiplier.
static const ALfloat LATE_LINE_MULTIPLIER = 9.0f;
// The lengths of the late cyclical delay lines.
static const ALfloat LATE_LINE_LENGTH[4] =
{
0.0211f, 0.0311f, 0.0461f, 0.0680f
};
// The late cyclical delay lines have a variable length dependent on the
// effect's density parameter (inverted for some reason) and this multiplier.
static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
// Input into the late reverb is decorrelated between four channels. Their
// timings are dependent on a fraction and multiplier. See VerbUpdate() for
// the calculations involved.
static const ALfloat DECO_FRACTION = 1.0f / 32.0f;
static const ALfloat DECO_MULTIPLIER = 2.0f;
// The maximum length of initial delay for the master delay line (a sum of
// the maximum early reflection and late reverb delays).
static const ALfloat MASTER_LINE_LENGTH = 0.3f + 0.1f;
// Find the next power of 2. Actually, this will return the input value if
// it is already a power of 2.
static ALuint NextPowerOf2(ALuint value)
{
ALuint powerOf2 = 1;
@@ -146,8 +168,8 @@ static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
State->Offset - State->Early.Offset[index]);
}
// Given an input sample, this function produces a decorrelated stereo output
// for early reflections.
// Given an input sample, this function produces stereo output for early
// reflections.
static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
{
ALfloat d[4], v, f[4];
@@ -161,11 +183,11 @@ static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *
/* The following uses a lossless scattering junction from waveguide
* theory. It actually amounts to a householder mixing matrix, which
* will produce a maximally diffuse response, and means this can probably
* be considered a simple FDN.
* be considered a simple feedback delay network (FDN).
* N
* ---
* \
* v = 2/N / di
* v = 2/N / d_i
* ---
* i=1
*/
@@ -194,6 +216,20 @@ static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *
out[1] = State->Early.Gain * f[3];
}
// All-pass input/output routine for late reverb.
static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
{
ALfloat out;
out = State->Late.ApCoeff[index] *
DelayLineOut(&State->Late.ApDelay[index],
State->Offset - State->Late.ApOffset[index]);
out -= (State->Late.ApFeedCoeff * in);
DelayLineIn(&State->Late.ApDelay[index], State->Offset,
(State->Late.ApFeedCoeff * out) + in);
return out;
}
// Delay line output routine for late reverb.
static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
{
@@ -205,94 +241,81 @@ static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
// Low-pass filter input/output routine for late reverb.
static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
{
State->Late.LpSample[index] = in + ((State->Late.LpSample[index] - in) *
State->Late.LpCoeff[index]);
State->Late.LpSample[index] = (State->Late.LpCoeff[index][0] * in) +
(State->Late.LpCoeff[index][1] * State->Late.LpSample[index]);
return State->Late.LpSample[index];
}
// Given an input sample, this function produces a decorrelated stereo output
// for late reverb.
static __inline ALvoid LateReverb(ALverbState *State, ALfloat in, ALfloat *out)
// Given four decorrelated input samples, this function produces stereo
// output for late reverb.
static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
{
ALfloat din, d[8], v, dv, f[8];
ALfloat d[4], f[4];
// Since the input will be sent directly to the output as in the early
// reflections function, it needs to take into account some immediate
// absorption.
in = LateLowPassInOut(State, 0, in);
// Obtain the decayed results of the cyclical delay lines, and add the
// corresponding input channels attenuated by density. Then pass the
// results through the low-pass filters.
d[0] = LateLowPassInOut(State, 0, (State->Late.DensityGain * in[0]) +
LateDelayLineOut(State, 0));
d[1] = LateLowPassInOut(State, 1, (State->Late.DensityGain * in[1]) +
LateDelayLineOut(State, 1));
d[2] = LateLowPassInOut(State, 2, (State->Late.DensityGain * in[2]) +
LateDelayLineOut(State, 2));
d[3] = LateLowPassInOut(State, 3, (State->Late.DensityGain * in[3]) +
LateDelayLineOut(State, 3));
// When diffusion is full, no input is directly passed to the variable-
// length delay lines (the last 4).
din = (1.0f - State->Late.Diffusion) * in;
// To help increase diffusion, run each line through an all-pass filter.
// The order of the all-pass filters is selected so that the shortest
// all-pass filter will feed the shortest delay line.
d[0] = LateAllPassInOut(State, 1, d[0]);
d[1] = LateAllPassInOut(State, 3, d[1]);
d[2] = LateAllPassInOut(State, 0, d[2]);
d[3] = LateAllPassInOut(State, 2, d[3]);
// Obtain the decayed results of the fixed-length delay lines.
d[0] = LateDelayLineOut(State, 0);
d[1] = LateDelayLineOut(State, 1);
d[2] = LateDelayLineOut(State, 2);
d[3] = LateDelayLineOut(State, 3);
// Obtain the decayed and low-pass filtered results of the variable-
// length delay lines.
d[4] = LateLowPassInOut(State, 1, LateDelayLineOut(State, 4));
d[5] = LateLowPassInOut(State, 2, LateDelayLineOut(State, 5));
d[6] = LateLowPassInOut(State, 3, LateDelayLineOut(State, 6));
d[7] = LateLowPassInOut(State, 4, LateDelayLineOut(State, 7));
/* Late reverb is done with a modified feedback delay network (FDN)
* topology. Four input lines are each fed through their own all-pass
* filter and then into the mixing matrix. The four outputs of the
* mixing matrix are then cycled back to the inputs. Each output feeds
* a different input to form a circlular feed cycle.
*
* The mixing matrix used is a 4D skew-symmetric rotation matrix derived
* using a single unitary rotational parameter:
*
* [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
* [ -a, d, c, -b ]
* [ -b, -c, d, a ]
* [ -c, b, -a, d ]
*
* The rotation is constructed from the effect's diffusion parameter,
* yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
* with differing signs, and d is the coefficient x. The matrix is thus:
*
* [ x, y, -y, y ] x = 1 - (0.5 diffusion^3)
* [ -y, x, y, y ] y = sqrt((1 - x^2) / 3)
* [ y, -y, x, y ]
* [ -y, -y, -y, x ]
*
* To reduce the number of multiplies, the x coefficient is applied with
* the cyclical delay line coefficients. Thus only the y coefficient is
* applied when mixing, and is modified to be: y / x.
*/
f[0] = d[0] + (State->Late.MixCoeff * ( d[1] - d[2] + d[3]));
f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
f[2] = d[2] + (State->Late.MixCoeff * ( d[0] - d[1] + d[3]));
f[3] = d[3] + (State->Late.MixCoeff * (-d[0] - d[1] - d[2]));
// The waveguide formula used in the early reflections function works
// great for high diffusion, but it is not obviously paramerized to allow
// a variable diffusion. With only limited time and resources, what
// follows is the best variation of that formula I could come up with.
// First, there are 8 delay lines used. The first 4 are fixed-length and
// generate the highest density of the diffuse response. The last 4 are
// variable-length, and are used to smooth out the diffuse response. The
// density effect parameter alters their length. The inner two delay
// lines of each group have their signs reversed (more about this later).
v = (d[0] - d[1] - d[2] + d[3] +
d[4] - d[5] - d[6] + d[7]) * 0.25f;
// Diffusion is applied as a reduction of the junction pressure for all
// branches. This presents two problems. When the diffusion factor (0
// to 1) reaches 0.5, the average feed value is reduced (the junction
// becomes lossy). Thus, at 0.5 the signal decays almost twice as fast
// as it should. The second problem is the introduction of some
// resonant frequencies (coloration). The reversed signs above are used
// to help combat some of the coloration by adding variations along the
// feed cycle.
v *= State->Late.Diffusion;
// Load the junction with the input. To reduce the noticeable echo of
// the longer delay lines (the variable-length ones) the input is loaded
// with the inverse of the effect diffusion. So at full diffusion, the
// input is not applied to the last 4 delay lines. Input signs reversed
// to balance the equation.
dv = v + din;
v += in;
// Output is tapped at the input to the shortest two cyclical delay
// lines, attenuated by the late reverb gain (which is attenuated by the
// mixing coefficient x).
out[0] = State->Late.Gain * f[0];
out[1] = State->Late.Gain * f[1];
// As with the reversed signs above, to balance the equation the signs
// need to be reversed here, too.
f[0] = d[0] - v;
f[1] = d[1] + v;
f[2] = d[2] + v;
f[3] = d[3] - v;
f[4] = d[4] - dv;
f[5] = d[5] + dv;
f[6] = d[6] + dv;
f[7] = d[7] - dv;
// Feed the fixed-length delay lines with their own cycle (0 -> 1 -> 3 ->
// 2 -> 0...).
// The delay lines are fed circularly in the order:
// 0 -> 1 -> 3 -> 2 -> 0 ...
DelayLineIn(&State->Late.Delay[0], State->Offset, f[2]);
DelayLineIn(&State->Late.Delay[1], State->Offset, f[0]);
DelayLineIn(&State->Late.Delay[2], State->Offset, f[3]);
DelayLineIn(&State->Late.Delay[3], State->Offset, f[1]);
// Feed the variable-length delay lines with their cycle (4 -> 6 -> 7 ->
// 5 -> 4...).
DelayLineIn(&State->Late.Delay[4], State->Offset, f[5]);
DelayLineIn(&State->Late.Delay[5], State->Offset, f[7]);
DelayLineIn(&State->Late.Delay[6], State->Offset, f[4]);
DelayLineIn(&State->Late.Delay[7], State->Offset, f[6]);
// Output is derived from the values fed to the inner two variable-length
// delay lines (5 and 6).
out[0] = State->Late.Gain * f[7];
out[1] = State->Late.Gain * f[4];
}
// This creates the reverb state. It should be called only when the reverb
@@ -300,33 +323,46 @@ static __inline ALvoid LateReverb(ALverbState *State, ALfloat in, ALfloat *out)
ALverbState *VerbCreate(ALCcontext *Context)
{
ALverbState *State = NULL;
ALuint length[13], totalLength, index;
ALuint samples, length[13], totalLength, index;
State = malloc(sizeof(ALverbState));
if(!State)
return NULL;
// All line lengths are powers of 2, calculated from the line timings and
// the addition of an extra sample (for safety).
length[0] = NextPowerOf2((ALuint)(MASTER_LINE_LENGTH*Context->Frequency) + 1);
// All line lengths are powers of 2, calculated from their lengths, with
// an additional sample in case of rounding errors.
// See VerbUpdate() for an explanation of the additional calculation
// added to the master line length.
samples = (ALuint)
((MASTER_LINE_LENGTH +
(LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER) *
(DECO_FRACTION * ((DECO_MULTIPLIER * DECO_MULTIPLIER *
DECO_MULTIPLIER) - 1.0f)))) *
Context->Frequency) + 1;
length[0] = NextPowerOf2(samples);
totalLength = length[0];
for(index = 0;index < 4;index++)
{
length[1+index] = NextPowerOf2((ALuint)(EARLY_LINE_LENGTH[index]*Context->Frequency) + 1);
totalLength += length[1+index];
samples = (ALuint)(EARLY_LINE_LENGTH[index] * Context->Frequency) + 1;
length[1 + index] = NextPowerOf2(samples);
totalLength += length[1 + index];
}
for(index = 0;index < 4;index++)
{
length[5+index] = NextPowerOf2((ALuint)(LATE_LINE_LENGTH[index]*Context->Frequency) + 1);
totalLength += length[5+index];
samples = (ALuint)(ALLPASS_LINE_LENGTH[index] * Context->Frequency) + 1;
length[5 + index] = NextPowerOf2(samples);
totalLength += length[5 + index];
}
for(index = 4;index < 8;index++)
for(index = 0;index < 4;index++)
{
length[5+index] = NextPowerOf2((ALuint)(LATE_LINE_LENGTH[index]*(1.0f + LATE_LINE_MULTIPLIER)*Context->Frequency) + 1);
totalLength += length[5+index];
samples = (ALuint)(LATE_LINE_LENGTH[index] *
(1.0f + LATE_LINE_MULTIPLIER) * Context->Frequency) + 1;
length[9 + index] = NextPowerOf2(samples);
totalLength += length[9 + index];
}
// They all share a single sample buffer.
// All lines share a single sample buffer.
State->SampleBuffer = malloc(totalLength * sizeof(ALfloat));
if(!State->SampleBuffer)
{
@@ -344,10 +380,11 @@ ALverbState *VerbCreate(ALCcontext *Context)
State->Tap[0] = 0;
State->Tap[1] = 0;
State->Tap[2] = 0;
State->Tap[3] = 0;
State->Tap[4] = 0;
State->Early.Gain = 0.0f;
// All fixed-length delay lines have their read-write offsets calculated
// one time.
for(index = 0;index < 4;index++)
{
State->Early.Coeff[index] = 0.0f;
@@ -355,30 +392,40 @@ ALverbState *VerbCreate(ALCcontext *Context)
State->Early.Delay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[1 + index];
State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * Context->Frequency);
// The early delay lines have their read offsets calculated once.
State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
Context->Frequency);
}
State->Late.Gain = 0.0f;
State->Late.Diffusion = 0.0f;
for(index = 0;index < 8;index++)
State->Late.DensityGain = 0.0f;
State->Late.ApFeedCoeff = 0.0f;
State->Late.MixCoeff = 0.0f;
for(index = 0;index < 4;index++)
{
State->Late.Coeff[index] = 0.0f;
State->Late.Delay[index].Mask = length[5 + index] - 1;
State->Late.Delay[index].Line = &State->SampleBuffer[totalLength];
State->Late.ApCoeff[index] = 0.0f;
State->Late.ApDelay[index].Mask = length[5 + index] - 1;
State->Late.ApDelay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[5 + index];
// The late all-pass lines have their read offsets calculated once.
State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
Context->Frequency);
}
for(index = 0;index < 4;index++)
{
State->Late.Coeff[index] = 0.0f;
State->Late.Delay[index].Mask = length[9 + index] - 1;
State->Late.Delay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[9 + index];
State->Late.Offset[index] = 0;
if(index < 4)
{
State->Late.Offset[index] = (ALuint)(LATE_LINE_LENGTH[index] * Context->Frequency);
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
else if(index == 4)
{
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
State->Late.LpCoeff[index][0] = 0.0f;
State->Late.LpCoeff[index][1] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
State->Offset = 0;
@@ -402,24 +449,37 @@ ALvoid VerbDestroy(ALverbState *State)
ALvoid VerbUpdate(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
{
ALverbState *State = Slot->ReverbState;
ALuint index, index2;
ALfloat length, lpcoeff, cw, g;
ALuint index;
ALfloat length, mixCoeff, cw, g, lpCoeff;
ALfloat hfRatio = Effect->Reverb.DecayHFRatio;
// Calculate the master gain (from the slot and master reverb gain).
// Calculate the master gain (from the slot and master effect gain).
State->Gain = Slot->Gain * Effect->Reverb.Gain;
// Calculate the initial delay taps.
length = Effect->Reverb.ReflectionsDelay;
State->Tap[0] = (ALuint)(length * Context->Frequency);
length += Effect->Reverb.LateReverbDelay;
State->Tap[1] = (ALuint)(length * Context->Frequency);
// Calculate the early reflections gain. Right now this uses a gain of
// 0.75 to compensate for the increase in density. It should probably
// use a power (RMS) based measurement from the resulting distribution of
// early delay lines.
State->Early.Gain = Effect->Reverb.ReflectionsGain * 0.75f;
length += Effect->Reverb.LateReverbDelay;
/* The four inputs to the late reverb are decorrelated to smooth the
* initial reverb and reduce harsh echos. The timings are calculated as
* multiples of a fraction of the smallest cyclical delay time. This
* result is then adjusted so that the first tap occurs immediately (all
* taps are reduced by the shortest fraction).
*
* offset[index] = ((FRACTION MULTIPLIER^index) - 1) delay
*/
for(index = 0;index < 4;index++)
{
length += LATE_LINE_LENGTH[0] *
(1.0f + (Effect->Reverb.Density * LATE_LINE_MULTIPLIER)) *
(DECO_FRACTION * (pow(DECO_MULTIPLIER, (ALfloat)index) - 1.0f));
State->Tap[1 + index] = (ALuint)(length * Context->Frequency);
}
// Set the early reflections gain.
State->Early.Gain = Effect->Reverb.ReflectionsGain;
// Calculate the gain (coefficient) for each early delay line.
for(index = 0;index < 4;index++)
@@ -427,29 +487,68 @@ ALvoid VerbUpdate(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
Effect->Reverb.LateReverbDelay *
-60.0f / 20.0f);
// Calculate the late reverb gain, adjusted by density, diffusion, and
// decay time. To be accurate, the adjustments should probably use power
// measurements for each contribution, but they are not too bad as they
// are.
State->Late.Gain = Effect->Reverb.LateReverbGain *
(0.45f + (0.55f * Effect->Reverb.Density)) *
(1.0f - (0.25f * Effect->Reverb.Diffusion)) *
(1.0f - (0.025f * Effect->Reverb.DecayTime));
State->Late.Diffusion = Effect->Reverb.Diffusion;
// Calculate the first mixing matrix coefficient (x).
mixCoeff = 1.0f - (0.5f * pow(Effect->Reverb.Diffusion, 3.0f));
// Set the late reverb gain. Since the output is tapped prior to the
// application of the delay line coefficients, this gain needs to be
// attenuated by the mix coefficient from above.
State->Late.Gain = Effect->Reverb.LateReverbGain * mixCoeff;
/* To compensate for changes in modal density and decay time of the late
* reverb signal, the input is attenuated based on the maximal energy of
* the outgoing signal. This is calculated as the ratio between a
* reference value and the current approximation of energy for the output
* signal.
*
* Reverb output matches exponential decay of the form Sum(a^n), where a
* is the attenuation coefficient, and n is the sample ranging from 0 to
* infinity. The signal energy can thus be approximated using the area
* under this curve, calculated as: 1 / (1 - a).
*
* The reference energy is calculated from a signal at the lowest (effect
* at 1.0) density with a decay time of one second.
*
* The coefficient is calculated as the average length of the cyclical
* delay lines. This produces a better result than calculating the gain
* for each line individually (most likely a side effect of diffusion).
*
* The final result is the square root of the ratio bound to a maximum
* value of 1 (no amplification) and attenuated by 1 / sqrt(2) to
* compensate for the four decorrelated inputs.
*/
length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]);
g = length * (1.0f + LATE_LINE_MULTIPLIER) * 0.25f;
g = pow(10.0f, g * -60.0f / 20.0f);
g = 1.0f / (1.0f - g);
length *= 1.0f + (Effect->Reverb.Density * LATE_LINE_MULTIPLIER) * 0.25f;
length = pow(10.0f, length / Effect->Reverb.DecayTime * -60.0f / 20.0f);
length = 1.0f / (1.0f - length);
State->Late.DensityGain = 0.707106f * __min(aluSqrt(g / length), 1.0f);
// Calculate the all-pass feed-back and feed-forward coefficient.
State->Late.ApFeedCoeff = 0.6f * pow(Effect->Reverb.Diffusion, 3.0f);
// Calculate the mixing matrix coefficient (y / x).
g = aluSqrt((1.0f - (mixCoeff * mixCoeff)) / 3.0f);
State->Late.MixCoeff = g / mixCoeff;
for(index = 0;index < 4;index++)
{
// Calculate the gain (coefficient) for each all-pass line.
State->Late.ApCoeff[index] = pow(10.0f, ALLPASS_LINE_LENGTH[index] /
Effect->Reverb.DecayTime *
-60.0f / 20.0f);
}
// The EFX specification does not make it clear whether the air
// absorption parameter should always take effect. Both Generic Software
// and Generic Hardware only apply it when HF limit is flagged, so that's
// what is done here.
// If the HF limit parameter is flagged, calculate an appropriate limit
// based on the air absorption parameter.
if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f)
{
ALfloat limitRatio;
// The following is my best guess at how to limit the HF ratio by the
// air absorption parameter.
// For each of the last 4 delays, find the attenuation due to air
// For each of the cyclical delays, find the attenuation due to air
// absorption in dB (converting delay time to meters using the speed
// of sound). Then reversing the decay equation, solve for HF ratio.
// The delay length is cancelled out of the equation, so it can be
@@ -466,59 +565,58 @@ ALvoid VerbUpdate(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
hfRatio = __min(hfRatio, limitRatio);
}
cw = cos(2.0f*3.141592654f * LOWPASSFREQCUTOFF / Context->Frequency);
// Calculate the filter frequency for low-pass or high-pass depending on
// whether the HF ratio is above 1.
cw = 2.0f * M_PI * LOWPASSFREQCUTOFF / Context->Frequency;
if(hfRatio > 1.0f)
cw = M_PI - cw;
cw = cos(cw);
for(index = 0;index < 8;index++)
for(index = 0;index < 4;index++)
{
// Calculate the length (in seconds) of each delay line.
length = LATE_LINE_LENGTH[index];
if(index >= 4)
{
// Calculate the delay offset for the variable-length delay
// lines.
length *= 1.0f + (Effect->Reverb.Density * LATE_LINE_MULTIPLIER);
State->Late.Offset[index] = (ALuint)(length * Context->Frequency);
}
// Calculate the gain (coefficient) for each line.
// Calculate the length (in seconds) of each cyclical delay line.
length = LATE_LINE_LENGTH[index] * (1.0f + (Effect->Reverb.Density *
LATE_LINE_MULTIPLIER));
// Calculate the delay offset for the cyclical delay lines.
State->Late.Offset[index] = (ALuint)(length * Context->Frequency);
// Calculate the gain (coefficient) for each cyclical line.
State->Late.Coeff[index] = pow(10.0f, length / Effect->Reverb.DecayTime *
-60.0f / 20.0f);
if(index >= 4)
{
index2 = index - 3;
// Calculate the decay equation for each low-pass filter.
g = pow(10.0f, length / (Effect->Reverb.DecayTime * hfRatio) *
-60.0f / 20.0f) /
State->Late.Coeff[index];
g = __max(g, 0.1f);
g *= g;
// Calculate the gain (coefficient) for each low-pass filter.
lpcoeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
lpcoeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
// Calculate the decay equation for each low-pass filter.
g = pow(10.0f, length / (Effect->Reverb.DecayTime * hfRatio) *
-60.0f / 20.0f);
if (hfRatio > 1.0f)
g = State->Late.Coeff[index] / g;
else
g = g / State->Late.Coeff[index];
g = __max(g, 0.1f);
g *= g;
// Very low decay times will produce minimal output, so apply an
// upper bound to the coefficient.
State->Late.LpCoeff[index2] = __min(lpcoeff, 0.98f);
// Calculate the gain (coefficient) for each low-pass filter.
lpCoeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
lpCoeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
// Very low decay times will produce minimal output, so apply an
// upper bound to the coefficient.
lpCoeff = __min(lpCoeff, 0.98f);
// Calculate the filter coefficients for high-pass or low-pass
// dependent on HF ratio being above 1.
if(hfRatio > 1.0f) {
State->Late.LpCoeff[index][0] = 1.0f + lpCoeff;
State->Late.LpCoeff[index][1] = -lpCoeff;
} else {
State->Late.LpCoeff[index][0] = 1.0f - lpCoeff;
State->Late.LpCoeff[index][1] = lpCoeff;
}
// Attenuate the cyclical line coefficients by the mixing coefficient
// (x).
State->Late.Coeff[index] *= mixCoeff;
}
// This just calculates the coefficient for the late reverb input low-
// pass filter. It is calculated based the average (hence -30 instead
// of -60) length of the inner two variable-length delay lines.
length = LATE_LINE_LENGTH[5] * (1.0f + Effect->Reverb.Density * LATE_LINE_MULTIPLIER) +
LATE_LINE_LENGTH[6] * (1.0f + Effect->Reverb.Density * LATE_LINE_MULTIPLIER);
g = pow(10.0f, ((length / (Effect->Reverb.DecayTime * hfRatio))-
(length / Effect->Reverb.DecayTime)) * -30.0f / 20.0f);
g = __max(g, 0.1f);
g *= g;
lpcoeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
lpcoeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
State->Late.LpCoeff[0] = __min(lpcoeff, 0.98f);
}
// This processes the reverb state, given the input samples and an output
@@ -526,7 +624,7 @@ ALvoid VerbUpdate(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALuint index;
ALfloat in, early[2], late[2], out[2];
ALfloat in[4], early[2], late[2], out[2];
for(index = 0;index < SamplesToDo;index++)
{
@@ -534,11 +632,14 @@ ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *Sample
DelayLineIn(&State->Delay, State->Offset, SamplesIn[index]);
// Calculate the early reflection from the first delay tap.
in = DelayLineOut(&State->Delay, State->Offset - State->Tap[0]);
EarlyReflection(State, in, early);
in[0] = DelayLineOut(&State->Delay, State->Offset - State->Tap[0]);
EarlyReflection(State, in[0], early);
// Calculate the late reverb from the second delay tap.
in = DelayLineOut(&State->Delay, State->Offset - State->Tap[1]);
// Calculate the late reverb from the last four delay taps.
in[0] = DelayLineOut(&State->Delay, State->Offset - State->Tap[1]);
in[1] = DelayLineOut(&State->Delay, State->Offset - State->Tap[2]);
in[2] = DelayLineOut(&State->Delay, State->Offset - State->Tap[3]);
in[3] = DelayLineOut(&State->Delay, State->Offset - State->Tap[4]);
LateReverb(State, in, late);
// Mix early reflections and late reverb.
+19 -34
View File
@@ -103,11 +103,10 @@ MAKE_FUNC(snd_ctl_card_info_get_name);
MAKE_FUNC(snd_card_next);
#undef MAKE_FUNC
#define MAX_DEVICES 16
#define MAX_ALL_DEVICES 32
static ALCchar *alsaDevice;
static DevMap allDevNameMap[MAX_ALL_DEVICES];
static ALCchar *alsaDeviceList[MAX_DEVICES];
static DevMap allCaptureDevNameMap[MAX_ALL_DEVICES];
static int xrun_recovery(snd_pcm_t *handle, int err)
@@ -321,6 +320,7 @@ static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceNam
snd_pcm_hw_params_t *p = NULL;
snd_pcm_access_t access;
unsigned int periods;
unsigned int rate;
alsa_data *data;
char driver[64];
const char *str;
@@ -348,21 +348,15 @@ static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceNam
goto open_alsa;
}
}
for(idx = 0;idx < MAX_DEVICES;idx++)
if(strcmp(deviceName, alsaDevice) == 0)
{
if(alsaDeviceList[idx] &&
strcmp(deviceName, alsaDeviceList[idx]) == 0)
{
device->szDeviceName = alsaDeviceList[idx];
if(idx > 0)
sprintf(driver, "hw:%zd,0", idx-1);
goto open_alsa;
}
device->szDeviceName = alsaDevice;
goto open_alsa;
}
return ALC_FALSE;
}
else
device->szDeviceName = alsaDeviceList[0];
device->szDeviceName = alsaDevice;
open_alsa:
data = (alsa_data*)calloc(1, sizeof(alsa_data));
@@ -401,6 +395,7 @@ open_alsa:
periods = GetConfigValueInt("alsa", "periods", 0);
bufferSizeInFrames = device->UpdateSize;
rate = device->Frequency;
str = GetConfigValue("alsa", "mmap", "true");
allowmmap = (strcasecmp(str, "true") == 0 ||
@@ -422,7 +417,7 @@ open_alsa:
/* set periods (implicitly constrains period/buffer parameters) */
(!periods || ok(psnd_pcm_hw_params_set_periods_near(data->pcmHandle, p, &periods, NULL), "set periods near")) &&
/* set rate (implicitly constrains period/buffer parameters) */
ok(psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &device->Frequency, NULL), "set rate near") &&
ok(psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL), "set rate near") &&
/* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
ok(psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames), "set buffer size near") &&
/* install and prepare hardware configuration */
@@ -456,8 +451,6 @@ open_alsa:
psnd_pcm_hw_params_free(p);
device->UpdateSize = bufferSizeInFrames;
data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
@@ -498,6 +491,9 @@ open_alsa:
return ALC_FALSE;
}
device->UpdateSize = bufferSizeInFrames;
device->Frequency = rate;
return ALC_TRUE;
}
@@ -901,7 +897,7 @@ void alc_alsa_init(BackendFuncs *func_list)
} while(0)
#else
str = NULL;
alsa_handle = 0xDEADBEEF;
alsa_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
@@ -962,15 +958,11 @@ LOAD_FUNC(snd_card_next);
card = -1;
if(psnd_card_next(&card) < 0 || card < 0)
AL_PRINT("no playback cards found...\n");
else
{
alsaDeviceList[0] = AppendDeviceList("ALSA Software on default");
allDevNameMap[0].name = AppendAllDeviceList("ALSA Software on default");
}
alsaDevice = AppendDeviceList("ALSA Software");
allDevNameMap[0].name = AppendAllDeviceList("ALSA Software on default");
while (card >= 0) {
int firstDev = 1;
sprintf(name, "hw:%d", card);
if ((err = psnd_ctl_open(&handle, name, 0)) < 0) {
AL_PRINT("control open (%i): %s\n", card, psnd_strerror(err));
@@ -991,13 +983,6 @@ LOAD_FUNC(snd_card_next);
if (dev < 0)
break;
if(firstDev && card < MAX_DEVICES-1) {
firstDev = 0;
snprintf(name, sizeof(name), "ALSA Software on %s",
psnd_ctl_card_info_get_name(info));
alsaDeviceList[card+1] = AppendDeviceList(name);
}
psnd_pcm_info_set_device(pcminfo, dev);
psnd_pcm_info_set_subdevice(pcminfo, 0);
psnd_pcm_info_set_stream(pcminfo, stream);
@@ -1009,8 +994,8 @@ LOAD_FUNC(snd_card_next);
cname = psnd_ctl_card_info_get_name(info);
dname = psnd_pcm_info_get_name(pcminfo);
snprintf(name, sizeof(name), "ALSA Software on %s [%s]",
cname, dname);
snprintf(name, sizeof(name), "ALSA Software on %s [%s] (hw:%d,%d)",
cname, dname, card, dev);
allDevNameMap[idx].name = AppendAllDeviceList(name);
allDevNameMap[idx].card = card;
allDevNameMap[idx].dev = dev;
@@ -1068,8 +1053,8 @@ next_card:
cname = psnd_ctl_card_info_get_name(info);
dname = psnd_pcm_info_get_name(pcminfo);
snprintf(name, sizeof(name), "ALSA Capture on %s [%s]",
cname, dname);
snprintf(name, sizeof(name), "ALSA Capture on %s [%s] (hw:%d,%d)",
cname, dname, card, dev);
allCaptureDevNameMap[idx].name = AppendCaptureDeviceList(name);
allCaptureDevNameMap[idx].card = card;
allCaptureDevNameMap[idx].dev = dev;
+36 -2
View File
@@ -39,6 +39,10 @@
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
static void *ds_handle;
static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
// Since DSound doesn't report the fragment size, emulate it
static int num_frags;
@@ -136,6 +140,9 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
DWORD speakers;
HRESULT hr;
if(ds_handle == NULL)
return ALC_FALSE;
if(deviceName)
{
int i;
@@ -167,7 +174,7 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
}
//DirectSound Init code
hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
hr = pDirectSoundCreate(guid, &pData->lpDS, NULL);
if(SUCCEEDED(hr))
hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
@@ -411,10 +418,37 @@ void alcDSoundInit(BackendFuncs *FuncList)
*FuncList = DSoundFuncs;
#ifdef _WIN32
ds_handle = LoadLibraryA("dsound.dll");
if(ds_handle == NULL)
{
AL_PRINT("Failed to load dsound.dll\n");
return;
}
#define LOAD_FUNC(f) do { \
p##f = (void*)GetProcAddress((HMODULE)ds_handle, #f); \
if(p##f == NULL) \
{ \
FreeLibrary(ds_handle); \
ds_handle = NULL; \
AL_PRINT("Could not load %s from dsound.dll\n", #f); \
return; \
} \
} while(0)
#else
ds_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
LOAD_FUNC(DirectSoundCreate);
LOAD_FUNC(DirectSoundEnumerateA);
#undef LOAD_FUNC
num_frags = GetConfigValueInt("dsound", "periods", 4);
if(num_frags < 2) num_frags = 2;
hr = DirectSoundEnumerate(DSoundEnumDevices, &iter);
hr = pDirectSoundEnumerateA(DSoundEnumDevices, &iter);
if(FAILED(hr))
AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
}
+3 -4
View File
@@ -221,8 +221,6 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
}
#undef ok
device->Frequency = ossSpeed;
if((int)aluChannelsFromFormat(device->Format) != numChannels)
{
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), numChannels);
@@ -240,8 +238,6 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
return ALC_FALSE;
}
device->UpdateSize = info.fragsize / frameSize;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
@@ -255,6 +251,9 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName
return ALC_FALSE;
}
device->Frequency = ossSpeed;
device->UpdateSize = info.fragsize / frameSize;
return ALC_TRUE;
}
+239
View File
@@ -0,0 +1,239 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 1999-2007 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <portaudio.h>
static void *pa_handle;
#define MAKE_FUNC(x) static typeof(x) * p##x
MAKE_FUNC(Pa_Initialize);
MAKE_FUNC(Pa_GetErrorText);
MAKE_FUNC(Pa_StartStream);
MAKE_FUNC(Pa_StopStream);
MAKE_FUNC(Pa_OpenStream);
MAKE_FUNC(Pa_CloseStream);
MAKE_FUNC(Pa_GetDefaultOutputDevice);
#undef MAKE_FUNC
static char *pa_device;
typedef struct {
PaStream *stream;
} pa_data;
static int pa_callback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData)
{
ALCdevice *device = (ALCdevice*)userData;
int frameSize;
(void)inputBuffer;
(void)timeInfo;
(void)statusFlags;
frameSize = aluBytesFromFormat(device->Format);
frameSize *= aluChannelsFromFormat(device->Format);
SuspendContext(NULL);
aluMixData(device->Context, outputBuffer, framesPerBuffer*frameSize, device->Format);
ProcessContext(NULL);
return 0;
}
static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
PaStreamParameters outParams;
pa_data *data;
int periods;
PaError err;
if(pa_handle == NULL)
return ALC_FALSE;
if(deviceName)
{
if(strcmp(deviceName, pa_device) != 0)
return ALC_FALSE;
}
device->szDeviceName = pa_device;
data = (pa_data*)calloc(1, sizeof(pa_data));
device->ExtraData = data;
outParams.device = GetConfigValueInt("port", "device", -1);
if(outParams.device < 0)
outParams.device = pPa_GetDefaultOutputDevice();
outParams.suggestedLatency = (float)device->UpdateSize /
(float)device->Frequency;
outParams.hostApiSpecificStreamInfo = NULL;
switch(aluBytesFromFormat(device->Format))
{
case 1:
outParams.sampleFormat = paUInt8;
break;
case 2:
outParams.sampleFormat = paInt16;
break;
default:
outParams.sampleFormat = -1;
AL_PRINT("Unknown format?! %x\n", device->Format);
}
periods = GetConfigValueInt("port", "periods", 4);
if((int)periods <= 0)
periods = 4;
outParams.channelCount = aluChannelsFromFormat(device->Format);
err = pPa_OpenStream(&data->stream, NULL, &outParams, device->Frequency,
device->UpdateSize/periods, paNoFlag,
pa_callback, device);
if(err != paNoError)
{
AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err));
device->ExtraData = NULL;
free(data);
return ALC_FALSE;
}
err = pPa_StartStream(data->stream);
if(err != paNoError)
{
AL_PRINT("Pa_StartStream() returned an error: %s\n", pPa_GetErrorText(err));
pPa_CloseStream(data->stream);
device->ExtraData = NULL;
free(data);
return ALC_FALSE;
}
device->UpdateSize /= periods;
return ALC_TRUE;
}
static void pa_close_playback(ALCdevice *device)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = pPa_StopStream(data->stream);
if(err != paNoError)
fprintf(stderr, "Error stopping stream: %s\n", pPa_GetErrorText(err));
err = pPa_CloseStream(data->stream);
if(err != paNoError)
fprintf(stderr, "Error closing stream: %s\n", pPa_GetErrorText(err));
free(data);
device->ExtraData = NULL;
}
static ALCboolean pa_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
{
return ALC_FALSE;
(void)device;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
}
static const BackendFuncs pa_funcs = {
pa_open_playback,
pa_close_playback,
pa_open_capture,
NULL,
NULL,
NULL,
NULL,
NULL
};
void alc_pa_init(BackendFuncs *func_list)
{
const char *str;
PaError err;
*func_list = pa_funcs;
#ifdef HAVE_DLFCN_H
#if defined(__APPLE__) && defined(__MACH__)
# define PALIB "libportaudio.2.dylib"
#else
# define PALIB "libportaudio.so.2"
#endif
pa_handle = dlopen(PALIB, RTLD_NOW);
if(!pa_handle)
return;
dlerror();
#define LOAD_FUNC(f) do { \
p##f = (typeof(f)*)dlsym(pa_handle, #f); \
if((str=dlerror()) != NULL) \
{ \
dlclose(pa_handle); \
pa_handle = NULL; \
AL_PRINT("Could not load %s from "PALIB": %s\n", #f, str); \
return; \
} \
} while(0)
#else
str = NULL;
pa_handle = (void*)0xDEADBEEF;
#define LOAD_FUNC(f) p##f = f
#endif
LOAD_FUNC(Pa_Initialize);
LOAD_FUNC(Pa_GetErrorText);
LOAD_FUNC(Pa_StartStream);
LOAD_FUNC(Pa_StopStream);
LOAD_FUNC(Pa_OpenStream);
LOAD_FUNC(Pa_CloseStream);
LOAD_FUNC(Pa_GetDefaultOutputDevice);
#undef LOAD_FUNC
if((err=pPa_Initialize()) != paNoError)
{
AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err));
return;
}
pa_device = AppendDeviceList("PortAudio Software");
AppendAllDeviceList(pa_device);
}
+2 -1
View File
@@ -50,6 +50,7 @@ static ALuint WaveProc(ALvoid *ptr)
ALuint frameSize;
ALuint now, last;
size_t WriteCnt;
size_t fs;
ALuint avail;
union {
short s;
@@ -89,7 +90,7 @@ static ALuint WaveProc(ALvoid *ptr)
fputc(bytes[i^1], data->f);
}
else
fwrite(data->buffer, frameSize, WriteCnt, data->f);
fs = fwrite(data->buffer, frameSize, WriteCnt, data->f);
if(ferror(data->f))
{
AL_PRINT("Error writing to file\n");
+47 -31
View File
@@ -26,6 +26,7 @@ OPTION(OSS "Check for OSS backend" ON)
OPTION(SOLARIS "Check for Solaris backend" ON)
OPTION(DSOUND "Check for DirectSound backend" ON)
OPTION(WINMM "Check for Windows Multimedia backend" ON)
OPTION(PORTAUDIO "Check for PortAudio backend" ON)
OPTION(DLOPEN "Check for the dlopen API for loading optional libs" ON)
@@ -33,19 +34,17 @@ OPTION(WERROR "Treat compile warnings as errors" OFF)
OPTION(EXAMPLES "Build example programs" ON)
OPTION(XCOMPILEWIN32 "Cross-compile to Win32" OFF)
IF(WIN32 OR XCOMPILEWIN32)
SET(LIBNAME openal32)
IF(WIN32)
SET(LIBNAME OpenAL32)
ADD_DEFINITIONS("-D_WIN32")
ELSE()
SET(LIBNAME openal)
ENDIF()
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "6")
SET(LIB_BUILD_VERSION "372")
SET(LIB_MINOR_VERSION "7")
SET(LIB_BUILD_VERSION "411")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_BUILD_VERSION}")
IF(NOT DEFINED LIB_INSTALL_DIR)
SET(LIB_INSTALL_DIR "lib")
@@ -66,6 +65,11 @@ IF(NOT CMAKE_BUILD_TYPE)
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
ENDIF()
IF(NOT CMAKE_DEBUG_POSTFIX)
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING
"Library postfix for debug builds. Normally left blank."
FORCE)
ENDIF()
IF(MSVC)
# ???
@@ -76,7 +80,7 @@ IF(MSVC)
ELSE()
ADD_DEFINITIONS(-Wall)
CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA)
IF("${HAVE_W_EXTRA}")
IF(HAVE_W_EXTRA)
ADD_DEFINITIONS(-Wextra)
ENDIF()
@@ -98,15 +102,15 @@ ELSE()
FORCE)
# Set visibility options if available
IF(NOT WIN32 AND NOT XCOMPILEWIN32)
IF(NOT WIN32)
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_SWITCH)
IF("${HAVE_VISIBILITY_SWITCH}")
IF(HAVE_VISIBILITY_SWITCH)
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((visibility(\"default\")));
int main() {return 0;}" HAVE_GCC_VISIBILITY)
IF("${HAVE_GCC_VISIBILITY}")
IF(HAVE_GCC_VISIBILITY)
ADD_DEFINITIONS(-fvisibility=hidden -DHAVE_GCC_VISIBILITY)
ENDIF()
ENDIF()
@@ -118,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)
@@ -283,16 +289,17 @@ ENDIF()
IF(DSOUND)
CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
IF(HAVE_DSOUND_H)
SET(HAVE_DSOUND 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c)
SET(BACKENDS "${BACKENDS} DirectSound,")
CHECK_LIBRARY_EXISTS(dsound DirectSoundCreate "" HAVE_LIBDSOUND)
IF(HAVE_LIBDSOUND OR WIN32)
SET(HAVE_DSOUND 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c)
SET(CMAKE_REQUIRED_LIBRARIES dsound)
CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBDSOUND)
SET(CMAKE_REQUIRED_LIBRARIES "")
# CHECK_LIBRARY_EXISTS(dsound DirectSoundCreate "" HAVE_LIBDSOUND)
IF(HAVE_LIBDSOUND)
SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
IF(WIN32)
SET(BACKENDS "${BACKENDS} DirectSound,")
ELSE()
SET(BACKENDS "${BACKENDS} DirectSound \(linked\),")
SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
ENDIF()
@@ -315,6 +322,24 @@ IF(HAVE_WINDOWS_H)
ENDIF()
ENDIF()
# Check PortAudio backend
IF(PORTAUDIO)
CHECK_INCLUDE_FILE(portaudio.h HAVE_PORTAUDIO_H)
IF(HAVE_PORTAUDIO_H)
CHECK_LIBRARY_EXISTS(portaudio Pa_Initialize "" HAVE_LIBPORTAUDIO)
IF(HAVE_LIBPORTAUDIO)
SET(HAVE_PORTAUDIO 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/portaudio.c)
IF(HAVE_DLFCN_H)
SET(BACKENDS "${BACKENDS} PortAudio,")
ELSE()
SET(BACKENDS "${BACKENDS} PortAudio \(linked\),")
SET(EXTRA_LIBS portaudio ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
ENDIF()
# This is always available
SET(BACKENDS "${BACKENDS} WaveFile")
@@ -347,15 +372,6 @@ SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
IF(WIN32)
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
ENDIF()
IF(XCOMPILEWIN32)
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "" SUFFIX .dll)
IF(EXAMPLES)
SET(EXAMPLES OFF)
MESSAGE(STATUS "")
MESSAGE(STATUS "Building examples disabled when cross-compiling")
ENDIF()
ENDIF()
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES OUTPUT_NAME ${LIBNAME})
TARGET_LINK_LIBRARIES(${LIBNAME} ${EXTRA_LIBS})
@@ -371,7 +387,7 @@ INSTALL(FILES include/AL/al.h
DESTINATION include/AL
)
INSTALL(FILES "${OpenAL_BINARY_DIR}/admin/pkgconfig/openal.pc"
DESTINATION lib/pkgconfig)
DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
IF(EXAMPLES)
ADD_EXECUTABLE(openal-info examples/openal-info.c)
@@ -388,7 +404,7 @@ MESSAGE(STATUS "Building OpenAL with support for the following backends:")
MESSAGE(STATUS " ${BACKENDS}")
MESSAGE(STATUS "")
IF(WIN32 OR XCOMPILEWIN32)
IF(WIN32)
IF(NOT HAVE_DSOUND)
MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output")
MESSAGE(STATUS " This is probably NOT what you want!")
+2 -1
View File
@@ -2,13 +2,14 @@
#define _AL_FILTER_H_
#include "AL/al.h"
#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
ALfloat history[4];
ALfloat history[OUTPUTCHANNELS*2];
ALfloat coeff;
} FILTER;
+9
View File
@@ -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*);
@@ -147,6 +150,7 @@ void alc_oss_init(BackendFuncs *func_list);
void alc_solaris_init(BackendFuncs *func_list);
void alcDSoundInit(BackendFuncs *func_list);
void alcWinMMInit(BackendFuncs *FuncList);
void alc_pa_init(BackendFuncs *func_list);
void alc_wave_init(BackendFuncs *func_list);
@@ -205,6 +209,11 @@ struct ALCcontext_struct
ALint lNumMonoSources;
ALint lNumStereoSources;
ALfloat PanningLUT[OUTPUTCHANNELS * LUT_NUM];
ALint NumChan;
ALfloat ChannelMatrix[OUTPUTCHANNELS][OUTPUTCHANNELS];
ALCdevice *Device;
const ALCchar *ExtensionList;
+1
View File
@@ -48,6 +48,7 @@ typedef struct ALsource
ALfloat vOrientation[3];
ALboolean bHeadRelative;
ALboolean bLooping;
ALenum DistanceModel;
ALuint ulBufferID;
+3 -1
View File
@@ -11,11 +11,12 @@ extern "C" {
enum {
FRONT_LEFT = 0,
FRONT_RIGHT,
FRONT_CENTER,
SIDE_LEFT,
SIDE_RIGHT,
BACK_LEFT,
BACK_RIGHT,
CENTER,
BACK_CENTER,
LFE,
OUTPUTCHANNELS
@@ -25,6 +26,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
+25 -4
View File
@@ -32,7 +32,7 @@
#include "alThunk.h"
#include "alAuxEffectSlot.h"
static ALvoid InitSourceParams(ALsource *pSource);
static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource);
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize);
static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
static ALint GetByteOffset(ALsource *pSource);
@@ -78,7 +78,7 @@ ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->source = sources[i];
InitSourceParams(*list);
InitSourceParams(Context, *list);
Context->SourceCount++;
i++;
@@ -359,7 +359,7 @@ ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
break;
case AL_ROOM_ROLLOFF_FACTOR:
if (flValue >= 0.0f && flValue <= 1.0f)
if (flValue >= 0.0f && flValue <= 10.0f)
pSource->RoomRolloffFactor = flValue;
else
alSetError(AL_INVALID_VALUE);
@@ -704,6 +704,19 @@ ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
alSetError(AL_INVALID_VALUE);
break;
case AL_DISTANCE_MODEL:
if(lValue == AL_NONE ||
lValue == AL_INVERSE_DISTANCE ||
lValue == AL_INVERSE_DISTANCE_CLAMPED ||
lValue == AL_LINEAR_DISTANCE ||
lValue == AL_LINEAR_DISTANCE_CLAMPED ||
lValue == AL_EXPONENT_DISTANCE ||
lValue == AL_EXPONENT_DISTANCE_CLAMPED)
pSource->DistanceModel = lValue;
else
alSetError(AL_INVALID_VALUE);
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -819,6 +832,7 @@ ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plVa
case AL_DIRECT_FILTER_GAINHF_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DISTANCE_MODEL:
alSourcei(source, eParam, plValues[0]);
break;
@@ -1212,6 +1226,10 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
*plValue = (ALint)pSource->DopplerFactor;
break;
case AL_DISTANCE_MODEL:
*plValue = pSource->DistanceModel;
break;
default:
alSetError(AL_INVALID_ENUM);
break;
@@ -1326,6 +1344,7 @@ ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValue
case AL_DIRECT_FILTER_GAINHF_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DISTANCE_MODEL:
alGetSourcei(source, eParam, plValues);
break;
@@ -1979,7 +1998,7 @@ ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint
}
static ALvoid InitSourceParams(ALsource *pSource)
static ALvoid InitSourceParams(ALCcontext *Context, ALsource *pSource)
{
pSource->flInnerAngle = 360.0f;
pSource->flOuterAngle = 360.0f;
@@ -2010,6 +2029,8 @@ static ALvoid InitSourceParams(ALsource *pSource)
pSource->RoomRolloffFactor = 0.0f;
pSource->DopplerFactor = 1.0f;
pSource->DistanceModel = Context->DistanceModel;
pSource->state = AL_INITIAL;
pSource->lSourceType = AL_UNDETERMINED;
+4
View File
@@ -24,6 +24,7 @@
#include "alMain.h"
#include "AL/alc.h"
#include "alError.h"
#include "alSource.h"
#include "alState.h"
static const ALchar alVendor[] = "OpenAL Community";
@@ -644,6 +645,7 @@ ALAPI ALvoid ALAPIENTRY alSpeedOfSound(ALfloat flSpeedOfSound)
ALAPI ALvoid ALAPIENTRY alDistanceModel(ALenum value)
{
ALCcontext *Context;
ALsource *Source;
Context=alcGetCurrentContext();
if (Context)
@@ -660,6 +662,8 @@ ALAPI ALvoid ALAPIENTRY alDistanceModel(ALenum value)
case AL_EXPONENT_DISTANCE:
case AL_EXPONENT_DISTANCE_CLAMPED:
Context->DistanceModel = value;
for(Source = Context->Source;Source != NULL;Source = Source->next)
Source->DistanceModel = value;
break;
default:
+24
View File
@@ -0,0 +1,24 @@
# Cross-compiling requires CMake 2.6 or newer. To cross-compile, first modify
# this file to set the proper settings and paths. Then use it from CMakeConf/
# like:
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt \
# -DCMAKE_INSTALL_PREFIX=/usr/mingw32/mingw
# If you already have a toolchain file setup, you may use that instead of this
# file.
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER mingw32-gcc)
SET(CMAKE_CXX_COMPILER mingw32-g++)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/mingw32/mingw)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+49 -7
View File
@@ -47,19 +47,19 @@ sources = 256 # Sets the maximum number of allocatable sources. Lower values
# may help for systems with apps that try to play more sounds
# than the CPU can handle. Default is 256
stereodup = # Sets whether to duplicate stereo sounds on the rear speakers for
# 4+ channel output. This can make stereo sources substantially
# louder than mono or even 4+ channel sources, but provides a
# "fuller" playback quality. True, yes, on, and non-0 values will
# duplicate stereo sources. 0 and anything else will cause stereo
# sounds to only play out the front speakers.
stereodup = # Sets whether to duplicate stereo sounds on the rear and side
# speakers for 4+ channel output. This can make stereo sources
# substantially louder than mono or even 4+ channel sources, but
# provides a "fuller" playback quality. True, yes, on, and non-0
# values will duplicate stereo sources. 0 and anything else will
# cause stereo sounds to only play out the front speakers.
# Default is false
drivers = # Sets the backend driver list order, comma-seperated. Unknown
# backends and duplicated names are ignored, and unlisted backends
# won't be considered for use. An empty list means the default.
# Default is:
# alsa,oss,solaris,dsound,winmm,wave
# alsa,oss,solaris,dsound,winmm,port,wave
excludefx = # Sets which effects to exclude, preventing apps from using them.
# This can help for apps that try to use effects which are too CPU
@@ -67,6 +67,42 @@ excludefx = # Sets which effects to exclude, preventing apps from using them.
# reverb
# Default is empty (all available effects enabled)
layout_STEREO = # Sets the speaker layout when using stereo output. Values are
specified in degrees, where 0 is straight in front, negative
goes left, and positive goes right. The values must define a
circular pattern, starting with the back-left at the most
negative, around the front to back-center. Unspecified
speakers will remain at their default position. Available
speakers are front-left(fl) and front-right(fr).
The default is:
fl=-90, fr=90
layout_QUAD = # Sets the speaker layout when using quadriphonic output.
Available speakers are back-left(bl), front-left(fl),
front-right(fr), and back-right(br).
The default is:
bl=-135, fl=-45, fr=45, br=135
layout_51CHN = # Sets the speaker layout when using 5.1 output. Available
speakers are back-left(bl), front-left(fl), front-center(fc),
front-right(fr), and back-right(br).
The default is:
bl=-110, fl=-30, fc=0, fr=30, br=110
layout_61CHN = # Sets the speaker layout when using 6.1 output. Available
speakers are side-left(sl), front-left(fl), front-center(fc),
front-right(fr), side-right(sr), and back-center(bc).
The default is:
sl=-90, fl=-30, fc=0, fr=30, sr=90, bc=180
layout_71CHN = # Sets the speaker layout when using 7.1 output. Available
speakers are back-left(bl), side-left(sl), front-left(fl),
front-center(fc), front-right(fr), side-right(sr), and
back-right(br).
The default is:
bl=-150, sl=-90, fl=-30, fc=0, fr=30, sr=90 br=150
[alsa] # ALSA backend stuff
device = default # Sets the device name for the default playback device.
# Default is default
@@ -100,6 +136,12 @@ periods = 4 # Sets the number of updates for the output buffer. Default is 4
[winmm] # Windows Multimedia backend stuff
# Nothing yet...
[port] # PortAudio backend stuff
device = -1 # Sets the device index for output. Negative values will use the
# default as given by PortAudio itself. Default is -1
periods = 4 # Sets the number of update buffers. Default is 4
[wave] # Wave File Writer stuff
file = # Sets the filename of the wave file to write to. An empty name
# prevents the backend from opening, even when explicitly requested.
+9
View File
@@ -19,6 +19,9 @@
/* Define if we have the Windows Multimedia backend */
#cmakedefine HAVE_WINMM
/* Define if we have the PortAudio backend */
#cmakedefine HAVE_PORTAUDIO
/* Define if we have dlfcn.h */
#cmakedefine HAVE_DLFCN_H
@@ -28,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