Merge branch 'master' of git://repo.or.cz/openal-soft

master
Aaron Lindsay 2012-03-13 22:53:12 -04:00
commit eb37458eb1
50 changed files with 5642 additions and 2330 deletions

648
Alc/ALc.c

File diff suppressed because it is too large Load Diff

361
Alc/ALu.c
View File

@ -37,6 +37,11 @@
#include "bs2b.h"
struct ChanMap {
enum Channel channel;
ALfloat angle;
};
/* Cone scalar */
ALfloat ConeScale = 0.5f;
@ -58,56 +63,69 @@ static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[
ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
{
static const ALfloat angles_Mono[1] = { 0.0f };
static const ALfloat angles_Stereo[2] = { -30.0f, 30.0f };
static const ALfloat angles_Rear[2] = { -150.0f, 150.0f };
static const ALfloat angles_Quad[4] = { -45.0f, 45.0f, -135.0f, 135.0f };
static const ALfloat angles_X51[6] = { -30.0f, 30.0f, 0.0f, 0.0f,
-110.0f, 110.0f };
static const ALfloat angles_X61[7] = { -30.0f, 30.0f, 0.0f, 0.0f,
180.0f, -90.0f, 90.0f };
static const ALfloat angles_X71[8] = { -30.0f, 30.0f, 0.0f, 0.0f,
-110.0f, 110.0f, -90.0f, 90.0f };
static const enum Channel chans_Mono[1] = { FRONT_CENTER };
static const enum Channel chans_Stereo[2] = { FRONT_LEFT, FRONT_RIGHT };
static const enum Channel chans_Rear[2] = { BACK_LEFT, BACK_RIGHT };
static const enum Channel chans_Quad[4] = { FRONT_LEFT, FRONT_RIGHT,
BACK_LEFT, BACK_RIGHT };
static const enum Channel chans_X51[6] = { FRONT_LEFT, FRONT_RIGHT,
FRONT_CENTER, LFE,
BACK_LEFT, BACK_RIGHT };
static const enum Channel chans_X61[7] = { FRONT_LEFT, FRONT_RIGHT,
FRONT_CENTER, LFE, BACK_CENTER,
SIDE_LEFT, SIDE_RIGHT };
static const enum Channel chans_X71[8] = { FRONT_LEFT, FRONT_RIGHT,
FRONT_CENTER, LFE,
BACK_LEFT, BACK_RIGHT,
SIDE_LEFT, SIDE_RIGHT };
static const struct ChanMap MonoMap[1] = { { FRONT_CENTER, 0.0f } };
static const struct ChanMap StereoMap[2] = {
{ FRONT_LEFT, -30.0f * F_PI/180.0f },
{ FRONT_RIGHT, 30.0f * F_PI/180.0f }
};
static const struct ChanMap RearMap[2] = {
{ BACK_LEFT, -150.0f * F_PI/180.0f },
{ BACK_RIGHT, 150.0f * F_PI/180.0f }
};
static const struct ChanMap QuadMap[4] = {
{ FRONT_LEFT, -45.0f * F_PI/180.0f },
{ FRONT_RIGHT, 45.0f * F_PI/180.0f },
{ BACK_LEFT, -135.0f * F_PI/180.0f },
{ BACK_RIGHT, 135.0f * F_PI/180.0f }
};
static const struct ChanMap X51Map[6] = {
{ FRONT_LEFT, -30.0f * F_PI/180.0f },
{ FRONT_RIGHT, 30.0f * F_PI/180.0f },
{ FRONT_CENTER, 0.0f * F_PI/180.0f },
{ LFE, 0.0f },
{ BACK_LEFT, -110.0f * F_PI/180.0f },
{ BACK_RIGHT, 110.0f * F_PI/180.0f }
};
static const struct ChanMap X61Map[7] = {
{ FRONT_LEFT, -30.0f * F_PI/180.0f },
{ FRONT_RIGHT, 30.0f * F_PI/180.0f },
{ FRONT_CENTER, 0.0f * F_PI/180.0f },
{ LFE, 0.0f },
{ BACK_CENTER, 180.0f * F_PI/180.0f },
{ SIDE_LEFT, -90.0f * F_PI/180.0f },
{ SIDE_RIGHT, 90.0f * F_PI/180.0f }
};
static const struct ChanMap X71Map[8] = {
{ FRONT_LEFT, -30.0f * F_PI/180.0f },
{ FRONT_RIGHT, 30.0f * F_PI/180.0f },
{ FRONT_CENTER, 0.0f * F_PI/180.0f },
{ LFE, 0.0f },
{ BACK_LEFT, -150.0f * F_PI/180.0f },
{ BACK_RIGHT, 150.0f * F_PI/180.0f },
{ SIDE_LEFT, -90.0f * F_PI/180.0f },
{ SIDE_RIGHT, 90.0f * F_PI/180.0f }
};
ALCdevice *Device = ALContext->Device;
ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
ALbufferlistitem *BufferListItem;
enum DevFmtChannels DevChans;
enum FmtChannels Channels;
ALfloat (*SrcMatrix)[MAXCHANNELS];
ALfloat DryGain, DryGainHF;
ALfloat WetGain[MAX_SENDS];
ALfloat WetGainHF[MAX_SENDS];
ALint NumSends, Frequency;
const ALfloat *SpeakerGain;
const ALfloat *angles = NULL;
const enum Channel *chans = NULL;
const ALfloat *ChannelGain;
const struct ChanMap *chans = NULL;
enum Resampler Resampler;
ALint num_channels = 0;
ALboolean VirtualChannels;
ALboolean DirectChannels;
ALfloat Pitch;
ALfloat cw;
ALuint pos;
ALint i, c;
/* Get device properties */
DevChans = Device->FmtChans;
NumSends = Device->NumAuxSends;
Frequency = Device->Frequency;
@ -120,7 +138,7 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
MaxVolume = ALSource->flMaxGain;
Pitch = ALSource->flPitch;
Resampler = ALSource->Resampler;
VirtualChannels = ALSource->VirtualChannels;
DirectChannels = ALSource->DirectChannels;
/* Calculate the stepping value */
Channels = FmtMono;
@ -130,8 +148,8 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALbuffer *ALBuffer;
if((ALBuffer=BufferListItem->buffer) != NULL)
{
ALint maxstep = STACK_DATA_SIZE / ALSource->NumChannels /
ALSource->SampleSize;
ALsizei maxstep = STACK_DATA_SIZE/sizeof(ALfloat) /
ALSource->NumChannels;
maxstep -= ResamplerPadding[Resampler] +
ResamplerPrePadding[Resampler] + 1;
maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
@ -145,18 +163,18 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
if(ALSource->Params.Step == 0)
ALSource->Params.Step = 1;
}
if(ALSource->Params.Step == FRACTIONONE)
Resampler = PointResampler;
Channels = ALBuffer->FmtChannels;
break;
}
BufferListItem = BufferListItem->next;
}
if(VirtualChannels && Device->Hrtf)
ALSource->Params.DoMix = SelectHrtfMixer((ALSource->Params.Step==FRACTIONONE) ?
POINT_RESAMPLER : Resampler);
if(!DirectChannels && Device->Hrtf)
ALSource->Params.DoMix = SelectHrtfMixer(Resampler);
else
ALSource->Params.DoMix = SelectMixer((ALSource->Params.Step==FRACTIONONE) ?
POINT_RESAMPLER : Resampler);
ALSource->Params.DoMix = SelectMixer(Resampler);
/* Calculate gains */
DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
@ -178,74 +196,77 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
switch(Channels)
{
case FmtMono:
angles = angles_Mono;
chans = chans_Mono;
chans = MonoMap;
num_channels = 1;
break;
case FmtStereo:
if(VirtualChannels && (Device->Flags&DEVICE_DUPLICATE_STEREO))
if(!DirectChannels && (Device->Flags&DEVICE_DUPLICATE_STEREO))
{
DryGain *= aluSqrt(2.0f/4.0f);
for(c = 0;c < 2;c++)
{
pos = aluCart2LUTpos(aluCos(F_PI/180.0f * angles_Rear[c]),
aluSin(F_PI/180.0f * angles_Rear[c]));
SpeakerGain = Device->PanningLUT[pos];
pos = aluCart2LUTpos(aluCos(RearMap[c].angle),
aluSin(RearMap[c].angle));
ChannelGain = Device->PanningLUT[pos];
for(i = 0;i < (ALint)Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
SrcMatrix[c][chan] += DryGain * ListenerGain *
SpeakerGain[chan];
ChannelGain[chan];
}
}
}
angles = angles_Stereo;
chans = chans_Stereo;
chans = StereoMap;
num_channels = 2;
break;
case FmtRear:
angles = angles_Rear;
chans = chans_Rear;
chans = RearMap;
num_channels = 2;
break;
case FmtQuad:
angles = angles_Quad;
chans = chans_Quad;
chans = QuadMap;
num_channels = 4;
break;
case FmtX51:
angles = angles_X51;
chans = chans_X51;
chans = X51Map;
num_channels = 6;
break;
case FmtX61:
angles = angles_X61;
chans = chans_X61;
chans = X61Map;
num_channels = 7;
break;
case FmtX71:
angles = angles_X71;
chans = chans_X71;
chans = X71Map;
num_channels = 8;
break;
}
if(VirtualChannels == AL_FALSE)
if(DirectChannels != AL_FALSE)
{
for(c = 0;c < num_channels;c++)
SrcMatrix[c][chans[c]] += DryGain * ListenerGain;
{
for(i = 0;i < (ALint)Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
if(chan == chans[c].channel)
{
SrcMatrix[c][chan] += DryGain * ListenerGain;
break;
}
}
}
}
else if(Device->Hrtf)
{
for(c = 0;c < num_channels;c++)
{
if(chans[c] == LFE)
if(chans[c].channel == LFE)
{
/* Skip LFE */
ALSource->Params.HrtfDelay[c][0] = 0;
@ -261,7 +282,7 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
/* Get the static HRIR coefficients and delays for this
* channel. */
GetLerpedHrtfCoeffs(Device->Hrtf,
0.0f, F_PI/180.0f * angles[c],
0.0f, chans[c].angle,
DryGain*ListenerGain,
ALSource->Params.HrtfCoeffs[c],
ALSource->Params.HrtfDelay[c]);
@ -273,26 +294,31 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
{
for(c = 0;c < num_channels;c++)
{
if(chans[c] == LFE) /* Special-case LFE */
if(chans[c].channel == LFE) /* Special-case LFE */
{
SrcMatrix[c][LFE] += DryGain * ListenerGain;
continue;
}
pos = aluCart2LUTpos(aluCos(F_PI/180.0f * angles[c]),
aluSin(F_PI/180.0f * angles[c]));
SpeakerGain = Device->PanningLUT[pos];
pos = aluCart2LUTpos(aluCos(chans[c].angle), aluSin(chans[c].angle));
ChannelGain = Device->PanningLUT[pos];
for(i = 0;i < (ALint)Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
SrcMatrix[c][chan] += DryGain * ListenerGain *
SpeakerGain[chan];
ChannelGain[chan];
}
}
}
for(i = 0;i < NumSends;i++)
{
ALSource->Params.Send[i].Slot = ALSource->Send[i].Slot;
ALeffectslot *Slot = ALSource->Send[i].Slot;
if(!Slot && i == 0)
Slot = Device->DefaultSlot;
if(Slot && Slot->effect.type == AL_EFFECT_NULL)
Slot = NULL;
ALSource->Params.Send[i].Slot = Slot;
ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
}
@ -320,7 +346,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALfloat Velocity[3],ListenerVel[3];
ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;
ALfloat DopplerFactor, SpeedOfSound;
ALfloat AirAbsorptionFactor;
ALfloat RoomAirAbsorption[MAX_SENDS];
ALbufferlistitem *BufferListItem;
@ -338,22 +364,22 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
enum Resampler Resampler;
ALfloat Matrix[4][4];
ALfloat Pitch;
ALuint Frequency;
ALint NumSends;
ALfloat cw;
ALint i;
ALint i, j;
DryGainHF = 1.0f;
for(i = 0;i < MAX_SENDS;i++)
WetGainHF[i] = 1.0f;
//Get context properties
DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
DopplerVelocity = ALContext->DopplerVelocity;
SpeedOfSound = ALContext->flSpeedOfSound;
NumSends = Device->NumAuxSends;
Frequency = Device->Frequency;
DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
SpeedOfSound = ALContext->flSpeedOfSound * ALContext->DopplerVelocity;
NumSends = Device->NumAuxSends;
Frequency = Device->Frequency;
//Get listener properties
ListenerGain = ALContext->Listener.Gain;
@ -391,8 +417,11 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
{
ALeffectslot *Slot = ALSource->Send[i].Slot;
if(!Slot && i == 0)
Slot = Device->DefaultSlot;
if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
{
Slot = NULL;
RoomRolloff[i] = 0.0f;
DecayDistance[i] = 0.0f;
RoomAirAbsorption[i] = 1.0f;
@ -425,17 +454,15 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALSource->Params.Send[i].Slot = Slot;
}
for(i = 0;i < 4;i++)
{
for(j = 0;j < 4;j++)
Matrix[i][j] = ALContext->Listener.Matrix[i][j];
}
//1. Translate Listener to origin (convert to head relative)
if(ALSource->bHeadRelative == AL_FALSE)
{
ALfloat Matrix[4][4];
for(i = 0;i < 4;i++)
{
ALint i2;
for(i2 = 0;i2 < 4;i2++)
Matrix[i][i2] = ALContext->Listener.Matrix[i][i2];
}
/* Translate position */
Position[0] -= ALContext->Listener.Position[0];
Position[1] -= ALContext->Listener.Position[1];
@ -445,12 +472,17 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
aluMatrixVector(Position, 1.0f, Matrix);
aluMatrixVector(Direction, 0.0f, Matrix);
aluMatrixVector(Velocity, 0.0f, Matrix);
/* Transform listener velocity into listener space */
aluMatrixVector(ListenerVel, 0.0f, Matrix);
}
else
{
ListenerVel[0] = 0.0f;
ListenerVel[1] = 0.0f;
ListenerVel[2] = 0.0f;
/* Transform listener velocity into listener space */
aluMatrixVector(ListenerVel, 0.0f, Matrix);
/* Offset the source velocity to be relative of the listener velocity */
Velocity[0] += ListenerVel[0];
Velocity[1] += ListenerVel[1];
Velocity[2] += ListenerVel[2];
}
SourceToListener[0] = -Position[0];
@ -605,26 +637,15 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
}
// Calculate Velocity
if(DopplerFactor != 0.0f)
if(DopplerFactor > 0.0f && SpeedOfSound > 0.5f)
{
ALfloat VSS, VLS;
ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
DopplerFactor;
VSS = aluDotproduct(Velocity, SourceToListener);
if(VSS >= MaxVelocity)
VSS = (MaxVelocity - 1.0f);
else if(VSS <= -MaxVelocity)
VSS = -MaxVelocity + 1.0f;
VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
VLS = aluDotproduct(ListenerVel, SourceToListener);
if(VLS >= MaxVelocity)
VLS = (MaxVelocity - 1.0f);
else if(VLS <= -MaxVelocity)
VLS = -MaxVelocity + 1.0f;
Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
}
BufferListItem = ALSource->queue;
@ -633,8 +654,8 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
ALbuffer *ALBuffer;
if((ALBuffer=BufferListItem->buffer) != NULL)
{
ALint maxstep = STACK_DATA_SIZE / ALSource->NumChannels /
ALSource->SampleSize;
ALsizei maxstep = STACK_DATA_SIZE/sizeof(ALfloat) /
ALSource->NumChannels;
maxstep -= ResamplerPadding[Resampler] +
ResamplerPrePadding[Resampler] + 1;
maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
@ -648,17 +669,17 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
if(ALSource->Params.Step == 0)
ALSource->Params.Step = 1;
}
if(ALSource->Params.Step == FRACTIONONE)
Resampler = PointResampler;
break;
}
BufferListItem = BufferListItem->next;
}
if(Device->Hrtf)
ALSource->Params.DoMix = SelectHrtfMixer((ALSource->Params.Step==FRACTIONONE) ?
POINT_RESAMPLER : Resampler);
ALSource->Params.DoMix = SelectHrtfMixer(Resampler);
else
ALSource->Params.DoMix = SelectMixer((ALSource->Params.Step==FRACTIONONE) ?
POINT_RESAMPLER : Resampler);
ALSource->Params.DoMix = SelectMixer(Resampler);
if(Device->Hrtf)
{
@ -719,7 +740,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
{
// Use energy-preserving panning algorithm for multi-speaker playback
ALfloat DirGain, AmbientGain;
const ALfloat *SpeakerGain;
const ALfloat *ChannelGain;
ALfloat length;
ALint pos;
@ -733,7 +754,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
}
pos = aluCart2LUTpos(-Position[2]*ZScale, Position[0]);
SpeakerGain = Device->PanningLUT[pos];
ChannelGain = Device->PanningLUT[pos];
DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
// elevation adjustment for directional gain. this sucks, but
@ -748,7 +769,7 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
for(i = 0;i < (ALint)Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
ALfloat gain = lerp(AmbientGain, SpeakerGain[chan], DirGain);
ALfloat gain = lerp(AmbientGain, ChannelGain[chan], DirGain);
ALSource->Params.DryGains[0][chan] = DryGain * gain;
}
}
@ -769,18 +790,22 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
static __inline ALfloat aluF2F(ALfloat val)
{ return val; }
static __inline ALshort aluF2S(ALfloat val)
static __inline ALint aluF2I(ALfloat val)
{
if(val > 1.0f) return 32767;
if(val < -1.0f) return -32768;
return fastf2i(val*32767.0f);
if(val > 1.0f) return 2147483647;
if(val < -1.0f) return -2147483647-1;
return fastf2i((ALfloat)(val*2147483647.0));
}
static __inline ALuint aluF2UI(ALfloat val)
{ return aluF2I(val)+2147483648u; }
static __inline ALshort aluF2S(ALfloat val)
{ return aluF2I(val)>>16; }
static __inline ALushort aluF2US(ALfloat val)
{ return aluF2S(val)+32768; }
static __inline ALbyte aluF2B(ALfloat val)
{ return aluF2S(val)>>8; }
{ return aluF2I(val)>>24; }
static __inline ALubyte aluF2UB(ALfloat val)
{ return aluF2US(val)>>8; }
{ return aluF2B(val)+128; }
#define DECL_TEMPLATE(T, N, func) \
static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
@ -790,38 +815,60 @@ static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
const enum Channel *ChanMap = device->DevChannels; \
ALuint i, j; \
\
for(i = 0;i < SamplesToDo;i++) \
for(j = 0;j < N;j++) \
{ \
for(j = 0;j < N;j++) \
*(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
T *RESTRICT out = buffer + j; \
enum Channel chan = ChanMap[j]; \
\
for(i = 0;i < SamplesToDo;i++) \
out[i*N] = func(DryBuffer[i][chan]); \
} \
}
DECL_TEMPLATE(ALfloat, 1, aluF2F)
DECL_TEMPLATE(ALfloat, 2, aluF2F)
DECL_TEMPLATE(ALfloat, 4, aluF2F)
DECL_TEMPLATE(ALfloat, 6, aluF2F)
DECL_TEMPLATE(ALfloat, 7, aluF2F)
DECL_TEMPLATE(ALfloat, 8, aluF2F)
DECL_TEMPLATE(ALuint, 1, aluF2UI)
DECL_TEMPLATE(ALuint, 2, aluF2UI)
DECL_TEMPLATE(ALuint, 4, aluF2UI)
DECL_TEMPLATE(ALuint, 6, aluF2UI)
DECL_TEMPLATE(ALuint, 7, aluF2UI)
DECL_TEMPLATE(ALuint, 8, aluF2UI)
DECL_TEMPLATE(ALint, 1, aluF2I)
DECL_TEMPLATE(ALint, 2, aluF2I)
DECL_TEMPLATE(ALint, 4, aluF2I)
DECL_TEMPLATE(ALint, 6, aluF2I)
DECL_TEMPLATE(ALint, 7, aluF2I)
DECL_TEMPLATE(ALint, 8, aluF2I)
DECL_TEMPLATE(ALushort, 1, aluF2US)
DECL_TEMPLATE(ALushort, 2, aluF2US)
DECL_TEMPLATE(ALushort, 4, aluF2US)
DECL_TEMPLATE(ALushort, 6, aluF2US)
DECL_TEMPLATE(ALushort, 7, aluF2US)
DECL_TEMPLATE(ALushort, 8, aluF2US)
DECL_TEMPLATE(ALshort, 1, aluF2S)
DECL_TEMPLATE(ALshort, 2, aluF2S)
DECL_TEMPLATE(ALshort, 4, aluF2S)
DECL_TEMPLATE(ALshort, 6, aluF2S)
DECL_TEMPLATE(ALshort, 7, aluF2S)
DECL_TEMPLATE(ALshort, 8, aluF2S)
DECL_TEMPLATE(ALubyte, 1, aluF2UB)
DECL_TEMPLATE(ALubyte, 2, aluF2UB)
DECL_TEMPLATE(ALubyte, 4, aluF2UB)
DECL_TEMPLATE(ALubyte, 6, aluF2UB)
DECL_TEMPLATE(ALubyte, 7, aluF2UB)
DECL_TEMPLATE(ALubyte, 8, aluF2UB)
DECL_TEMPLATE(ALbyte, 1, aluF2B)
DECL_TEMPLATE(ALbyte, 2, aluF2B)
DECL_TEMPLATE(ALbyte, 4, aluF2B)
DECL_TEMPLATE(ALbyte, 6, aluF2B)
DECL_TEMPLATE(ALbyte, 7, aluF2B)
@ -829,44 +876,6 @@ DECL_TEMPLATE(ALbyte, 8, aluF2B)
#undef DECL_TEMPLATE
#define DECL_TEMPLATE(T, N, func) \
static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
ALuint SamplesToDo) \
{ \
ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
const enum Channel *ChanMap = device->DevChannels; \
ALuint i, j; \
\
if(device->Bs2b) \
{ \
for(i = 0;i < SamplesToDo;i++) \
{ \
float samples[2]; \
samples[0] = DryBuffer[i][ChanMap[0]]; \
samples[1] = DryBuffer[i][ChanMap[1]]; \
bs2b_cross_feed(device->Bs2b, samples); \
*(buffer++) = func(samples[0]); \
*(buffer++) = func(samples[1]); \
} \
} \
else \
{ \
for(i = 0;i < SamplesToDo;i++) \
{ \
for(j = 0;j < N;j++) \
*(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
} \
} \
}
DECL_TEMPLATE(ALfloat, 2, aluF2F)
DECL_TEMPLATE(ALushort, 2, aluF2US)
DECL_TEMPLATE(ALshort, 2, aluF2S)
DECL_TEMPLATE(ALubyte, 2, aluF2UB)
DECL_TEMPLATE(ALbyte, 2, aluF2B)
#undef DECL_TEMPLATE
#define DECL_TEMPLATE(T) \
static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
{ \
@ -895,6 +904,8 @@ static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
}
DECL_TEMPLATE(ALfloat)
DECL_TEMPLATE(ALuint)
DECL_TEMPLATE(ALint)
DECL_TEMPLATE(ALushort)
DECL_TEMPLATE(ALshort)
DECL_TEMPLATE(ALubyte)
@ -977,6 +988,27 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
ctx = ctx->next;
}
slot = &device->DefaultSlot;
if(*slot != NULL)
{
for(c = 0;c < SamplesToDo;c++)
{
(*slot)->WetBuffer[c] += (*slot)->ClickRemoval[0];
(*slot)->ClickRemoval[0] -= (*slot)->ClickRemoval[0] * (1.0f/256.0f);
}
(*slot)->ClickRemoval[0] += (*slot)->PendingClicks[0];
(*slot)->PendingClicks[0] = 0.0f;
if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
ALeffectState_Update((*slot)->EffectState, ctx, *slot);
ALeffectState_Process((*slot)->EffectState, SamplesToDo,
(*slot)->WetBuffer, device->DryBuffer);
for(i = 0;i < SamplesToDo;i++)
(*slot)->WetBuffer[i] = 0.0f;
}
UnlockDevice(device);
//Post processing loop
@ -1006,6 +1038,11 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
device->ClickRemoval[c] += device->PendingClicks[c];
device->PendingClicks[c] = 0.0f;
}
if(device->Bs2b)
{
for(i = 0;i < SamplesToDo;i++)
bs2b_cross_feed(device->Bs2b, &device->DryBuffer[i][0]);
}
}
else
{
@ -1040,6 +1077,12 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
case DevFmtUShort:
Write_ALushort(device, buffer, SamplesToDo);
break;
case DevFmtInt:
Write_ALint(device, buffer, SamplesToDo);
break;
case DevFmtUInt:
Write_ALuint(device, buffer, SamplesToDo);
break;
case DevFmtFloat:
Write_ALfloat(device, buffer, SamplesToDo);
break;

View File

@ -54,7 +54,7 @@ static ALvoid DedicatedUpdate(ALeffectState *effect, ALCcontext *Context, const
{
ALdedicatedState *state = (ALdedicatedState*)effect;
ALCdevice *device = Context->Device;
const ALfloat *SpeakerGain;
const ALfloat *ChannelGain;
ALfloat Gain;
ALint pos;
ALsizei s;
@ -66,10 +66,10 @@ static ALvoid DedicatedUpdate(ALeffectState *effect, ALCcontext *Context, const
if(Slot->effect.type == AL_EFFECT_DEDICATED_DIALOGUE)
{
pos = aluCart2LUTpos(1.0f, 0.0f);
SpeakerGain = device->PanningLUT[pos];
ChannelGain = device->PanningLUT[pos];
for(s = 0;s < MAXCHANNELS;s++)
state->gains[s] = SpeakerGain[s] * Gain;
state->gains[s] = ChannelGain[s] * Gain;
}
else if(Slot->effect.type == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
state->gains[LFE] = Gain;

View File

@ -96,7 +96,7 @@ static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeff
ALCdevice *Device = Context->Device;
ALuint frequency = Device->Frequency;
ALfloat dirGain, ambientGain;
const ALfloat *speakerGain;
const ALfloat *ChannelGain;
ALfloat lrpan, cw, g, gain;
ALuint i, pos;
@ -124,22 +124,22 @@ static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeff
/* First tap panning */
pos = aluCart2LUTpos(0.0f, ((lrpan>0.0f)?-1.0f:1.0f));
speakerGain = Device->PanningLUT[pos];
ChannelGain = Device->PanningLUT[pos];
for(i = 0;i < Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
state->Gain[0][chan] = lerp(ambientGain, speakerGain[chan], dirGain) * gain;
state->Gain[0][chan] = lerp(ambientGain, ChannelGain[chan], dirGain) * gain;
}
/* Second tap panning */
pos = aluCart2LUTpos(0.0f, ((lrpan>0.0f)?1.0f:-1.0f));
speakerGain = Device->PanningLUT[pos];
ChannelGain = Device->PanningLUT[pos];
for(i = 0;i < Device->NumChan;i++)
{
enum Channel chan = Device->Speaker2Chan[i];
state->Gain[1][chan] = lerp(ambientGain, speakerGain[chan], dirGain) * gain;
state->Gain[1][chan] = lerp(ambientGain, ChannelGain[chan], dirGain) * gain;
}
}

View File

@ -1016,7 +1016,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
ReflectionsPan[2] };
ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
LateReverbPan[2] };
const ALfloat *speakerGain;
const ALfloat *ChannelGain;
ALfloat ambientGain;
ALfloat dirGain;
ALfloat length;
@ -1054,7 +1054,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
* panning direction.
*/
pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]);
speakerGain = Device->PanningLUT[pos];
ChannelGain = Device->PanningLUT[pos];
dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
for(index = 0;index < MAXCHANNELS;index++)
@ -1062,12 +1062,12 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
for(index = 0;index < Device->NumChan;index++)
{
enum Channel chan = Device->Speaker2Chan[index];
State->Early.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
State->Early.PanGain[chan] = lerp(ambientGain, ChannelGain[chan], dirGain) * Gain;
}
pos = aluCart2LUTpos(latePan[2], latePan[0]);
speakerGain = Device->PanningLUT[pos];
ChannelGain = Device->PanningLUT[pos];
dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
for(index = 0;index < MAXCHANNELS;index++)
@ -1075,7 +1075,7 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
for(index = 0;index < Device->NumChan;index++)
{
enum Channel chan = Device->Speaker2Chan[index];
State->Late.PanGain[chan] = lerp(ambientGain, speakerGain[chan], dirGain) * Gain;
State->Late.PanGain[chan] = lerp(ambientGain, ChannelGain[chan], dirGain) * Gain;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -173,6 +173,17 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
return ALC_INVALID_VALUE;
}
/* init and start the default audio unit... */
err = AudioUnitInitialize(data->audioUnit);
if(err != noErr)
{
ERR("AudioUnitInitialize failed\n");
CloseComponent(data->audioUnit);
free(data);
device->ExtraData = NULL;
return ALC_FALSE;
}
return ALC_NO_ERROR;
}
@ -180,6 +191,7 @@ static void ca_close_playback(ALCdevice *device)
{
ca_data *data = (ca_data*)device->ExtraData;
AudioUnitUninitialize(data->audioUnit);
CloseComponent(data->audioUnit);
free(data);
@ -194,20 +206,9 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
OSStatus err;
UInt32 size;
/* init and start the default audio unit... */
err = AudioUnitInitialize(data->audioUnit);
err = AudioUnitUninitialize(data->audioUnit);
if(err != noErr)
{
ERR("AudioUnitInitialize failed\n");
return ALC_FALSE;
}
err = AudioOutputUnitStart(data->audioUnit);
if(err != noErr)
{
ERR("AudioOutputUnitStart failed\n");
return ALC_FALSE;
}
ERR("-- AudioUnitUninitialize failed.\n");
/* retrieve default output unit's properties (output side) */
size = sizeof(AudioStreamBasicDescription);
@ -238,10 +239,6 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
if(device->Frequency != streamFormat.mSampleRate)
{
if((device->Flags&DEVICE_FREQUENCY_REQUEST))
ERR("CoreAudio does not support changing sample rates (wanted %dhz, got %dhz)\n", device->Frequency, streamFormat.mSampleRate);
device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
streamFormat.mSampleRate /
device->Frequency);
@ -253,62 +250,25 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
switch(streamFormat.mChannelsPerFrame)
{
case 1:
if((device->Flags&DEVICE_CHANNELS_REQUEST) &&
device->FmtChans != DevFmtMono)
{
ERR("Failed to set %s, got Mono instead\n", DevFmtChannelsString(device->FmtChans));
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
}
device->FmtChans = DevFmtMono;
break;
case 2:
if((device->Flags&DEVICE_CHANNELS_REQUEST) &&
device->FmtChans != DevFmtStereo)
{
ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(device->FmtChans));
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
}
device->FmtChans = DevFmtStereo;
break;
case 4:
if((device->Flags&DEVICE_CHANNELS_REQUEST) &&
device->FmtChans != DevFmtQuad)
{
ERR("Failed to set %s, got Quad instead\n", DevFmtChannelsString(device->FmtChans));
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
}
device->FmtChans = DevFmtQuad;
break;
case 6:
if((device->Flags&DEVICE_CHANNELS_REQUEST) &&
device->FmtChans != DevFmtX51)
{
ERR("Failed to set %s, got 5.1 Surround instead\n", DevFmtChannelsString(device->FmtChans));
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
}
device->FmtChans = DevFmtX51;
break;
case 7:
if((device->Flags&DEVICE_CHANNELS_REQUEST) &&
device->FmtChans != DevFmtX61)
{
ERR("Failed to set %s, got 6.1 Surround instead\n", DevFmtChannelsString(device->FmtChans));
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
}
device->FmtChans = DevFmtX61;
break;
case 8:
if((device->Flags&DEVICE_CHANNELS_REQUEST) &&
device->FmtChans != DevFmtX71)
{
ERR("Failed to set %s, got 7.1 Surround instead\n", DevFmtChannelsString(device->FmtChans));
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
}
device->FmtChans = DevFmtX71;
break;
default:
ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
device->FmtChans = DevFmtStereo;
streamFormat.mChannelsPerFrame = 2;
break;
@ -337,6 +297,14 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
/* fall-through */
case DevFmtInt:
streamFormat.mBitsPerChannel = 32;
streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
break;
}
streamFormat.mFormatID = kAudioFormatLinearPCM;
streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
@ -362,6 +330,29 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
return ALC_FALSE;
}
/* init the default audio unit... */
err = AudioUnitInitialize(data->audioUnit);
if(err != noErr)
{
ERR("AudioUnitInitialize failed\n");
return ALC_FALSE;
}
return ALC_TRUE;
}
static ALCboolean ca_start_playback(ALCdevice *device)
{
ca_data *data = (ca_data*)device->ExtraData;
OSStatus err;
err = AudioOutputUnitStart(data->audioUnit);
if(err != noErr)
{
ERR("AudioOutputUnitStart failed\n");
return ALC_FALSE;
}
return ALC_TRUE;
}
@ -370,10 +361,9 @@ static void ca_stop_playback(ALCdevice *device)
ca_data *data = (ca_data*)device->ExtraData;
OSStatus err;
AudioOutputUnitStop(data->audioUnit);
err = AudioUnitUninitialize(data->audioUnit);
err = AudioOutputUnitStop(data->audioUnit);
if(err != noErr)
ERR("-- AudioUnitUninitialize failed.\n");
ERR("AudioOutputUnitStop failed\n");
}
static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
@ -496,12 +486,17 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
requestedFormat.mBitsPerChannel = 16;
requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
break;
case DevFmtInt:
requestedFormat.mBitsPerChannel = 32;
requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
break;
case DevFmtFloat:
requestedFormat.mBitsPerChannel = 32;
requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
break;
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
goto error;
}
@ -673,6 +668,7 @@ static const BackendFuncs ca_funcs = {
ca_open_playback,
ca_close_playback,
ca_reset_playback,
ca_start_playback,
ca_stop_playback,
ca_open_capture,
ca_close_capture,
@ -696,9 +692,6 @@ void alc_ca_probe(enum DevProbe type)
{
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(ca_device);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(ca_device);
break;

View File

@ -47,12 +47,16 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
static HMODULE ds_handle;
static void *ds_handle;
static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter);
static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter);
static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
#define DirectSoundCreate pDirectSoundCreate
#define DirectSoundEnumerateA pDirectSoundEnumerateA
#define DirectSoundCreate pDirectSoundCreate
#define DirectSoundEnumerateA pDirectSoundEnumerateA
#define DirectSoundCaptureCreate pDirectSoundCaptureCreate
#define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
typedef struct {
@ -65,7 +69,16 @@ typedef struct {
volatile int killNow;
ALvoid *thread;
} DSoundData;
} DSoundPlaybackData;
typedef struct {
// DirectSound Capture Device
IDirectSoundCapture *lpDSC;
IDirectSoundCaptureBuffer *DSCbuffer;
DWORD dwBufferBytes;
DWORD dwCursor;
RingBuffer *pRing;
} DSoundCaptureData;
typedef struct {
@ -73,47 +86,47 @@ typedef struct {
GUID guid;
} DevMap;
static const ALCchar dsDevice[] = "DirectSound Default";
static DevMap *DeviceList;
static ALuint NumDevices;
static DevMap *PlaybackDeviceList;
static ALuint NumPlaybackDevices;
static DevMap *CaptureDeviceList;
static ALuint NumCaptureDevices;
#define MAX_UPDATES 128
static ALCboolean DSoundLoad(void)
{
ALCboolean ok = ALC_TRUE;
if(!ds_handle)
{
ds_handle = LoadLibraryA("dsound.dll");
ds_handle = LoadLib("dsound.dll");
if(ds_handle == NULL)
{
ERR("Failed to load dsound.dll\n");
return ALC_FALSE;
}
#define LOAD_FUNC(x) do { \
if((p##x = (void*)GetProcAddress(ds_handle, #x)) == NULL) { \
ERR("Could not load %s from dsound.dll\n", #x); \
ok = ALC_FALSE; \
#define LOAD_FUNC(f) do { \
p##f = GetSymbol(ds_handle, #f); \
if(p##f == NULL) { \
CloseLib(ds_handle); \
ds_handle = NULL; \
return ALC_FALSE; \
} \
} while(0)
LOAD_FUNC(DirectSoundCreate);
LOAD_FUNC(DirectSoundEnumerateA);
LOAD_FUNC(DirectSoundCaptureCreate);
LOAD_FUNC(DirectSoundCaptureEnumerateA);
#undef LOAD_FUNC
if(!ok)
{
FreeLibrary(ds_handle);
ds_handle = NULL;
}
}
return ok;
return ALC_TRUE;
}
static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
{
LPOLESTR guidstr = NULL;
char str[1024];
HRESULT hr;
void *temp;
int count;
ALuint i;
@ -132,30 +145,87 @@ static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname,
snprintf(str, sizeof(str), "%s #%d", desc, count+1);
count++;
for(i = 0;i < NumDevices;i++)
for(i = 0;i < NumPlaybackDevices;i++)
{
if(strcmp(str, DeviceList[i].name) == 0)
if(strcmp(str, PlaybackDeviceList[i].name) == 0)
break;
}
} while(i != NumDevices);
} while(i != NumPlaybackDevices);
temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
hr = StringFromCLSID(guid, &guidstr);
if(SUCCEEDED(hr))
{
TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
CoTaskMemFree(guidstr);
}
temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
if(temp)
{
DeviceList = temp;
DeviceList[NumDevices].name = strdup(str);
DeviceList[NumDevices].guid = *guid;
NumDevices++;
PlaybackDeviceList = temp;
PlaybackDeviceList[NumPlaybackDevices].name = strdup(str);
PlaybackDeviceList[NumPlaybackDevices].guid = *guid;
NumPlaybackDevices++;
}
return TRUE;
}
static ALuint DSoundProc(ALvoid *ptr)
static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
{
LPOLESTR guidstr = NULL;
char str[1024];
HRESULT hr;
void *temp;
int count;
ALuint i;
(void)data;
(void)drvname;
if(!guid)
return TRUE;
count = 0;
do {
if(count == 0)
snprintf(str, sizeof(str), "%s", desc);
else
snprintf(str, sizeof(str), "%s #%d", desc, count+1);
count++;
for(i = 0;i < NumCaptureDevices;i++)
{
if(strcmp(str, CaptureDeviceList[i].name) == 0)
break;
}
} while(i != NumCaptureDevices);
hr = StringFromCLSID(guid, &guidstr);
if(SUCCEEDED(hr))
{
TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
CoTaskMemFree(guidstr);
}
temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
if(temp)
{
CaptureDeviceList = temp;
CaptureDeviceList[NumCaptureDevices].name = strdup(str);
CaptureDeviceList[NumCaptureDevices].guid = *guid;
NumCaptureDevices++;
}
return TRUE;
}
static ALuint DSoundPlaybackProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
DSoundData *pData = (DSoundData*)pDevice->ExtraData;
DSoundPlaybackData *pData = (DSoundPlaybackData*)pDevice->ExtraData;
DSBCAPS DSBCaps;
DWORD LastCursor = 0;
DWORD PlayCursor;
@ -255,37 +325,40 @@ static ALuint DSoundProc(ALvoid *ptr)
static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
{
DSoundData *pData = NULL;
DSoundPlaybackData *pData = NULL;
LPGUID guid = NULL;
HRESULT hr;
if(!deviceName)
deviceName = dsDevice;
else if(strcmp(deviceName, dsDevice) != 0)
if(!PlaybackDeviceList)
{
hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
if(FAILED(hr))
ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
}
if(!deviceName && NumPlaybackDevices > 0)
{
deviceName = PlaybackDeviceList[0].name;
guid = &PlaybackDeviceList[0].guid;
}
else
{
ALuint i;
if(!DeviceList)
for(i = 0;i < NumPlaybackDevices;i++)
{
hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL);
if(FAILED(hr))
ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
}
for(i = 0;i < NumDevices;i++)
{
if(strcmp(deviceName, DeviceList[i].name) == 0)
if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
{
guid = &DeviceList[i].guid;
guid = &PlaybackDeviceList[i].guid;
break;
}
}
if(i == NumDevices)
if(i == NumPlaybackDevices)
return ALC_INVALID_VALUE;
}
//Initialise requested device
pData = calloc(1, sizeof(DSoundData));
pData = calloc(1, sizeof(DSoundPlaybackData));
if(!pData)
return ALC_OUT_OF_MEMORY;
@ -317,7 +390,17 @@ static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
static void DSoundClosePlayback(ALCdevice *device)
{
DSoundData *pData = device->ExtraData;
DSoundPlaybackData *pData = device->ExtraData;
if(pData->DSnotify)
IDirectSoundNotify_Release(pData->DSnotify);
pData->DSnotify = NULL;
if(pData->DSsbuffer)
IDirectSoundBuffer_Release(pData->DSsbuffer);
pData->DSsbuffer = NULL;
if(pData->DSpbuffer != NULL)
IDirectSoundBuffer_Release(pData->DSpbuffer);
pData->DSpbuffer = NULL;
IDirectSound_Release(pData->lpDS);
CloseHandle(pData->hNotifyEvent);
@ -327,7 +410,7 @@ static void DSoundClosePlayback(ALCdevice *device)
static ALCboolean DSoundResetPlayback(ALCdevice *device)
{
DSoundData *pData = (DSoundData*)device->ExtraData;
DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData;
DSBUFFERDESC DSBDescription;
WAVEFORMATEXTENSIBLE OutputType;
DWORD speakers;
@ -335,6 +418,16 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
memset(&OutputType, 0, sizeof(OutputType));
if(pData->DSnotify)
IDirectSoundNotify_Release(pData->DSnotify);
pData->DSnotify = NULL;
if(pData->DSsbuffer)
IDirectSoundBuffer_Release(pData->DSsbuffer);
pData->DSsbuffer = NULL;
if(pData->DSpbuffer != NULL)
IDirectSoundBuffer_Release(pData->DSpbuffer);
pData->DSpbuffer = NULL;
switch(device->FmtType)
{
case DevFmtByte:
@ -343,8 +436,12 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
case DevFmtUShort:
device->FmtType = DevFmtShort;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
break;
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
case DevFmtFloat:
break;
}
@ -421,6 +518,8 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
break;
}
retry_open:
hr = S_OK;
OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
@ -439,6 +538,10 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
else
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
if(pData->DSpbuffer)
IDirectSoundBuffer_Release(pData->DSpbuffer);
pData->DSpbuffer = NULL;
}
else
{
@ -469,6 +572,11 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
OutputType.Format.nBlockAlign;
DSBDescription.lpwfxFormat=&OutputType.Format;
hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
if(FAILED(hr) && device->FmtType == DevFmtFloat)
{
device->FmtType = DevFmtShort;
goto retry_open;
}
}
if(SUCCEEDED(hr))
@ -490,15 +598,6 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
}
}
if(SUCCEEDED(hr))
{
ResetEvent(pData->hNotifyEvent);
SetDefaultWFXChannelOrder(device);
pData->thread = StartThread(DSoundProc, device);
if(pData->thread == NULL)
hr = E_FAIL;
}
if(FAILED(hr))
{
if(pData->DSnotify != NULL)
@ -513,12 +612,26 @@ static ALCboolean DSoundResetPlayback(ALCdevice *device)
return ALC_FALSE;
}
ResetEvent(pData->hNotifyEvent);
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean DSoundStartPlayback(ALCdevice *device)
{
DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData;
pData->thread = StartThread(DSoundPlaybackProc, device);
if(pData->thread == NULL)
return ALC_FALSE;
return ALC_TRUE;
}
static void DSoundStopPlayback(ALCdevice *device)
{
DSoundData *pData = device->ExtraData;
DSoundPlaybackData *pData = device->ExtraData;
if(!pData->thread)
return;
@ -528,28 +641,309 @@ static void DSoundStopPlayback(ALCdevice *device)
pData->thread = NULL;
pData->killNow = 0;
IDirectSoundNotify_Release(pData->DSnotify);
pData->DSnotify = NULL;
IDirectSoundBuffer_Release(pData->DSsbuffer);
pData->DSsbuffer = NULL;
if(pData->DSpbuffer != NULL)
IDirectSoundBuffer_Release(pData->DSpbuffer);
pData->DSpbuffer = NULL;
IDirectSoundBuffer_Stop(pData->DSsbuffer);
}
static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
{
DSoundCaptureData *pData = NULL;
WAVEFORMATEXTENSIBLE InputType;
DSCBUFFERDESC DSCBDescription;
LPGUID guid = NULL;
HRESULT hr, hrcom;
ALuint samples;
if(!CaptureDeviceList)
{
/* Initialize COM to prevent name truncation */
hrcom = CoInitialize(NULL);
hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
if(FAILED(hr))
ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
if(SUCCEEDED(hrcom))
CoUninitialize();
}
if(!deviceName && NumCaptureDevices > 0)
{
deviceName = CaptureDeviceList[0].name;
guid = &CaptureDeviceList[0].guid;
}
else
{
ALuint i;
for(i = 0;i < NumCaptureDevices;i++)
{
if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
{
guid = &CaptureDeviceList[i].guid;
break;
}
}
if(i == NumCaptureDevices)
return ALC_INVALID_VALUE;
}
switch(device->FmtType)
{
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
return ALC_INVALID_ENUM;
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
case DevFmtFloat:
break;
}
//Initialise requested device
pData = calloc(1, sizeof(DSoundCaptureData));
if(!pData)
return ALC_OUT_OF_MEMORY;
hr = DS_OK;
//DirectSoundCapture Init code
if(SUCCEEDED(hr))
hr = DirectSoundCaptureCreate(guid, &pData->lpDSC, NULL);
if(SUCCEEDED(hr))
{
memset(&InputType, 0, sizeof(InputType));
switch(device->FmtChans)
{
case DevFmtMono:
InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
break;
case DevFmtStereo:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT;
break;
case DevFmtQuad:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
break;
case DevFmtX51:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
break;
case DevFmtX51Side:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtX61:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_CENTER |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtX71:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
}
InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
InputType.Format.nSamplesPerSec = device->Frequency;
InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
InputType.Format.cbSize = 0;
if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
{
InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
if(device->FmtType == DevFmtFloat)
InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
else
InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
}
samples = device->UpdateSize * device->NumUpdates;
samples = maxu(samples, 100 * device->Frequency / 1000);
memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
DSCBDescription.dwFlags = 0;
DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
DSCBDescription.lpwfxFormat = &InputType.Format;
hr = IDirectSoundCapture_CreateCaptureBuffer(pData->lpDSC, &DSCBDescription, &pData->DSCbuffer, NULL);
}
if(SUCCEEDED(hr))
{
pData->pRing = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
if(pData->pRing == NULL)
hr = DSERR_OUTOFMEMORY;
}
if(FAILED(hr))
{
ERR("Device init failed: 0x%08lx\n", hr);
DestroyRingBuffer(pData->pRing);
pData->pRing = NULL;
if(pData->DSCbuffer != NULL)
IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
pData->DSCbuffer = NULL;
if(pData->lpDSC)
IDirectSoundCapture_Release(pData->lpDSC);
pData->lpDSC = NULL;
free(pData);
return ALC_INVALID_VALUE;
}
pData->dwBufferBytes = DSCBDescription.dwBufferBytes;
SetDefaultWFXChannelOrder(device);
device->szDeviceName = strdup(deviceName);
device->ExtraData = pData;
return ALC_NO_ERROR;
}
static void DSoundCloseCapture(ALCdevice *device)
{
DSoundCaptureData *pData = device->ExtraData;
DestroyRingBuffer(pData->pRing);
pData->pRing = NULL;
if(pData->DSCbuffer != NULL)
{
IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
pData->DSCbuffer = NULL;
}
IDirectSoundCapture_Release(pData->lpDSC);
pData->lpDSC = NULL;
free(pData);
device->ExtraData = NULL;
}
static void DSoundStartCapture(ALCdevice *device)
{
DSoundCaptureData *pData = device->ExtraData;
HRESULT hr;
hr = IDirectSoundCaptureBuffer_Start(pData->DSCbuffer, DSCBSTART_LOOPING);
if(FAILED(hr))
{
ERR("start failed: 0x%08lx\n", hr);
aluHandleDisconnect(device);
}
}
static void DSoundStopCapture(ALCdevice *device)
{
DSoundCaptureData *pData = device->ExtraData;
HRESULT hr;
hr = IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
if(FAILED(hr))
{
ERR("stop failed: 0x%08lx\n", hr);
aluHandleDisconnect(device);
}
}
static ALCenum DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
{
DSoundCaptureData *pData = pDevice->ExtraData;
ReadRingBuffer(pData->pRing, pBuffer, lSamples);
return ALC_NO_ERROR;
}
static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
{
DSoundCaptureData *pData = pDevice->ExtraData;
DWORD dwRead, dwCursor, dwBufferBytes, dwNumBytes;
void *pvAudio1, *pvAudio2;
DWORD dwAudioBytes1, dwAudioBytes2;
DWORD FrameSize;
HRESULT hr;
if(!pDevice->Connected)
goto done;
FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
dwBufferBytes = pData->dwBufferBytes;
dwCursor = pData->dwCursor;
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pData->DSCbuffer, NULL, &dwRead);
if(SUCCEEDED(hr))
{
dwNumBytes = (dwBufferBytes + dwRead - dwCursor) % dwBufferBytes;
if(dwNumBytes == 0)
goto done;
hr = IDirectSoundCaptureBuffer_Lock(pData->DSCbuffer,
dwCursor, dwNumBytes,
&pvAudio1, &dwAudioBytes1,
&pvAudio2, &dwAudioBytes2, 0);
}
if(SUCCEEDED(hr))
{
WriteRingBuffer(pData->pRing, pvAudio1, dwAudioBytes1/FrameSize);
if(pvAudio2 != NULL)
WriteRingBuffer(pData->pRing, pvAudio2, dwAudioBytes2/FrameSize);
hr = IDirectSoundCaptureBuffer_Unlock(pData->DSCbuffer,
pvAudio1, dwAudioBytes1,
pvAudio2, dwAudioBytes2);
pData->dwCursor = (dwCursor + dwAudioBytes1 + dwAudioBytes2) % dwBufferBytes;
}
if(FAILED(hr))
{
ERR("update failed: 0x%08lx\n", hr);
aluHandleDisconnect(pDevice);
}
done:
return RingBufferSize(pData->pRing);
}
static const BackendFuncs DSoundFuncs = {
DSoundOpenPlayback,
DSoundClosePlayback,
DSoundResetPlayback,
DSoundStartPlayback,
DSoundStopPlayback,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
DSoundOpenCapture,
DSoundCloseCapture,
DSoundStartCapture,
DSoundStopCapture,
DSoundCaptureSamples,
DSoundAvailableSamples
};
@ -565,46 +959,66 @@ void alcDSoundDeinit(void)
{
ALuint i;
for(i = 0;i < NumDevices;++i)
free(DeviceList[i].name);
free(DeviceList);
DeviceList = NULL;
NumDevices = 0;
for(i = 0;i < NumPlaybackDevices;++i)
free(PlaybackDeviceList[i].name);
free(PlaybackDeviceList);
PlaybackDeviceList = NULL;
NumPlaybackDevices = 0;
for(i = 0;i < NumCaptureDevices;++i)
free(CaptureDeviceList[i].name);
free(CaptureDeviceList);
CaptureDeviceList = NULL;
NumCaptureDevices = 0;
if(ds_handle)
FreeLibrary(ds_handle);
CloseLib(ds_handle);
ds_handle = NULL;
}
void alcDSoundProbe(enum DevProbe type)
{
HRESULT hr;
HRESULT hr, hrcom;
ALuint i;
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(dsDevice);
break;
case ALL_DEVICE_PROBE:
for(i = 0;i < NumDevices;++i)
free(DeviceList[i].name);
free(DeviceList);
DeviceList = NULL;
NumDevices = 0;
for(i = 0;i < NumPlaybackDevices;++i)
free(PlaybackDeviceList[i].name);
free(PlaybackDeviceList);
PlaybackDeviceList = NULL;
NumPlaybackDevices = 0;
hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL);
hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
if(FAILED(hr))
ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
else
{
for(i = 0;i < NumDevices;i++)
AppendAllDeviceList(DeviceList[i].name);
for(i = 0;i < NumPlaybackDevices;i++)
AppendAllDeviceList(PlaybackDeviceList[i].name);
}
break;
case CAPTURE_DEVICE_PROBE:
for(i = 0;i < NumCaptureDevices;++i)
free(CaptureDeviceList[i].name);
free(CaptureDeviceList);
CaptureDeviceList = NULL;
NumCaptureDevices = 0;
/* Initialize COM to prevent name truncation */
hrcom = CoInitialize(NULL);
hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
if(FAILED(hr))
ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
else
{
for(i = 0;i < NumCaptureDevices;i++)
AppendCaptureDeviceList(CaptureDeviceList[i].name);
}
if(SUCCEEDED(hrcom))
CoUninitialize();
break;
}
}

View File

@ -43,6 +43,12 @@ static ALCboolean loopback_reset_playback(ALCdevice *device)
return ALC_TRUE;
}
static ALCboolean loopback_start_playback(ALCdevice *device)
{
return ALC_TRUE;
(void)device;
}
static void loopback_stop_playback(ALCdevice *device)
{
(void)device;
@ -52,6 +58,7 @@ static const BackendFuncs loopback_funcs = {
loopback_open_playback,
loopback_close_playback,
loopback_reset_playback,
loopback_start_playback,
loopback_stop_playback,
NULL,
NULL,

View File

@ -29,6 +29,9 @@
#include <audioclient.h>
#include <cguid.h>
#include <mmreg.h>
#include <propsys.h>
#include <propkey.h>
#include <devpkey.h>
#ifndef _WAVEFORMATEXTENSIBLE_
#include <ks.h>
#include <ksmedia.h>
@ -52,8 +55,11 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0
typedef struct {
WCHAR *devid;
IMMDevice *mmdev;
IAudioClient *client;
IAudioRenderClient *render;
HANDLE hNotifyEvent;
HANDLE MsgEvent;
@ -63,7 +69,15 @@ typedef struct {
} MMDevApiData;
static const ALCchar mmDevice[] = "WASAPI Default";
typedef struct {
ALCchar *name;
WCHAR *devid;
} DevMap;
static DevMap *PlaybackDeviceList;
static ALuint NumPlaybackDevices;
static DevMap *CaptureDeviceList;
static ALuint NumCaptureDevices;
static HANDLE ThreadHdl;
@ -76,8 +90,10 @@ typedef struct {
#define WM_USER_OpenDevice (WM_USER+0)
#define WM_USER_ResetDevice (WM_USER+1)
#define WM_USER_StopDevice (WM_USER+2)
#define WM_USER_CloseDevice (WM_USER+3)
#define WM_USER_StartDevice (WM_USER+2)
#define WM_USER_StopDevice (WM_USER+3)
#define WM_USER_CloseDevice (WM_USER+4)
#define WM_USER_Enumerate (WM_USER+5)
static HRESULT WaitForResponse(ThreadRequest *req)
{
@ -88,15 +104,120 @@ static HRESULT WaitForResponse(ThreadRequest *req)
}
static ALCchar *get_device_name(IMMDevice *device)
{
ALCchar *name = NULL;
IPropertyStore *ps;
PROPVARIANT pvname;
HRESULT hr;
int len;
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
if(FAILED(hr))
{
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
return calloc(1, 1);
}
PropVariantInit(&pvname);
hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
if(FAILED(hr))
{
WARN("GetValue failed: 0x%08lx\n", hr);
name = calloc(1, 1);
}
else
{
if((len=WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, NULL, 0, NULL, NULL)) > 0)
{
name = calloc(1, len);
WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, name, len, NULL, NULL);
}
}
PropVariantClear(&pvname);
IPropertyStore_Release(ps);
return name;
}
static void add_device(IMMDevice *device, DevMap *devmap)
{
LPWSTR devid;
HRESULT hr;
hr = IMMDevice_GetId(device, &devid);
if(SUCCEEDED(hr))
{
devmap->devid = strdupW(devid);
devmap->name = get_device_name(device);
TRACE("Got device \"%s\", \"%ls\"\n", devmap->name, devmap->devid);
CoTaskMemFree(devid);
}
}
static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALuint *numdevs)
{
IMMDeviceCollection *coll;
IMMDevice *defdev = NULL;
DevMap *devlist = NULL;
HRESULT hr;
UINT count;
UINT idx;
UINT i;
hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll);
if(FAILED(hr))
{
ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr);
return NULL;
}
idx = count = 0;
hr = IMMDeviceCollection_GetCount(coll, &count);
if(SUCCEEDED(hr) && count > 0)
{
devlist = calloc(count, sizeof(*devlist));
if(!devlist)
{
IMMDeviceCollection_Release(coll);
return NULL;
}
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir,
eMultimedia, &defdev);
}
if(SUCCEEDED(hr) && defdev != NULL)
add_device(defdev, &devlist[idx++]);
for(i = 0;i < count && idx < count;++i)
{
IMMDevice *device;
if(FAILED(IMMDeviceCollection_Item(coll, i, &device)))
continue;
if(device != defdev)
add_device(device, &devlist[idx++]);
IMMDevice_Release(device);
}
if(defdev) IMMDevice_Release(defdev);
IMMDeviceCollection_Release(coll);
*numdevs = idx;
return devlist;
}
static ALuint MMDevApiProc(ALvoid *ptr)
{
ALCdevice *device = ptr;
MMDevApiData *data = device->ExtraData;
union {
IAudioRenderClient *iface;
void *ptr;
} render;
UINT32 written, len;
UINT32 buffer_len, written;
ALuint update_size, len;
BYTE *buffer;
HRESULT hr;
@ -108,16 +229,18 @@ static ALuint MMDevApiProc(ALvoid *ptr)
return 0;
}
hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &render.ptr);
hr = IAudioClient_GetBufferSize(data->client, &buffer_len);
if(FAILED(hr))
{
ERR("Failed to get AudioRenderClient service: 0x%08lx\n", hr);
ERR("Failed to get audio buffer size: 0x%08lx\n", hr);
aluHandleDisconnect(device);
CoUninitialize();
return 0;
}
SetRTPriority();
update_size = device->UpdateSize;
while(!data->killNow)
{
hr = IAudioClient_GetCurrentPadding(data->client, &written);
@ -128,8 +251,8 @@ static ALuint MMDevApiProc(ALvoid *ptr)
break;
}
len = device->UpdateSize*device->NumUpdates - written;
if(len < device->UpdateSize)
len = buffer_len - written;
if(len < update_size)
{
DWORD res;
res = WaitForSingleObjectEx(data->hNotifyEvent, 2000, FALSE);
@ -137,13 +260,13 @@ static ALuint MMDevApiProc(ALvoid *ptr)
ERR("WaitForSingleObjectEx error: 0x%lx\n", res);
continue;
}
len -= len%device->UpdateSize;
len -= len%update_size;
hr = IAudioRenderClient_GetBuffer(render.iface, len, &buffer);
hr = IAudioRenderClient_GetBuffer(data->render, len, &buffer);
if(SUCCEEDED(hr))
{
aluMixData(device, buffer, len);
hr = IAudioRenderClient_ReleaseBuffer(render.iface, len, 0);
hr = IAudioRenderClient_ReleaseBuffer(data->render, len, 0);
}
if(FAILED(hr))
{
@ -153,8 +276,6 @@ static ALuint MMDevApiProc(ALvoid *ptr)
}
}
IAudioRenderClient_Release(render.iface);
CoUninitialize();
return 0;
}
@ -164,7 +285,7 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *
{
memset(out, 0, sizeof(*out));
if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
*out = *(WAVEFORMATEXTENSIBLE*)in;
*out = *(const WAVEFORMATEXTENSIBLE*)in;
else if(in->wFormatTag == WAVE_FORMAT_PCM)
{
out->Format = *in;
@ -204,7 +325,7 @@ static HRESULT DoReset(ALCdevice *device)
MMDevApiData *data = device->ExtraData;
WAVEFORMATEXTENSIBLE OutputType;
WAVEFORMATEX *wfx = NULL;
REFERENCE_TIME min_per;
REFERENCE_TIME min_per, buf_time;
UINT32 buffer_len, min_len;
HRESULT hr;
@ -223,6 +344,9 @@ static HRESULT DoReset(ALCdevice *device)
CoTaskMemFree(wfx);
wfx = NULL;
buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 +
device->Frequency-1) / device->Frequency;
if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
device->Frequency = OutputType.Format.nSamplesPerSec;
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
@ -294,6 +418,14 @@ static HRESULT DoReset(ALCdevice *device)
OutputType.Samples.wValidBitsPerSample = 16;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
/* fall-through */
case DevFmtInt:
OutputType.Format.wBitsPerSample = 32;
OutputType.Samples.wValidBitsPerSample = 32;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
break;
case DevFmtFloat:
OutputType.Format.wBitsPerSample = 32;
OutputType.Samples.wValidBitsPerSample = 32;
@ -329,153 +461,91 @@ static HRESULT DoReset(ALCdevice *device)
CoTaskMemFree(wfx);
wfx = NULL;
if(device->Frequency != OutputType.Format.nSamplesPerSec)
device->Frequency = OutputType.Format.nSamplesPerSec;
if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO)
device->FmtChans = DevFmtMono;
else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO)
device->FmtChans = DevFmtStereo;
else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD)
device->FmtChans = DevFmtQuad;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
device->FmtChans = DevFmtX51;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
device->FmtChans = DevFmtX51Side;
else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
device->FmtChans = DevFmtX61;
else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
device->FmtChans = DevFmtX71;
else
{
if((device->Flags&DEVICE_FREQUENCY_REQUEST))
ERR("Failed to set %dhz, got %ldhz instead\n", device->Frequency, OutputType.Format.nSamplesPerSec);
device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
device->Frequency = OutputType.Format.nSamplesPerSec;
}
if(!((device->FmtChans == DevFmtMono && OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) ||
(device->FmtChans == DevFmtStereo && OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) ||
(device->FmtChans == DevFmtQuad && OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) ||
(device->FmtChans == DevFmtX51 && OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) ||
(device->FmtChans == DevFmtX51Side && OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE) ||
(device->FmtChans == DevFmtX61 && OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) ||
(device->FmtChans == DevFmtX71 && OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)))
{
if((device->Flags&DEVICE_CHANNELS_REQUEST))
ERR("Failed to set %s, got %d channels (0x%08lx) instead\n", DevFmtChannelsString(device->FmtChans), OutputType.Format.nChannels, OutputType.dwChannelMask);
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO)
device->FmtChans = DevFmtMono;
else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO)
device->FmtChans = DevFmtStereo;
else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD)
device->FmtChans = DevFmtQuad;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
device->FmtChans = DevFmtX51;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
device->FmtChans = DevFmtX51Side;
else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
device->FmtChans = DevFmtX61;
else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
device->FmtChans = DevFmtX71;
else
{
ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
device->FmtChans = DevFmtStereo;
OutputType.Format.nChannels = 2;
OutputType.dwChannelMask = STEREO;
}
ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
device->FmtChans = DevFmtStereo;
OutputType.Format.nChannels = 2;
OutputType.dwChannelMask = STEREO;
}
if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
{
if(OutputType.Samples.wValidBitsPerSample == 0)
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
if(OutputType.Samples.wValidBitsPerSample != OutputType.Format.wBitsPerSample ||
!((device->FmtType == DevFmtUByte && OutputType.Format.wBitsPerSample == 8) ||
(device->FmtType == DevFmtShort && OutputType.Format.wBitsPerSample == 16)))
if(OutputType.Format.wBitsPerSample == 8)
device->FmtType = DevFmtUByte;
else if(OutputType.Format.wBitsPerSample == 16)
device->FmtType = DevFmtShort;
else if(OutputType.Format.wBitsPerSample == 32)
device->FmtType = DevFmtInt;
else
{
ERR("Failed to set %s samples, got %d/%d-bit instead\n", DevFmtTypeString(device->FmtType), OutputType.Samples.wValidBitsPerSample, OutputType.Format.wBitsPerSample);
if(OutputType.Format.wBitsPerSample == 8)
device->FmtType = DevFmtUByte;
else if(OutputType.Format.wBitsPerSample == 16)
device->FmtType = DevFmtShort;
else
{
device->FmtType = DevFmtShort;
OutputType.Format.wBitsPerSample = 16;
}
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
device->FmtType = DevFmtShort;
OutputType.Format.wBitsPerSample = 16;
}
}
else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
{
if(OutputType.Samples.wValidBitsPerSample == 0)
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
if(OutputType.Samples.wValidBitsPerSample != OutputType.Format.wBitsPerSample ||
!((device->FmtType == DevFmtFloat && OutputType.Format.wBitsPerSample == 32)))
{
ERR("Failed to set %s samples, got %d/%d-bit instead\n", DevFmtTypeString(device->FmtType), OutputType.Samples.wValidBitsPerSample, OutputType.Format.wBitsPerSample);
if(OutputType.Format.wBitsPerSample != 32)
{
device->FmtType = DevFmtFloat;
OutputType.Format.wBitsPerSample = 32;
}
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
}
device->FmtType = DevFmtFloat;
OutputType.Format.wBitsPerSample = 32;
}
else
{
ERR("Unhandled format sub-type\n");
device->FmtType = DevFmtShort;
OutputType.Format.wBitsPerSample = 16;
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
}
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
}
SetDefaultWFXChannelOrder(device);
hr = IAudioClient_GetDevicePeriod(data->client, &min_per, NULL);
if(SUCCEEDED(hr))
{
min_len = (min_per*device->Frequency + 10000000-1) / 10000000;
if(min_len < device->UpdateSize)
min_len *= (device->UpdateSize + min_len/2)/min_len;
device->NumUpdates = (device->NumUpdates*device->UpdateSize + min_len/2) /
min_len;
device->NumUpdates = maxu(device->NumUpdates, 2);
device->UpdateSize = min_len;
hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
((REFERENCE_TIME)device->UpdateSize*
device->NumUpdates*10000000 +
device->Frequency-1) / device->Frequency,
0, &OutputType.Format, NULL);
}
hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
buf_time, 0, &OutputType.Format, NULL);
if(FAILED(hr))
{
ERR("Failed to initialize audio client: 0x%08lx\n", hr);
return hr;
}
hr = IAudioClient_GetBufferSize(data->client, &buffer_len);
hr = IAudioClient_GetDevicePeriod(data->client, &min_per, NULL);
if(SUCCEEDED(hr))
{
min_len = (UINT32)((min_per*device->Frequency + 10000000-1) / 10000000);
/* Find the nearest multiple of the period size to the update size */
if(min_len < device->UpdateSize)
min_len *= (device->UpdateSize + min_len/2)/min_len;
hr = IAudioClient_GetBufferSize(data->client, &buffer_len);
}
if(FAILED(hr))
{
ERR("Failed to get audio buffer info: 0x%08lx\n", hr);
return hr;
}
device->UpdateSize = min_len;
device->NumUpdates = buffer_len / device->UpdateSize;
if(device->NumUpdates <= 1)
{
device->NumUpdates = 1;
ERR("Audio client returned buffer_len < period*2; expect break up\n");
}
ResetEvent(data->hNotifyEvent);
hr = IAudioClient_SetEventHandle(data->client, data->hNotifyEvent);
if(SUCCEEDED(hr))
hr = IAudioClient_Start(data->client);
if(FAILED(hr))
{
ERR("Failed to start audio client: 0x%08lx\n", hr);
return hr;
}
data->thread = StartThread(MMDevApiProc, device);
if(!data->thread)
{
IAudioClient_Stop(data->client);
ERR("Failed to start thread\n");
return E_FAIL;
device->NumUpdates = 2;
device->UpdateSize = buffer_len / device->NumUpdates;
}
return hr;
@ -489,16 +559,16 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
ALuint deviceCount = 0;
MMDevApiData *data;
ALCdevice *device;
HRESULT hr;
HRESULT hr, cohr;
MSG msg;
TRACE("Starting message thread\n");
hr = CoInitialize(NULL);
if(FAILED(hr))
cohr = CoInitialize(NULL);
if(FAILED(cohr))
{
WARN("Failed to initialize COM: 0x%08lx\n", hr);
req->result = hr;
WARN("Failed to initialize COM: 0x%08lx\n", cohr);
req->result = cohr;
SetEvent(req->FinishedEvt);
return 0;
}
@ -532,28 +602,36 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
device = (ALCdevice*)msg.lParam;
data = device->ExtraData;
hr = S_OK;
hr = cohr = S_OK;
if(++deviceCount == 1)
hr = CoInitialize(NULL);
hr = cohr = CoInitialize(NULL);
if(SUCCEEDED(hr))
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
if(SUCCEEDED(hr))
{
Enumerator = ptr;
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
if(!data->devid)
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
else
hr = IMMDeviceEnumerator_GetDevice(Enumerator, data->devid, &data->mmdev);
IMMDeviceEnumerator_Release(Enumerator);
Enumerator = NULL;
}
if(SUCCEEDED(hr))
hr = IMMDevice_Activate(data->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
if(SUCCEEDED(hr))
{
data->client = ptr;
device->szDeviceName = get_device_name(data->mmdev);
}
if(FAILED(hr))
{
if(data->mmdev)
IMMDevice_Release(data->mmdev);
data->mmdev = NULL;
if(--deviceCount == 0 && SUCCEEDED(cohr))
CoUninitialize();
}
req->result = hr;
@ -568,6 +646,43 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
SetEvent(req->FinishedEvt);
continue;
case WM_USER_StartDevice:
req = (ThreadRequest*)msg.wParam;
device = (ALCdevice*)msg.lParam;
data = device->ExtraData;
ResetEvent(data->hNotifyEvent);
hr = IAudioClient_SetEventHandle(data->client, data->hNotifyEvent);
if(FAILED(hr))
ERR("Failed to set event handle: 0x%08lx\n", hr);
else
{
hr = IAudioClient_Start(data->client);
if(FAILED(hr))
ERR("Failed to start audio client: 0x%08lx\n", hr);
}
if(SUCCEEDED(hr))
hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr);
if(SUCCEEDED(hr))
{
data->render = ptr;
data->thread = StartThread(MMDevApiProc, device);
if(!data->thread)
{
if(data->render)
IAudioRenderClient_Release(data->render);
data->render = NULL;
IAudioClient_Stop(data->client);
ERR("Failed to start thread\n");
hr = E_FAIL;
}
}
req->result = hr;
SetEvent(req->FinishedEvt);
continue;
case WM_USER_StopDevice:
req = (ThreadRequest*)msg.wParam;
device = (ALCdevice*)msg.lParam;
@ -581,6 +696,8 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
data->killNow = 0;
IAudioRenderClient_Release(data->render);
data->render = NULL;
IAudioClient_Stop(data->client);
}
@ -606,6 +723,57 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
SetEvent(req->FinishedEvt);
continue;
case WM_USER_Enumerate:
req = (ThreadRequest*)msg.wParam;
hr = cohr = S_OK;
if(++deviceCount == 1)
hr = cohr = CoInitialize(NULL);
if(SUCCEEDED(hr))
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
if(SUCCEEDED(hr))
{
EDataFlow flowdir;
DevMap **devlist;
ALuint *numdevs;
ALuint i;
Enumerator = ptr;
if(msg.lParam == CAPTURE_DEVICE_PROBE)
{
flowdir = eCapture;
devlist = &CaptureDeviceList;
numdevs = &NumCaptureDevices;
}
else
{
flowdir = eRender;
devlist = &PlaybackDeviceList;
numdevs = &NumPlaybackDevices;
}
for(i = 0;i < *numdevs;i++)
{
free((*devlist)[i].name);
free((*devlist)[i].devid);
}
free(*devlist);
*devlist = NULL;
*numdevs = 0;
*devlist = ProbeDevices(Enumerator, flowdir, numdevs);
IMMDeviceEnumerator_Release(Enumerator);
Enumerator = NULL;
}
if(--deviceCount == 0 && SUCCEEDED(cohr))
CoUninitialize();
req->result = S_OK;
SetEvent(req->FinishedEvt);
continue;
default:
ERR("Unexpected message: %u\n", msg.message);
continue;
@ -645,11 +813,6 @@ static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName
MMDevApiData *data = NULL;
HRESULT hr;
if(!deviceName)
deviceName = mmDevice;
else if(strcmp(deviceName, mmDevice) != 0)
return ALC_INVALID_VALUE;
//Initialise requested device
data = calloc(1, sizeof(MMDevApiData));
if(!data)
@ -662,6 +825,32 @@ static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName
if(data->hNotifyEvent == NULL || data->MsgEvent == NULL)
hr = E_FAIL;
if(SUCCEEDED(hr))
{
if(deviceName)
{
ALuint i;
if(!PlaybackDeviceList)
{
ThreadRequest req = { data->MsgEvent, 0 };
if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE))
(void)WaitForResponse(&req);
}
hr = E_FAIL;
for(i = 0;i < NumPlaybackDevices;i++)
{
if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
{
data->devid = strdupW(PlaybackDeviceList[i].devid);
hr = S_OK;
break;
}
}
}
}
if(SUCCEEDED(hr))
{
ThreadRequest req = { data->MsgEvent, 0 };
@ -687,7 +876,6 @@ static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName
return ALC_INVALID_VALUE;
}
device->szDeviceName = strdup(deviceName);
return ALC_NO_ERROR;
}
@ -705,6 +893,9 @@ static void MMDevApiClosePlayback(ALCdevice *device)
CloseHandle(data->hNotifyEvent);
data->hNotifyEvent = NULL;
free(data->devid);
data->devid = NULL;
free(data);
device->ExtraData = NULL;
}
@ -721,6 +912,18 @@ static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
}
static ALCboolean MMDevApiStartPlayback(ALCdevice *device)
{
MMDevApiData *data = device->ExtraData;
ThreadRequest req = { data->MsgEvent, 0 };
HRESULT hr = E_FAIL;
if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)device))
hr = WaitForResponse(&req);
return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
}
static void MMDevApiStopPlayback(ALCdevice *device)
{
MMDevApiData *data = device->ExtraData;
@ -735,6 +938,7 @@ static const BackendFuncs MMDevApiFuncs = {
MMDevApiOpenPlayback,
MMDevApiClosePlayback,
MMDevApiResetPlayback,
MMDevApiStartPlayback,
MMDevApiStopPlayback,
NULL,
NULL,
@ -755,6 +959,26 @@ ALCboolean alcMMDevApiInit(BackendFuncs *FuncList)
void alcMMDevApiDeinit(void)
{
ALuint i;
for(i = 0;i < NumPlaybackDevices;i++)
{
free(PlaybackDeviceList[i].name);
free(PlaybackDeviceList[i].devid);
}
free(PlaybackDeviceList);
PlaybackDeviceList = NULL;
NumPlaybackDevices = 0;
for(i = 0;i < NumCaptureDevices;i++)
{
free(CaptureDeviceList[i].name);
free(CaptureDeviceList[i].devid);
}
free(CaptureDeviceList);
CaptureDeviceList = NULL;
NumCaptureDevices = 0;
if(ThreadHdl)
{
TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID);
@ -766,15 +990,32 @@ void alcMMDevApiDeinit(void)
void alcMMDevApiProbe(enum DevProbe type)
{
ThreadRequest req = { NULL, 0 };
HRESULT hr = E_FAIL;
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(mmDevice);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(mmDevice);
req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
if(req.FinishedEvt == NULL)
ERR("Failed to create event: %lu\n", GetLastError());
else if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type))
hr = WaitForResponse(&req);
if(SUCCEEDED(hr))
{
ALuint i;
for(i = 0;i < NumPlaybackDevices;i++)
{
if(PlaybackDeviceList[i].name)
AppendAllDeviceList(PlaybackDeviceList[i].name);
}
}
break;
case CAPTURE_DEVICE_PROBE:
break;
}
if(req.FinishedEvt != NULL)
CloseHandle(req.FinishedEvt);
req.FinishedEvt = NULL;
}

View File

@ -52,9 +52,9 @@ static ALuint NullProc(ALvoid *ptr)
avail = (ALuint64)(now-start) * Device->Frequency / 1000;
if(avail < done)
{
/* Timer wrapped. Add the remainder of the cycle to the available
* count and reset the number of samples done */
avail += (ALuint64)0xFFFFFFFFu*Device->Frequency/1000 - done;
/* Timer wrapped (50 days???). Add the remainder of the cycle to
* the available count and reset the number of samples done */
avail += ((ALuint64)1<<32)*Device->Frequency/1000 - done;
done = 0;
}
if(avail-done < Device->UpdateSize)
@ -99,9 +99,13 @@ static void null_close_playback(ALCdevice *device)
static ALCboolean null_reset_playback(ALCdevice *device)
{
null_data *data = (null_data*)device->ExtraData;
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean null_start_playback(ALCdevice *device)
{
null_data *data = (null_data*)device->ExtraData;
data->thread = StartThread(NullProc, device);
if(data->thread == NULL)
@ -129,6 +133,7 @@ static const BackendFuncs null_funcs = {
null_open_playback,
null_close_playback,
null_reset_playback,
null_start_playback,
null_stop_playback,
NULL,
NULL,
@ -152,9 +157,6 @@ void alc_null_probe(enum DevProbe type)
{
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(nullDevice);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(nullDevice);
break;

View File

@ -244,6 +244,10 @@ static void opensl_close_playback(ALCdevice *Device)
{
osl_data *data = Device->ExtraData;
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
data->bufferQueueObject = NULL;
SLObjectItf_Destroy(data->outputMix);
data->outputMix = NULL;
@ -259,16 +263,13 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device)
{
osl_data *data = Device->ExtraData;
SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
SLAndroidSimpleBufferQueueItf bufferQueue;
SLDataLocator_OutputMix loc_outmix;
SLDataFormat_PCM format_pcm;
SLDataSource audioSrc;
SLDataSink audioSnk;
SLPlayItf player;
SLInterfaceID id;
SLboolean req;
SLresult result;
ALuint i;
Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency;
@ -311,6 +312,10 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device)
audioSnk.pFormat = NULL;
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
data->bufferQueueObject = NULL;
result = SLEngineItf_CreateAudioPlayer(data->engine, &data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
PRINTERR(result, "engine->CreateAudioPlayer");
if(SL_RESULT_SUCCESS == result)
@ -318,11 +323,29 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device)
result = SLObjectItf_Realize(data->bufferQueueObject, SL_BOOLEAN_FALSE);
PRINTERR(result, "bufferQueue->Realize");
}
if(SL_RESULT_SUCCESS == result)
if(SL_RESULT_SUCCESS != result)
{
result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue);
PRINTERR(result, "bufferQueue->GetInterface");
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
data->bufferQueueObject = NULL;
return ALC_FALSE;
}
return ALC_TRUE;
}
static ALCboolean opensl_start_playback(ALCdevice *Device)
{
osl_data *data = Device->ExtraData;
SLAndroidSimpleBufferQueueItf bufferQueue;
SLPlayItf player;
SLresult result;
ALuint i;
result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue);
PRINTERR(result, "bufferQueue->GetInterface");
if(SL_RESULT_SUCCESS == result)
{
result = (*bufferQueue)->RegisterCallback(bufferQueue, opensl_callback, Device);
@ -380,10 +403,6 @@ static void opensl_stop_playback(ALCdevice *Device)
{
osl_data *data = Device->ExtraData;
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
data->bufferQueueObject = NULL;
free(data->buffer);
data->buffer = NULL;
data->bufferSize = 0;
@ -394,6 +413,7 @@ static const BackendFuncs opensl_funcs = {
opensl_open_playback,
opensl_close_playback,
opensl_reset_playback,
opensl_start_playback,
opensl_stop_playback,
NULL,
NULL,
@ -418,9 +438,6 @@ void alc_opensl_probe(enum DevProbe type)
{
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(opensl_device);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(opensl_device);
break;

View File

@ -49,6 +49,9 @@
static const ALCchar oss_device[] = "OSS Default";
static const char *oss_driver = "/dev/dsp";
static const char *oss_capture = "/dev/dsp";
typedef struct {
int fd;
volatile int killNow;
@ -149,11 +152,8 @@ static ALuint OSSCaptureProc(ALvoid *ptr)
static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
char driver[64];
oss_data *data;
strncpy(driver, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(!deviceName)
deviceName = oss_device;
else if(strcmp(deviceName, oss_device) != 0)
@ -162,11 +162,11 @@ static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
data = (oss_data*)calloc(1, sizeof(oss_data));
data->killNow = 0;
data->fd = open(driver, O_WRONLY);
data->fd = open(oss_driver, O_WRONLY);
if(data->fd == -1)
{
free(data);
ERR("Could not open %s: %s\n", driver, strerror(errno));
ERR("Could not open %s: %s\n", oss_driver, strerror(errno));
return ALC_INVALID_VALUE;
}
@ -206,6 +206,8 @@ static ALCboolean oss_reset_playback(ALCdevice *device)
ossFormat = AFMT_U8;
break;
case DevFmtUShort:
case DevFmtInt:
case DevFmtUInt:
case DevFmtFloat:
device->FmtType = DevFmtShort;
/* fall-through */
@ -262,21 +264,22 @@ static ALCboolean oss_reset_playback(ALCdevice *device)
return ALC_FALSE;
}
if(device->Frequency != (ALuint)ossSpeed)
{
if((device->Flags&DEVICE_FREQUENCY_REQUEST))
ERR("Failed to set %dhz, got %dhz instead\n", device->Frequency, ossSpeed);
device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
device->Frequency = ossSpeed;
}
device->Frequency = ossSpeed;
device->UpdateSize = info.fragsize / frameSize;
device->NumUpdates = info.fragments + 1;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
SetDefaultChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean oss_start_playback(ALCdevice *device)
{
oss_data *data = (oss_data*)device->ExtraData;
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
data->thread = StartThread(OSSProc, device);
if(data->thread == NULL)
{
@ -316,15 +319,11 @@ static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
audio_buf_info info;
ALuint frameSize;
int numChannels;
char driver[64];
oss_data *data;
int ossFormat;
int ossSpeed;
char *err;
strncpy(driver, GetConfigValue("oss", "capture", "/dev/dsp"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(!deviceName)
deviceName = oss_device;
else if(strcmp(deviceName, oss_device) != 0)
@ -333,11 +332,11 @@ static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
data = (oss_data*)calloc(1, sizeof(oss_data));
data->killNow = 0;
data->fd = open(driver, O_RDONLY);
data->fd = open(oss_capture, O_RDONLY);
if(data->fd == -1)
{
free(data);
ERR("Could not open %s: %s\n", driver, strerror(errno));
ERR("Could not open %s: %s\n", oss_capture, strerror(errno));
return ALC_INVALID_VALUE;
}
@ -353,9 +352,11 @@ static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
ossFormat = AFMT_S16_NE;
break;
case DevFmtUShort:
case DevFmtInt:
case DevFmtUInt:
case DevFmtFloat:
free(data);
ERR("%s capture samples not supported on OSS\n", DevFmtTypeString(device->FmtType));
ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
return ALC_INVALID_VALUE;
}
@ -479,6 +480,7 @@ static const BackendFuncs oss_funcs = {
oss_open_playback,
oss_close_playback,
oss_reset_playback,
oss_start_playback,
oss_stop_playback,
oss_open_capture,
oss_close_capture,
@ -490,6 +492,9 @@ static const BackendFuncs oss_funcs = {
ALCboolean alc_oss_init(BackendFuncs *func_list)
{
ConfigValueStr("oss", "device", &oss_driver);
ConfigValueStr("oss", "capture", &oss_capture);
*func_list = oss_funcs;
return ALC_TRUE;
}
@ -502,21 +507,11 @@ void alc_oss_probe(enum DevProbe type)
{
switch(type)
{
case DEVICE_PROBE:
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0)
#endif
AppendDeviceList(oss_device);
}
break;
case ALL_DEVICE_PROBE:
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0)
if(stat(oss_device, &buf) == 0)
#endif
AppendAllDeviceList(oss_device);
}
@ -526,7 +521,7 @@ void alc_oss_probe(enum DevProbe type)
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(GetConfigValue("oss", "capture", "/dev/dsp"), &buf) == 0)
if(stat(oss_capture, &buf) == 0)
#endif
AppendCaptureDeviceList(oss_device);
}

View File

@ -33,8 +33,8 @@
static const ALCchar pa_device[] = "PortAudio Default";
static void *pa_handle;
#ifdef HAVE_DYNLOAD
static void *pa_handle;
#define MAKE_FUNC(x) static typeof(x) * p##x
MAKE_FUNC(Pa_Initialize);
MAKE_FUNC(Pa_Terminate);
@ -60,11 +60,11 @@ MAKE_FUNC(Pa_GetStreamInfo);
static ALCboolean pa_load(void)
{
if(!pa_handle)
{
PaError err;
PaError err;
#ifdef HAVE_DYNLOAD
if(!pa_handle)
{
#ifdef _WIN32
# define PALIB "portaudio.dll"
#elif defined(__APPLE__) && defined(__MACH__)
@ -98,9 +98,6 @@ static ALCboolean pa_load(void)
LOAD_FUNC(Pa_GetDefaultOutputDevice);
LOAD_FUNC(Pa_GetStreamInfo);
#undef LOAD_FUNC
#else
pa_handle = (void*)0xDEADBEEF;
#endif
if((err=Pa_Initialize()) != paNoError)
{
@ -110,6 +107,13 @@ static ALCboolean pa_load(void)
return ALC_FALSE;
}
}
#else
if((err=Pa_Initialize()) != paNoError)
{
ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
return ALC_FALSE;
}
#endif
return ALC_TRUE;
}
@ -175,6 +179,9 @@ static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
(float)device->Frequency;
outParams.hostApiSpecificStreamInfo = NULL;
outParams.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
retry_open:
switch(device->FmtType)
{
case DevFmtByte:
@ -189,26 +196,32 @@ static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
case DevFmtShort:
outParams.sampleFormat = paInt16;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
/* fall-through */
case DevFmtInt:
outParams.sampleFormat = paInt32;
break;
case DevFmtFloat:
outParams.sampleFormat = paFloat32;
break;
}
outParams.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
SetDefaultChannelOrder(device);
err = Pa_OpenStream(&data->stream, NULL, &outParams, device->Frequency,
device->UpdateSize, paNoFlag, pa_callback, device);
if(err != paNoError)
{
if(device->FmtType == DevFmtFloat)
{
device->FmtType = DevFmtShort;
goto retry_open;
}
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
device->ExtraData = NULL;
free(data);
return ALC_INVALID_VALUE;
}
device->szDeviceName = strdup(deviceName);
if((ALuint)outParams.channelCount != ChannelsFromDevFmt(device->FmtChans))
{
if(outParams.channelCount != 1 && outParams.channelCount != 2)
@ -224,6 +237,9 @@ static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
device->FmtChans = ((outParams.channelCount==1) ? DevFmtMono : DevFmtStereo);
}
SetDefaultChannelOrder(device);
device->szDeviceName = strdup(deviceName);
return ALC_NO_ERROR;
}
@ -245,18 +261,19 @@ static ALCboolean pa_reset_playback(ALCdevice *device)
{
pa_data *data = (pa_data*)device->ExtraData;
const PaStreamInfo *streamInfo;
PaError err;
streamInfo = Pa_GetStreamInfo(data->stream);
if(device->Frequency != streamInfo->sampleRate)
{
if((device->Flags&DEVICE_FREQUENCY_REQUEST))
ERR("PortAudio does not support changing sample rates (wanted %dhz, got %.1fhz)\n", device->Frequency, streamInfo->sampleRate);
device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
device->Frequency = streamInfo->sampleRate;
}
device->Frequency = streamInfo->sampleRate;
device->UpdateSize = data->update_size;
return ALC_TRUE;
}
static ALCboolean pa_start_playback(ALCdevice *device)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = Pa_StartStream(data->stream);
if(err != paNoError)
{
@ -316,11 +333,15 @@ static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
case DevFmtShort:
inParams.sampleFormat = paInt16;
break;
case DevFmtInt:
inParams.sampleFormat = paInt32;
break;
case DevFmtFloat:
inParams.sampleFormat = paFloat32;
break;
case DevFmtUInt:
case DevFmtUShort:
ERR("Unsigned short samples not supported\n");
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
goto error;
}
inParams.channelCount = ChannelsFromDevFmt(device->FmtChans);
@ -395,6 +416,7 @@ static const BackendFuncs pa_funcs = {
pa_open_playback,
pa_close_playback,
pa_reset_playback,
pa_start_playback,
pa_stop_playback,
pa_open_capture,
pa_close_capture,
@ -414,23 +436,22 @@ ALCboolean alc_pa_init(BackendFuncs *func_list)
void alc_pa_deinit(void)
{
#ifdef HAVE_DYNLOAD
if(pa_handle)
{
Pa_Terminate();
#ifdef HAVE_DYNLOAD
CloseLib(pa_handle);
#endif
pa_handle = NULL;
}
#else
Pa_Terminate();
#endif
}
void alc_pa_probe(enum DevProbe type)
{
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(pa_device);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(pa_device);
break;

File diff suppressed because it is too large Load Diff

View File

@ -33,8 +33,8 @@
static const ALCchar sndio_device[] = "SndIO Default";
static void *sndio_handle;
#ifdef HAVE_DYNLOAD
static void *sndio_handle;
#define MAKE_FUNC(x) static typeof(x) * p##x
MAKE_FUNC(sio_initpar);
MAKE_FUNC(sio_open);
@ -76,9 +76,9 @@ MAKE_FUNC(sio_onvol);
static ALCboolean sndio_load(void)
{
#ifdef HAVE_DYNLOAD
if(!sndio_handle)
{
#ifdef HAVE_DYNLOAD
sndio_handle = LoadLib("libsndio.so");
if(!sndio_handle)
return ALC_FALSE;
@ -109,10 +109,8 @@ static ALCboolean sndio_load(void)
LOAD_FUNC(sio_setvol);
LOAD_FUNC(sio_onvol);
#undef LOAD_FUNC
#else
sndio_handle = (void*)0xDEADBEEF;
#endif
}
#endif
return ALC_TRUE;
}
@ -208,7 +206,6 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
sio_initpar(&par);
par.rate = device->Frequency;
par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1);
switch(device->FmtType)
@ -222,8 +219,6 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
par.sig = 0;
break;
case DevFmtFloat:
device->FmtType = DevFmtShort;
/* fall-through */
case DevFmtShort:
par.bits = 16;
par.sig = 1;
@ -232,6 +227,14 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
par.bits = 16;
par.sig = 0;
break;
case DevFmtInt:
par.bits = 32;
par.sig = 1;
break;
case DevFmtUInt:
par.bits = 32;
par.sig = 0;
break;
}
par.le = SIO_LE_NATIVE;
@ -239,40 +242,21 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
if(!par.appbufsz) par.appbufsz = device->UpdateSize;
if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par))
{
ERR("Failed to set device parameters\n");
return ALC_FALSE;
}
if(par.rate != device->Frequency)
{
if((device->Flags&DEVICE_FREQUENCY_REQUEST))
ERR("Failed to set frequency %uhz, got %uhz instead\n", device->Frequency, par.rate);
device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
device->Frequency = par.rate;
}
if(par.pchan != ChannelsFromDevFmt(device->FmtChans))
{
if(par.pchan != 1 && par.pchan != 2)
{
ERR("Unhandled channel count: %u\n", par.pchan);
return ALC_FALSE;
}
if((device->Flags&DEVICE_CHANNELS_REQUEST))
ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), par.pchan);
device->Flags &= ~DEVICE_CHANNELS_REQUEST;
device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
}
if(par.bits != par.bps*8)
{
ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
return ALC_FALSE;
}
device->Frequency = par.rate;
device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
if(par.bits == 8 && par.sig == 1)
device->FmtType = DevFmtByte;
else if(par.bits == 8 && par.sig == 0)
@ -281,18 +265,27 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
device->FmtType = DevFmtShort;
else if(par.bits == 16 && par.sig == 0)
device->FmtType = DevFmtUShort;
else if(par.bits == 32 && par.sig == 1)
device->FmtType = DevFmtInt;
else if(par.bits == 32 && par.sig == 0)
device->FmtType = DevFmtUInt;
else
{
ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits);
return ALC_FALSE;
}
device->UpdateSize = par.round;
device->NumUpdates = (par.bufsz/par.round) + 1;
SetDefaultChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean sndio_start_playback(ALCdevice *device)
{
sndio_data *data = device->ExtraData;
if(!sio_start(data->sndHandle))
{
@ -300,7 +293,7 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
return ALC_FALSE;
}
data->data_size = device->UpdateSize * par.bps * par.pchan;
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
data->thread = StartThread(sndio_proc, device);
@ -339,6 +332,7 @@ static const BackendFuncs sndio_funcs = {
sndio_open_playback,
sndio_close_playback,
sndio_reset_playback,
sndio_start_playback,
sndio_stop_playback,
NULL,
NULL,
@ -369,9 +363,6 @@ void alc_sndio_probe(enum DevProbe type)
{
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(sndio_device);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(sndio_device);
break;

View File

@ -39,6 +39,8 @@
static const ALCchar solaris_device[] = "Solaris Default";
static const char *solaris_driver = "/dev/audio";
typedef struct {
int fd;
volatile int killNow;
@ -93,12 +95,8 @@ static ALuint SolarisProc(ALvoid *ptr)
static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
char driver[64];
solaris_data *data;
strncpy(driver, GetConfigValue("solaris", "device", "/dev/audio"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(!deviceName)
deviceName = solaris_device;
else if(strcmp(deviceName, solaris_device) != 0)
@ -107,11 +105,11 @@ static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceNam
data = (solaris_data*)calloc(1, sizeof(solaris_data));
data->killNow = 0;
data->fd = open(driver, O_WRONLY);
data->fd = open(solaris_driver, O_WRONLY);
if(data->fd == -1)
{
free(data);
ERR("Could not open %s: %s\n", driver, strerror(errno));
ERR("Could not open %s: %s\n", solaris_driver, strerror(errno));
return ALC_INVALID_VALUE;
}
@ -156,6 +154,8 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
info.play.encoding = AUDIO_ENCODING_LINEAR8;
break;
case DevFmtUShort:
case DevFmtInt:
case DevFmtUInt:
case DevFmtFloat:
device->FmtType = DevFmtShort;
/* fall-through */
@ -180,32 +180,31 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
return ALC_FALSE;
}
if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR &&
device->FmtType == DevFmtByte) ||
(info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 &&
device->FmtType == DevFmtUByte) ||
(info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR &&
device->FmtType == DevFmtShort)))
if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) ||
(info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) ||
(info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) ||
(info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt)))
{
ERR("Could not set %#x sample type, got %d (%#x)\n",
device->FmtType, info.play.precision, info.play.encoding);
ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType),
info.play.precision, info.play.encoding);
return ALC_FALSE;
}
if(device->Frequency != info.play.sample_rate)
{
if((device->Flags&DEVICE_FREQUENCY_REQUEST))
ERR("Failed to set requested frequency %dhz, got %dhz instead\n", device->Frequency, info.play.sample_rate);
device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
device->Frequency = info.play.sample_rate;
}
device->Frequency = info.play.sample_rate;
device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
SetDefaultChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean solaris_start_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
data->thread = StartThread(SolarisProc, device);
if(data->thread == NULL)
{
@ -241,6 +240,7 @@ static const BackendFuncs solaris_funcs = {
solaris_open_playback,
solaris_close_playback,
solaris_reset_playback,
solaris_start_playback,
solaris_stop_playback,
NULL,
NULL,
@ -252,6 +252,8 @@ static const BackendFuncs solaris_funcs = {
ALCboolean alc_solaris_init(BackendFuncs *func_list)
{
ConfigValueStr("solaris", "device", &solaris_driver);
*func_list = solaris_funcs;
return ALC_TRUE;
}
@ -262,20 +264,18 @@ void alc_solaris_deinit(void)
void alc_solaris_probe(enum DevProbe type)
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(GetConfigValue("solaris", "device", "/dev/audio"), &buf) != 0)
return;
#endif
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(solaris_device);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(solaris_device);
break;
{
#ifdef HAVE_STAT
struct stat buf;
if(stat(solaris_driver, &buf) == 0)
#endif
AppendAllDeviceList(solaris_device);
}
break;
case CAPTURE_DEVICE_PROBE:
break;
}

View File

@ -87,14 +87,9 @@ static ALuint WaveProc(ALvoid *ptr)
ALuint now, start;
ALuint64 avail, done;
size_t fs;
union {
short s;
char b[sizeof(short)];
} uSB;
const ALuint restTime = (ALuint64)pDevice->UpdateSize * 1000 /
pDevice->Frequency / 2;
uSB.s = 1;
frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
done = 0;
@ -106,9 +101,9 @@ static ALuint WaveProc(ALvoid *ptr)
avail = (ALuint64)(now-start) * pDevice->Frequency / 1000;
if(avail < done)
{
/* Timer wrapped. Add the remainder of the cycle to the available
* count and reset the number of samples done */
avail += (ALuint64)0xFFFFFFFFu*pDevice->Frequency/1000 - done;
/* Timer wrapped (50 days???). Add the remainder of the cycle to
* the available count and reset the number of samples done */
avail += ((ALuint64)1<<32)*pDevice->Frequency/1000 - done;
done = 0;
}
if(avail-done < pDevice->UpdateSize)
@ -122,7 +117,7 @@ static ALuint WaveProc(ALvoid *ptr)
aluMixData(pDevice, data->buffer, pDevice->UpdateSize);
done += pDevice->UpdateSize;
if(uSB.b[0] != 1)
if(!IS_LITTLE_ENDIAN)
{
ALuint bytesize = BytesFromDevFmt(pDevice->FmtType);
ALubyte *bytes = data->buffer;
@ -214,8 +209,12 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
case DevFmtUShort:
device->FmtType = DevFmtShort;
break;
case DevFmtUInt:
device->FmtType = DevFmtInt;
break;
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
case DevFmtFloat:
break;
}
@ -259,10 +258,18 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
ERR("Error writing header: %s\n", strerror(errno));
return ALC_FALSE;
}
data->DataStart = ftell(data->f);
data->size = device->UpdateSize * channels * bits / 8;
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean wave_start_playback(ALCdevice *device)
{
wave_data *data = (wave_data*)device->ExtraData;
data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->buffer = malloc(data->size);
if(!data->buffer)
{
@ -270,8 +277,6 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
return ALC_FALSE;
}
SetDefaultWFXChannelOrder(device);
data->thread = StartThread(WaveProc, device);
if(data->thread == NULL)
{
@ -317,6 +322,7 @@ static const BackendFuncs wave_funcs = {
wave_open_playback,
wave_close_playback,
wave_reset_playback,
wave_start_playback,
wave_stop_playback,
NULL,
NULL,
@ -343,9 +349,6 @@ void alc_wave_probe(enum DevProbe type)
switch(type)
{
case DEVICE_PROBE:
AppendDeviceList(waveDevice);
break;
case ALL_DEVICE_PROBE:
AppendAllDeviceList(waveDevice);
break;

View File

@ -31,6 +31,10 @@
#include "AL/al.h"
#include "AL/alc.h"
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
typedef struct {
// MMSYSTEM Device
@ -38,7 +42,7 @@ typedef struct {
HANDLE hWaveThreadEvent;
HANDLE hWaveThread;
DWORD ulWaveThreadID;
LONG lWaveBuffersCommitted;
volatile LONG lWaveBuffersCommitted;
WAVEHDR WaveBuffer[4];
union {
@ -46,14 +50,12 @@ typedef struct {
HWAVEOUT Out;
} hWaveHandle;
ALuint Frequency;
WAVEFORMATEX wfexFormat;
RingBuffer *pRing;
} WinMMData;
static const ALCchar woDefault[] = "WaveOut Default";
static ALCchar **PlaybackDeviceList;
static ALuint NumPlaybackDevices;
static ALCchar **CaptureDeviceList;
@ -156,22 +158,8 @@ static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance
if(uMsg != WOM_DONE)
return;
// Decrement number of buffers in use
InterlockedDecrement(&pData->lWaveBuffersCommitted);
if(pData->bWaveShutdown == AL_FALSE)
{
// Notify Wave Processor Thread that a Wave Header has returned
PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
}
else
{
if(pData->lWaveBuffersCommitted == 0)
{
// Post 'Quit' Message to WaveOut Processor Thread
PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
}
}
PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
}
/*
@ -194,9 +182,16 @@ static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message != WOM_DONE || pData->bWaveShutdown)
if(msg.message != WOM_DONE)
continue;
if(pData->bWaveShutdown)
{
if(pData->lWaveBuffersCommitted == 0)
break;
continue;
}
pWaveHdr = ((LPWAVEHDR)msg.lParam);
aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);
@ -232,22 +227,8 @@ static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,D
if(uMsg != WIM_DATA)
return;
// Decrement number of buffers in use
InterlockedDecrement(&pData->lWaveBuffersCommitted);
if(pData->bWaveShutdown == AL_FALSE)
{
// Notify Wave Processor Thread that a Wave Header has returned
PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
}
else
{
if(pData->lWaveBuffersCommitted == 0)
{
// Post 'Quit' Message to WaveIn Processor Thread
PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0);
}
}
PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
}
/*
@ -268,8 +249,12 @@ static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
while(GetMessage(&msg, NULL, 0, 0))
{
if(msg.message != WIM_DATA || pData->bWaveShutdown)
if(msg.message != WIM_DATA)
continue;
/* Don't wait for other buffers to finish before quitting. We're
* closing so we don't need them. */
if(pData->bWaveShutdown)
break;
pWaveHdr = ((LPWAVEHDR)msg.lParam);
@ -293,75 +278,62 @@ static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
static ALCenum WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
{
WAVEFORMATEX wfexFormat;
WinMMData *pData = NULL;
UINT lDeviceID = 0;
MMRESULT res;
ALuint i = 0;
// Find the Device ID matching the deviceName if valid
if(!deviceName || strcmp(deviceName, woDefault) == 0)
lDeviceID = WAVE_MAPPER;
else
{
if(!PlaybackDeviceList)
ProbePlaybackDevices();
if(!PlaybackDeviceList)
ProbePlaybackDevices();
for(i = 0;i < NumPlaybackDevices;i++)
// Find the Device ID matching the deviceName if valid
for(i = 0;i < NumPlaybackDevices;i++)
{
if(PlaybackDeviceList[i] &&
(!deviceName || strcmp(deviceName, PlaybackDeviceList[i]) == 0))
{
if(PlaybackDeviceList[i] &&
strcmp(deviceName, PlaybackDeviceList[i]) == 0)
{
lDeviceID = i;
break;
}
lDeviceID = i;
break;
}
if(i == NumPlaybackDevices)
return ALC_INVALID_VALUE;
}
if(i == NumPlaybackDevices)
return ALC_INVALID_VALUE;
pData = calloc(1, sizeof(*pData));
if(!pData)
return ALC_OUT_OF_MEMORY;
pDevice->ExtraData = pData;
if(pDevice->FmtChans != DevFmtMono)
retry_open:
memset(&pData->wfexFormat, 0, sizeof(WAVEFORMATEX));
if(pDevice->FmtType == DevFmtFloat)
{
if((pDevice->Flags&DEVICE_CHANNELS_REQUEST) &&
pDevice->FmtChans != DevFmtStereo)
pData->wfexFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
pData->wfexFormat.wBitsPerSample = 32;
}
else
{
pData->wfexFormat.wFormatTag = WAVE_FORMAT_PCM;
if(pDevice->FmtType == DevFmtUByte || pDevice->FmtType == DevFmtByte)
pData->wfexFormat.wBitsPerSample = 8;
else
pData->wfexFormat.wBitsPerSample = 16;
}
pData->wfexFormat.nChannels = ((pDevice->FmtChans == DevFmtMono) ? 1 : 2);
pData->wfexFormat.nBlockAlign = pData->wfexFormat.wBitsPerSample *
pData->wfexFormat.nChannels / 8;
pData->wfexFormat.nSamplesPerSec = pDevice->Frequency;
pData->wfexFormat.nAvgBytesPerSec = pData->wfexFormat.nSamplesPerSec *
pData->wfexFormat.nBlockAlign;
pData->wfexFormat.cbSize = 0;
if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &pData->wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
{
if(pDevice->FmtType == DevFmtFloat)
{
ERR("Failed to set %s, got Stereo instead\n", DevFmtChannelsString(pDevice->FmtChans));
pDevice->Flags &= ~DEVICE_CHANNELS_REQUEST;
}
pDevice->FmtChans = DevFmtStereo;
}
switch(pDevice->FmtType)
{
case DevFmtByte:
pDevice->FmtType = DevFmtUByte;
break;
case DevFmtUShort:
case DevFmtFloat:
pDevice->FmtType = DevFmtShort;
break;
case DevFmtUByte:
case DevFmtShort:
break;
}
memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
wfexFormat.wFormatTag = WAVE_FORMAT_PCM;
wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
wfexFormat.nChannels / 8;
wfexFormat.nSamplesPerSec = pDevice->Frequency;
wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
wfexFormat.nBlockAlign;
wfexFormat.cbSize = 0;
if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
{
goto retry_open;
}
ERR("waveOutOpen failed: %u\n", res);
goto failure;
}
@ -373,10 +345,7 @@ static ALCenum WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
goto failure;
}
pData->Frequency = pDevice->Frequency;
pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
PlaybackDeviceList[lDeviceID]);
pDevice->szDeviceName = strdup(PlaybackDeviceList[lDeviceID]);
return ALC_NO_ERROR;
failure:
@ -407,6 +376,59 @@ static void WinMMClosePlayback(ALCdevice *device)
}
static ALCboolean WinMMResetPlayback(ALCdevice *device)
{
WinMMData *data = (WinMMData*)device->ExtraData;
device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
data->wfexFormat.nSamplesPerSec /
device->Frequency);
device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4;
device->NumUpdates = 4;
device->Frequency = data->wfexFormat.nSamplesPerSec;
if(data->wfexFormat.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
{
if(data->wfexFormat.wBitsPerSample == 32)
device->FmtType = DevFmtFloat;
else
{
ERR("Unhandled IEEE float sample depth: %d\n", data->wfexFormat.wBitsPerSample);
return ALC_FALSE;
}
}
else if(data->wfexFormat.wFormatTag == WAVE_FORMAT_PCM)
{
if(data->wfexFormat.wBitsPerSample == 16)
device->FmtType = DevFmtShort;
else if(data->wfexFormat.wBitsPerSample == 8)
device->FmtType = DevFmtUByte;
else
{
ERR("Unhandled PCM sample depth: %d\n", data->wfexFormat.wBitsPerSample);
return ALC_FALSE;
}
}
else
{
ERR("Unhandled format tag: 0x%04x\n", data->wfexFormat.wFormatTag);
return ALC_FALSE;
}
if(data->wfexFormat.nChannels == 2)
device->FmtChans = DevFmtStereo;
else if(data->wfexFormat.nChannels == 1)
device->FmtChans = DevFmtMono;
else
{
ERR("Unhandled channel count: %d\n", data->wfexFormat.nChannels);
return ALC_FALSE;
}
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean WinMMStartPlayback(ALCdevice *device)
{
WinMMData *pData = (WinMMData*)device->ExtraData;
ALbyte *BufferData;
@ -417,18 +439,6 @@ static ALCboolean WinMMResetPlayback(ALCdevice *device)
if(pData->hWaveThread == NULL)
return ALC_FALSE;
device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
pData->Frequency / device->Frequency);
if(device->Frequency != pData->Frequency)
{
if((device->Flags&DEVICE_FREQUENCY_REQUEST))
ERR("WinMM does not support changing sample rates (wanted %dhz, got %dhz)\n", device->Frequency, pData->Frequency);
device->Flags &= ~DEVICE_FREQUENCY_REQUEST;
device->Frequency = pData->Frequency;
}
SetDefaultWFXChannelOrder(device);
pData->lWaveBuffersCommitted = 0;
// Create 4 Buffers
@ -484,7 +494,6 @@ static void WinMMStopPlayback(ALCdevice *device)
static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
{
WAVEFORMATEX wfexCaptureFormat;
ALbyte *BufferData = NULL;
DWORD ulCapturedDataSize;
WinMMData *pData = NULL;
@ -497,53 +506,64 @@ static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
ProbeCaptureDevices();
// Find the Device ID matching the deviceName if valid
if(deviceName)
for(i = 0;i < NumCaptureDevices;i++)
{
for(i = 0;i < NumCaptureDevices;i++)
if(CaptureDeviceList[i] &&
(!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0))
{
if(CaptureDeviceList[i] &&
strcmp(deviceName, CaptureDeviceList[i]) == 0)
{
lDeviceID = i;
break;
}
}
}
else
{
for(i = 0;i < NumCaptureDevices;i++)
{
if(CaptureDeviceList[i])
{
lDeviceID = i;
break;
}
lDeviceID = i;
break;
}
}
if(i == NumCaptureDevices)
return ALC_INVALID_VALUE;
switch(pDevice->FmtChans)
{
case DevFmtMono:
case DevFmtStereo:
break;
case DevFmtQuad:
case DevFmtX51:
case DevFmtX51Side:
case DevFmtX61:
case DevFmtX71:
return ALC_INVALID_ENUM;
}
switch(pDevice->FmtType)
{
case DevFmtUByte:
case DevFmtShort:
case DevFmtInt:
case DevFmtFloat:
break;
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
return ALC_INVALID_ENUM;
}
pData = calloc(1, sizeof(*pData));
if(!pData)
return ALC_OUT_OF_MEMORY;
pDevice->ExtraData = pData;
if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) ||
(pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort))
goto failure;
memset(&pData->wfexFormat, 0, sizeof(WAVEFORMATEX));
pData->wfexFormat.wFormatTag = ((pDevice->FmtType == DevFmtFloat) ?
WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
pData->wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
pData->wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
pData->wfexFormat.nBlockAlign = pData->wfexFormat.wBitsPerSample *
pData->wfexFormat.nChannels / 8;
pData->wfexFormat.nSamplesPerSec = pDevice->Frequency;
pData->wfexFormat.nAvgBytesPerSec = pData->wfexFormat.nSamplesPerSec *
pData->wfexFormat.nBlockAlign;
pData->wfexFormat.cbSize = 0;
memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM;
wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
wfexCaptureFormat.nChannels / 8;
wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
wfexCaptureFormat.nBlockAlign;
wfexCaptureFormat.cbSize = 0;
if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &pData->wfexFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
{
ERR("waveInOpen failed: %u\n", res);
goto failure;
@ -556,24 +576,22 @@ static ALCenum WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
goto failure;
}
pData->Frequency = pDevice->Frequency;
// Allocate circular memory buffer for the captured audio
ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
// Make sure circular buffer is at least 100ms in size
if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10))
ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10;
if(ulCapturedDataSize < (pData->wfexFormat.nSamplesPerSec / 10))
ulCapturedDataSize = pData->wfexFormat.nSamplesPerSec / 10;
pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize);
pData->pRing = CreateRingBuffer(pData->wfexFormat.nBlockAlign, ulCapturedDataSize);
if(!pData->pRing)
goto failure;
pData->lWaveBuffersCommitted = 0;
// Create 4 Buffers of 50ms each
lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20;
lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign);
lBufferSize = pData->wfexFormat.nAvgBytesPerSec / 20;
lBufferSize -= (lBufferSize % pData->wfexFormat.nBlockAlign);
BufferData = calloc(4, lBufferSize);
if(!BufferData)
@ -631,13 +649,15 @@ static void WinMMCloseCapture(ALCdevice *pDevice)
void *buffer = NULL;
int i;
// Call waveOutReset to shutdown wave device
/* Tell the processing thread to quit and wait for it to do so. */
pData->bWaveShutdown = AL_TRUE;
waveInReset(pData->hWaveHandle.In);
PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
// Wait for signal that Wave Thread has been destroyed
WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
/* Make sure capture is stopped and all pending buffers are flushed. */
waveInReset(pData->hWaveHandle.In);
CloseHandle(pData->hWaveThread);
pData->hWaveThread = 0;
@ -694,6 +714,7 @@ static const BackendFuncs WinMMFuncs = {
WinMMOpenPlayback,
WinMMClosePlayback,
WinMMResetPlayback,
WinMMStartPlayback,
WinMMStopPlayback,
WinMMOpenCapture,
WinMMCloseCapture,
@ -735,16 +756,8 @@ void alcWinMMProbe(enum DevProbe type)
switch(type)
{
case DEVICE_PROBE:
ProbePlaybackDevices();
if(NumPlaybackDevices > 0)
AppendDeviceList(woDefault);
break;
case ALL_DEVICE_PROBE:
ProbePlaybackDevices();
if(NumPlaybackDevices > 0)
AppendAllDeviceList(woDefault);
for(i = 0;i < NumPlaybackDevices;i++)
{
if(PlaybackDeviceList[i])

View File

@ -24,6 +24,7 @@
#include "config.h"
#include <math.h>
#include <string.h>
#include "bs2b.h"
@ -147,26 +148,9 @@ int bs2b_get_srate(struct bs2b *bs2b)
void bs2b_clear(struct bs2b *bs2b)
{
int loopv = sizeof(bs2b->last_sample);
while (loopv)
{
((char *)&bs2b->last_sample)[--loopv] = 0;
}
memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample));
} /* bs2b_clear */
int bs2b_is_clear(struct bs2b *bs2b)
{
int loopv = sizeof(bs2b->last_sample);
while (loopv)
{
if (((char *)&bs2b->last_sample)[--loopv] != 0)
return 0;
}
return 1;
} /* bs2b_is_clear */
void bs2b_cross_feed(struct bs2b *bs2b, float *sample)
{
/* Lowpass filter */

View File

@ -44,6 +44,12 @@ DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xd
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
#ifdef HAVE_MMDEVAPI
#include <devpropdef.h>
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
#endif
#endif
#include "alMain.h"
@ -99,6 +105,22 @@ void *GetSymbol(void *handle, const char *name)
return ret;
}
WCHAR *strdupW(const WCHAR *str)
{
const WCHAR *n;
WCHAR *ret;
size_t len;
n = str;
while(*n) n++;
len = n - str;
ret = calloc(sizeof(WCHAR), len+1);
if(ret != NULL)
memcpy(ret, str, sizeof(WCHAR)*len);
return ret;
}
#else
void InitializeCriticalSection(CRITICAL_SECTION *cs)

View File

@ -28,21 +28,6 @@
#include "alMain.h"
#include "alSource.h"
/* External HRTF file format (LE byte order):
*
* ALchar magic[8] = "MinPHR00";
* ALuint sampleRate;
*
* ALushort hrirCount; // Required value: 828
* ALushort hrirSize; // Required value: 32
* ALubyte evCount; // Required value: 19
*
* ALushort evOffset[evCount]; // Required values:
* { 0, 1, 13, 37, 73, 118, 174, 234, 306, 378, 450, 522, 594, 654, 710, 755, 791, 815, 827 }
*
* ALshort coefficients[hrirCount][hrirSize];
* ALubyte delays[hrirCount]; // Element values must not exceed 127
*/
static const ALchar magicMarker[8] = "MinPHR00";
@ -94,7 +79,7 @@ static void CalcAzIndices(ALuint evidx, ALfloat az, ALuint *azidx, ALfloat *azmu
// values.
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3])
{
ALfloat gainChange, angleChange;
ALfloat gainChange, angleChange, change;
// Calculate the normalized dB gain change.
newGain = maxf(newGain, 0.0001f);
@ -117,7 +102,8 @@ ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3],
// Use the largest of the two changes for the delta factor, and apply a
// significance shaping function to it.
return clampf(angleChange*2.0f, gainChange*2.0f, 1.0f);
change = maxf(angleChange, gainChange) * 2.0f;
return minf(change, 1.0f);
}
// Calculates static HRIR coefficients and delays for the given polar

View File

@ -251,7 +251,7 @@ static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
ALfloat *RESTRICT WetPendingClicks; \
FILTER *WetFilter; \
\
if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
if(Slot == NULL) \
continue; \
\
WetBuffer = Slot->WetBuffer; \
@ -381,7 +381,7 @@ static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
ALfloat *WetPendingClicks; \
FILTER *WetFilter; \
\
if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
if(Slot == NULL) \
continue; \
\
WetBuffer = Slot->WetBuffer; \
@ -439,14 +439,13 @@ MixerFunc SelectMixer(enum Resampler Resampler)
{
switch(Resampler)
{
case POINT_RESAMPLER:
case PointResampler:
return Mix_ALfloat_point32;
case LINEAR_RESAMPLER:
case LinearResampler:
return Mix_ALfloat_lerp32;
case CUBIC_RESAMPLER:
case CubicResampler:
return Mix_ALfloat_cubic32;
case RESAMPLER_MIN:
case RESAMPLER_MAX:
case ResamplerMax:
break;
}
return NULL;
@ -456,14 +455,13 @@ MixerFunc SelectHrtfMixer(enum Resampler Resampler)
{
switch(Resampler)
{
case POINT_RESAMPLER:
case PointResampler:
return Mix_Hrtf_ALfloat_point32;
case LINEAR_RESAMPLER:
case LinearResampler:
return Mix_Hrtf_ALfloat_lerp32;
case CUBIC_RESAMPLER:
case CubicResampler:
return Mix_Hrtf_ALfloat_cubic32;
case RESAMPLER_MIN:
case RESAMPLER_MAX:
case ResamplerMax:
break;
}
return NULL;

View File

@ -167,6 +167,7 @@ ALint aluCart2LUTpos(ALfloat re, ALfloat im)
ALvoid aluInitPanning(ALCdevice *Device)
{
ALfloat SpeakerAngle[MAXCHANNELS];
const char *layoutname = NULL;
enum Channel *Speaker2Chan;
ALfloat Alpha, Theta;
ALint pos;
@ -179,6 +180,7 @@ ALvoid aluInitPanning(ALCdevice *Device)
Device->NumChan = 1;
Speaker2Chan[0] = FRONT_CENTER;
SpeakerAngle[0] = F_PI/180.0f * 0.0f;
layoutname = NULL;
break;
case DevFmtStereo:
@ -187,7 +189,7 @@ ALvoid aluInitPanning(ALCdevice *Device)
Speaker2Chan[1] = FRONT_RIGHT;
SpeakerAngle[0] = F_PI/180.0f * -90.0f;
SpeakerAngle[1] = F_PI/180.0f * 90.0f;
SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan);
layoutname = "layout_stereo";
break;
case DevFmtQuad:
@ -200,7 +202,7 @@ ALvoid aluInitPanning(ALCdevice *Device)
SpeakerAngle[1] = F_PI/180.0f * -45.0f;
SpeakerAngle[2] = F_PI/180.0f * 45.0f;
SpeakerAngle[3] = F_PI/180.0f * 135.0f;
SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan);
layoutname = "layout_quad";
break;
case DevFmtX51:
@ -215,7 +217,7 @@ ALvoid aluInitPanning(ALCdevice *Device)
SpeakerAngle[2] = F_PI/180.0f * 0.0f;
SpeakerAngle[3] = F_PI/180.0f * 30.0f;
SpeakerAngle[4] = F_PI/180.0f * 110.0f;
SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
layoutname = "layout_surround51";
break;
case DevFmtX51Side:
@ -230,7 +232,7 @@ ALvoid aluInitPanning(ALCdevice *Device)
SpeakerAngle[2] = F_PI/180.0f * 0.0f;
SpeakerAngle[3] = F_PI/180.0f * 30.0f;
SpeakerAngle[4] = F_PI/180.0f * 90.0f;
SetSpeakerArrangement("layout_51SIDECHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
layoutname = "layout_side51";
break;
case DevFmtX61:
@ -247,7 +249,7 @@ ALvoid aluInitPanning(ALCdevice *Device)
SpeakerAngle[3] = F_PI/180.0f * 30.0f;
SpeakerAngle[4] = F_PI/180.0f * 90.0f;
SpeakerAngle[5] = F_PI/180.0f * 180.0f;
SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
layoutname = "layout_surround61";
break;
case DevFmtX71:
@ -266,9 +268,11 @@ ALvoid aluInitPanning(ALCdevice *Device)
SpeakerAngle[4] = F_PI/180.0f * 30.0f;
SpeakerAngle[5] = F_PI/180.0f * 90.0f;
SpeakerAngle[6] = F_PI/180.0f * 150.0f;
SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
layoutname = "layout_surround71";
break;
}
if(layoutname && Device->Type != Loopback)
SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan);
for(pos = 0; pos < LUT_NUM; pos++)
{

View File

@ -17,6 +17,7 @@ INCLUDE(CheckSymbolExists)
INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCSourceCompiles)
INCLUDE(CheckTypeSize)
INCLUDE(FindPkgConfig)
PROJECT(OpenAL C)
@ -59,12 +60,14 @@ OPTION(WERROR "Treat compile warnings as errors" OFF)
OPTION(UTILS "Build and install utility programs" ON)
OPTION(EXAMPLES "Build and install example programs" ON)
OPTION(ALSOFT_CONFIG "Install alsoft.conf configuration file" OFF)
IF(WIN32)
SET(LIBNAME OpenAL32)
ADD_DEFINITIONS("-D_WIN32 -D_WIN32_WINNT=0x0500")
ADD_DEFINITIONS("-D_WIN32 -D_WIN32_WINNT=0x0501")
ELSE()
SET(LIBNAME openal)
ENDIF()
@ -332,7 +335,7 @@ IF(DLOPEN)
ENDIF()
# Check if we have Windows headers
CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0500)
CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0501)
IF(NOT HAVE_WINDOWS_H)
CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY)
IF(NOT HAVE_GETTIMEOFDAY)
@ -378,7 +381,7 @@ ENDIF()
CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
IF(NOT HAVE_STDINT_H)
IF(HAVE_WINDOWS_H)
CHECK_C_SOURCE_COMPILES("\#define _WIN32_WINNT 0x0500
CHECK_C_SOURCE_COMPILES("\#define _WIN32_WINNT 0x0501
\#include <windows.h>
__int64 foo;
int main() {return 0;}" HAVE___INT64)
@ -436,6 +439,7 @@ SET(HAVE_OSS 0)
SET(HAVE_SOLARIS 0)
SET(HAVE_SNDIO 0)
SET(HAVE_DSOUND 0)
SET(HAVE_MMDEVAPI 0)
SET(HAVE_WINMM 0)
SET(HAVE_PORTAUDIO 0)
SET(HAVE_PULSEAUDIO 0)
@ -552,7 +556,7 @@ ENDIF()
IF(HAVE_WINDOWS_H)
IF(WINMM)
CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0500)
CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0501)
IF(HAVE_MMSYSTEM_H AND HAVE_LIBWINMM)
SET(HAVE_WINMM 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/backends/winmm.c)
@ -616,6 +620,18 @@ IF(COREAUDIO)
SET(EXTRA_LIBS /System/Library/Frameworks/CoreAudio.framework ${EXTRA_LIBS})
SET(EXTRA_LIBS /System/Library/Frameworks/AudioUnit.framework ${EXTRA_LIBS})
SET(EXTRA_LIBS /System/Library/Frameworks/ApplicationServices.framework ${EXTRA_LIBS})
# Some versions of OSX may need the AudioToolbox framework. Add it if
# it's found.
FIND_LIBRARY(AUDIOTOOLBOX_LIBRARY
NAMES AudioToolbox
PATHS ~/Library/Frameworks
/Library/Frameworks
/System/Library/Frameworks
)
IF(AUDIOTOOLBOX_LIBRARY)
SET(EXTRA_LIBS ${AUDIOTOOLBOX_LIBRARY} ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
IF(REQUIRE_COREAUDIO AND NOT HAVE_COREAUDIO)
@ -672,6 +688,10 @@ ENDIF()
# This is always available
SET(BACKENDS "${BACKENDS} Null")
IF(EXAMPLES)
PKG_CHECK_MODULES(FFMPEG libavcodec libavformat)
ENDIF()
IF(LIBTYPE STREQUAL "STATIC")
ADD_DEFINITIONS(-DAL_LIBTYPE_STATIC)
SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC ${PKG_CONFIG_CFLAGS})
@ -717,6 +737,7 @@ INSTALL(FILES include/AL/al.h
include/AL/alext.h
include/AL/efx.h
include/AL/efx-creative.h
include/AL/efx-presets.h
DESTINATION include/AL
)
INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
@ -757,3 +778,19 @@ IF(UTILS)
MESSAGE(STATUS "Building utility programs")
MESSAGE(STATUS "")
ENDIF()
IF(EXAMPLES)
IF(FFMPEG_FOUND)
ADD_EXECUTABLE(alstream examples/alhelpers.c examples/alffmpeg.c examples/alstream.c)
TARGET_LINK_LIBRARIES(alstream ${FFMPEG_LIBRARIES} ${LIBNAME})
SET_TARGET_PROPERTIES(alstream PROPERTIES COMPILE_FLAGS "${FFMPEG_CFLAGS}")
INSTALL(TARGETS alstream
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
MESSAGE(STATUS "Building ffmpeg example programs")
MESSAGE(STATUS "")
ENDIF()
ENDIF()

View File

@ -35,9 +35,9 @@ typedef struct ALeffectslot
} ALeffectslot;
ALenum InitEffectSlot(ALeffectslot *slot);
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
struct ALeffectState {
ALvoid (*Destroy)(ALeffectState *State);
ALboolean (*DeviceUpdate)(ALeffectState *State, ALCdevice *Device);
@ -56,6 +56,7 @@ ALeffectState *DedicatedCreate(void);
#define ALeffectState_Update(a,b,c) ((a)->Update((a),(b),(c)))
#define ALeffectState_Process(a,b,c,d) ((a)->Process((a),(b),(c),(d)))
ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
#ifdef __cplusplus
}

View File

@ -9,28 +9,28 @@ extern "C" {
/* User formats */
enum UserFmtType {
UserFmtByte = AL_BYTE,
UserFmtUByte = AL_UNSIGNED_BYTE,
UserFmtShort = AL_SHORT,
UserFmtUShort = AL_UNSIGNED_SHORT,
UserFmtInt = AL_INT,
UserFmtUInt = AL_UNSIGNED_INT,
UserFmtFloat = AL_FLOAT,
UserFmtDouble = AL_DOUBLE,
UserFmtMulaw = AL_MULAW,
UserFmtAlaw = AL_ALAW,
UserFmtIMA4 = AL_IMA4,
UserFmtByte3 = AL_BYTE3,
UserFmtUByte3 = AL_UNSIGNED_BYTE3,
UserFmtByte = AL_BYTE_SOFT,
UserFmtUByte = AL_UNSIGNED_BYTE_SOFT,
UserFmtShort = AL_SHORT_SOFT,
UserFmtUShort = AL_UNSIGNED_SHORT_SOFT,
UserFmtInt = AL_INT_SOFT,
UserFmtUInt = AL_UNSIGNED_INT_SOFT,
UserFmtFloat = AL_FLOAT_SOFT,
UserFmtDouble = AL_DOUBLE_SOFT,
UserFmtByte3 = AL_BYTE3_SOFT,
UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT,
UserFmtMulaw,
UserFmtAlaw,
UserFmtIMA4,
};
enum UserFmtChannels {
UserFmtMono = AL_MONO,
UserFmtStereo = AL_STEREO,
UserFmtRear = AL_REAR,
UserFmtQuad = AL_QUAD,
UserFmtX51 = AL_5POINT1, /* (WFX order) */
UserFmtX61 = AL_6POINT1, /* (WFX order) */
UserFmtX71 = AL_7POINT1 /* (WFX order) */
UserFmtMono = AL_MONO_SOFT,
UserFmtStereo = AL_STEREO_SOFT,
UserFmtRear = AL_REAR_SOFT,
UserFmtQuad = AL_QUAD_SOFT,
UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */
UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */
UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */
};
ALuint BytesFromUserFmt(enum UserFmtType type);

View File

@ -102,8 +102,11 @@ typedef struct ALeffect
static __inline ALboolean IsReverbEffect(ALenum type)
{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
ALenum InitEffect(ALeffect *effect);
ALvoid ReleaseALEffects(ALCdevice *device);
ALvoid GetReverbEffect(const char *name, ALeffect *effect);
#ifdef __cplusplus
}
#endif

View File

@ -39,94 +39,16 @@
#define ALC_6POINT1_SOFT 0x1505 /* (WFX order) */
#define ALC_7POINT1_SOFT 0x1506 /* (WFX order) */
typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(void);
typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type);
typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*);
typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum);
typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei);
#ifdef AL_ALEXT_PROTOTYPES
ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(void);
ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName);
ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type);
ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples);
#endif
#endif
#ifndef AL_SOFT_buffer_samples
#define AL_SOFT_buffer_samples 1
/* Sample types */
#define AL_BYTE 0x1400
#define AL_UNSIGNED_BYTE 0x1401
#define AL_SHORT 0x1402
#define AL_UNSIGNED_SHORT 0x1403
#define AL_INT 0x1404
#define AL_UNSIGNED_INT 0x1405
#define AL_FLOAT 0x1406
#define AL_DOUBLE 0x1407
#define AL_BYTE3 0x1408
#define AL_UNSIGNED_BYTE3 0x1409
#define AL_MULAW 0x1410
#define AL_ALAW 0x1411
#define AL_IMA4 0x1412
/* Channel configurations */
#define AL_MONO 0x1500
#define AL_STEREO 0x1501
#define AL_REAR 0x1502
#define AL_QUAD 0x1503
#define AL_5POINT1 0x1504 /* (WFX order) */
#define AL_6POINT1 0x1505 /* (WFX order) */
#define AL_7POINT1 0x1506 /* (WFX order) */
/* Storage formats */
#define AL_MONO8 0x1100
#define AL_MONO16 0x1101
#define AL_MONO32F 0x10010
#define AL_STEREO8 0x1102
#define AL_STEREO16 0x1103
#define AL_STEREO32F 0x10011
#define AL_QUAD8 0x1204
#define AL_QUAD16 0x1205
#define AL_QUAD32F 0x1206
#define AL_REAR8 0x1207
#define AL_REAR16 0x1208
#define AL_REAR32F 0x1209
#define AL_5POINT1_8 0x120A
#define AL_5POINT1_16 0x120B
#define AL_5POINT1_32F 0x120C
#define AL_6POINT1_8 0x120D
#define AL_6POINT1_16 0x120E
#define AL_6POINT1_32F 0x120F
#define AL_7POINT1_8 0x1210
#define AL_7POINT1_16 0x1211
#define AL_7POINT1_32F 0x1212
/* Buffer attributes */
#define AL_INTERNAL_FORMAT 0x2008
#define AL_BYTE_LENGTH 0x2009
#define AL_SAMPLE_LENGTH 0x200A
#define AL_SEC_LENGTH 0x200B
typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*);
typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*);
typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*);
typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
ALuint samplerate, ALenum internalformat, ALsizei samples,
ALenum channels, ALenum type, const ALvoid *data);
AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
ALsizei offset, ALsizei samples,
ALenum channels, ALenum type, const ALvoid *data);
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
ALsizei offset, ALsizei samples,
ALenum channels, ALenum type, ALvoid *data);
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
#endif
#endif
#ifndef AL_SOFT_non_virtual_channels
#define AL_SOFT_non_virtual_channels 1
#define AL_VIRTUAL_CHANNELS_SOFT 0x1033
#endif
#ifndef AL_SOFT_deferred_updates
#define AL_SOFT_deferred_updates 1
#define AL_DEFERRED_UPDATES_SOFT 0xC002
@ -172,6 +94,14 @@ typedef ptrdiff_t ALsizeiptrEXT;
#endif
static const union {
ALuint u;
ALubyte b[sizeof(ALuint)];
} EndianTest = { 1 };
#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
#define COUNTOF(x) (sizeof((x))/sizeof((x)[0]))
#ifdef _WIN32
#include <windows.h>
@ -187,6 +117,8 @@ void *LoadLib(const char *name);
void CloseLib(void *handle);
void *GetSymbol(void *handle, const char *name);
WCHAR *strdupW(const WCHAR *str);
typedef LONG pthread_once_t;
#define PTHREAD_ONCE_INIT 0
void pthread_once(pthread_once_t *once, void (*callback)(void));
@ -226,6 +158,8 @@ void *GetSymbol(void *handle, const char *name);
#endif
typedef void *volatile XchgPtr;
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
typedef ALuint RefCount;
static __inline RefCount IncrementRef(volatile RefCount *ptr)
@ -237,7 +171,7 @@ static __inline int ExchangeInt(volatile int *ptr, int newval)
{
return __sync_lock_test_and_set(ptr, newval);
}
static __inline void *ExchangePtr(void *volatile*ptr, void *newval)
static __inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{
return __sync_lock_test_and_set(ptr, newval);
}
@ -245,7 +179,7 @@ static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int new
{
return __sync_bool_compare_and_swap(ptr, oldval, newval);
}
static __inline ALboolean CompExchangePtr(void *volatile*ptr, void *oldval, void *newval)
static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
{
return __sync_bool_compare_and_swap(ptr, oldval, newval);
}
@ -288,7 +222,7 @@ static __inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int ne
return ret == oldval;
}
static __inline void *ExchangePtr(void *volatile*dest, void *newval)
static __inline void *ExchangePtr(XchgPtr *dest, void *newval)
{
void *ret;
__asm__ __volatile__(
@ -304,7 +238,7 @@ static __inline void *ExchangePtr(void *volatile*dest, void *newval)
return ret;
}
static __inline ALboolean CompExchangePtr(void *volatile*dest, void *oldval, void *newval)
static __inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
{
void *ret;
__asm__ __volatile__(
@ -338,7 +272,7 @@ static __inline int ExchangeInt(volatile int *ptr, int newval)
} u = { ptr };
return InterlockedExchange(u.l, newval);
}
static __inline void *ExchangePtr(void *volatile*ptr, void *newval)
static __inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{
return InterlockedExchangePointer(ptr, newval);
}
@ -350,7 +284,7 @@ static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int new
} u = { ptr };
return InterlockedCompareExchange(u.l, newval, oldval) == oldval;
}
static __inline ALboolean CompExchangePtr(void *volatile*ptr, void *oldval, void *newval)
static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
{
return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval;
}
@ -374,7 +308,7 @@ static __inline int ExchangeInt(volatile int *ptr, int newval)
} while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr));
return oldval;
}
static __inline void *ExchangePtr(void *volatile*ptr, void *newval)
static __inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{
void *oldval;
do {
@ -386,7 +320,7 @@ static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int new
{
return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr);
}
static __inline ALboolean CompExchangePtr(void *volatile*ptr, void *oldval, void *newval)
static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
{
return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr);
}
@ -448,6 +382,7 @@ extern "C" {
#define DEFAULT_OUTPUT_RATE (44100)
#define MIN_OUTPUT_RATE (8000)
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
@ -480,7 +415,7 @@ static __inline ALuint NextPowerOf2(ALuint value)
static __inline ALint fastf2i(ALfloat f)
{
ALint i;
#if defined(_MSC_VER) && !defined(_WIN64)
#if defined(_MSC_VER) && defined(_M_IX86)
__asm fld f
__asm fistp i
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
@ -501,7 +436,6 @@ static __inline ALuint fastf2u(ALfloat f)
enum DevProbe {
DEVICE_PROBE,
ALL_DEVICE_PROBE,
CAPTURE_DEVICE_PROBE
};
@ -510,6 +444,7 @@ typedef struct {
ALCenum (*OpenPlayback)(ALCdevice*, const ALCchar*);
void (*ClosePlayback)(ALCdevice*);
ALCboolean (*ResetPlayback)(ALCdevice*);
ALCboolean (*StartPlayback)(ALCdevice*);
void (*StopPlayback)(ALCdevice*);
ALCenum (*OpenCapture)(ALCdevice*, const ALCchar*);
@ -581,6 +516,8 @@ enum DevFmtType {
DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT,
DevFmtShort = ALC_SHORT_SOFT,
DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT,
DevFmtInt = ALC_INT_SOFT,
DevFmtUInt = ALC_UNSIGNED_INT_SOFT,
DevFmtFloat = ALC_FLOAT_SOFT
};
enum DevFmtChannels {
@ -612,13 +549,18 @@ extern const struct EffectList {
} EffectList[];
enum DeviceType {
Playback,
Capture,
Loopback
};
struct ALCdevice_struct
{
volatile RefCount ref;
ALCboolean Connected;
ALboolean IsCaptureDevice;
ALboolean IsLoopbackDevice;
ALCboolean Connected;
enum DeviceType Type;
CRITICAL_SECTION Mutex;
@ -672,6 +614,9 @@ struct ALCdevice_struct
ALfloat ClickRemoval[MAXCHANNELS];
ALfloat PendingClicks[MAXCHANNELS];
/* Default effect slot */
struct ALeffectslot *DefaultSlot;
// Contexts created on this device
ALCcontext *volatile ContextList;
@ -684,6 +629,7 @@ struct ALCdevice_struct
#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b)))
#define ALCdevice_ClosePlayback(a) ((a)->Funcs->ClosePlayback((a)))
#define ALCdevice_ResetPlayback(a) ((a)->Funcs->ResetPlayback((a)))
#define ALCdevice_StartPlayback(a) ((a)->Funcs->StartPlayback((a)))
#define ALCdevice_StopPlayback(a) ((a)->Funcs->StopPlayback((a)))
#define ALCdevice_OpenCapture(a,b) ((a)->Funcs->OpenCapture((a), (b)))
#define ALCdevice_CloseCapture(a) ((a)->Funcs->CloseCapture((a)))
@ -698,6 +644,8 @@ struct ALCdevice_struct
#define DEVICE_FREQUENCY_REQUEST (1<<1)
// Channel configuration was requested by the config file
#define DEVICE_CHANNELS_REQUEST (1<<2)
// Sample type was requested by the config file
#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3)
// Specifies if the device is currently running
#define DEVICE_RUNNING (1<<31)
@ -755,14 +703,19 @@ ALCcontext *GetContextRef(void);
void ALCcontext_IncRef(ALCcontext *context);
void ALCcontext_DecRef(ALCcontext *context);
void AppendDeviceList(const ALCchar *name);
void AppendAllDeviceList(const ALCchar *name);
void AppendCaptureDeviceList(const ALCchar *name);
ALCvoid LockDevice(ALCdevice *device);
ALCvoid UnlockDevice(ALCdevice *device);
ALCvoid LockContext(ALCcontext *context);
ALCvoid UnlockContext(ALCcontext *context);
static __inline void LockDevice(ALCdevice *device)
{ EnterCriticalSection(&device->Mutex); }
static __inline void UnlockDevice(ALCdevice *device)
{ LeaveCriticalSection(&device->Mutex); }
static __inline void LockContext(ALCcontext *context)
{ LockDevice(context->Device); }
static __inline void UnlockContext(ALCcontext *context)
{ UnlockDevice(context->Device); }
ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr);
ALuint StopThread(ALvoid *thread);

View File

@ -17,8 +17,8 @@ extern "C" {
extern enum Resampler DefaultResampler;
extern const ALsizei ResamplerPadding[RESAMPLER_MAX];
extern const ALsizei ResamplerPrePadding[RESAMPLER_MAX];
extern const ALsizei ResamplerPadding[ResamplerMax];
extern const ALsizei ResamplerPrePadding[ResamplerMax];
typedef struct ALbufferlistitem
@ -46,7 +46,7 @@ typedef struct ALsource
volatile ALboolean bHeadRelative;
volatile ALboolean bLooping;
volatile enum DistanceModel DistanceModel;
volatile ALboolean VirtualChannels;
volatile ALboolean DirectChannels;
enum Resampler Resampler;

View File

@ -127,13 +127,11 @@ typedef ALvoid (*MixerFunc)(struct ALsource *self, ALCdevice *Device,
ALuint BufferSize);
enum Resampler {
POINT_RESAMPLER = 0,
LINEAR_RESAMPLER,
CUBIC_RESAMPLER,
PointResampler,
LinearResampler,
CubicResampler,
RESAMPLER_MAX,
RESAMPLER_MIN = -1,
RESAMPLER_DEFAULT = LINEAR_RESAMPLER
ResamplerMax,
};
enum Channel {
@ -157,7 +155,9 @@ enum DistanceModel {
InverseDistance = AL_INVERSE_DISTANCE,
LinearDistance = AL_LINEAR_DISTANCE,
ExponentDistance = AL_EXPONENT_DISTANCE,
DisableDistance = AL_NONE
DisableDistance = AL_NONE,
DefaultDistanceModel = InverseDistanceClamped
};
#define BUFFERSIZE 4096

View File

@ -91,9 +91,6 @@ int bs2b_get_srate(struct bs2b *bs2b);
/* Clear buffer */
void bs2b_clear(struct bs2b *bs2b);
/* Return 1 if buffer is clear */
int bs2b_is_clear(struct bs2b *bs2b);
/* Crossfeeds one stereo sample that are pointed by sample.
* [0] - first channel, [1] - second channel.
* Returns crossfided samle by sample pointer.

View File

@ -32,7 +32,6 @@
#include "alSource.h"
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
static ALenum ResizeEffectSlotArray(ALCcontext *Context, ALsizei count);
static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *val);
@ -40,18 +39,16 @@ static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *val);
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *Context;
ALCdevice *Device;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
if(n < 0 || IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
alSetError(Context, AL_INVALID_VALUE);
else
{
ALenum err;
ALsizei i, j;
ALsizei i;
err = ResizeEffectSlotArray(Context, n);
if(err != AL_NO_ERROR)
@ -63,7 +60,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
for(i = 0;i < n;i++)
{
ALeffectslot *slot = calloc(1, sizeof(ALeffectslot));
if(!slot || !(slot->EffectState=NoneCreate()))
if(!slot || InitEffectSlot(slot) != AL_NO_ERROR)
{
free(slot);
// We must have run out or memory
@ -72,18 +69,6 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
break;
}
slot->Gain = 1.0;
slot->AuxSendAuto = AL_TRUE;
slot->NeedsUpdate = AL_FALSE;
for(j = 0;j < BUFFERSIZE;j++)
slot->WetBuffer[j] = 0.0f;
for(j = 0;j < 1;j++)
{
slot->ClickRemoval[j] = 0.0f;
slot->PendingClicks[j] = 0.0f;
}
slot->ref = 0;
LockContext(Context);
err = ResizeEffectSlotArray(Context, 1);
if(err == AL_NO_ERROR)
@ -512,7 +497,7 @@ static ALenum ResizeEffectSlotArray(ALCcontext *Context, ALsizei count)
return AL_NO_ERROR;
}
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
{
ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL);
ALeffectState *State = NULL;
@ -565,12 +550,13 @@ static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, AL
if(ALeffectState_DeviceUpdate(State, Context->Device) == AL_FALSE)
{
RestoreFPUMode(oldMode);
UnlockContext(Context);
ALeffectState_Destroy(State);
alSetError(Context, AL_OUT_OF_MEMORY);
return;
}
State = ExchangePtr((void**)&EffectSlot->EffectState, State);
State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State);
if(!effect)
memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
@ -600,6 +586,28 @@ static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, AL
}
ALenum InitEffectSlot(ALeffectslot *slot)
{
ALint i;
if(!(slot->EffectState=NoneCreate()))
return AL_OUT_OF_MEMORY;
slot->Gain = 1.0;
slot->AuxSendAuto = AL_TRUE;
slot->NeedsUpdate = AL_FALSE;
for(i = 0;i < BUFFERSIZE;i++)
slot->WetBuffer[i] = 0.0f;
for(i = 0;i < 1;i++)
{
slot->ClickRemoval[i] = 0.0f;
slot->PendingClicks[i] = 0.0f;
}
slot->ref = 0;
return AL_NO_ERROR;
}
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
{
ALsizei pos;

View File

@ -330,6 +330,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid
enum UserFmtType SrcType;
ALCcontext *Context;
ALCdevice *device;
ALuint FrameSize;
ALenum NewFormat;
ALbuffer *ALBuf;
ALenum err;
@ -351,8 +353,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid
case UserFmtUShort:
case UserFmtInt:
case UserFmtUInt:
case UserFmtFloat: {
ALuint FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
case UserFmtFloat:
FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
if((size%FrameSize) != 0)
err = AL_INVALID_VALUE;
else
@ -360,13 +362,13 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid
SrcChannels, SrcType, data, AL_TRUE);
if(err != AL_NO_ERROR)
alSetError(Context, err);
} break;
break;
case UserFmtByte3:
case UserFmtUByte3:
case UserFmtDouble: {
ALuint FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
ALenum NewFormat = AL_FORMAT_MONO_FLOAT32;
case UserFmtDouble:
FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
NewFormat = AL_FORMAT_MONO_FLOAT32;
switch(SrcChannels)
{
case UserFmtMono: NewFormat = AL_FORMAT_MONO_FLOAT32; break;
@ -384,19 +386,12 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid
SrcChannels, SrcType, data, AL_TRUE);
if(err != AL_NO_ERROR)
alSetError(Context, err);
} break;
break;
case UserFmtMulaw:
case UserFmtAlaw:
case UserFmtIMA4: {
/* Here is where things vary:
* nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
* Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
*/
ALuint FrameSize = (SrcType == UserFmtIMA4) ?
(ChannelsFromUserFmt(SrcChannels) * 36) :
FrameSizeFromUserFmt(SrcChannels, SrcType);
ALenum NewFormat = AL_FORMAT_MONO16;
FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType);
NewFormat = AL_FORMAT_MONO16;
switch(SrcChannels)
{
case UserFmtMono: NewFormat = AL_FORMAT_MONO16; break;
@ -414,6 +409,32 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid
SrcChannels, SrcType, data, AL_TRUE);
if(err != AL_NO_ERROR)
alSetError(Context, err);
break;
case UserFmtIMA4: {
/* Here is where things vary:
* nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
* Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
*/
ALuint FrameSize = ChannelsFromUserFmt(SrcChannels) * 36;
ALenum NewFormat = AL_FORMAT_MONO16;
switch(SrcChannels)
{
case UserFmtMono: NewFormat = AL_FORMAT_MONO16; break;
case UserFmtStereo: NewFormat = AL_FORMAT_STEREO16; break;
case UserFmtRear: NewFormat = AL_FORMAT_REAR16; break;
case UserFmtQuad: NewFormat = AL_FORMAT_QUAD16; break;
case UserFmtX51: NewFormat = AL_FORMAT_51CHN16; break;
case UserFmtX61: NewFormat = AL_FORMAT_61CHN16; break;
case UserFmtX71: NewFormat = AL_FORMAT_71CHN16; break;
}
if((size%FrameSize) != 0)
err = AL_INVALID_VALUE;
else
err = LoadData(ALBuf, freq, NewFormat, size/FrameSize*65,
SrcChannels, SrcType, data, AL_TRUE);
if(err != AL_NO_ERROR)
alSetError(Context, err);
} break;
}
@ -468,11 +489,12 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const
ALuint Bytes = BytesFromFmt(ALBuf->FmtType);
if(SrcType == UserFmtIMA4)
{
/* offset -> byte offset, length -> block count */
/* offset -> byte offset, length -> sample count */
offset /= 36;
offset *= 65;
offset *= Bytes;
length /= original_align;
length *= 65;
}
else
{
@ -513,15 +535,8 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
alSetError(Context, AL_INVALID_ENUM);
else
{
err = AL_NO_ERROR;
if(type == UserFmtIMA4)
{
if((samples%65) == 0) samples /= 65;
else err = AL_INVALID_VALUE;
}
if(err == AL_NO_ERROR)
err = LoadData(ALBuf, samplerate, internalformat, samples,
channels, type, data, AL_FALSE);
err = LoadData(ALBuf, samplerate, internalformat, samples,
channels, type, data, AL_FALSE);
if(err != AL_NO_ERROR)
alSetError(Context, err);
}
@ -557,14 +572,10 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
alSetError(Context, AL_INVALID_ENUM);
else if(offset > ALBuf->SampleLen || samples > ALBuf->SampleLen-offset)
alSetError(Context, AL_INVALID_VALUE);
else if(type == UserFmtIMA4 && (samples%65) != 0)
alSetError(Context, AL_INVALID_VALUE);
else
{
/* offset -> byte offset */
offset *= FrameSize;
/* samples -> IMA4 block count */
if(type == UserFmtIMA4) samples /= 65;
ConvertData(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
data, type,
ChannelsFromFmt(ALBuf->FmtChannels), samples);
@ -609,8 +620,6 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
{
/* offset -> byte offset */
offset *= FrameSize;
/* samples -> IMA4 block count */
if(type == UserFmtIMA4) samples /= 65;
ConvertData(data, type,
&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
ChannelsFromFmt(ALBuf->FmtChannels), samples);
@ -839,7 +848,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum eParam, ALfloat *pf
{
switch(eParam)
{
case AL_SEC_LENGTH:
case AL_SEC_LENGTH_SOFT:
ReadLock(&pBuffer->lock);
if(pBuffer->SampleLen != 0)
*pflValue = pBuffer->SampleLen / (ALfloat)pBuffer->Frequency;
@ -892,7 +901,7 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum eParam, ALfloat* pfl
switch(eParam)
{
case AL_SEC_LENGTH:
case AL_SEC_LENGTH_SOFT:
alGetBufferf(buffer, eParam, pflValues);
return;
}
@ -956,15 +965,15 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plVa
ReadUnlock(&pBuffer->lock);
break;
case AL_INTERNAL_FORMAT:
case AL_INTERNAL_FORMAT_SOFT:
*plValue = pBuffer->Format;
break;
case AL_BYTE_LENGTH:
case AL_BYTE_LENGTH_SOFT:
*plValue = pBuffer->OriginalSize;
break;
case AL_SAMPLE_LENGTH:
case AL_SAMPLE_LENGTH_SOFT:
*plValue = pBuffer->SampleLen;
break;
@ -1017,9 +1026,9 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum eParam, ALint* plVal
case AL_BITS:
case AL_CHANNELS:
case AL_SIZE:
case AL_INTERNAL_FORMAT:
case AL_BYTE_LENGTH:
case AL_SAMPLE_LENGTH:
case AL_INTERNAL_FORMAT_SOFT:
case AL_BYTE_LENGTH_SOFT:
case AL_SAMPLE_LENGTH_SOFT:
alGetBufferi(buffer, eParam, plValues);
return;
}
@ -1059,9 +1068,11 @@ typedef ALubyte ALima4;
typedef struct {
ALbyte b[3];
} ALbyte3;
extern ALbyte ALbyte3_size_is_not_3[(sizeof(ALbyte3)==sizeof(ALbyte[3]))?1:-1];
typedef struct {
ALubyte b[3];
} ALubyte3;
extern ALbyte ALubyte3_size_is_not_3[(sizeof(ALubyte3)==sizeof(ALubyte[3]))?1:-1];
static __inline ALshort DecodeMuLaw(ALmulaw val)
{ return muLawDecompressionTable[val]; }
@ -1234,11 +1245,6 @@ static void EncodeIMA4Block(ALima4 *dst, const ALshort *src, ALint *sample, ALin
}
}
static const union {
ALuint u;
ALubyte b[sizeof(ALuint)];
} EndianTest = { 1 };
#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
static __inline ALint DecodeByte3(ALbyte3 val)
{
@ -1784,16 +1790,22 @@ DECL_TEMPLATE(ALubyte3, ALubyte3)
#define DECL_TEMPLATE(T) \
static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \
ALuint numblocks) \
ALuint len) \
{ \
ALuint i, j; \
ALshort tmp[65*MAXCHANNELS]; /* Max samples an IMA4 frame can be */ \
for(i = 0;i < numblocks;i++) \
ALuint i, j, k; \
\
i = 0; \
while(i < len) \
{ \
DecodeIMA4Block(tmp, src, numchans); \
src += 36*numchans; \
for(j = 0;j < 65*numchans;j++) \
*(dst++) = Conv_##T##_ALshort(tmp[j]); \
\
for(j = 0;j < 65 && i < len;j++,i++) \
{ \
for(k = 0;k < numchans;k++) \
*(dst++) = Conv_##T##_ALshort(tmp[j*numchans + k]); \
} \
} \
}
@ -1814,13 +1826,14 @@ DECL_TEMPLATE(ALubyte3)
#define DECL_TEMPLATE(T) \
static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \
ALuint numblocks) \
ALuint len) \
{ \
ALuint i, j; \
ALshort tmp[65*MAXCHANNELS]; /* Max samples an IMA4 frame can be */ \
ALint sample[MAXCHANNELS] = {0,0,0,0,0,0,0,0}; \
ALint index[MAXCHANNELS] = {0,0,0,0,0,0,0,0}; \
for(i = 0;i < numblocks;i++) \
ALuint i, j; \
\
for(i = 0;i < len;i += 65) \
{ \
for(j = 0;j < 65*numchans;j++) \
tmp[j] = Conv_ALshort_##T(*(src++)); \
@ -1974,6 +1987,19 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
ALuint64 newsize;
ALvoid *temp;
if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
(long)SrcChannels != (long)DstChannels)
return AL_INVALID_ENUM;
NewChannels = ChannelsFromFmt(DstChannels);
NewBytes = BytesFromFmt(DstType);
newsize = frames;
newsize *= NewBytes;
newsize *= NewChannels;
if(newsize > INT_MAX)
return AL_OUT_OF_MEMORY;
WriteLock(&ALBuf->lock);
if(ALBuf->ref != 0)
{
@ -1981,94 +2007,39 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
return AL_INVALID_OPERATION;
}
if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE ||
(long)SrcChannels != (long)DstChannels)
temp = realloc(ALBuf->data, (size_t)newsize);
if(!temp && newsize)
{
WriteUnlock(&ALBuf->lock);
return AL_INVALID_ENUM;
return AL_OUT_OF_MEMORY;
}
ALBuf->data = temp;
NewChannels = ChannelsFromFmt(DstChannels);
NewBytes = BytesFromFmt(DstType);
if(data != NULL)
ConvertData(ALBuf->data, DstType, data, SrcType, NewChannels, frames);
if(SrcType == UserFmtIMA4)
if(storesrc)
{
ALuint OrigChannels = ChannelsFromUserFmt(SrcChannels);
newsize = frames;
newsize *= 65;
newsize *= NewBytes;
newsize *= NewChannels;
if(newsize > INT_MAX)
{
WriteUnlock(&ALBuf->lock);
return AL_OUT_OF_MEMORY;
}
temp = realloc(ALBuf->data, (size_t)newsize);
if(!temp && newsize)
{
WriteUnlock(&ALBuf->lock);
return AL_OUT_OF_MEMORY;
}
ALBuf->data = temp;
ALBuf->SampleLen = frames*65;
if(data != NULL)
ConvertData(ALBuf->data, DstType, data, SrcType, NewChannels, frames);
if(storesrc)
{
ALBuf->OriginalChannels = SrcChannels;
ALBuf->OriginalType = SrcType;
ALBuf->OriginalSize = frames * 36 * OrigChannels;
}
ALBuf->OriginalChannels = SrcChannels;
ALBuf->OriginalType = SrcType;
if(SrcType == UserFmtIMA4)
ALBuf->OriginalSize = frames / 65 * 36 * ChannelsFromUserFmt(SrcChannels);
else
ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType);
}
else
{
ALuint OrigBytes = BytesFromUserFmt(SrcType);
ALuint OrigChannels = ChannelsFromUserFmt(SrcChannels);
newsize = frames;
newsize *= NewBytes;
newsize *= NewChannels;
if(newsize > INT_MAX)
{
WriteUnlock(&ALBuf->lock);
return AL_OUT_OF_MEMORY;
}
temp = realloc(ALBuf->data, (size_t)newsize);
if(!temp && newsize)
{
WriteUnlock(&ALBuf->lock);
return AL_OUT_OF_MEMORY;
}
ALBuf->data = temp;
ALBuf->SampleLen = frames;
if(data != NULL)
ConvertData(ALBuf->data, DstType, data, SrcType, NewChannels, frames);
if(storesrc)
{
ALBuf->OriginalChannels = SrcChannels;
ALBuf->OriginalType = SrcType;
ALBuf->OriginalSize = frames * OrigBytes * OrigChannels;
}
}
if(!storesrc)
{
ALBuf->OriginalChannels = DstChannels;
ALBuf->OriginalType = DstType;
ALBuf->OriginalSize = frames * NewBytes * NewChannels;
}
ALBuf->Frequency = freq;
ALBuf->FmtChannels = DstChannels;
ALBuf->FmtType = DstType;
ALBuf->Format = NewFormat;
ALBuf->SampleLen = frames;
ALBuf->LoopStart = 0;
ALBuf->LoopEnd = ALBuf->SampleLen;
@ -2165,7 +2136,7 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
};
ALuint i;
for(i = 0;i < sizeof(list)/sizeof(list[0]);i++)
for(i = 0;i < COUNTOF(list);i++)
{
if(list[i].format == format)
{
@ -2209,40 +2180,40 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm
enum FmtChannels channels;
enum FmtType type;
} list[] = {
{ AL_MONO8, FmtMono, FmtByte },
{ AL_MONO16, FmtMono, FmtShort },
{ AL_MONO32F, FmtMono, FmtFloat },
{ AL_MONO8_SOFT, FmtMono, FmtByte },
{ AL_MONO16_SOFT, FmtMono, FmtShort },
{ AL_MONO32F_SOFT, FmtMono, FmtFloat },
{ AL_STEREO8, FmtStereo, FmtByte },
{ AL_STEREO16, FmtStereo, FmtShort },
{ AL_STEREO32F, FmtStereo, FmtFloat },
{ AL_STEREO8_SOFT, FmtStereo, FmtByte },
{ AL_STEREO16_SOFT, FmtStereo, FmtShort },
{ AL_STEREO32F_SOFT, FmtStereo, FmtFloat },
{ AL_REAR8, FmtRear, FmtByte },
{ AL_REAR16, FmtRear, FmtShort },
{ AL_REAR32F, FmtRear, FmtFloat },
{ AL_REAR8_SOFT, FmtRear, FmtByte },
{ AL_REAR16_SOFT, FmtRear, FmtShort },
{ AL_REAR32F_SOFT, FmtRear, FmtFloat },
{ AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte },
{ AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort },
{ AL_QUAD8, FmtQuad, FmtByte },
{ AL_QUAD16, FmtQuad, FmtShort },
{ AL_QUAD32F, FmtQuad, FmtFloat },
{ AL_QUAD8_SOFT, FmtQuad, FmtByte },
{ AL_QUAD16_SOFT, FmtQuad, FmtShort },
{ AL_QUAD32F_SOFT, FmtQuad, FmtFloat },
{ AL_5POINT1_8, FmtX51, FmtByte },
{ AL_5POINT1_16, FmtX51, FmtShort },
{ AL_5POINT1_32F, FmtX51, FmtFloat },
{ AL_5POINT1_8_SOFT, FmtX51, FmtByte },
{ AL_5POINT1_16_SOFT, FmtX51, FmtShort },
{ AL_5POINT1_32F_SOFT, FmtX51, FmtFloat },
{ AL_6POINT1_8, FmtX61, FmtByte },
{ AL_6POINT1_16, FmtX61, FmtShort },
{ AL_6POINT1_32F, FmtX61, FmtFloat },
{ AL_6POINT1_8_SOFT, FmtX61, FmtByte },
{ AL_6POINT1_16_SOFT, FmtX61, FmtShort },
{ AL_6POINT1_32F_SOFT, FmtX61, FmtFloat },
{ AL_7POINT1_8, FmtX71, FmtByte },
{ AL_7POINT1_16, FmtX71, FmtShort },
{ AL_7POINT1_32F, FmtX71, FmtFloat },
{ AL_7POINT1_8_SOFT, FmtX71, FmtByte },
{ AL_7POINT1_16_SOFT, FmtX71, FmtShort },
{ AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
};
ALuint i;
for(i = 0;i < sizeof(list)/sizeof(list[0]);i++)
for(i = 0;i < COUNTOF(list);i++)
{
if(list[i].format == format)
{
@ -2260,19 +2231,16 @@ static ALboolean IsValidType(ALenum type)
{
switch(type)
{
case AL_BYTE:
case AL_UNSIGNED_BYTE:
case AL_SHORT:
case AL_UNSIGNED_SHORT:
case AL_INT:
case AL_UNSIGNED_INT:
case AL_FLOAT:
case AL_DOUBLE:
case AL_MULAW:
case AL_ALAW:
case AL_IMA4:
case AL_BYTE3:
case AL_UNSIGNED_BYTE3:
case AL_BYTE_SOFT:
case AL_UNSIGNED_BYTE_SOFT:
case AL_SHORT_SOFT:
case AL_UNSIGNED_SHORT_SOFT:
case AL_INT_SOFT:
case AL_UNSIGNED_INT_SOFT:
case AL_FLOAT_SOFT:
case AL_DOUBLE_SOFT:
case AL_BYTE3_SOFT:
case AL_UNSIGNED_BYTE3_SOFT:
return AL_TRUE;
}
return AL_FALSE;
@ -2282,13 +2250,13 @@ static ALboolean IsValidChannels(ALenum channels)
{
switch(channels)
{
case AL_MONO:
case AL_STEREO:
case AL_REAR:
case AL_QUAD:
case AL_5POINT1:
case AL_6POINT1:
case AL_7POINT1:
case AL_MONO_SOFT:
case AL_STEREO_SOFT:
case AL_REAR_SOFT:
case AL_QUAD_SOFT:
case AL_5POINT1_SOFT:
case AL_6POINT1_SOFT:
case AL_7POINT1_SOFT:
return AL_TRUE;
}
return AL_FALSE;

View File

@ -55,13 +55,13 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
for(i = 0;i < n;i++)
{
ALeffect *effect = calloc(1, sizeof(ALeffect));
if(!effect)
if(!effect || InitEffect(effect) != AL_NO_ERROR)
{
free(effect);
alSetError(Context, AL_OUT_OF_MEMORY);
alDeleteEffects(i, effects);
break;
}
InitEffectParams(effect, AL_EFFECT_NULL);
err = NewThunkEntry(&effect->effect);
if(err == AL_NO_ERROR)
@ -1173,6 +1173,12 @@ static void null_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param,
{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); }
ALenum InitEffect(ALeffect *effect)
{
InitEffectParams(effect, AL_EFFECT_NULL);
return AL_NO_ERROR;
}
ALvoid ReleaseALEffects(ALCdevice *device)
{
ALsizei i;
@ -1306,3 +1312,200 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
}
effect->type = type;
}
#include "AL/efx-presets.h"
#define DECL(x) { #x, EFX_REVERB_PRESET_##x }
static const struct {
const char name[32];
EFXEAXREVERBPROPERTIES props;
} reverblist[] = {
DECL(GENERIC),
DECL(PADDEDCELL),
DECL(ROOM),
DECL(BATHROOM),
DECL(LIVINGROOM),
DECL(STONEROOM),
DECL(AUDITORIUM),
DECL(CONCERTHALL),
DECL(CAVE),
DECL(ARENA),
DECL(HANGAR),
DECL(CARPETEDHALLWAY),
DECL(HALLWAY),
DECL(STONECORRIDOR),
DECL(ALLEY),
DECL(FOREST),
DECL(CITY),
DECL(MOUNTAINS),
DECL(QUARRY),
DECL(PLAIN),
DECL(PARKINGLOT),
DECL(SEWERPIPE),
DECL(UNDERWATER),
DECL(DRUGGED),
DECL(DIZZY),
DECL(PSYCHOTIC),
DECL(CASTLE_SMALLROOM),
DECL(CASTLE_SHORTPASSAGE),
DECL(CASTLE_MEDIUMROOM),
DECL(CASTLE_LARGEROOM),
DECL(CASTLE_LONGPASSAGE),
DECL(CASTLE_HALL),
DECL(CASTLE_CUPBOARD),
DECL(CASTLE_COURTYARD),
DECL(CASTLE_ALCOVE),
DECL(FACTORY_SMALLROOM),
DECL(FACTORY_SHORTPASSAGE),
DECL(FACTORY_MEDIUMROOM),
DECL(FACTORY_LARGEROOM),
DECL(FACTORY_LONGPASSAGE),
DECL(FACTORY_HALL),
DECL(FACTORY_CUPBOARD),
DECL(FACTORY_COURTYARD),
DECL(FACTORY_ALCOVE),
DECL(ICEPALACE_SMALLROOM),
DECL(ICEPALACE_SHORTPASSAGE),
DECL(ICEPALACE_MEDIUMROOM),
DECL(ICEPALACE_LARGEROOM),
DECL(ICEPALACE_LONGPASSAGE),
DECL(ICEPALACE_HALL),
DECL(ICEPALACE_CUPBOARD),
DECL(ICEPALACE_COURTYARD),
DECL(ICEPALACE_ALCOVE),
DECL(SPACESTATION_SMALLROOM),
DECL(SPACESTATION_SHORTPASSAGE),
DECL(SPACESTATION_MEDIUMROOM),
DECL(SPACESTATION_LARGEROOM),
DECL(SPACESTATION_LONGPASSAGE),
DECL(SPACESTATION_HALL),
DECL(SPACESTATION_CUPBOARD),
DECL(SPACESTATION_ALCOVE),
DECL(WOODEN_SMALLROOM),
DECL(WOODEN_SHORTPASSAGE),
DECL(WOODEN_MEDIUMROOM),
DECL(WOODEN_LARGEROOM),
DECL(WOODEN_LONGPASSAGE),
DECL(WOODEN_HALL),
DECL(WOODEN_CUPBOARD),
DECL(WOODEN_COURTYARD),
DECL(WOODEN_ALCOVE),
DECL(SPORT_EMPTYSTADIUM),
DECL(SPORT_SQUASHCOURT),
DECL(SPORT_SMALLSWIMMINGPOOL),
DECL(SPORT_LARGESWIMMINGPOOL),
DECL(SPORT_GYMNASIUM),
DECL(SPORT_FULLSTADIUM),
DECL(SPORT_STADIUMTANNOY),
DECL(PREFAB_WORKSHOP),
DECL(PREFAB_SCHOOLROOM),
DECL(PREFAB_PRACTISEROOM),
DECL(PREFAB_OUTHOUSE),
DECL(PREFAB_CARAVAN),
DECL(DOME_TOMB),
DECL(PIPE_SMALL),
DECL(DOME_SAINTPAULS),
DECL(PIPE_LONGTHIN),
DECL(PIPE_LARGE),
DECL(PIPE_RESONANT),
DECL(OUTDOORS_BACKYARD),
DECL(OUTDOORS_ROLLINGPLAINS),
DECL(OUTDOORS_DEEPCANYON),
DECL(OUTDOORS_CREEK),
DECL(OUTDOORS_VALLEY),
DECL(MOOD_HEAVEN),
DECL(MOOD_HELL),
DECL(MOOD_MEMORY),
DECL(DRIVING_COMMENTATOR),
DECL(DRIVING_PITGARAGE),
DECL(DRIVING_INCAR_RACER),
DECL(DRIVING_INCAR_SPORTS),
DECL(DRIVING_INCAR_LUXURY),
DECL(DRIVING_FULLGRANDSTAND),
DECL(DRIVING_EMPTYGRANDSTAND),
DECL(DRIVING_TUNNEL),
DECL(CITY_STREETS),
DECL(CITY_SUBWAY),
DECL(CITY_MUSEUM),
DECL(CITY_LIBRARY),
DECL(CITY_UNDERPASS),
DECL(CITY_ABANDONED),
DECL(DUSTYROOM),
DECL(CHAPEL),
DECL(SMALLWATERROOM),
};
#undef DECL
static const ALsizei reverblistsize = COUNTOF(reverblist);
ALvoid GetReverbEffect(const char *name, ALeffect *effect)
{
int i;
if(strcasecmp(name, "NONE") == 0)
{
InitEffectParams(effect, AL_EFFECT_NULL);
TRACE("Loading reverb '%s'\n", "NONE");
return;
}
if(!DisabledEffects[EAXREVERB])
InitEffectParams(effect, AL_EFFECT_EAXREVERB);
else if(!DisabledEffects[REVERB])
InitEffectParams(effect, AL_EFFECT_REVERB);
else
InitEffectParams(effect, AL_EFFECT_NULL);
for(i = 0;i < reverblistsize;i++)
{
const EFXEAXREVERBPROPERTIES *props;
if(strcasecmp(name, reverblist[i].name) != 0)
continue;
TRACE("Loading reverb '%s'\n", reverblist[i].name);
props = &reverblist[i].props;
effect->Reverb.Density = props->flDensity;
effect->Reverb.Diffusion = props->flDiffusion;
effect->Reverb.Gain = props->flGain;
effect->Reverb.GainHF = props->flGainHF;
effect->Reverb.GainLF = props->flGainLF;
effect->Reverb.DecayTime = props->flDecayTime;
effect->Reverb.DecayHFRatio = props->flDecayHFRatio;
effect->Reverb.DecayLFRatio = props->flDecayLFRatio;
effect->Reverb.ReflectionsGain = props->flReflectionsGain;
effect->Reverb.ReflectionsDelay = props->flReflectionsDelay;
effect->Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
effect->Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
effect->Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
effect->Reverb.LateReverbGain = props->flLateReverbGain;
effect->Reverb.LateReverbDelay = props->flLateReverbDelay;
effect->Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
effect->Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
effect->Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
effect->Reverb.EchoTime = props->flEchoTime;
effect->Reverb.EchoDepth = props->flEchoDepth;
effect->Reverb.ModulationTime = props->flModulationTime;
effect->Reverb.ModulationDepth = props->flModulationDepth;
effect->Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
effect->Reverb.HFReference = props->flHFReference;
effect->Reverb.LFReference = props->flLFReference;
effect->Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
effect->Reverb.DecayHFLimit = props->iDecayHFLimit;
break;
}
if(i == reverblistsize)
WARN("Reverb preset '%s' not found\n", name);
}

View File

@ -75,7 +75,7 @@ static const ALenums enumeration[] = {
{ "AL_STREAMING", AL_STREAMING },
{ "AL_UNDETERMINED", AL_UNDETERMINED },
{ "AL_METERS_PER_UNIT", AL_METERS_PER_UNIT },
{ "AL_VIRTUAL_CHANNELS_SOFT", AL_VIRTUAL_CHANNELS_SOFT },
{ "AL_DIRECT_CHANNELS_SOFT", AL_DIRECT_CHANNELS_SOFT },
// Source EFX Properties
{ "AL_DIRECT_FILTER", AL_DIRECT_FILTER },
@ -139,61 +139,58 @@ static const ALenums enumeration[] = {
{ "AL_FORMAT_STEREO_ALAW_EXT", AL_FORMAT_STEREO_ALAW_EXT },
// Internal Buffer Formats
{ "AL_MONO8", AL_MONO8 },
{ "AL_MONO16", AL_MONO16 },
{ "AL_MONO32F", AL_MONO32F },
{ "AL_STEREO8", AL_STEREO8 },
{ "AL_STEREO16", AL_STEREO16 },
{ "AL_STEREO32F", AL_STEREO32F },
{ "AL_QUAD8", AL_QUAD8 },
{ "AL_QUAD16", AL_QUAD16 },
{ "AL_QUAD32F", AL_QUAD32F },
{ "AL_REAR8", AL_REAR8 },
{ "AL_REAR16", AL_REAR16 },
{ "AL_REAR32F", AL_REAR32F },
{ "AL_5POINT1_8", AL_5POINT1_8 },
{ "AL_5POINT1_16", AL_5POINT1_16 },
{ "AL_5POINT1_32F", AL_5POINT1_32F },
{ "AL_6POINT1_8", AL_6POINT1_8 },
{ "AL_6POINT1_16", AL_6POINT1_16 },
{ "AL_6POINT1_32F", AL_6POINT1_32F },
{ "AL_7POINT1_8", AL_7POINT1_8 },
{ "AL_7POINT1_16", AL_7POINT1_16 },
{ "AL_7POINT1_32F", AL_7POINT1_32F },
{ "AL_MONO8_SOFT", AL_MONO8_SOFT },
{ "AL_MONO16_SOFT", AL_MONO16_SOFT },
{ "AL_MONO32F_SOFT", AL_MONO32F_SOFT },
{ "AL_STEREO8_SOFT", AL_STEREO8_SOFT },
{ "AL_STEREO16_SOFT", AL_STEREO16_SOFT },
{ "AL_STEREO32F_SOFT", AL_STEREO32F_SOFT },
{ "AL_QUAD8_SOFT", AL_QUAD8_SOFT },
{ "AL_QUAD16_SOFT", AL_QUAD16_SOFT },
{ "AL_QUAD32F_SOFT", AL_QUAD32F_SOFT },
{ "AL_REAR8_SOFT", AL_REAR8_SOFT },
{ "AL_REAR16_SOFT", AL_REAR16_SOFT },
{ "AL_REAR32F_SOFT", AL_REAR32F_SOFT },
{ "AL_5POINT1_8_SOFT", AL_5POINT1_8_SOFT },
{ "AL_5POINT1_16_SOFT", AL_5POINT1_16_SOFT },
{ "AL_5POINT1_32F_SOFT", AL_5POINT1_32F_SOFT },
{ "AL_6POINT1_8_SOFT", AL_6POINT1_8_SOFT },
{ "AL_6POINT1_16_SOFT", AL_6POINT1_16_SOFT },
{ "AL_6POINT1_32F_SOFT", AL_6POINT1_32F_SOFT },
{ "AL_7POINT1_8_SOFT", AL_7POINT1_8_SOFT },
{ "AL_7POINT1_16_SOFT", AL_7POINT1_16_SOFT },
{ "AL_7POINT1_32F_SOFT", AL_7POINT1_32F_SOFT },
// Buffer Channel Configurations
{ "AL_MONO", AL_MONO },
{ "AL_STEREO", AL_STEREO },
{ "AL_QUAD", AL_QUAD },
{ "AL_REAR", AL_REAR },
{ "AL_5POINT1", AL_5POINT1 },
{ "AL_6POINT1", AL_6POINT1 },
{ "AL_7POINT1", AL_7POINT1 },
{ "AL_MONO_SOFT", AL_MONO_SOFT },
{ "AL_STEREO_SOFT", AL_STEREO_SOFT },
{ "AL_QUAD_SOFT", AL_QUAD_SOFT },
{ "AL_REAR_SOFT", AL_REAR_SOFT },
{ "AL_5POINT1_SOFT", AL_5POINT1_SOFT },
{ "AL_6POINT1_SOFT", AL_6POINT1_SOFT },
{ "AL_7POINT1_SOFT", AL_7POINT1_SOFT },
// Buffer Sample Types
{ "AL_BYTE", AL_BYTE },
{ "AL_UNSIGNED_BYTE", AL_UNSIGNED_BYTE },
{ "AL_SHORT", AL_SHORT },
{ "AL_UNSIGNED_SHORT", AL_UNSIGNED_SHORT },
{ "AL_INT", AL_INT },
{ "AL_UNSIGNED_INT", AL_UNSIGNED_INT },
{ "AL_FLOAT", AL_FLOAT },
{ "AL_DOUBLE", AL_DOUBLE },
{ "AL_MULAW", AL_MULAW },
{ "AL_ALAW", AL_ALAW },
{ "AL_IMA4", AL_IMA4 },
{ "AL_BYTE3", AL_BYTE3 },
{ "AL_UNSIGNED_BYTE3", AL_UNSIGNED_BYTE3 },
{ "AL_BYTE_SOFT", AL_BYTE_SOFT },
{ "AL_UNSIGNED_BYTE_SOFT", AL_UNSIGNED_BYTE_SOFT },
{ "AL_SHORT_SOFT", AL_SHORT_SOFT },
{ "AL_UNSIGNED_SHORT_SOFT", AL_UNSIGNED_SHORT_SOFT },
{ "AL_INT_SOFT", AL_INT_SOFT },
{ "AL_UNSIGNED_INT_SOFT", AL_UNSIGNED_INT_SOFT },
{ "AL_FLOAT_SOFT", AL_FLOAT_SOFT },
{ "AL_DOUBLE_SOFT", AL_DOUBLE_SOFT },
{ "AL_BYTE3_SOFT", AL_BYTE3_SOFT },
{ "AL_UNSIGNED_BYTE3_SOFT", AL_UNSIGNED_BYTE3_SOFT },
// Buffer attributes
{ "AL_FREQUENCY", AL_FREQUENCY },
{ "AL_BITS", AL_BITS },
{ "AL_CHANNELS", AL_CHANNELS },
{ "AL_SIZE", AL_SIZE },
{ "AL_INTERNAL_FORMAT", AL_INTERNAL_FORMAT },
{ "AL_BYTE_LENGTH", AL_BYTE_LENGTH },
{ "AL_SAMPLE_LENGTH", AL_SAMPLE_LENGTH },
{ "AL_SEC_LENGTH", AL_SEC_LENGTH },
{ "AL_INTERNAL_FORMAT_SOFT", AL_INTERNAL_FORMAT_SOFT },
{ "AL_BYTE_LENGTH_SOFT", AL_BYTE_LENGTH_SOFT },
{ "AL_SAMPLE_LENGTH_SOFT", AL_SAMPLE_LENGTH_SOFT },
{ "AL_SEC_LENGTH_SOFT", AL_SEC_LENGTH_SOFT },
// Buffer States (not supported yet)
{ "AL_UNUSED", AL_UNUSED },

View File

@ -33,13 +33,13 @@
#include "alAuxEffectSlot.h"
enum Resampler DefaultResampler = RESAMPLER_DEFAULT;
const ALsizei ResamplerPadding[RESAMPLER_MAX] = {
enum Resampler DefaultResampler = LinearResampler;
const ALsizei ResamplerPadding[ResamplerMax] = {
0, /* Point */
1, /* Linear */
2, /* Cubic */
};
const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
const ALsizei ResamplerPrePadding[ResamplerMax] = {
0, /* Point */
0, /* Linear */
1, /* Cubic */
@ -54,12 +54,10 @@ static ALint GetSampleOffset(ALsource *Source);
AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
{
ALCcontext *Context;
ALCdevice *Device;
Context = GetContextRef();
if(!Context) return;
Device = Context->Device;
if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
alSetError(Context, AL_INVALID_VALUE);
else
@ -583,7 +581,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
// Increment reference counter for buffer
IncrementRef(&buffer->ref);
oldlist = ExchangePtr((void**)&Source->queue, BufferListItem);
oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
Source->BuffersInQueue = 1;
ReadLock(&buffer->lock);
@ -600,7 +598,7 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
{
// Source is now in UNDETERMINED mode
Source->lSourceType = AL_UNDETERMINED;
oldlist = ExchangePtr((void**)&Source->queue, NULL);
oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
}
// Delete all previous elements in the queue
@ -706,10 +704,10 @@ AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
alSetError(pContext, AL_INVALID_VALUE);
break;
case AL_VIRTUAL_CHANNELS_SOFT:
case AL_DIRECT_CHANNELS_SOFT:
if(lValue == AL_TRUE || lValue == AL_FALSE)
{
Source->VirtualChannels = lValue;
Source->DirectChannels = lValue;
Source->NeedsUpdate = AL_TRUE;
}
else
@ -780,7 +778,7 @@ AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1,
/* Release refcount on the previous slot, and add one for
* the new slot */
if(ALEffectSlot) IncrementRef(&ALEffectSlot->ref);
ALEffectSlot = ExchangePtr((void**)&Source->Send[lValue2].Slot, ALEffectSlot);
ALEffectSlot = ExchangePtr((XchgPtr*)&Source->Send[lValue2].Slot, ALEffectSlot);
if(ALEffectSlot) DecrementRef(&ALEffectSlot->ref);
if(!ALFilter)
@ -838,7 +836,7 @@ AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* pl
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DISTANCE_MODEL:
case AL_VIRTUAL_CHANNELS_SOFT:
case AL_DIRECT_CHANNELS_SOFT:
alSourcei(source, eParam, plValues[0]);
return;
@ -1211,8 +1209,8 @@ AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plVa
*plValue = (ALint)Source->DopplerFactor;
break;
case AL_VIRTUAL_CHANNELS_SOFT:
*plValue = Source->VirtualChannels;
case AL_DIRECT_CHANNELS_SOFT:
*plValue = Source->DirectChannels;
break;
case AL_DISTANCE_MODEL:
@ -1317,7 +1315,7 @@ AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plVal
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DISTANCE_MODEL:
case AL_VIRTUAL_CHANNELS_SOFT:
case AL_DIRECT_CHANNELS_SOFT:
alGetSourcei(source, eParam, plValues);
return;
@ -1824,9 +1822,9 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->AirAbsorptionFactor = 0.0f;
Source->RoomRolloffFactor = 0.0f;
Source->DopplerFactor = 1.0f;
Source->VirtualChannels = AL_TRUE;
Source->DirectChannels = AL_FALSE;
Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
Source->DistanceModel = DefaultDistanceModel;
Source->Resampler = DefaultResampler;
@ -1985,6 +1983,9 @@ static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, A
return;
}
if(updateLen > 0.0 && updateLen < 0.015)
updateLen = 0.015;
// Get Current SamplesPlayed (NOTE : This is the offset into the *current* buffer)
readPos = Source->position;
// Add length of any processed buffers in the queue

View File

@ -5,35 +5,29 @@
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
# specific override settings in ~/.alsoftrc.
# For Windows, these settings should go into %AppData%\alsoft.ini
# The environment variable ALSOFT_CONF can be used to specify another config
# override
# Option and block names are case-insenstive. The supplied values are only
# hints and may not be honored (though generally it'll try to get as close as
# possible). Note: options that are left unset may default to app- or system-
# specified values. These are the current available settings:
## format:
# Sets the output format. Can be one of:
# AL_FORMAT_MONO8 (8-bit mono)
# AL_FORMAT_STEREO8 (8-bit stereo)
# AL_FORMAT_QUAD8 (8-bit 4-channel)
# AL_FORMAT_51CHN8 (8-bit 5.1 output)
# AL_FORMAT_61CHN8 (8-bit 6.1 output)
# AL_FORMAT_71CHN8 (8-bit 7.1 output)
# AL_FORMAT_MONO16 (16-bit mono)
# AL_FORMAT_STEREO16 (16-bit stereo)
# AL_FORMAT_QUAD16 (16-bit 4-channel)
# AL_FORMAT_51CHN16 (16-bit 5.1 output)
# AL_FORMAT_61CHN16 (16-bit 6.1 output)
# AL_FORMAT_71CHN16 (16-bit 7.1 output)
# AL_FORMAT_MONO32 (32-bit float mono)
# AL_FORMAT_STEREO32 (32-bit float stereo)
# AL_FORMAT_QUAD32 (32-bit float 4-channel)
# AL_FORMAT_51CHN32 (32-bit float 5.1 output)
# AL_FORMAT_61CHN32 (32-bit float 6.1 output)
# AL_FORMAT_71CHN32 (32-bit float 7.1 output)
#format = AL_FORMAT_STEREO16
## channels:
# Sets the output channel configuration. If left unspecified, one will try to
# be detected from the system, and defaulting to stereo. The available values
# are: mono, stereo, quad, surround51, surround61, surround71
#channels = stereo
## sample-type:
# Sets the output sample type. Currently, all mixing is done with 32-bit float
# and converted to the output sample type as needed. Available values are:
# int8 - signed 8-bit int
# uint8 - unsigned 8-bit int
# int16 - signed 16-bit int
# uint16 - unsigned 16-bit int
# int32 - signed 32-bit int
# uint32 - unsigned 32-bit int
# float32 - 32-bit float
#sample-type = float32
## hrtf:
# Enables HRTF filters. These filters provide for better sound spatialization
@ -42,6 +36,12 @@
# Default is disabled since stereo speaker output quality may suffer.
#hrtf = false
## hrtf_tables
# Specifies a comma-separated list of files containing HRTF data sets. The
# listed data sets can be used in place of or in addiiton to the the built-in
# set. The format of the files are described in hrtf.txt.
#hrtf_tables =
## cf_level:
# Sets the crossfeed level for stereo output. Valid values are:
# 0 - No crossfeed
@ -61,11 +61,11 @@
## resampler:
# Selects the resampler used when mixing sources. Valid values are:
# 0 - None (nearest sample, no interpolation)
# 1 - Linear (extrapolates samples using a linear slope between samples)
# 2 - Cubic (extrapolates samples using a Catmull-Rom spline)
# point - nearest sample, no interpolation
# linear - extrapolates samples using a linear slope between samples
# cubic - extrapolates samples using a Catmull-Rom spline
# Specifying other values will result in using the default (linear).
#resampler = 1
#resampler = linear
## rt-prio:
# Sets real-time priority for the mixing thread. Not all drivers may use this
@ -78,13 +78,14 @@
## period_size:
# Sets the update period size, in frames. This is the number of frames needed
# for each mixing update.
# for each mixing update. Acceptable values range between 64 and 8192.
#period_size = 1024
## periods:
# Sets the number of update periods. Higher values create a larger mix ahead,
# which helps protect against skips when the CPU is under load, but increases
# the delay between a sound getting mixed and being heard.
# the delay between a sound getting mixed and being heard. Acceptable values
# range between 2 and 16.
#periods = 4
## sources:
@ -93,13 +94,13 @@
#sources = 256
## stereodup:
# Sets whether to duplicate stereo sounds behind the listener for 4+ channel
# output. This provides a "fuller" playback quality for surround sound output
# modes, although each individual speaker will have a slight reduction in
# volume to compensate for the extra output speakers. True, yes, on, and non-0
# values will duplicate stereo sources. 0 and anything else will cause stereo
# sounds to only play in front. This only has an effect when a suitable output
# format is used (ie. those that contain side and/or rear speakers).
# Sets whether to duplicate stereo sounds behind the listener. This provides a
# "fuller" playback quality for surround sound output modes, although each
# individual speaker will have a slight reduction in volume to compensate for
# the extra output speakers. True, yes, on, and non-0 values will duplicate
# stereo sources. 0 and anything else will cause stereo sounds to only play in
# front. This only has an effect when a suitable output format is used (ie.
# those that contain side and/or rear speakers).
#stereodup = true
## drivers:
@ -144,26 +145,31 @@
# Channel-specific layouts may be specified to override the layout option. The
# same speakers as the layout option are available, and the default settings
# are shown below.
#layout_STEREO = fl=-90, fr=90
#layout_QUAD = fl=-45, fr=45, bl=-135, br=135
#layout_51CHN = fl=-30, fr=30, fc=0, bl=-110, br=110
#layout_61CHN = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180
#layout_71CHN = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150
#layout_stereo = fl=-90, fr=90
#layout_quad = fl=-45, fr=45, bl=-135, br=135
#layout_surround51 = fl=-30, fr=30, fc=0, bl=-110, br=110
#layout_surround61 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180
#layout_surround71 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150
## default-reverb:
# A reverb preset that applies by default to all sources on send 0
# (applications that set their own slots on send 0 will override this).
# Available presets are: None, Generic, PaddedCell, Room, Bathroom,
# Livingroom, Stoneroom, Auditorium, ConcertHall, Cave, Arena, Hangar,
# CarpetedHallway, Hallway, StoneCorridor, Alley, Forest, City, Moutains,
# Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic.
#default-reverb =
## trap-alc-error:
# Generates a SIGTRAP signal when an ALC device error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a device error. On Windows, a breakpoint exception is generated.
# Optionally, the __ALSOFT_TRAP_ALC_ERROR env var may be set before running
# the app instead.
#trap-alc-error = false
## trap-al-error:
# Generates a SIGTRAP signal when an AL context error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a context error. On Windows, a breakpoint exception is generated.
# Optionally, the __ALSOFT_TRAP_AL_ERROR env var may be set before running the
# app instead.
#trap-al-error = false
##
@ -199,16 +205,30 @@
# device index for the requested device name.
#device-prefix = plughw:
## device-prefix-*:
# Card- and device-specific prefixes may be used to override the device-prefix
# option. The option may specify the card id (eg, device-prefix-NVidia), or
# the card id and device index (eg, device-prefix-NVidia-0). The card id is
# case-sensitive.
#defice-prefix- =
## capture:
# Sets the device name for the default capture device.
#capture = default
## capture-prefix:
# Sets the prefix used by the discovered (non-default) capture devices. This
# will be appended with "CARD=c,DEV=d", where c is the card number and d is
# the device number for the requested device name.
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
# device number for the requested device name.
#capture-prefix = plughw:
## capture-prefix-*:
# Card- and device-specific prefixes may be used to override the
# capture-prefix option. The option may specify the card id (eg,
# capture-prefix-NVidia), or the card id and device index (eg,
# capture-prefix-NVidia-0). The card id is case-sensitive.
#capture-prefix- =
## mmap:
# Sets whether to try using mmap mode (helps reduce latencies and CPU
# consumption). If mmap isn't available, it will automatically fall back to

71
env-vars.txt Normal file
View File

@ -0,0 +1,71 @@
Useful Environment Variables
Below is a list of environment variables that can be set to aid with running or
debugging apps that use OpenAL Soft. They should be set before the app is run.
*** Logging ***
ALSOFT_LOGLEVEL
Specifies the amount of logging OpenAL Soft will write out:
0 - Effectively disables all logging
1 - Prints out errors only
2 - Prints out warnings and errors
3 - Prints out additional information, as well as warnings and errors
4 - Same as 3, but also device and context reference count changes. This will
print out *a lot* of info, and is generally not useful unless you're trying
to track a reference leak within the library.
ALSOFT_LOGFILE
Specifies a filename that logged output will be written to. Note that the file
will be first cleared when logging is initialized.
*** Overrides ***
ALSOFT_CONF
Specifies an additional configuration file to load settings from. These
settings will take precedence over the global and user configs, but not other
environment variable settings.
ALSOFT_DRIVERS
Overrides the drivers config option. This specifies which backend drivers to
consider or not consider for use. Please see the drivers option in
alsoftrc.sample for a list of available drivers.
ALSOFT_DEFAULT_REVERB
Specifies the default reverb preset to apply to sources. Please see the
default-reverb option in alsoftrc.sample for additional information and a list
of available presets.
ALSOFT_TRAP_AL_ERROR
Set to "true" or "1" to force trapping AL errors. Like the trap-al-error config
option, this will raise a SIGTRAP signal (or a breakpoint exception under
Windows) when a context-level error is generated. Useful when run under a
debugger as it will break execution right when the error occurs, making it
easier to track the cause.
ALSOFT_TRAP_ALC_ERROR
Set to "true" or "1" to force trapping ALC errors. Like the trap-alc-error
config option, this will raise a SIGTRAP signal (or a breakpoint exception
under Windows) when a device-level error is generated. Useful when run under a
debugger as it will break execution right when the error occurs, making it
easier to track the cause.
ALSOFT_TRAP_ERROR
Set to "true" or "1" to force trapping both ALC and AL errors.
*** Compatibility ***
__ALSOFT_HALF_ANGLE_CONES
Older versions of OpenAL Soft incorrectly calculated the cone angles to range
between 0 and 180 degrees, instead of the expected range of 0 to 360 degrees.
Setting this to "true" or "1" restores the old buggy behavior, for apps that
were written to expect the incorrect range.
__ALSOFT_REVERSE_Z
Applications that don't natively use OpenAL's coordinate system have to convert
to it before passing in 3D coordinates. Depending on how exactly this is done,
it can cause correct output for stereo but incorrect Z panning for surround
sound (i.e., sounds that are supposed to be behind you sound like they're in
front, and vice-versa). Setting this to "true" or "1" will negate the localized
Z coordinate to attempt to fix output for apps that have incorrect front/back
panning.

625
examples/alffmpeg.c Normal file
View File

@ -0,0 +1,625 @@
/*
* FFmpeg Decoder Helpers
*
* Copyright (c) 2011 by Chris Robinson <chris.kcat@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* This file contains routines for helping to decode audio using libavformat
* and libavcodec (ffmpeg). There's very little OpenAL-specific code here. */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <assert.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alhelpers.h"
#include "alffmpeg.h"
static size_t NextPowerOf2(size_t value)
{
size_t powerOf2 = 1;
if(value)
{
value--;
while(value)
{
value >>= 1;
powerOf2 <<= 1;
}
}
return powerOf2;
}
struct MemData {
char *buffer;
size_t length;
size_t pos;
};
static int MemData_read(void *opaque, uint8_t *buf, int buf_size)
{
struct MemData *membuf = (struct MemData*)opaque;
int rem = membuf->length - membuf->pos;
if(rem > buf_size)
rem = buf_size;
memcpy(buf, &membuf->buffer[membuf->pos], rem);
membuf->pos += rem;
return rem;
}
static int MemData_write(void *opaque, uint8_t *buf, int buf_size)
{
struct MemData *membuf = (struct MemData*)opaque;
int rem = membuf->length - membuf->pos;
if(rem > buf_size)
rem = buf_size;
memcpy(&membuf->buffer[membuf->pos], buf, rem);
membuf->pos += rem;
return rem;
}
static int64_t MemData_seek(void *opaque, int64_t offset, int whence)
{
struct MemData *membuf = (struct MemData*)opaque;
whence &= ~AVSEEK_FORCE;
switch(whence)
{
case SEEK_SET:
if(offset < 0 || offset > membuf->length)
return -1;
membuf->pos = offset;
break;
case SEEK_CUR:
if((offset >= 0 && offset > membuf->length-membuf->pos) ||
(offset < 0 && offset < -membuf->pos))
return -1;
membuf->pos += offset;
break;
case SEEK_END:
if(offset > 0 || offset < -membuf->length)
return -1;
membuf->pos = membuf->length + offset;
break;
case AVSEEK_SIZE:
return membuf->length;
default:
return -1;
}
return membuf->pos;
}
struct PacketList {
AVPacket pkt;
struct PacketList *next;
};
struct MyStream {
AVCodecContext *CodecCtx;
int StreamIdx;
struct PacketList *Packets;
char *DecodedData;
size_t DecodedDataSize;
FilePtr parent;
};
struct MyFile {
AVFormatContext *FmtCtx;
StreamPtr *Streams;
size_t StreamsSize;
struct MemData membuf;
};
static int done_init = 0;
FilePtr openAVFile(const char *fname)
{
FilePtr file;
/* We need to make sure ffmpeg is initialized. Optionally silence warning
* output from the lib */
if(!done_init) {av_register_all();
av_log_set_level(AV_LOG_ERROR);
done_init = 1;}
file = (FilePtr)calloc(1, sizeof(*file));
if(file && avformat_open_input(&file->FmtCtx, fname, NULL, NULL) == 0)
{
/* After opening, we must search for the stream information because not
* all formats will have it in stream headers */
if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0)
return file;
av_close_input_file(file->FmtCtx);
}
free(file);
return NULL;
}
FilePtr openAVData(const char *name, char *buffer, size_t buffer_len)
{
FilePtr file;
if(!done_init) {av_register_all();
av_log_set_level(AV_LOG_ERROR);
done_init = 1;}
if(!name)
name = "";
file = (FilePtr)calloc(1, sizeof(*file));
if(file && (file->FmtCtx=avformat_alloc_context()) != NULL)
{
file->membuf.buffer = buffer;
file->membuf.length = buffer_len;
file->membuf.pos = 0;
file->FmtCtx->pb = avio_alloc_context(NULL, 0, 0, &file->membuf,
MemData_read, MemData_write,
MemData_seek);
if(file->FmtCtx->pb && avformat_open_input(&file->FmtCtx, name, NULL, NULL) == 0)
{
if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0)
return file;
}
av_close_input_file(file->FmtCtx);
}
free(file);
return NULL;
}
FilePtr openAVCustom(const char *name, void *user_data,
int (*read_packet)(void *user_data, uint8_t *buf, int buf_size),
int (*write_packet)(void *user_data, uint8_t *buf, int buf_size),
int64_t (*seek)(void *user_data, int64_t offset, int whence))
{
FilePtr file;
if(!done_init) {av_register_all();
av_log_set_level(AV_LOG_ERROR);
done_init = 1;}
if(!name)
name = "";
file = (FilePtr)calloc(1, sizeof(*file));
if(file && (file->FmtCtx=avformat_alloc_context()) != NULL)
{
file->FmtCtx->pb = avio_alloc_context(NULL, 0, 0, user_data,
read_packet, write_packet, seek);
if(file->FmtCtx->pb && avformat_open_input(&file->FmtCtx, name, NULL, NULL) == 0)
{
if(avformat_find_stream_info(file->FmtCtx, NULL) >= 0)
return file;
}
av_close_input_file(file->FmtCtx);
}
free(file);
return NULL;
}
void closeAVFile(FilePtr file)
{
size_t i;
if(!file) return;
for(i = 0;i < file->StreamsSize;i++)
{
StreamPtr stream = file->Streams[i];
while(stream->Packets)
{
struct PacketList *self;
self = stream->Packets;
stream->Packets = self->next;
av_free_packet(&self->pkt);
av_free(self);
}
avcodec_close(stream->CodecCtx);
av_free(stream->DecodedData);
free(stream);
}
free(file->Streams);
av_close_input_file(file->FmtCtx);
free(file);
}
int getAVFileInfo(FilePtr file, int *numaudiostreams)
{
unsigned int i;
int audiocount = 0;
if(!file) return 1;
for(i = 0;i < file->FmtCtx->nb_streams;i++)
{
if(file->FmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
audiocount++;
}
*numaudiostreams = audiocount;
return 0;
}
StreamPtr getAVAudioStream(FilePtr file, int streamnum)
{
unsigned int i;
if(!file) return NULL;
for(i = 0;i < file->FmtCtx->nb_streams;i++)
{
if(file->FmtCtx->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
continue;
if(streamnum == 0)
{
StreamPtr stream;
AVCodec *codec;
void *temp;
size_t j;
/* Found the requested stream. Check if a handle to this stream
* already exists and return it if it does */
for(j = 0;j < file->StreamsSize;j++)
{
if(file->Streams[j]->StreamIdx == (int)i)
return file->Streams[j];
}
/* Doesn't yet exist. Now allocate a new stream object and fill in
* its info */
stream = (StreamPtr)calloc(1, sizeof(*stream));
if(!stream) return NULL;
stream->parent = file;
stream->CodecCtx = file->FmtCtx->streams[i]->codec;
stream->StreamIdx = i;
/* Try to find the codec for the given codec ID, and open it */
codec = avcodec_find_decoder(stream->CodecCtx->codec_id);
if(!codec || avcodec_open(stream->CodecCtx, codec) < 0)
{
free(stream);
return NULL;
}
/* Allocate space for the decoded data to be stored in before it
* gets passed to the app */
stream->DecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
if(!stream->DecodedData)
{
avcodec_close(stream->CodecCtx);
free(stream);
return NULL;
}
/* Append the new stream object to the stream list. The original
* pointer will remain valid if realloc fails, so we need to use
* another pointer to watch for errors and not leak memory */
temp = realloc(file->Streams, (file->StreamsSize+1) *
sizeof(*file->Streams));
if(!temp)
{
avcodec_close(stream->CodecCtx);
av_free(stream->DecodedData);
free(stream);
return NULL;
}
file->Streams = (StreamPtr*)temp;
file->Streams[file->StreamsSize++] = stream;
return stream;
}
streamnum--;
}
return NULL;
}
int getAVAudioInfo(StreamPtr stream, ALuint *rate, ALenum *channels, ALenum *type)
{
if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
return 1;
/* Get the sample type for OpenAL given the format detected by ffmpeg. */
if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_U8)
*type = AL_UNSIGNED_BYTE_SOFT;
else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_S16)
*type = AL_SHORT_SOFT;
else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_S32)
*type = AL_INT_SOFT;
else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_FLT)
*type = AL_FLOAT_SOFT;
else if(stream->CodecCtx->sample_fmt == AV_SAMPLE_FMT_DBL)
*type = AL_DOUBLE_SOFT;
else
{
fprintf(stderr, "Unsupported ffmpeg sample format: %s\n",
av_get_sample_fmt_name(stream->CodecCtx->sample_fmt));
return 1;
}
/* Get the OpenAL channel configuration using the channel layout detected
* by ffmpeg. NOTE: some file types may not specify a channel layout. In
* that case, one must be guessed based on the channel count. */
if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_MONO)
*channels = AL_MONO_SOFT;
else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_STEREO)
*channels = AL_STEREO_SOFT;
else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_QUAD)
*channels = AL_QUAD_SOFT;
else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK)
*channels = AL_5POINT1_SOFT;
else if(stream->CodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1)
*channels = AL_7POINT1_SOFT;
else if(stream->CodecCtx->channel_layout == 0)
{
/* Unknown channel layout. Try to guess. */
if(stream->CodecCtx->channels == 1)
*channels = AL_MONO_SOFT;
else if(stream->CodecCtx->channels == 2)
*channels = AL_STEREO_SOFT;
else
{
fprintf(stderr, "Unsupported ffmpeg raw channel count: %d\n",
stream->CodecCtx->channels);
return 1;
}
}
else
{
char str[1024];
av_get_channel_layout_string(str, sizeof(str), stream->CodecCtx->channels,
stream->CodecCtx->channel_layout);
fprintf(stderr, "Unsupported ffmpeg channel layout: %s\n", str);
return 1;
}
*rate = stream->CodecCtx->sample_rate;
return 0;
}
/* Used by getAV*Data to search for more compressed data, and buffer it in the
* correct stream. It won't buffer data for streams that the app doesn't have a
* handle for. */
static int getNextPacket(FilePtr file, int streamidx)
{
struct PacketList *packet;
packet = (struct PacketList*)av_malloc(sizeof(*packet));
packet->next = NULL;
next_packet:
while(av_read_frame(file->FmtCtx, &packet->pkt) >= 0)
{
StreamPtr *iter = file->Streams;
StreamPtr *iter_end = iter + file->StreamsSize;
/* Check each stream the user has a handle for, looking for the one
* this packet belongs to */
while(iter != iter_end)
{
if((*iter)->StreamIdx == packet->pkt.stream_index)
{
struct PacketList **last;
last = &(*iter)->Packets;
while(*last != NULL)
last = &(*last)->next;
*last = packet;
if((*iter)->StreamIdx == streamidx)
return 1;
packet = (struct PacketList*)av_malloc(sizeof(*packet));
packet->next = NULL;
goto next_packet;
}
iter++;
}
/* Free the packet and look for another */
av_free_packet(&packet->pkt);
}
av_free(packet);
return 0;
}
void *getAVAudioData(StreamPtr stream, size_t *length)
{
int size;
int len;
if(length) *length = 0;
if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
return NULL;
stream->DecodedDataSize = 0;
next_packet:
if(!stream->Packets && !getNextPacket(stream->parent, stream->StreamIdx))
return NULL;
/* Decode some data, and check for errors */
size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
while((len=avcodec_decode_audio3(stream->CodecCtx,
(int16_t*)stream->DecodedData, &size,
&stream->Packets->pkt)) == 0)
{
struct PacketList *self;
if(size > 0)
break;
/* Packet went unread and no data was given? Drop it and try the next,
* I guess... */
self = stream->Packets;
stream->Packets = self->next;
av_free_packet(&self->pkt);
av_free(self);
if(!stream->Packets)
goto next_packet;
size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
}
if(len < 0)
return NULL;
if(len < stream->Packets->pkt.size)
{
/* Move the unread data to the front and clear the end bits */
int remaining = stream->Packets->pkt.size - len;
memmove(stream->Packets->pkt.data, &stream->Packets->pkt.data[len],
remaining);
memset(&stream->Packets->pkt.data[remaining], 0,
stream->Packets->pkt.size - remaining);
stream->Packets->pkt.size -= len;
}
else
{
struct PacketList *self;
self = stream->Packets;
stream->Packets = self->next;
av_free_packet(&self->pkt);
av_free(self);
}
if(size == 0)
goto next_packet;
/* Set the output buffer size */
stream->DecodedDataSize = size;
if(length) *length = stream->DecodedDataSize;
return stream->DecodedData;
}
size_t readAVAudioData(StreamPtr stream, void *data, size_t length)
{
size_t dec = 0;
if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
return 0;
while(dec < length)
{
/* If there's no decoded data, find some */
if(stream->DecodedDataSize == 0)
{
if(getAVAudioData(stream, NULL) == NULL)
break;
}
if(stream->DecodedDataSize > 0)
{
/* Get the amount of bytes remaining to be written, and clamp to
* the amount of decoded data we have */
size_t rem = length-dec;
if(rem > stream->DecodedDataSize)
rem = stream->DecodedDataSize;
/* Copy the data to the app's buffer and increment */
if(data != NULL)
{
memcpy(data, stream->DecodedData, rem);
data = (char*)data + rem;
}
dec += rem;
/* If there's any decoded data left, move it to the front of the
* buffer for next time */
if(rem < stream->DecodedDataSize)
memmove(stream->DecodedData, &stream->DecodedData[rem],
stream->DecodedDataSize - rem);
stream->DecodedDataSize -= rem;
}
}
/* Return the number of bytes we were able to get */
return dec;
}
void *decodeAVAudioStream(StreamPtr stream, size_t *length)
{
char *outbuf = NULL;
size_t buflen = 0;
void *inbuf;
size_t got;
*length = 0;
if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
return NULL;
while((inbuf=getAVAudioData(stream, &got)) != NULL && got > 0)
{
void *ptr;
ptr = realloc(outbuf, NextPowerOf2(buflen+got));
if(ptr == NULL)
break;
outbuf = (char*)ptr;
memcpy(&outbuf[buflen], inbuf, got);
buflen += got;
}
outbuf = (char*)realloc(outbuf, buflen);
*length = buflen;
return outbuf;
}

66
examples/alffmpeg.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef ALFFMPEG_H
#define ALFFMPEG_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
/* Opaque handles to files and streams. Apps don't need to concern themselves
* with the internals */
typedef struct MyFile *FilePtr;
typedef struct MyStream *StreamPtr;
/* Opens a file with ffmpeg and sets up the streams' information */
FilePtr openAVFile(const char *fname);
/* Opens a named file image with ffmpeg and sets up the streams' information */
FilePtr openAVData(const char *name, char *buffer, size_t buffer_len);
/* Opens a named data stream with ffmpeg, using the specified data pointer and
* callbacks, and sets up the streams' information */
FilePtr openAVCustom(const char *name, void *user_data,
int (*read_packet)(void *user_data, uint8_t *buf, int buf_size),
int (*write_packet)(void *user_data, uint8_t *buf, int buf_size),
int64_t (*seek)(void *user_data, int64_t offset, int whence));
/* Closes/frees an opened file and any of its streams */
void closeAVFile(FilePtr file);
/* Reports certain information from the file, eg, the number of audio
* streams. Returns 0 on success. */
int getAVFileInfo(FilePtr file, int *numaudiostreams);
/* Retrieves a handle for the given audio stream number (generally 0, but some
* files can have multiple audio streams in one file). */
StreamPtr getAVAudioStream(FilePtr file, int streamnum);
/* Returns information about the given audio stream. Returns 0 on success. */
int getAVAudioInfo(StreamPtr stream, ALuint *rate, ALenum *channels, ALenum *type);
/* Returns a pointer to the next available packet of decoded audio. Any data
* from a previously-decoded packet is dropped. The size (in bytes) of the
* returned data buffer is stored in 'length', and the returned pointer is only
* valid until the next call to getAVAudioData or readAVAudioData. */
void *getAVAudioData(StreamPtr stream, size_t *length);
/* The "meat" function. Decodes audio and writes, at most, length bytes into
* the provided data buffer. Will only return less for end-of-stream or error
* conditions. Returns the number of bytes written. */
size_t readAVAudioData(StreamPtr stream, void *data, size_t length);
/* Decodes all remaining data from the stream and returns a buffer containing
* the audio data, with the size stored in 'length'. The returned pointer must
* be freed with a call to free(). Note that since this decodes the whole
* stream, using it on lengthy streams (eg, music) will use a lot of memory.
* Such streams are better handled using getAVAudioData or readAVAudioData to
* keep smaller chunks in memory at any given time. */
void *decodeAVAudioStream(StreamPtr stream, size_t *length);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* ALFFMPEG_H */

319
examples/alhelpers.c Normal file
View File

@ -0,0 +1,319 @@
/*
* OpenAL Helpers
*
* Copyright (c) 2011 by Chris Robinson <chris.kcat@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* This file contains routines to help with some menial OpenAL-related tasks,
* such as opening a device and setting up a context, closing the device and
* destroying its context, converting between frame counts and byte lengths,
* finding an appropriate buffer format, and getting readable strings for
* channel configs and sample types. */
#include <stdio.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alhelpers.h"
const char *ChannelsName(ALenum chans)
{
switch(chans)
{
case AL_MONO_SOFT: return "Mono";
case AL_STEREO_SOFT: return "Stereo";
case AL_REAR_SOFT: return "Rear";
case AL_QUAD_SOFT: return "Quadraphonic";
case AL_5POINT1_SOFT: return "5.1 Surround";
case AL_6POINT1_SOFT: return "6.1 Surround";
case AL_7POINT1_SOFT: return "7.1 Surround";
}
return "Unknown Channels";
}
const char *TypeName(ALenum type)
{
switch(type)
{
case AL_BYTE_SOFT: return "S8";
case AL_UNSIGNED_BYTE_SOFT: return "U8";
case AL_SHORT_SOFT: return "S16";
case AL_UNSIGNED_SHORT_SOFT: return "U16";
case AL_INT_SOFT: return "S32";
case AL_UNSIGNED_INT_SOFT: return "U32";
case AL_FLOAT_SOFT: return "Float32";
case AL_DOUBLE_SOFT: return "Float64";
}
return "Unknown Type";
}
ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type)
{
switch(channels)
{
case AL_MONO_SOFT: size *= 1; break;
case AL_STEREO_SOFT: size *= 2; break;
case AL_REAR_SOFT: size *= 2; break;
case AL_QUAD_SOFT: size *= 4; break;
case AL_5POINT1_SOFT: size *= 6; break;
case AL_6POINT1_SOFT: size *= 7; break;
case AL_7POINT1_SOFT: size *= 8; break;
}
switch(type)
{
case AL_BYTE_SOFT: size *= sizeof(ALbyte); break;
case AL_UNSIGNED_BYTE_SOFT: size *= sizeof(ALubyte); break;
case AL_SHORT_SOFT: size *= sizeof(ALshort); break;
case AL_UNSIGNED_SHORT_SOFT: size *= sizeof(ALushort); break;
case AL_INT_SOFT: size *= sizeof(ALint); break;
case AL_UNSIGNED_INT_SOFT: size *= sizeof(ALuint); break;
case AL_FLOAT_SOFT: size *= sizeof(ALfloat); break;
case AL_DOUBLE_SOFT: size *= sizeof(ALdouble); break;
}
return size;
}
ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type)
{
return size / FramesToBytes(1, channels, type);
}
ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT)
{
ALenum format = AL_NONE;
/* If using AL_SOFT_buffer_samples, try looking through its formats */
if(palIsBufferFormatSupportedSOFT)
{
/* AL_SOFT_buffer_samples is more lenient with matching formats. The
* specified sample type does not need to match the returned format,
* but it is nice to try to get something close. */
if(type == AL_UNSIGNED_BYTE_SOFT || type == AL_BYTE_SOFT)
{
if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT;
}
else if(type == AL_UNSIGNED_SHORT_SOFT || type == AL_SHORT_SOFT)
{
if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT;
}
else if(type == AL_UNSIGNED_BYTE3_SOFT || type == AL_BYTE3_SOFT ||
type == AL_UNSIGNED_INT_SOFT || type == AL_INT_SOFT ||
type == AL_FLOAT_SOFT || type == AL_DOUBLE_SOFT)
{
if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT;
}
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
/* A matching format was not found or supported. Try 32-bit float. */
if(format == AL_NONE)
{
if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT;
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
}
/* 32-bit float not supported. Try 16-bit int. */
if(format == AL_NONE)
{
if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT;
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
}
/* 16-bit int not supported. Try 8-bit int. */
if(format == AL_NONE)
{
if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT;
else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT;
else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT;
else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT;
else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT;
else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT;
if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format))
format = AL_NONE;
}
return format;
}
/* We use the AL_EXT_MCFORMATS extension to provide output of Quad, 5.1,
* and 7.1 channel configs, AL_EXT_FLOAT32 for 32-bit float samples, and
* AL_EXT_DOUBLE for 64-bit float samples. */
if(type == AL_UNSIGNED_BYTE_SOFT)
{
if(channels == AL_MONO_SOFT)
format = AL_FORMAT_MONO8;
else if(channels == AL_STEREO_SOFT)
format = AL_FORMAT_STEREO8;
else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
if(channels == AL_QUAD_SOFT)
format = alGetEnumValue("AL_FORMAT_QUAD8");
else if(channels == AL_5POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_51CHN8");
else if(channels == AL_6POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_61CHN8");
else if(channels == AL_7POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_71CHN8");
}
}
else if(type == AL_SHORT_SOFT)
{
if(channels == AL_MONO_SOFT)
format = AL_FORMAT_MONO16;
else if(channels == AL_STEREO_SOFT)
format = AL_FORMAT_STEREO16;
else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
if(channels == AL_QUAD_SOFT)
format = alGetEnumValue("AL_FORMAT_QUAD16");
else if(channels == AL_5POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_51CHN16");
else if(channels == AL_6POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_61CHN16");
else if(channels == AL_7POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_71CHN16");
}
}
else if(type == AL_FLOAT_SOFT && alIsExtensionPresent("AL_EXT_FLOAT32"))
{
if(channels == AL_MONO_SOFT)
format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
else if(channels == AL_STEREO_SOFT)
format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
else if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
if(channels == AL_QUAD_SOFT)
format = alGetEnumValue("AL_FORMAT_QUAD32");
else if(channels == AL_5POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_51CHN32");
else if(channels == AL_6POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_61CHN32");
else if(channels == AL_7POINT1_SOFT)
format = alGetEnumValue("AL_FORMAT_71CHN32");
}
}
else if(type == AL_DOUBLE_SOFT && alIsExtensionPresent("AL_EXT_DOUBLE"))
{
if(channels == AL_MONO_SOFT)
format = alGetEnumValue("AL_FORMAT_MONO_DOUBLE");
else if(channels == AL_STEREO_SOFT)
format = alGetEnumValue("AL_FORMAT_STEREO_DOUBLE");
}
/* NOTE: It seems OSX returns -1 from alGetEnumValue for unknown enums, as
* opposed to 0. Correct it. */
if(format == -1)
format = 0;
return format;
}
void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate,
ALenum internalformat, ALsizei samples,
ALenum channels, ALenum type,
const ALvoid *data)
{
alBufferData(buffer, internalformat, data,
FramesToBytes(samples, channels, type),
samplerate);
}
int InitAL(void)
{
ALCdevice *device;
ALCcontext *ctx;
/* Open and initialize a device with default settings */
device = alcOpenDevice(NULL);
if(!device)
{
fprintf(stderr, "Could not open a device!\n");
return 1;
}
ctx = alcCreateContext(device, NULL);
if(ctx == NULL || alcMakeContextCurrent(ctx) == ALC_FALSE)
{
if(ctx != NULL)
alcDestroyContext(ctx);
alcCloseDevice(device);
fprintf(stderr, "Could not set a context!\n");
return 1;
}
return 0;
}
void CloseAL(void)
{
ALCdevice *device;
ALCcontext *ctx;
/* Close the device belonging to the current context, and destroy the
* context. */
ctx = alcGetCurrentContext();
if(ctx == NULL)
return;
device = alcGetContextsDevice(ctx);
alcMakeContextCurrent(NULL);
alcDestroyContext(ctx);
alcCloseDevice(device);
}

47
examples/alhelpers.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef ALHELPERS_H
#define ALHELPERS_H
#ifndef _WIN32
#include <unistd.h>
#define Sleep(x) usleep((x)*1000)
#else
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Some helper functions to get the name from the channel and type enums. */
const char *ChannelsName(ALenum chans);
const char *TypeName(ALenum type);
/* Helpers to convert frame counts and byte lengths. */
ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type);
ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type);
/* Retrieves a compatible buffer format given the channel configuration and
* sample type. If an alIsBufferFormatSupportedSOFT-compatible function is
* provided, it will be called to find the closest-matching format from
* AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be
* found. */
ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT);
/* Loads samples into a buffer using the standard alBufferData call, but with a
* LPALBUFFERSAMPLESSOFT-compatible prototype. Assumes internalformat is valid
* for alBufferData, and that channels and type match it. */
void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate,
ALenum internalformat, ALsizei samples,
ALenum channels, ALenum type,
const ALvoid *data);
/* Easy device init/deinit functions. InitAL returns 0 on success. */
int InitAL(void);
void CloseAL(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* ALHELPERS_H */

346
examples/alstream.c Normal file
View File

@ -0,0 +1,346 @@
/*
* OpenAL Audio Stream Example
*
* Copyright (c) 2011 by Chris Robinson <chris.kcat@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* This file contains a relatively simple streaming audio player. */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <assert.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
#include "alhelpers.h"
#include "alffmpeg.h"
LPALBUFFERSAMPLESSOFT palBufferSamplesSOFT = wrap_BufferSamples;
LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT = NULL;
/* Define the number of buffers and buffer size (in samples) to use. 4 buffers
* with 8192 samples each gives a nice per-chunk size, and lets the queue last
* for almost 3/4ths of a second for a 44.1khz stream. */
#define NUM_BUFFERS 4
#define BUFFER_SIZE 8192
typedef struct StreamPlayer {
/* These are the buffers and source to play out through OpenAL with */
ALuint buffers[NUM_BUFFERS];
ALuint source;
/* Handles for the audio stream */
FilePtr file;
StreamPtr stream;
/* A temporary data buffer for readAVAudioData to write to and pass to
* OpenAL with */
ALbyte *data;
ALsizei datasize;
/* The format of the output stream */
ALenum format;
ALenum channels;
ALenum type;
ALuint rate;
} StreamPlayer;
static StreamPlayer *NewPlayer(void);
static void DeletePlayer(StreamPlayer *player);
static int OpenPlayerFile(StreamPlayer *player, const char *filename);
static void ClosePlayerFile(StreamPlayer *player);
static int StartPlayer(StreamPlayer *player);
static int UpdatePlayer(StreamPlayer *player);
/* Creates a new player object, and allocates the needed OpenAL source and
* buffer objects. Error checking is simplified for the purposes of this
* example, and will cause an abort if needed. */
static StreamPlayer *NewPlayer(void)
{
StreamPlayer *player;
player = malloc(sizeof(*player));
assert(player != NULL);
memset(player, 0, sizeof(*player));
/* Generate the buffers and source */
alGenBuffers(NUM_BUFFERS, player->buffers);
assert(alGetError() == AL_NO_ERROR && "Could not create buffers");
alGenSources(1, &player->source);
assert(alGetError() == AL_NO_ERROR && "Could not create source");
/* Set parameters so mono sources play out the front-center speaker and
* won't distance attenuate. */
alSource3i(player->source, AL_POSITION, 0, 0, -1);
alSourcei(player->source, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcei(player->source, AL_ROLLOFF_FACTOR, 0);
assert(alGetError() == AL_NO_ERROR && "Could not set source parameters");
return player;
}
/* Destroys a player object, deleting the source and buffers. No error handling
* since these calls shouldn't fail with a properly-made player object. */
static void DeletePlayer(StreamPlayer *player)
{
ClosePlayerFile(player);
alDeleteSources(1, &player->source);
alDeleteBuffers(NUM_BUFFERS, player->buffers);
if(alGetError() != AL_NO_ERROR)
fprintf(stderr, "Failed to delete object IDs\n");
memset(player, 0, sizeof(*player));
free(player);
}
/* Opens the first audio stream of the named file. If a file is already open,
* it will be closed first. */
static int OpenPlayerFile(StreamPlayer *player, const char *filename)
{
ClosePlayerFile(player);
/* Open the file and get the first stream from it */
player->file = openAVFile(filename);
player->stream = getAVAudioStream(player->file, 0);
if(!player->stream)
{
fprintf(stderr, "Could not open audio in %s\n", filename);
goto error;
}
/* Get the stream format, and figure out the OpenAL format */
if(getAVAudioInfo(player->stream, &player->rate, &player->channels,
&player->type) != 0)
{
fprintf(stderr, "Error getting audio info for %s\n", filename);
goto error;
}
player->format = GetFormat(player->channels, player->type, palIsBufferFormatSupportedSOFT);
if(player->format == 0)
{
fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
ChannelsName(player->channels), TypeName(player->type),
filename);
goto error;
}
/* Allocate enough space for the temp buffer, given the format */
player->datasize = FramesToBytes(BUFFER_SIZE, player->channels,
player->type);
player->data = malloc(player->datasize);
if(player->data == NULL)
{
fprintf(stderr, "Error allocating %d bytes\n", player->datasize);
goto error;
}
return 1;
error:
closeAVFile(player->file);
player->file = NULL;
player->stream = NULL;
player->datasize = 0;
return 0;
}
/* Closes the audio file stream */
static void ClosePlayerFile(StreamPlayer *player)
{
closeAVFile(player->file);
player->file = NULL;
player->stream = NULL;
free(player->data);
player->data = NULL;
player->datasize = 0;
}
/* Prebuffers some audio from the file, and starts playing the source */
static int StartPlayer(StreamPlayer *player)
{
size_t i, got;
/* Rewind the source position and clear the buffer queue */
alSourceRewind(player->source);
alSourcei(player->source, AL_BUFFER, 0);
/* Fill the buffer queue */
for(i = 0;i < NUM_BUFFERS;i++)
{
/* Get some data to give it to the buffer */
got = readAVAudioData(player->stream, player->data, player->datasize);
if(got == 0) break;
palBufferSamplesSOFT(player->buffers[i], player->rate, player->format,
BytesToFrames(got, player->channels, player->type),
player->channels, player->type, player->data);
}
if(alGetError() != AL_NO_ERROR)
{
fprintf(stderr, "Error buffering for playback\n");
return 0;
}
/* Now queue and start playback! */
alSourceQueueBuffers(player->source, i, player->buffers);
alSourcePlay(player->source);
if(alGetError() != AL_NO_ERROR)
{
fprintf(stderr, "Error starting playback\n");
return 0;
}
return 1;
}
static int UpdatePlayer(StreamPlayer *player)
{
ALint processed, state;
/* Get relevant source info */
alGetSourcei(player->source, AL_SOURCE_STATE, &state);
alGetSourcei(player->source, AL_BUFFERS_PROCESSED, &processed);
if(alGetError() != AL_NO_ERROR)
{
fprintf(stderr, "Error checking source state\n");
return 0;
}
/* Unqueue and handle each processed buffer */
while(processed > 0)
{
ALuint bufid;
size_t got;
alSourceUnqueueBuffers(player->source, 1, &bufid);
processed--;
/* Read the next chunk of data, refill the buffer, and queue it
* back on the source */
got = readAVAudioData(player->stream, player->data, player->datasize);
if(got > 0)
{
palBufferSamplesSOFT(bufid, player->rate, player->format,
BytesToFrames(got, player->channels, player->type),
player->channels, player->type, player->data);
alSourceQueueBuffers(player->source, 1, &bufid);
}
if(alGetError() != AL_NO_ERROR)
{
fprintf(stderr, "Error buffering data\n");
return 0;
}
}
/* Make sure the source hasn't underrun */
if(state != AL_PLAYING && state != AL_PAUSED)
{
ALint queued;
/* If no buffers are queued, playback is finished */
alGetSourcei(player->source, AL_BUFFERS_QUEUED, &queued);
if(queued == 0)
return 0;
alSourcePlay(player->source);
if(alGetError() != AL_NO_ERROR)
{
fprintf(stderr, "Error restarting playback\n");
return 0;
}
}
return 1;
}
int main(int argc, char **argv)
{
StreamPlayer *player;
int i;
/* Print out usage if no file was specified */
if(argc < 2)
{
fprintf(stderr, "Usage: %s <filenames...>\n", argv[0]);
return 1;
}
if(InitAL() != 0)
return 1;
if(alIsExtensionPresent("AL_SOFT_buffer_samples"))
{
printf("AL_SOFT_buffer_samples supported!\n");
palBufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT");
palIsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT");
}
else
printf("AL_SOFT_buffer_samples not supported\n");
player = NewPlayer();
/* Play each file listed on the command line */
for(i = 1;i < argc;i++)
{
if(!OpenPlayerFile(player, argv[i]))
continue;
fprintf(stderr, "Playing %s (%s, %s, %dhz)\n", argv[i],
TypeName(player->type), ChannelsName(player->channels),
player->rate);
if(!StartPlayer(player))
{
ClosePlayerFile(player);
continue;
}
while(UpdatePlayer(player))
Sleep(10);
/* All done with this file. Close it and go to the next */
ClosePlayerFile(player);
}
fprintf(stderr, "Done.\n");
/* All files done. Delete the player, and close OpenAL */
DeletePlayer(player);
player = NULL;
CloseAL();
return 0;
}

93
hrtf.txt Normal file
View File

@ -0,0 +1,93 @@
HRTF Support
============
Starting with OpenAL Soft 1.14, HRTFs can be used to enable enhanced
spatialization for both 3D (mono) and multi-channel sources, when used with
headphones/stereo output. This can be enabled using the 'hrtf' config option.
For multi-channel sources this creates a virtual speaker effect, making it
sound as if speakers provide a discrete position for each channel around the
listener. For mono sources this provides much more versatility in the perceived
placement of sounds, making it seem as though they are coming from all around,
including above and below the listener, instead of just to the front, back, and
sides.
The built-in data set is based on the KEMAR HRTF diffuse data provided by MIT,
which can be found at <http://sound.media.mit.edu/resources/KEMAR.html>. It's
only available when using 44100hz playback.
External HRTF Data Sets
=======================
OpenAL Soft also provides an option to use user-specified data sets, in
addition to or in place of the built-in set. This allows users to provide their
own data sets, which could be better suited for their heads, or to work with
stereo speakers instead of headphones, or to support more playback sample
rates, for example.
The file format for the data sets is specified below. It uses little-endian
byte order. Certain data fields are restricted to specific values (these
restriction may be lifted in future versions of the lib).
==
ALchar magic[8] = "MinPHR00";
ALuint sampleRate;
ALushort hrirCount; /* Required value: 828 */
ALushort hrirSize; /* Required value: 32 */
ALubyte evCount; /* Required value: 19 */
ALushort evOffset[evCount]; /* Required values:
{ 0, 1, 13, 37, 73, 118, 174, 234, 306, 378, 450, 522, 594, 654, 710, 755,
791, 815, 827 } */
ALshort coefficients[hrirCount][hrirSize];
ALubyte delays[hrirCount]; /* Element values must not exceed 127 */
==
The data is described as thus:
The file first starts with the 8-byte marker, "MinPHR00", to identify it as an
HRTF data set. This is followed by an unsigned 32-bit integer, specifying the
sample rate the data set is designed for (OpenAL Soft will not use it if the
output device's playback rate doesn't match).
Afterward, an unsigned 16-bit integer specifies the total number of HRIR sets
(each HRIR set is a collection of impulse responses forming the coefficients
for a convolution filter). The next unsigned 16-bit integer specifies how many
samples are in each HRIR set (the number of coefficients in the filter). The
following unsigned 8-bit integer specifies the number of elevations used by the
data set. The elevations start at the bottom, and increment upwards.
Following this is an array of unsigned 16-bit integers, one for each elevation
which specifies the index offset to the start of the HRIR sets for each given
elevation (the number of HRIR sets at each elevation is infered by the offset
to the next elevation, or by the total count for the last elevation).
The actual coefficients follow. Each coefficient is a signed 16-bit sample,
with each HRIR set being a consecutive number of samples. For each elevation,
the HRIR sets first start with a neutral "in-front" set (that is, one that is
applied equally to the left and right outputs). After this, the sets follow a
clockwise pattern, constructing a full circle for the left ear only. The right
ear uses the same sets but in reverse (ie, left = angle, right = 360-angle).
After the coefficients is an array of unsigned 8-bit delay values, one for each
HRIR set. This is the delay, in samples, after recieving an input sample before
before it's added in to the convolution filter that the corresponding HRIR set
operates on and gets heard.
Note that the HRTF data is expected to be minimum-phase reconstructed. The
time delays are handled by OpenAL Soft according to the specified delay[]
values, and afterward the samples are fed into the convolution filter using the
corresponding coefficients. This allows for less processing by using a shorter
convolution filter, as it skips the first coefficients that do little more than
cause a timed delay, as well as the tailing coefficients that are used to
equalize the length of all the sets and contribute nothing.
For reference, the built-in data set uses a 32-sample convolution filter while
even the smallest data set provided by MIT used a 128-sample filter (a 4x
reduction by applying minimum-phase reconstruction). Theoretically, one could
further reduce the minimum-phase version down to a 16-sample convolution filter
with little quality loss.

View File

@ -287,7 +287,7 @@ typedef void ALvoid;
/** Errors: No Error. */
#define AL_NO_ERROR AL_FALSE
#define AL_NO_ERROR 0
/**
* Invalid Name paramater passed to AL call.

View File

@ -120,7 +120,7 @@ typedef void ALCvoid;
/**
* No error
*/
#define ALC_NO_ERROR ALC_FALSE
#define ALC_NO_ERROR 0
/**
* No device

View File

@ -188,6 +188,75 @@ AL_API void AL_APIENTRY alRequestFoldbackStop(void);
#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000
#endif
#ifndef AL_SOFT_buffer_samples
#define AL_SOFT_buffer_samples 1
/* Channel configurations */
#define AL_MONO_SOFT 0x1500
#define AL_STEREO_SOFT 0x1501
#define AL_REAR_SOFT 0x1502
#define AL_QUAD_SOFT 0x1503
#define AL_5POINT1_SOFT 0x1504
#define AL_6POINT1_SOFT 0x1505
#define AL_7POINT1_SOFT 0x1506
/* Sample types */
#define AL_BYTE_SOFT 0x1400
#define AL_UNSIGNED_BYTE_SOFT 0x1401
#define AL_SHORT_SOFT 0x1402
#define AL_UNSIGNED_SHORT_SOFT 0x1403
#define AL_INT_SOFT 0x1404
#define AL_UNSIGNED_INT_SOFT 0x1405
#define AL_FLOAT_SOFT 0x1406
#define AL_DOUBLE_SOFT 0x1407
#define AL_BYTE3_SOFT 0x1408
#define AL_UNSIGNED_BYTE3_SOFT 0x1409
/* Storage formats */
#define AL_MONO8_SOFT 0x1100
#define AL_MONO16_SOFT 0x1101
#define AL_MONO32F_SOFT 0x10010
#define AL_STEREO8_SOFT 0x1102
#define AL_STEREO16_SOFT 0x1103
#define AL_STEREO32F_SOFT 0x10011
#define AL_QUAD8_SOFT 0x1204
#define AL_QUAD16_SOFT 0x1205
#define AL_QUAD32F_SOFT 0x1206
#define AL_REAR8_SOFT 0x1207
#define AL_REAR16_SOFT 0x1208
#define AL_REAR32F_SOFT 0x1209
#define AL_5POINT1_8_SOFT 0x120A
#define AL_5POINT1_16_SOFT 0x120B
#define AL_5POINT1_32F_SOFT 0x120C
#define AL_6POINT1_8_SOFT 0x120D
#define AL_6POINT1_16_SOFT 0x120E
#define AL_6POINT1_32F_SOFT 0x120F
#define AL_7POINT1_8_SOFT 0x1210
#define AL_7POINT1_16_SOFT 0x1211
#define AL_7POINT1_32F_SOFT 0x1212
/* Buffer attributes */
#define AL_INTERNAL_FORMAT_SOFT 0x2008
#define AL_BYTE_LENGTH_SOFT 0x2009
#define AL_SAMPLE_LENGTH_SOFT 0x200A
#define AL_SEC_LENGTH_SOFT 0x200B
typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*);
typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*);
typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*);
typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data);
AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data);
AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format);
#endif
#endif
#ifndef AL_SOFT_direct_channels
#define AL_SOFT_direct_channels 1
#define AL_DIRECT_CHANNELS_SOFT 0x1033
#endif
#ifdef __cplusplus
}
#endif

402
include/AL/efx-presets.h Normal file
View File

@ -0,0 +1,402 @@
/* Reverb presets for EFX */
#ifndef EFX_PRESETS_H
#define EFX_PRESETS_H
#ifndef EFXEAXREVERBPROPERTIES_DEFINED
#define EFXEAXREVERBPROPERTIES_DEFINED
typedef struct {
float flDensity;
float flDiffusion;
float flGain;
float flGainHF;
float flGainLF;
float flDecayTime;
float flDecayHFRatio;
float flDecayLFRatio;
float flReflectionsGain;
float flReflectionsDelay;
float flReflectionsPan[3];
float flLateReverbGain;
float flLateReverbDelay;
float flLateReverbPan[3];
float flEchoTime;
float flEchoDepth;
float flModulationTime;
float flModulationDepth;
float flAirAbsorptionGainHF;
float flHFReference;
float flLFReference;
float flRoomRolloffFactor;
int iDecayHFLimit;
} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES;
#endif
/* Default Presets */
#define EFX_REVERB_PRESET_GENERIC \
{ 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PADDEDCELL \
{ 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ROOM \
{ 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_BATHROOM \
{ 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_LIVINGROOM \
{ 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_STONEROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_AUDITORIUM \
{ 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CONCERTHALL \
{ 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CAVE \
{ 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_ARENA \
{ 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_HANGAR \
{ 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CARPETEDHALLWAY \
{ 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_HALLWAY \
{ 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_STONECORRIDOR \
{ 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ALLEY \
{ 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FOREST \
{ 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY \
{ 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_MOUNTAINS \
{ 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_QUARRY \
{ 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PLAIN \
{ 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PARKINGLOT \
{ 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_SEWERPIPE \
{ 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_UNDERWATER \
{ 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRUGGED \
{ 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DIZZY \
{ 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PSYCHOTIC \
{ 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
/* Castle Presets */
#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \
{ 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \
{ 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \
{ 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \
{ 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \
{ 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_HALL \
{ 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \
{ 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CASTLE_COURTYARD \
{ 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_CASTLE_ALCOVE \
{ 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 }
/* Factory Presets */
#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \
{ 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \
{ 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \
{ 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \
{ 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \
{ 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_HALL \
{ 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \
{ 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_COURTYARD \
{ 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_FACTORY_ALCOVE \
{ 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 }
/* Ice Palace Presets */
#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \
{ 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \
{ 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \
{ 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \
{ 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \
{ 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_HALL \
{ 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \
{ 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \
{ 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \
{ 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 }
/* Space Station Presets */
#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \
{ 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \
{ 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \
{ 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \
{ 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \
{ 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_HALL \
{ 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \
{ 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \
{ 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 }
/* Wooden Galleon Presets */
#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \
{ 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \
{ 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \
{ 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_HALL \
{ 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \
{ 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_COURTYARD \
{ 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_WOODEN_ALCOVE \
{ 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 }
/* Sports Presets */
#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \
{ 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \
{ 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \
{ 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \
{ 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \
{ 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \
{ 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \
{ 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
/* Prefab Presets */
#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \
{ 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \
{ 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \
{ 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \
{ 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PREFAB_CARAVAN \
{ 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
/* Dome and Pipe Presets */
#define EFX_REVERB_PRESET_DOME_TOMB \
{ 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PIPE_SMALL \
{ 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DOME_SAINTPAULS \
{ 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PIPE_LONGTHIN \
{ 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_PIPE_LARGE \
{ 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_PIPE_RESONANT \
{ 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 }
/* Outdoors Presets */
#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \
{ 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \
{ 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \
{ 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_CREEK \
{ 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \
{ 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
/* Mood Presets */
#define EFX_REVERB_PRESET_MOOD_HEAVEN \
{ 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_MOOD_HELL \
{ 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_MOOD_MEMORY \
{ 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
/* Driving Presets */
#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \
{ 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \
{ 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \
{ 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \
{ 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \
{ 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \
{ 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \
{ 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_DRIVING_TUNNEL \
{ 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 }
/* City Presets */
#define EFX_REVERB_PRESET_CITY_STREETS \
{ 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY_SUBWAY \
{ 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY_MUSEUM \
{ 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_CITY_LIBRARY \
{ 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 }
#define EFX_REVERB_PRESET_CITY_UNDERPASS \
{ 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CITY_ABANDONED \
{ 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
/* Misc. Presets */
#define EFX_REVERB_PRESET_DUSTYROOM \
{ 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_CHAPEL \
{ 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_SMALLWATERROOM \
{ 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
#endif /* EFX_PRESETS_H */

View File

@ -277,7 +277,10 @@ int main(int argc, char *argv[])
return 1;
}
printf("\n** Info for device \"%s\" **\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
if(alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
printf("\n** Info for device \"%s\" **\n", alcGetString(device, ALC_ALL_DEVICES_SPECIFIER));
else
printf("\n** Info for device \"%s\" **\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
printALCInfo(device);
context = alcCreateContext(device, NULL);