[openal-soft] 01/02: New upstream version 1.18.2
Bret Curtis
psi29a at gmail.com
Wed Jan 3 14:25:10 UTC 2018
This is an automated email from the git hooks/post-receive script.
psi29a-guest pushed a commit to branch master
in repository openal-soft.
commit f652d5d2e21794ae86310ffc690990be59a4feca
Author: Bret Curtis <psi29a at gmail.com>
Date: Wed Jan 3 15:24:53 2018 +0100
New upstream version 1.18.2
---
Alc/ALc.c | 256 ++++++-----
Alc/ALu.c | 274 +++++-------
Alc/backends/base.c | 154 -------
Alc/backends/base.h | 3 +-
Alc/backends/jack.c | 10 +-
Alc/backends/mmdevapi.c | 45 +-
Alc/backends/oss.c | 16 +-
Alc/backends/pulseaudio.c | 19 +-
Alc/backends/qsa.c | 248 +++++++++--
Alc/backends/wave.c | 5 +-
Alc/bformatdec.c | 39 ++
Alc/bformatdec.h | 12 +
Alc/converter.c | 46 +-
Alc/converter.h | 1 +
Alc/effects/chorus.c | 128 +++---
Alc/effects/flanger.c | 127 +++---
Alc/effects/modulator.c | 2 +-
Alc/effects/reverb.c | 111 ++---
Alc/helpers.c | 36 +-
Alc/hrtf.c | 108 ++---
Alc/hrtf.h | 4 -
Alc/mastering.c | 2 +-
Alc/mixer.c | 34 +-
Alc/panning.c | 16 +-
CMakeLists.txt | 250 +++++++----
ChangeLog | 34 ++
OpenAL32/Include/alListener.h | 2 +-
OpenAL32/Include/alMain.h | 71 +--
OpenAL32/Include/alu.h | 4 +-
OpenAL32/alAuxEffectSlot.c | 7 +-
OpenAL32/alSource.c | 12 +-
alsoftrc.sample | 13 +-
appveyor.yml | 2 +-
cmake/FindOSS.cmake | 14 +-
common/math_defs.h | 13 +-
common/threads.c | 6 +-
config.h.in | 6 +
examples/alffplay.cpp | 35 +-
examples/alrecord.c | 386 +++++++++++++++++
examples/altonegen.c | 69 ++-
hrtf/default-44100.mhr | Bin 53853 -> 53853 bytes
hrtf/default-48000.mhr | Bin 53853 -> 53853 bytes
presets/itu5.1-nocenter.ambdec | 46 ++
router/al.c | 132 ++++++
router/alc.c | 956 +++++++++++++++++++++++++++++++++++++++++
router/router.c | 512 ++++++++++++++++++++++
router/router.h | 196 +++++++++
utils/makehrtf.c | 134 +++---
48 files changed, 3503 insertions(+), 1093 deletions(-)
diff --git a/Alc/ALc.c b/Alc/ALc.c
index b31c4f0..8c032dd 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -54,57 +54,52 @@
struct BackendInfo {
const char *name;
ALCbackendFactory* (*getFactory)(void);
- ALCboolean (*Init)(BackendFuncs*);
- void (*Deinit)(void);
- void (*Probe)(enum DevProbe);
- BackendFuncs Funcs;
};
-#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
static struct BackendInfo BackendList[] = {
#ifdef HAVE_JACK
- { "jack", ALCjackBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "jack", ALCjackBackendFactory_getFactory },
#endif
#ifdef HAVE_PULSEAUDIO
- { "pulse", ALCpulseBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "pulse", ALCpulseBackendFactory_getFactory },
#endif
#ifdef HAVE_ALSA
- { "alsa", ALCalsaBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "alsa", ALCalsaBackendFactory_getFactory },
#endif
#ifdef HAVE_COREAUDIO
- { "core", ALCcoreAudioBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "core", ALCcoreAudioBackendFactory_getFactory },
#endif
#ifdef HAVE_OSS
- { "oss", ALCossBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "oss", ALCossBackendFactory_getFactory },
#endif
#ifdef HAVE_SOLARIS
- { "solaris", ALCsolarisBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "solaris", ALCsolarisBackendFactory_getFactory },
#endif
#ifdef HAVE_SNDIO
- { "sndio", ALCsndioBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "sndio", ALCsndioBackendFactory_getFactory },
#endif
#ifdef HAVE_QSA
- { "qsa", NULL, alc_qsa_init, alc_qsa_deinit, alc_qsa_probe, EmptyFuncs },
+ { "qsa", ALCqsaBackendFactory_getFactory },
#endif
#ifdef HAVE_MMDEVAPI
- { "mmdevapi", ALCmmdevBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "mmdevapi", ALCmmdevBackendFactory_getFactory },
#endif
#ifdef HAVE_DSOUND
- { "dsound", ALCdsoundBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "dsound", ALCdsoundBackendFactory_getFactory },
#endif
#ifdef HAVE_WINMM
- { "winmm", ALCwinmmBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "winmm", ALCwinmmBackendFactory_getFactory },
#endif
#ifdef HAVE_PORTAUDIO
- { "port", ALCportBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "port", ALCportBackendFactory_getFactory },
#endif
#ifdef HAVE_OPENSL
- { "opensl", ALCopenslBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "opensl", ALCopenslBackendFactory_getFactory },
#endif
- { "null", ALCnullBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "null", ALCnullBackendFactory_getFactory },
#ifdef HAVE_WAVE
- { "wave", ALCwaveBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+ { "wave", ALCwaveBackendFactory_getFactory },
#endif
};
static ALsizei BackendListSize = COUNTOF(BackendList);
@@ -1091,43 +1086,20 @@ static void alc_initconfig(void)
for(i = 0;i < BackendListSize && (!PlaybackBackend.name || !CaptureBackend.name);i++)
{
- if(BackendList[i].getFactory)
- {
- ALCbackendFactory *factory = BackendList[i].getFactory();
- if(!V0(factory,init)())
- {
- WARN("Failed to initialize backend \"%s\"\n", BackendList[i].name);
- continue;
- }
-
- TRACE("Initialized backend \"%s\"\n", BackendList[i].name);
- if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback))
- {
- PlaybackBackend = BackendList[i];
- TRACE("Added \"%s\" for playback\n", PlaybackBackend.name);
- }
- if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture))
- {
- CaptureBackend = BackendList[i];
- TRACE("Added \"%s\" for capture\n", CaptureBackend.name);
- }
-
- continue;
- }
-
- if(!BackendList[i].Init(&BackendList[i].Funcs))
+ ALCbackendFactory *factory = BackendList[i].getFactory();
+ if(!V0(factory,init)())
{
WARN("Failed to initialize backend \"%s\"\n", BackendList[i].name);
continue;
}
TRACE("Initialized backend \"%s\"\n", BackendList[i].name);
- if(BackendList[i].Funcs.OpenPlayback && !PlaybackBackend.name)
+ if(!PlaybackBackend.name && V(factory,querySupport)(ALCbackend_Playback))
{
PlaybackBackend = BackendList[i];
TRACE("Added \"%s\" for playback\n", PlaybackBackend.name);
}
- if(BackendList[i].Funcs.OpenCapture && !CaptureBackend.name)
+ if(!CaptureBackend.name && V(factory,querySupport)(ALCbackend_Capture))
{
CaptureBackend = BackendList[i];
TRACE("Added \"%s\" for capture\n", CaptureBackend.name);
@@ -1241,7 +1213,6 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void* UNUSED(reserved))
pthread_setspecific(gJVMThreadKey, env);
return JNI_VERSION_1_4;
}
-
#endif
@@ -1299,13 +1270,8 @@ static void alc_deinit(void)
for(i = 0;i < BackendListSize;i++)
{
- if(!BackendList[i].getFactory)
- BackendList[i].Deinit();
- else
- {
- ALCbackendFactory *factory = BackendList[i].getFactory();
- V0(factory,deinit)();
- }
+ ALCbackendFactory *factory = BackendList[i].getFactory();
+ V0(factory,deinit)();
}
{
ALCbackendFactory *factory = ALCloopbackFactory_getFactory();
@@ -1321,18 +1287,16 @@ static void alc_deinit(void)
************************************************/
static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DevProbe type)
{
+ ALCbackendFactory *factory;
+
DO_INITCONFIG();
LockLists();
alstr_clear(list);
- if(backendinfo->Probe)
- backendinfo->Probe(type);
- else if(backendinfo->getFactory)
- {
- ALCbackendFactory *factory = backendinfo->getFactory();
- V(factory,probe)(type);
- }
+ factory = backendinfo->getFactory();
+ V(factory,probe)(type);
+
UnlockLists();
}
static void ProbeAllDevicesList(void)
@@ -1777,7 +1741,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
ALCsizei hrtf_id = -1;
ALCcontext *context;
ALCuint oldFreq;
- FPUCtl oldMode;
size_t size;
ALCsizei i;
int val;
@@ -2222,6 +2185,39 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
device->SourcesMax, device->NumMonoSources, device->NumStereoSources,
device->AuxiliaryEffectSlotMax, device->NumAuxSends);
+ device->DitherDepth = 0.0f;
+ if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "dither", 1))
+ {
+ ALint depth = 0;
+ ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "dither-depth", &depth);
+ if(depth <= 0)
+ {
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ case DevFmtUByte:
+ depth = 8;
+ break;
+ case DevFmtShort:
+ case DevFmtUShort:
+ depth = 16;
+ break;
+ case DevFmtInt:
+ case DevFmtUInt:
+ case DevFmtFloat:
+ break;
+ }
+ }
+ else if(depth > 24)
+ depth = 24;
+ device->DitherDepth = (depth > 0) ? powf(2.0f, (ALfloat)(depth-1)) : 0.0f;
+ }
+ if(!(device->DitherDepth > 0.0f))
+ TRACE("Dithering disabled\n");
+ else
+ TRACE("Dithering enabled (%g-bit, %g)\n", log2f(device->DitherDepth)+1.0f,
+ device->DitherDepth);
+
if(ConfigValueBool(alstr_get_cstr(device->DeviceName), NULL, "output-limiter", &val))
gainLimiter = val ? ALC_TRUE : ALC_FALSE;
/* Valid values for gainLimiter are ALC_DONT_CARE_SOFT, ALC_TRUE, and
@@ -2247,25 +2243,25 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
* allocated with the appropriate size.
*/
update_failed = AL_FALSE;
- SetMixerFPUMode(&oldMode);
- if(device->DefaultSlot)
- {
- ALeffectslot *slot = device->DefaultSlot;
- ALeffectState *state = slot->Effect.State;
-
- state->OutBuffer = device->Dry.Buffer;
- state->OutChannels = device->Dry.NumChannels;
- if(V(state,deviceUpdate)(device) == AL_FALSE)
- update_failed = AL_TRUE;
- else
- UpdateEffectSlotProps(slot);
- }
-
+ START_MIXER_MODE();
context = ATOMIC_LOAD_SEQ(&device->ContextList);
while(context)
{
ALsizei pos;
+ if(context->DefaultSlot)
+ {
+ ALeffectslot *slot = context->DefaultSlot;
+ ALeffectState *state = slot->Effect.State;
+
+ state->OutBuffer = device->Dry.Buffer;
+ state->OutChannels = device->Dry.NumChannels;
+ if(V(state,deviceUpdate)(device) == AL_FALSE)
+ update_failed = AL_TRUE;
+ else
+ UpdateEffectSlotProps(slot);
+ }
+
WriteLock(&context->PropLock);
LockUIntMapRead(&context->EffectSlotMap);
for(pos = 0;pos < context->EffectSlotMap.size;pos++)
@@ -2362,7 +2358,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
context = context->next;
}
- RestoreFPUMode(&oldMode);
+ END_MIXER_MODE();
if(update_failed)
return ALC_INVALID_DEVICE;
@@ -2393,12 +2389,6 @@ static ALCvoid FreeDevice(ALCdevice *device)
almtx_destroy(&device->BackendLock);
- if(device->DefaultSlot)
- {
- DeinitEffectSlot(device->DefaultSlot);
- device->DefaultSlot = NULL;
- }
-
if(device->BufferMap.size > 0)
{
WARN("(%p) Deleting %d Buffer%s\n", device, device->BufferMap.size,
@@ -2559,8 +2549,17 @@ static ALvoid InitContext(ALCcontext *Context)
InitUIntMap(&Context->SourceMap, Context->Device->SourcesMax);
InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax);
- auxslots = al_calloc(DEF_ALIGN, sizeof(struct ALeffectslotArray));
- auxslots->count = 0;
+ if(Context->DefaultSlot)
+ {
+ auxslots = al_calloc(DEF_ALIGN, FAM_SIZE(struct ALeffectslotArray, slot, 1));
+ auxslots->count = 1;
+ auxslots->slot[0] = Context->DefaultSlot;
+ }
+ else
+ {
+ auxslots = al_calloc(DEF_ALIGN, sizeof(struct ALeffectslotArray));
+ auxslots->count = 0;
+ }
ATOMIC_INIT(&Context->ActiveAuxSlots, auxslots);
//Set globals
@@ -2590,6 +2589,12 @@ static void FreeContext(ALCcontext *context)
TRACE("%p\n", context);
+ if(context->DefaultSlot)
+ {
+ DeinitEffectSlot(context->DefaultSlot);
+ context->DefaultSlot = NULL;
+ }
+
auxslots = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, NULL, almemory_order_relaxed);
al_free(auxslots);
@@ -3598,7 +3603,10 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR);
- ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener));
+ if(device->Type == Playback && DefaultEffect.type != AL_EFFECT_NULL)
+ ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener)+sizeof(ALeffectslot));
+ else
+ ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener));
if(!ALContext)
{
almtx_unlock(&device->BackendLock);
@@ -3610,6 +3618,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
InitRef(&ALContext->ref, 1);
ALContext->Listener = (ALlistener*)ALContext->_listener_mem;
+ ALContext->DefaultSlot = NULL;
ALContext->Voices = NULL;
ALContext->VoiceCount = 0;
@@ -3621,9 +3630,6 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
{
almtx_unlock(&device->BackendLock);
- al_free(ALContext->Voices);
- ALContext->Voices = NULL;
-
al_free(ALContext);
ALContext = NULL;
@@ -3639,6 +3645,18 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
}
AllocateVoices(ALContext, 256, device->NumAuxSends);
+ if(DefaultEffect.type != AL_EFFECT_NULL && device->Type == Playback)
+ {
+ ALContext->DefaultSlot = (ALeffectslot*)(ALContext->_listener_mem + sizeof(ALlistener));
+ if(InitEffectSlot(ALContext->DefaultSlot) == AL_NO_ERROR)
+ aluInitEffectPanning(ALContext->DefaultSlot);
+ else
+ {
+ ALContext->DefaultSlot = NULL;
+ ERR("Failed to initialize the default effect slot\n");
+ }
+ }
+
ALCdevice_IncRef(ALContext->Device);
InitContext(ALContext);
@@ -3666,6 +3684,14 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
}
almtx_unlock(&device->BackendLock);
+ if(ALContext->DefaultSlot)
+ {
+ if(InitializeEffect(device, ALContext->DefaultSlot, &DefaultEffect) == AL_NO_ERROR)
+ UpdateEffectSlotProps(ALContext->DefaultSlot);
+ else
+ ERR("Failed to initialize the default effect\n");
+ }
+
ALCdevice_DecRef(device);
TRACE("Created context %p\n", ALContext);
@@ -3801,6 +3827,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context)
*/
ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
{
+ ALCbackendFactory *factory;
const ALCchar *fmt;
ALCdevice *device;
ALCenum err;
@@ -3826,7 +3853,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
))
deviceName = NULL;
- device = al_calloc(16, sizeof(ALCdevice)+sizeof(ALeffectslot));
+ device = al_calloc(16, sizeof(ALCdevice));
if(!device)
{
alcSetError(NULL, ALC_OUT_OF_MEMORY);
@@ -3887,14 +3914,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
device->NumUpdates = 3;
device->UpdateSize = 1024;
- if(!PlaybackBackend.getFactory)
- device->Backend = create_backend_wrapper(device, &PlaybackBackend.Funcs,
- ALCbackend_Playback);
- else
- {
- ALCbackendFactory *factory = PlaybackBackend.getFactory();
- device->Backend = V(factory,createBackend)(device, ALCbackend_Playback);
- }
+ factory = PlaybackBackend.getFactory();
+ device->Backend = V(factory,createBackend)(device, ALCbackend_Playback);
if(!device->Backend)
{
al_free(device);
@@ -4026,32 +4047,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
ERR("Unsupported ambi-format: %s\n", fmt);
}
- device->DitherEnabled = GetConfigValueBool(
- alstr_get_cstr(device->DeviceName), NULL, "dither", 1
- );
-
device->Limiter = CreateDeviceLimiter(device);
- if(DefaultEffect.type != AL_EFFECT_NULL)
- {
- device->DefaultSlot = (ALeffectslot*)device->_slot_mem;
- if(InitEffectSlot(device->DefaultSlot) != AL_NO_ERROR)
- {
- device->DefaultSlot = NULL;
- ERR("Failed to initialize the default effect slot\n");
- }
- else
- {
- aluInitEffectPanning(device->DefaultSlot);
- if(InitializeEffect(device, device->DefaultSlot, &DefaultEffect) != AL_NO_ERROR)
- {
- DeinitEffectSlot(device->DefaultSlot);
- device->DefaultSlot = NULL;
- ERR("Failed to initialize the default effect\n");
- }
- }
- }
-
{
ALCdevice *head = ATOMIC_LOAD_SEQ(&DeviceList);
do {
@@ -4126,6 +4123,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
************************************************/
ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples)
{
+ ALCbackendFactory *factory;
ALCdevice *device = NULL;
ALCenum err;
ALCsizei i;
@@ -4183,14 +4181,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
device->ChannelDelay[i].Buffer = NULL;
}
- if(!CaptureBackend.getFactory)
- device->Backend = create_backend_wrapper(device, &CaptureBackend.Funcs,
- ALCbackend_Capture);
- else
- {
- ALCbackendFactory *factory = CaptureBackend.getFactory();
- device->Backend = V(factory,createBackend)(device, ALCbackend_Capture);
- }
+ factory = CaptureBackend.getFactory();
+ device->Backend = V(factory,createBackend)(device, ALCbackend_Capture);
if(!device->Backend)
{
al_free(device);
@@ -4450,8 +4442,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
// Open the "backend"
V(device->Backend,open)("Loopback");
- device->DitherEnabled = GetConfigValueBool(NULL, NULL, "dither", 1);
-
device->Limiter = CreateDeviceLimiter(device);
{
diff --git a/Alc/ALu.c b/Alc/ALu.c
index 11b3fd2..fa9634b 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -142,11 +142,11 @@ static inline HrtfDirectMixerFunc SelectHrtfMixer(void)
/* Prior to VS2013, MSVC lacks the round() family of functions. */
#if defined(_MSC_VER) && _MSC_VER < 1800
-static long lroundf(float val)
+static float roundf(float val)
{
- if(val < 0.0)
- return fastf2i(ceilf(val-0.5f));
- return fastf2i(floorf(val+0.5f));
+ if(val < 0.0f)
+ return ceilf(val-0.5f);
+ return floorf(val+0.5f);
}
#endif
@@ -214,7 +214,7 @@ static aluVector aluMatrixfVector(const aluMatrixf *mtx, const aluVector *vec)
* modified for use with an interpolated increment for buttery-smooth pitch
* changes.
*/
-static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
+ALboolean BsincPrepare(const ALuint increment, BsincState *state)
{
static const ALfloat scaleBase = 1.510578918e-01f, scaleRange = 1.177936623e+00f;
static const ALuint m[BSINC_SCALE_COUNT] = { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 };
@@ -231,7 +231,7 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
{ 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 0 }
};
ALfloat sf;
- ALuint si, pi;
+ ALsizei si, pi;
ALboolean uncut = AL_TRUE;
if(increment > FRACTIONONE)
@@ -249,7 +249,7 @@ static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
else
{
sf = (BSINC_SCALE_COUNT - 1) * (sf - scaleBase) * scaleRange;
- si = fastf2u(sf);
+ si = fastf2i(sf);
/* The interpolation factor is fit to this diagonally-symmetric
* curve to reduce the transition ripple caused by interpolating
* different scales of the sinc function.
@@ -1030,7 +1030,7 @@ static void CalcNonAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *p
{
SendSlots[i] = props->Send[i].Slot;
if(!SendSlots[i] && i == 0)
- SendSlots[i] = Device->DefaultSlot;
+ SendSlots[i] = ALContext->DefaultSlot;
if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL)
{
SendSlots[i] = NULL;
@@ -1100,7 +1100,7 @@ static void CalcAttnSourceParams(ALvoice *voice, const struct ALvoiceProps *prop
{
SendSlots[i] = props->Send[i].Slot;
if(!SendSlots[i] && i == 0)
- SendSlots[i] = Device->DefaultSlot;
+ SendSlots[i] = ALContext->DefaultSlot;
if(!SendSlots[i] || SendSlots[i]->Params.EffectType == AL_EFFECT_NULL)
{
SendSlots[i] = NULL;
@@ -1526,11 +1526,37 @@ static void ApplyDistanceComp(ALfloatBUFFERSIZE *restrict Samples, DistanceComp
}
}
+static void ApplyDither(ALfloatBUFFERSIZE *restrict Samples, ALuint *dither_seed,
+ const ALfloat quant_scale, const ALsizei SamplesToDo,
+ const ALsizei numchans)
+{
+ const ALfloat invscale = 1.0f / quant_scale;
+ ALuint seed = *dither_seed;
+ ALsizei c, i;
+
+ /* Dithering. Step 1, generate whitenoise (uniform distribution of random
+ * values between -1 and +1). Step 2 is to add the noise to the samples,
+ * before rounding and after scaling up to the desired quantization depth.
+ */
+ for(c = 0;c < numchans;c++)
+ {
+ ALfloat *restrict samples = Samples[c];
+ for(i = 0;i < SamplesToDo;i++)
+ {
+ ALfloat val = samples[i] * quant_scale;
+ ALuint rng0 = dither_rng(&seed);
+ ALuint rng1 = dither_rng(&seed);
+ val += (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX));
+ samples[i] = roundf(val) * invscale;
+ }
+ }
+ *dither_seed = seed;
+}
+
-/* NOTE: Non-dithered conversions have unused extra parameters. */
-static inline ALfloat aluF2F(ALfloat val, ...)
+static inline ALfloat Conv_ALfloat(ALfloat val)
{ return val; }
-static inline ALint aluF2I(ALfloat val, ...)
+static inline ALint Conv_ALint(ALfloat val)
{
/* Floats only have a 24-bit mantissa, so [-16777216, +16777216] is the max
* integer range normalized floats can be safely converted to (a bit of the
@@ -1538,87 +1564,58 @@ static inline ALint aluF2I(ALfloat val, ...)
*/
return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f))<<7;
}
-static inline ALshort aluF2S(ALfloat val, ...)
+static inline ALshort Conv_ALshort(ALfloat val)
{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); }
-static inline ALbyte aluF2B(ALfloat val, ...)
+static inline ALbyte Conv_ALbyte(ALfloat val)
{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); }
-/* Dithered conversion functions. Only applies to 8- and 16-bit output for now,
- * as 32-bit int and float are at the limits of the rendered sample depth. This
- * can change if the dithering bit depth becomes configurable (effectively
- * quantizing to a lower bit depth than the output is capable of).
- */
-static inline ALshort aluF2SDithered(ALfloat val, const ALfloat dither_val)
-{
- val = val*32768.0f + dither_val;
- return lroundf(clampf(val, -32768.0f, 32767.0f));
-}
-static inline ALbyte aluF2BDithered(ALfloat val, const ALfloat dither_val)
-{
- val = val*128.0f + dither_val;
- return lroundf(clampf(val, -128.0f, 127.0f));
-}
-
/* Define unsigned output variations. */
-#define DECL_TEMPLATE(T, Name, func, O) \
-static inline T Name(ALfloat val, const ALfloat dither_val) \
-{ return func(val, dither_val)+O; }
+#define DECL_TEMPLATE(T, func, O) \
+static inline T Conv_##T(ALfloat val) { return func(val)+O; }
-DECL_TEMPLATE(ALubyte, aluF2UB, aluF2B, 128)
-DECL_TEMPLATE(ALushort, aluF2US, aluF2S, 32768)
-DECL_TEMPLATE(ALuint, aluF2UI, aluF2I, 2147483648u)
-DECL_TEMPLATE(ALubyte, aluF2UBDithered, aluF2BDithered, 128)
-DECL_TEMPLATE(ALushort, aluF2USDithered, aluF2SDithered, 32768)
+DECL_TEMPLATE(ALubyte, Conv_ALbyte, 128)
+DECL_TEMPLATE(ALushort, Conv_ALshort, 32768)
+DECL_TEMPLATE(ALuint, Conv_ALint, 2147483648u)
#undef DECL_TEMPLATE
-#define DECL_TEMPLATE(T, D, func) \
-static void Write##T##D(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
- const ALfloat *restrict DitherValues, \
- ALsizei SamplesToDo, ALsizei numchans) \
+#define DECL_TEMPLATE(T, A) \
+static void Write##A(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
+ ALsizei Offset, ALsizei SamplesToDo, ALsizei numchans) \
{ \
ALsizei i, j; \
for(j = 0;j < numchans;j++) \
{ \
const ALfloat *restrict in = ASSUME_ALIGNED(InBuffer[j], 16); \
- T *restrict out = (T*)OutBuffer + j; \
+ T *restrict out = (T*)OutBuffer + Offset*numchans + j; \
\
for(i = 0;i < SamplesToDo;i++) \
- out[i*numchans] = func(in[i], DitherValues[i]); \
+ out[i*numchans] = Conv_##T(in[i]); \
} \
}
-DECL_TEMPLATE(ALfloat, /*no dither*/, aluF2F)
-DECL_TEMPLATE(ALuint, /*no dither*/, aluF2UI)
-DECL_TEMPLATE(ALint, /*no dither*/, aluF2I)
-DECL_TEMPLATE(ALushort, /*no dither*/, aluF2US)
-DECL_TEMPLATE(ALshort, /*no dither*/, aluF2S)
-DECL_TEMPLATE(ALubyte, /*no dither*/, aluF2UB)
-DECL_TEMPLATE(ALbyte, /*no dither*/, aluF2B)
-
-DECL_TEMPLATE(ALushort, _Dithered, aluF2USDithered)
-DECL_TEMPLATE(ALshort, _Dithered, aluF2SDithered)
-DECL_TEMPLATE(ALubyte, _Dithered, aluF2UBDithered)
-DECL_TEMPLATE(ALbyte, _Dithered, aluF2BDithered)
+DECL_TEMPLATE(ALfloat, F32)
+DECL_TEMPLATE(ALuint, UI32)
+DECL_TEMPLATE(ALint, I32)
+DECL_TEMPLATE(ALushort, UI16)
+DECL_TEMPLATE(ALshort, I16)
+DECL_TEMPLATE(ALubyte, UI8)
+DECL_TEMPLATE(ALbyte, I8)
#undef DECL_TEMPLATE
-void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
+void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples)
{
ALsizei SamplesToDo;
- ALvoice **voice, **voice_end;
- ALeffectslot *slot;
- ALsource *source;
+ ALsizei SamplesDone;
ALCcontext *ctx;
- FPUCtl oldMode;
ALsizei i, c;
- SetMixerFPUMode(&oldMode);
-
- while(size > 0)
+ START_MIXER_MODE();
+ for(SamplesDone = 0;SamplesDone < NumSamples;)
{
- SamplesToDo = mini(size, BUFFERSIZE);
+ SamplesToDo = mini(NumSamples-SamplesDone, BUFFERSIZE);
for(c = 0;c < device->Dry.NumChannels;c++)
memset(device->Dry.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
if(device->Dry.Buffer != device->FOAOut.Buffer)
@@ -1630,13 +1627,6 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
IncrementRef(&device->MixCount);
- if((slot=device->DefaultSlot) != NULL)
- {
- CalcEffectSlotParams(device->DefaultSlot, device);
- for(c = 0;c < slot->NumChannels;c++)
- memset(slot->WetBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
- }
-
ctx = ATOMIC_LOAD(&device->ContextList, almemory_order_acquire);
while(ctx)
{
@@ -1653,18 +1643,17 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
}
/* source processing */
- voice = ctx->Voices;
- voice_end = voice + ctx->VoiceCount;
- for(;voice != voice_end;++voice)
+ for(i = 0;i < ctx->VoiceCount;i++)
{
- source = ATOMIC_LOAD(&(*voice)->Source, almemory_order_acquire);
- if(source && ATOMIC_LOAD(&(*voice)->Playing, almemory_order_relaxed) &&
- (*voice)->Step > 0)
+ ALvoice *voice = ctx->Voices[i];
+ ALsource *source = ATOMIC_LOAD(&voice->Source, almemory_order_acquire);
+ if(source && ATOMIC_LOAD(&voice->Playing, almemory_order_relaxed) &&
+ voice->Step > 0)
{
- if(!MixSource(*voice, source, device, SamplesToDo))
+ if(!MixSource(voice, source, device, SamplesToDo))
{
- ATOMIC_STORE(&(*voice)->Source, NULL, almemory_order_relaxed);
- ATOMIC_STORE(&(*voice)->Playing, false, almemory_order_release);
+ ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
+ ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
}
}
}
@@ -1681,14 +1670,6 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
ctx = ctx->next;
}
- if(device->DefaultSlot != NULL)
- {
- const ALeffectslot *slot = device->DefaultSlot;
- ALeffectState *state = slot->Params.EffectState;
- V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer,
- state->OutChannels);
- }
-
/* Increment the clock time. Every second's worth of samples is
* converted and added to clock base so that large sample counts don't
* overflow during conversion. This also guarantees an exact, stable
@@ -1770,133 +1751,80 @@ void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
}
}
- if(buffer)
+ if(OutBuffer)
{
- ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer;
- ALsizei OutChannels = device->RealOut.NumChannels;
- struct Compressor *Limiter = device->Limiter;
- ALfloat *DitherValues;
+ ALfloat (*Buffer)[BUFFERSIZE] = device->RealOut.Buffer;
+ ALsizei Channels = device->RealOut.NumChannels;
/* Use NFCtrlData for temp value storage. */
- ApplyDistanceComp(OutBuffer, device->ChannelDelay, device->NFCtrlData,
- SamplesToDo, OutChannels);
+ ApplyDistanceComp(Buffer, device->ChannelDelay, device->NFCtrlData,
+ SamplesToDo, Channels);
- if(Limiter)
- ApplyCompression(Limiter, OutChannels, SamplesToDo, OutBuffer);
+ if(device->Limiter)
+ ApplyCompression(device->Limiter, Channels, SamplesToDo, Buffer);
- /* Dithering. Step 1, generate whitenoise (uniform distribution of
- * random values between -1 and +1). Use NFCtrlData for random
- * value storage. Step 2 is to add the noise to the samples, before
- * rounding and after scaling up to the desired quantization depth,
- * which occurs in the sample conversion stage.
- */
- if(!device->DitherEnabled)
- memset(device->NFCtrlData, 0, SamplesToDo*sizeof(ALfloat));
- else
- {
- ALuint dither_seed = device->DitherSeed;
- ALsizei i;
-
- for(i = 0;i < SamplesToDo;i++)
- {
- ALuint rng0 = dither_rng(&dither_seed);
- ALuint rng1 = dither_rng(&dither_seed);
- device->NFCtrlData[i] = (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX));
- }
- device->DitherSeed = dither_seed;
- }
- DitherValues = device->NFCtrlData;
+ if(device->DitherDepth > 0.0f)
+ ApplyDither(Buffer, &device->DitherSeed, device->DitherDepth, SamplesToDo,
+ Channels);
-#define WRITE(T, D, a, b, c, d, e) do { \
- Write##T##D(SAFE_CONST(ALfloatBUFFERSIZE*,(a)), (b), (c), (d), (e)); \
- buffer = (T*)buffer + (d)*(e); \
-} while(0)
switch(device->FmtType)
{
case DevFmtByte:
- if(device->DitherEnabled)
- WRITE(ALbyte, _Dithered, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
- else
- WRITE(ALbyte, /*no dither*/, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
+ WriteI8(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels);
break;
case DevFmtUByte:
- if(device->DitherEnabled)
- WRITE(ALubyte, _Dithered, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
- else
- WRITE(ALubyte, /*no dither*/, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
+ WriteUI8(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels);
break;
case DevFmtShort:
- if(device->DitherEnabled)
- WRITE(ALshort, _Dithered, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
- else
- WRITE(ALshort, /*no dither*/, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
+ WriteI16(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels);
break;
case DevFmtUShort:
- if(device->DitherEnabled)
- WRITE(ALushort, _Dithered, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
- else
- WRITE(ALushort, /*no dither*/, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
+ WriteUI16(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels);
break;
case DevFmtInt:
- WRITE(ALint, /*no dither*/, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
+ WriteI32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels);
break;
case DevFmtUInt:
- WRITE(ALuint, /*no dither*/, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
+ WriteUI32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels);
break;
case DevFmtFloat:
- WRITE(ALfloat, /*no dither*/, OutBuffer, buffer, DitherValues,
- SamplesToDo, OutChannels);
+ WriteF32(Buffer, OutBuffer, SamplesDone, SamplesToDo, Channels);
break;
}
-#undef WRITE
}
- size -= SamplesToDo;
+ SamplesDone += SamplesToDo;
}
-
- RestoreFPUMode(&oldMode);
+ END_MIXER_MODE();
}
void aluHandleDisconnect(ALCdevice *device)
{
- ALCcontext *Context;
+ ALCcontext *ctx;
device->Connected = ALC_FALSE;
- Context = ATOMIC_LOAD_SEQ(&device->ContextList);
- while(Context)
+ ctx = ATOMIC_LOAD_SEQ(&device->ContextList);
+ while(ctx)
{
- ALvoice **voice, **voice_end;
-
- voice = Context->Voices;
- voice_end = voice + Context->VoiceCount;
- while(voice != voice_end)
+ ALsizei i;
+ for(i = 0;i < ctx->VoiceCount;i++)
{
- ALsource *source = ATOMIC_EXCHANGE_PTR(&(*voice)->Source, NULL,
- almemory_order_acq_rel);
- ATOMIC_STORE(&(*voice)->Playing, false, almemory_order_release);
+ ALvoice *voice = ctx->Voices[i];
+ ALsource *source;
+
+ source = ATOMIC_EXCHANGE_PTR(&voice->Source, NULL, almemory_order_acq_rel);
+ ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
if(source)
{
ALenum playing = AL_PLAYING;
(void)(ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(&source->state, &playing, AL_STOPPED));
}
-
- voice++;
}
- Context->VoiceCount = 0;
+ ctx->VoiceCount = 0;
- Context = Context->next;
+ ctx = ctx->next;
}
}
diff --git a/Alc/backends/base.c b/Alc/backends/base.c
index 902c431..5f568d8 100644
--- a/Alc/backends/base.c
+++ b/Alc/backends/base.c
@@ -79,157 +79,3 @@ void ALCbackend_unlock(ALCbackend *self)
void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self))
{
}
-
-
-/* Wrappers to use an old-style backend with the new interface. */
-typedef struct PlaybackWrapper {
- DERIVE_FROM_TYPE(ALCbackend);
-
- const BackendFuncs *Funcs;
-} PlaybackWrapper;
-
-static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct)
-static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
-static void PlaybackWrapper_close(PlaybackWrapper *self);
-static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self);
-static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self);
-static void PlaybackWrapper_stop(PlaybackWrapper *self);
-static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency)
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
-DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
-DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
-
-static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
-{
- ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
- SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
-
- self->Funcs = funcs;
-}
-
-static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->OpenPlayback(device, name);
-}
-
-static void PlaybackWrapper_close(PlaybackWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- self->Funcs->ClosePlayback(device);
-}
-
-static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->ResetPlayback(device);
-}
-
-static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->StartPlayback(device);
-}
-
-static void PlaybackWrapper_stop(PlaybackWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- self->Funcs->StopPlayback(device);
-}
-
-
-typedef struct CaptureWrapper {
- DERIVE_FROM_TYPE(ALCbackend);
-
- const BackendFuncs *Funcs;
-} CaptureWrapper;
-
-static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
-static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct)
-static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
-static void CaptureWrapper_close(CaptureWrapper *self);
-static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset)
-static ALCboolean CaptureWrapper_start(CaptureWrapper *self);
-static void CaptureWrapper_stop(CaptureWrapper *self);
-static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples);
-static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
-static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency)
-static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
-static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
-DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
-DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
-
-static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
-{
- ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
- SET_VTABLE2(CaptureWrapper, ALCbackend, self);
-
- self->Funcs = funcs;
-}
-
-static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->OpenCapture(device, name);
-}
-
-static void CaptureWrapper_close(CaptureWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- self->Funcs->CloseCapture(device);
-}
-
-static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- self->Funcs->StartCapture(device);
- return ALC_TRUE;
-}
-
-static void CaptureWrapper_stop(CaptureWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- self->Funcs->StopCapture(device);
-}
-
-static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->CaptureSamples(device, buffer, samples);
-}
-
-static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->AvailableSamples(device);
-}
-
-
-ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type)
-{
- if(type == ALCbackend_Playback)
- {
- PlaybackWrapper *backend;
-
- NEW_OBJ(backend, PlaybackWrapper)(device, funcs);
- if(!backend) return NULL;
-
- return STATIC_CAST(ALCbackend, backend);
- }
-
- if(type == ALCbackend_Capture)
- {
- CaptureWrapper *backend;
-
- NEW_OBJ(backend, CaptureWrapper)(device, funcs);
- if(!backend) return NULL;
-
- return STATIC_CAST(ALCbackend, backend);
- }
-
- return NULL;
-}
diff --git a/Alc/backends/base.h b/Alc/backends/base.h
index 961a4d1..8464fde 100644
--- a/Alc/backends/base.h
+++ b/Alc/backends/base.h
@@ -142,6 +142,7 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void);
ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
ALCbackendFactory *ALCsndioBackendFactory_getFactory(void);
+ALCbackendFactory *ALCqsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
@@ -151,6 +152,4 @@ ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
ALCbackendFactory *ALCloopbackFactory_getFactory(void);
-ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type);
-
#endif /* AL_BACKENDS_BASE_H */
diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c
index 85d5d9c..ceff0b3 100644
--- a/Alc/backends/jack.c
+++ b/Alc/backends/jack.c
@@ -63,6 +63,7 @@ static const ALCchar jackDevice[] = "JACK Default";
static void *jack_handle;
#define MAKE_FUNC(f) static __typeof(f) * p##f
JACK_FUNCS(MAKE_FUNC);
+static __typeof(jack_error_callback) * pjack_error_callback;
#undef MAKE_FUNC
#define jack_client_open pjack_client_open
@@ -84,6 +85,7 @@ JACK_FUNCS(MAKE_FUNC);
#define jack_set_buffer_size_callback pjack_set_buffer_size_callback
#define jack_set_buffer_size pjack_set_buffer_size
#define jack_get_buffer_size pjack_get_buffer_size
+#define jack_error_callback (*pjack_error_callback)
#endif
@@ -120,6 +122,10 @@ static ALCboolean jack_load(void)
} while(0)
JACK_FUNCS(LOAD_FUNC);
#undef LOAD_FUNC
+ /* Optional symbols. These don't exist in all versions of JACK. */
+#define LOAD_SYM(f) p##f = GetSymbol(jack_handle, #f)
+ LOAD_SYM(jack_error_callback);
+#undef LOAD_SYM
if(error)
{
@@ -556,6 +562,7 @@ typedef struct ALCjackBackendFactory {
static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self))
{
+ void (*old_error_cb)(const char*);
jack_client_t *client;
jack_status_t status;
@@ -565,9 +572,10 @@ static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self)
if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0))
ClientOptions |= JackNoStartServer;
+ old_error_cb = (&jack_error_callback ? jack_error_callback : NULL);
jack_set_error_function(jack_msg_handler);
client = jack_client_open("alsoft", ClientOptions, &status, NULL);
- jack_set_error_function(NULL);
+ jack_set_error_function(old_error_cb);
if(client == NULL)
{
WARN("jack_client_open() failed, 0x%02x\n", status);
diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c
index 43d8429..9afb62f 100644
--- a/Alc/backends/mmdevapi.c
+++ b/Alc/backends/mmdevapi.c
@@ -65,6 +65,8 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x
#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER)
+#define REFTIME_PER_SEC ((REFERENCE_TIME)10000000)
+
#define DEVNAME_HEAD "OpenAL Soft on "
@@ -109,6 +111,15 @@ typedef struct {
#define WM_USER_Enumerate (WM_USER+5)
#define WM_USER_Last (WM_USER+5)
+static const char MessageStr[WM_USER_Last+1-WM_USER][20] = {
+ "Open Device",
+ "Reset Device",
+ "Start Device",
+ "Stop Device",
+ "Close Device",
+ "Enumerate Devices",
+};
+
static inline void ReturnMsgResponse(ThreadRequest *req, HRESULT res)
{
req->result = res;
@@ -403,7 +414,11 @@ static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr)
TRACE("Starting message loop\n");
while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
{
- TRACE("Got message %u (lparam=%p, wparam=%p)\n", msg.message, (void*)msg.lParam, (void*)msg.wParam);
+ TRACE("Got message \"%s\" (0x%04x, lparam=%p, wparam=%p)\n",
+ (msg.message >= WM_USER && msg.message <= WM_USER_Last) ?
+ MessageStr[msg.message-WM_USER] : "Unknown",
+ msg.message, (void*)msg.lParam, (void*)msg.wParam
+ );
switch(msg.message)
{
case WM_USER_OpenDevice:
@@ -891,8 +906,8 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
CoTaskMemFree(wfx);
wfx = NULL;
- buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 +
- device->Frequency-1) / device->Frequency;
+ buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC,
+ device->Frequency);
if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
device->Frequency = OutputType.Format.nSamplesPerSec;
@@ -1081,7 +1096,7 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
hr = IAudioClient_GetDevicePeriod(self->client, &min_per, NULL);
if(SUCCEEDED(hr))
{
- min_len = (UINT32)((min_per*device->Frequency + 10000000-1) / 10000000);
+ min_len = (UINT32)ScaleCeil(min_per, device->Frequency, REFTIME_PER_SEC);
/* 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;
@@ -1600,8 +1615,12 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
}
self->client = ptr;
- buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 +
- device->Frequency-1) / device->Frequency;
+ buf_time = ScaleCeil(device->UpdateSize*device->NumUpdates, REFTIME_PER_SEC,
+ device->Frequency);
+ // Make sure buffer is at least 100ms in size
+ buf_time = maxu64(buf_time, REFTIME_PER_SEC/10);
+ device->UpdateSize = (ALuint)ScaleCeil(buf_time, device->Frequency, REFTIME_PER_SEC) /
+ device->NumUpdates;
OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
switch(device->FmtChans)
@@ -1741,9 +1760,10 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
device->FmtChans);
if(!self->ChannelConv)
{
- ERR("Failed to create stereo-to-mono converter\n");
+ ERR("Failed to create %s stereo-to-mono converter\n", DevFmtTypeString(srcType));
return E_FAIL;
}
+ TRACE("Created %s stereo-to-mono converter\n", DevFmtTypeString(srcType));
/* The channel converter always outputs float, so change the input type
* for the resampler/type-converter.
*/
@@ -1755,9 +1775,10 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
device->FmtChans);
if(!self->ChannelConv)
{
- ERR("Failed to create mono-to-stereo converter\n");
+ ERR("Failed to create %s mono-to-stereo converter\n", DevFmtTypeString(srcType));
return E_FAIL;
}
+ TRACE("Created %s mono-to-stereo converter\n", DevFmtTypeString(srcType));
srcType = DevFmtFloat;
}
@@ -1769,12 +1790,14 @@ static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
);
if(!self->SampleConv)
{
- ERR("Failed to create converter for format, dst: %s %s %uhz, src: %d-bit %luhz\n",
+ ERR("Failed to create converter for %s format, dst: %s %uhz, src: %s %luhz\n",
DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
- device->Frequency, OutputType.Format.wBitsPerSample,
- OutputType.Format.nSamplesPerSec);
+ device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec);
return E_FAIL;
}
+ TRACE("Created converter for %s format, dst: %s %uhz, src: %s %luhz\n",
+ DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
+ device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec);
}
hr = IAudioClient_Initialize(self->client,
diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c
index 33ea55e..9c63d9d 100644
--- a/Alc/backends/oss.c
+++ b/Alc/backends/oss.c
@@ -163,12 +163,12 @@ static void ALCossListPopulate(struct oss_device *devlist, int type_flag)
if((fd=open("/dev/mixer", O_RDONLY)) < 0)
{
- ERR("Could not open /dev/mixer\n");
+ TRACE("Could not open /dev/mixer: %s\n", strerror(errno));
return;
}
if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1)
{
- ERR("SNDCTL_SYSINFO failed: %s\n", strerror(errno));
+ TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno));
goto done;
}
for(i = 0;i < si.numaudios;i++)
@@ -821,7 +821,11 @@ void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProb
cur = &oss_playback;
while(cur != NULL)
{
- AppendAllDevicesList(cur->handle);
+#ifdef HAVE_STAT
+ struct stat buf;
+ if(stat(cur->path, &buf) == 0)
+#endif
+ AppendAllDevicesList(cur->handle);
cur = cur->next;
}
break;
@@ -832,7 +836,11 @@ void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProb
cur = &oss_capture;
while(cur != NULL)
{
- AppendCaptureDeviceList(cur->handle);
+#ifdef HAVE_STAT
+ struct stat buf;
+ if(stat(cur->path, &buf) == 0)
+#endif
+ AppendCaptureDeviceList(cur->handle);
cur = cur->next;
}
break;
diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c
index 43761e2..8c5469b 100644
--- a/Alc/backends/pulseaudio.c
+++ b/Alc/backends/pulseaudio.c
@@ -817,7 +817,6 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
pa_threaded_mainloop_lock(self->loop);
frame_size = pa_frame_size(&self->spec);
- buffer_size = device->UpdateSize * device->NumUpdates * frame_size;
while(!self->killNow && device->Connected)
{
@@ -830,15 +829,17 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
}
/* Make sure we're going to write at least 2 'periods' (minreqs), in
- * case the server increased it since starting playback.
+ * case the server increased it since starting playback. Also round up
+ * the number of writable periods if it's not an integer count.
*/
- buffer_size = maxu(buffer_size, self->attr.minreq*2);
+ buffer_size = maxu((self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2) *
+ self->attr.minreq;
/* NOTE: This assumes pa_stream_writable_size returns between 0 and
* tlength, else there will be more latency than intended.
*/
len = mini(len - (ssize_t)self->attr.tlength, 0) + buffer_size;
- if(len < self->attr.minreq)
+ if(len < (int32_t)self->attr.minreq)
{
if(pa_stream_is_corked(self->stream))
{
@@ -968,7 +969,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
const char *mapname = NULL;
pa_channel_map chanmap;
pa_operation *o;
- ALuint len;
pa_threaded_mainloop_lock(self->loop);
@@ -1107,11 +1107,10 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
ALCpulsePlayback_bufferAttrCallback(self->stream, self);
- len = self->attr.minreq / pa_frame_size(&self->spec);
- device->NumUpdates = (ALuint)clampd(
- (ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5, 2.0, 16.0
+ device->NumUpdates = (ALuint)clampu64(
+ (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2, 16
);
- device->UpdateSize = len;
+ device->UpdateSize = self->attr.minreq / pa_frame_size(&self->spec);
/* HACK: prebuf should be 0 as that's what we set it to. However on some
* systems it comes back as non-0, so we have to make sure the device will
@@ -1121,7 +1120,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
*/
if(self->attr.prebuf != 0)
{
- len = self->attr.prebuf / pa_frame_size(&self->spec);
+ ALuint len = self->attr.prebuf / pa_frame_size(&self->spec);
if(len <= device->UpdateSize*device->NumUpdates)
ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n",
len, self->attr.prebuf, device->UpdateSize*device->NumUpdates);
diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c
index 9da55b5..58193c9 100644
--- a/Alc/backends/qsa.c
+++ b/Alc/backends/qsa.c
@@ -159,10 +159,33 @@ static void deviceList(int type, vector_DevMap *devmap)
}
-FORCE_ALIGN static int qsa_proc_playback(void* ptr)
+/* Wrappers to use an old-style backend with the new interface. */
+typedef struct PlaybackWrapper {
+ DERIVE_FROM_TYPE(ALCbackend);
+ qsa_data *ExtraData;
+} PlaybackWrapper;
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device);
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct)
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
+static void PlaybackWrapper_close(PlaybackWrapper *self);
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self);
+static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self);
+static void PlaybackWrapper_stop(PlaybackWrapper *self);
+static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
+DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
+
+
+FORCE_ALIGN static int qsa_proc_playback(void *ptr)
{
- ALCdevice* device=(ALCdevice*)ptr;
- qsa_data* data=(qsa_data*)device->ExtraData;
+ PlaybackWrapper *self = ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
snd_pcm_channel_status_t status;
struct sched_param param;
struct timeval timeout;
@@ -250,8 +273,9 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
/* Playback */
/************/
-static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
+static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName)
{
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
qsa_data *data;
int card, dev;
int status;
@@ -299,14 +323,14 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
}
alstr_copy_cstr(&device->DeviceName, deviceName);
- device->ExtraData = data;
+ self->ExtraData = data;
return ALC_NO_ERROR;
}
-static void qsa_close_playback(ALCdevice* device)
+static void qsa_close_playback(PlaybackWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
if (data->buffer!=NULL)
{
@@ -317,12 +341,13 @@ static void qsa_close_playback(ALCdevice* device)
snd_pcm_close(data->pcmHandle);
free(data);
- device->ExtraData=NULL;
+ self->ExtraData = NULL;
}
-static ALCboolean qsa_reset_playback(ALCdevice* device)
+static ALCboolean qsa_reset_playback(PlaybackWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
int32_t format=-1;
switch(device->FmtType)
@@ -567,20 +592,20 @@ static ALCboolean qsa_reset_playback(ALCdevice* device)
return ALC_TRUE;
}
-static ALCboolean qsa_start_playback(ALCdevice* device)
+static ALCboolean qsa_start_playback(PlaybackWrapper *self)
{
- qsa_data *data = (qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
data->killNow = 0;
- if(althrd_create(&data->thread, qsa_proc_playback, device) != althrd_success)
+ if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
-static void qsa_stop_playback(ALCdevice* device)
+static void qsa_stop_playback(PlaybackWrapper *self)
{
- qsa_data *data = (qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
int res;
if(data->killNow)
@@ -590,12 +615,70 @@ static void qsa_stop_playback(ALCdevice* device)
althrd_join(data->thread, &res);
}
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
+
+ self->ExtraData = NULL;
+}
+
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
+{
+ return qsa_open_playback(self, name);
+}
+
+static void PlaybackWrapper_close(PlaybackWrapper *self)
+{
+ qsa_close_playback(self);
+}
+
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
+{
+ return qsa_reset_playback(self);
+}
+
+static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
+{
+ return qsa_start_playback(self);
+}
+
+static void PlaybackWrapper_stop(PlaybackWrapper *self)
+{
+ qsa_stop_playback(self);
+}
+
+
+
/***********/
/* Capture */
/***********/
-static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
+typedef struct CaptureWrapper {
+ DERIVE_FROM_TYPE(ALCbackend);
+ qsa_data *ExtraData;
+} CaptureWrapper;
+
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct)
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
+static void CaptureWrapper_close(CaptureWrapper *self);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset)
+static ALCboolean CaptureWrapper_start(CaptureWrapper *self);
+static void CaptureWrapper_stop(CaptureWrapper *self);
+static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples);
+static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
+DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
+
+
+static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName)
{
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
qsa_data *data;
int card, dev;
int format=-1;
@@ -646,7 +729,7 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
}
alstr_copy_cstr(&device->DeviceName, deviceName);
- device->ExtraData = data;
+ self->ExtraData = data;
switch (device->FmtType)
{
@@ -699,7 +782,6 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
{
snd_pcm_close(data->pcmHandle);
free(data);
- device->ExtraData=NULL;
return ALC_INVALID_VALUE;
}
@@ -707,20 +789,20 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
return ALC_NO_ERROR;
}
-static void qsa_close_capture(ALCdevice* device)
+static void qsa_close_capture(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
if (data->pcmHandle!=NULL)
snd_pcm_close(data->pcmHandle);
free(data);
- device->ExtraData=NULL;
+ self->ExtraData = NULL;
}
-static void qsa_start_capture(ALCdevice* device)
+static void qsa_start_capture(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ qsa_data *data = self->ExtraData;
int rstatus;
if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
@@ -740,16 +822,16 @@ static void qsa_start_capture(ALCdevice* device)
snd_pcm_capture_go(data->pcmHandle);
}
-static void qsa_stop_capture(ALCdevice* device)
+static void qsa_stop_capture(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
-
+ qsa_data *data = self->ExtraData;
snd_pcm_capture_flush(data->pcmHandle);
}
-static ALCuint qsa_available_samples(ALCdevice* device)
+static ALCuint qsa_available_samples(CaptureWrapper *self)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
snd_pcm_channel_status_t status;
ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
ALint free_size;
@@ -778,9 +860,10 @@ static ALCuint qsa_available_samples(ALCdevice* device)
return free_size/frame_size;
}
-static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples)
{
- qsa_data* data=(qsa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ qsa_data *data = self->ExtraData;
char* read_ptr;
snd_pcm_channel_status_t status;
fd_set rfds;
@@ -853,27 +936,65 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
return ALC_NO_ERROR;
}
-static const BackendFuncs qsa_funcs= {
- qsa_open_playback,
- qsa_close_playback,
- qsa_reset_playback,
- qsa_start_playback,
- qsa_stop_playback,
- qsa_open_capture,
- qsa_close_capture,
- qsa_start_capture,
- qsa_stop_capture,
- qsa_capture_samples,
- qsa_available_samples
-};
-ALCboolean alc_qsa_init(BackendFuncs* func_list)
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(CaptureWrapper, ALCbackend, self);
+
+ self->ExtraData = NULL;
+}
+
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
+{
+ return qsa_open_capture(self, name);
+}
+
+static void CaptureWrapper_close(CaptureWrapper *self)
+{
+ qsa_close_capture(self);
+}
+
+static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
+{
+ qsa_start_capture(self);
+ return ALC_TRUE;
+}
+
+static void CaptureWrapper_stop(CaptureWrapper *self)
+{
+ qsa_stop_capture(self);
+}
+
+static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
+{
+ return qsa_capture_samples(self, buffer, samples);
+}
+
+static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
+{
+ return qsa_available_samples(self);
+}
+
+
+typedef struct ALCqsaBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCqsaBackendFactory;
+#define ALCQSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self));
+static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self));
+static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type);
+static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type);
+static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory);
+
+static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self))
{
- *func_list = qsa_funcs;
return ALC_TRUE;
}
-void alc_qsa_deinit(void)
+static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self))
{
#define FREE_NAME(iter) free((iter)->name)
VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
@@ -884,7 +1005,14 @@ void alc_qsa_deinit(void)
#undef FREE_NAME
}
-void alc_qsa_probe(enum DevProbe type)
+static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type)
{
switch (type)
{
@@ -913,3 +1041,29 @@ void alc_qsa_probe(enum DevProbe type)
break;
}
}
+
+static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ PlaybackWrapper *backend;
+ NEW_OBJ(backend, PlaybackWrapper)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+ if(type == ALCbackend_Capture)
+ {
+ CaptureWrapper *backend;
+ NEW_OBJ(backend, CaptureWrapper)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+ALCbackendFactory *ALCqsaBackendFactory_getFactory(void)
+{
+ static ALCqsaBackendFactory factory = ALCQSABACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c
index c72a632..bdf76ed 100644
--- a/Alc/backends/wave.c
+++ b/Alc/backends/wave.c
@@ -320,8 +320,9 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
// 32-bit val, channel mask
fwrite32le(chanmask, self->mFile);
// 16 byte GUID, sub-type format
- val = fwrite(((bits==32) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
- (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile);
+ val = fwrite((device->FmtType == DevFmtFloat) ?
+ (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
+ (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, self->mFile);
(void)val;
fputs("data", self->mFile);
diff --git a/Alc/bformatdec.c b/Alc/bformatdec.c
index 92a2aec..ba6daac 100644
--- a/Alc/bformatdec.c
+++ b/Alc/bformatdec.c
@@ -75,6 +75,45 @@ void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat
}
+void splitterap_init(SplitterAllpass *splitter, ALfloat freq_mult)
+{
+ ALfloat w = freq_mult * F_TAU;
+ ALfloat cw = cosf(w);
+ if(cw > FLT_EPSILON)
+ splitter->coeff = (sinf(w) - 1.0f) / cw;
+ else
+ splitter->coeff = cw * -0.5f;
+
+ splitter->z1 = 0.0f;
+}
+
+void splitterap_clear(SplitterAllpass *splitter)
+{
+ splitter->z1 = 0.0f;
+}
+
+void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count)
+{
+ ALfloat coeff, d, x;
+ ALfloat z1;
+ ALsizei i;
+
+ coeff = splitter->coeff;
+ z1 = splitter->z1;
+ for(i = 0;i < count;i++)
+ {
+ x = samples[i];
+
+ d = x - coeff*z1;
+ x = z1 + coeff*d;
+ z1 = d;
+
+ samples[i] = x;
+ }
+ splitter->z1 = z1;
+}
+
+
static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
diff --git a/Alc/bformatdec.h b/Alc/bformatdec.h
index 162f265..8f44fc2 100644
--- a/Alc/bformatdec.h
+++ b/Alc/bformatdec.h
@@ -60,4 +60,16 @@ void bandsplit_clear(BandSplitter *splitter);
void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
const ALfloat *input, ALsizei count);
+/* The all-pass portion of the band splitter. Applies the same phase shift
+ * without splitting the signal.
+ */
+typedef struct SplitterAllpass {
+ ALfloat coeff;
+ ALfloat z1;
+} SplitterAllpass;
+
+void splitterap_init(SplitterAllpass *splitter, ALfloat freq_mult);
+void splitterap_clear(SplitterAllpass *splitter);
+void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count);
+
#endif /* BFORMATDEC_H */
diff --git a/Alc/converter.c b/Alc/converter.c
index f1a3a96..5cfe703 100644
--- a/Alc/converter.c
+++ b/Alc/converter.c
@@ -9,6 +9,7 @@
SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate)
{
SampleConverter *converter;
+ ALsizei step;
if(numchans <= 0 || srcRate <= 0 || dstRate <= 0)
return NULL;
@@ -21,17 +22,21 @@ SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType
converter->mDstTypeSize = BytesFromDevFmt(dstType);
converter->mSrcPrepCount = 0;
-
converter->mFracOffset = 0;
- converter->mIncrement = (ALsizei)clampu64((ALuint64)srcRate*FRACTIONONE/dstRate,
- 1, MAX_PITCH*FRACTIONONE);
+
+ /* Have to set the mixer FPU mode since that's what the resampler code expects. */
+ START_MIXER_MODE();
+ step = fastf2i(minf((ALdouble)srcRate / dstRate, MAX_PITCH)*FRACTIONONE + 0.5f);
+ converter->mIncrement = maxi(step, 1);
if(converter->mIncrement == FRACTIONONE)
converter->mResample = Resample_copy32_C;
else
{
/* TODO: Allow other resamplers. */
- converter->mResample = SelectResampler(LinearResampler);
+ BsincPrepare(converter->mIncrement, &converter->mState.bsinc);
+ converter->mResample = SelectResampler(BSincResampler);
}
+ END_MIXER_MODE();
return converter;
}
@@ -59,7 +64,7 @@ static inline ALfloat Sample_ALushort(ALushort val)
static inline ALfloat Sample_ALint(ALint val)
{ return (val>>7) * (1.0f/16777216.0f); }
static inline ALfloat Sample_ALuint(ALuint val)
-{ return ((ALint)(val>>7) - 16777216) * (1.0f/16777216.0f); }
+{ return Sample_ALint(val - INT_MAX - 1); }
static inline ALfloat Sample_ALfloat(ALfloat val)
{ return val; }
@@ -113,17 +118,17 @@ static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum Dev
static inline ALbyte ALbyte_Sample(ALfloat val)
-{ return (ALbyte)clampf(val*128.0f, -128.0f, 127.0f); }
+{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); }
static inline ALubyte ALubyte_Sample(ALfloat val)
{ return ALbyte_Sample(val)+128; }
static inline ALshort ALshort_Sample(ALfloat val)
-{ return (ALshort)clampf(val*32768.0f, -32768.0f, 32767.0f); }
+{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); }
static inline ALushort ALushort_Sample(ALfloat val)
{ return ALshort_Sample(val)+32768; }
static inline ALint ALint_Sample(ALfloat val)
-{ return (ALint)clampf(val*16777216.0f, -16777216.0f, 16777215.0f) << 7; }
+{ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f)) << 7; }
static inline ALuint ALuint_Sample(ALfloat val)
{ return ALint_Sample(val)+INT_MAX+1; }
@@ -194,6 +199,12 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe
prepcount = 0;
}
+ if(srcframes < 1)
+ {
+ /* No output samples if there's no input samples. */
+ return 0;
+ }
+
if(prepcount < MAX_POST_SAMPLES+MAX_PRE_SAMPLES &&
MAX_POST_SAMPLES+MAX_PRE_SAMPLES-prepcount >= srcframes)
{
@@ -208,7 +219,7 @@ ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframe
DataSize64 -= DataPosFrac;
/* If we have a full prep, we can generate at least one sample. */
- return (ALsizei)clampu64(DataSize64/increment, 1, INT_MAX);
+ return (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE);
}
@@ -219,7 +230,8 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
const ALsizei increment = converter->mIncrement;
ALsizei pos = 0;
- while(pos < dstframes)
+ START_MIXER_MODE();
+ while(pos < dstframes && *srcframes > 0)
{
ALfloat *restrict SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16);
ALfloat *restrict DstData = ASSUME_ALIGNED(converter->mDstSamples, 16);
@@ -241,7 +253,8 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
}
*src = (const ALbyte*)*src + SrcFrameSize*-prepcount;
*srcframes += prepcount;
- prepcount = 0;
+ converter->mSrcPrepCount = 0;
+ continue;
}
toread = mini(*srcframes, BUFFERSIZE-(MAX_POST_SAMPLES+MAX_PRE_SAMPLES));
@@ -253,7 +266,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
*/
for(chan = 0;chan < converter->mNumChannels;chan++)
LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount],
- (const ALbyte*)src + converter->mSrcTypeSize*chan,
+ (const ALbyte*)*src + converter->mSrcTypeSize*chan,
converter->mNumChannels, converter->mSrcType, toread
);
@@ -269,13 +282,13 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
DataSize64 -= DataPosFrac;
/* If we have a full prep, we can generate at least one sample. */
- DstSize = (ALsizei)clampu64(DataSize64/increment, 1, BUFFERSIZE);
+ DstSize = (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE);
DstSize = mini(DstSize, dstframes-pos);
for(chan = 0;chan < converter->mNumChannels;chan++)
{
const ALbyte *SrcSamples = (const ALbyte*)*src + converter->mSrcTypeSize*chan;
- ALbyte *DstSamples = (ALbyte*)dst + converter->mSrcTypeSize*chan;
+ ALbyte *DstSamples = (ALbyte*)dst + converter->mDstTypeSize*chan;
const ALfloat *ResampledData;
ALsizei SrcDataEnd;
@@ -294,7 +307,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
SrcDataEnd = (DataPosFrac + increment*DstSize)>>FRACTIONBITS;
if(SrcDataEnd >= prepcount+toread)
memset(converter->Chan[chan].mPrevSamples, 0,
- sizeof(converter->Chan[chan].mPrevSamples));
+ sizeof(converter->Chan[chan].mPrevSamples));
else
{
size_t len = mini(MAX_PRE_SAMPLES+MAX_POST_SAMPLES, prepcount+toread-SrcDataEnd);
@@ -305,7 +318,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
}
/* Now resample, and store the result in the output buffer. */
- ResampledData = converter->mResample(NULL,
+ ResampledData = converter->mResample(&converter->mState,
SrcData+MAX_PRE_SAMPLES, DataPosFrac, increment,
DstData, DstSize
);
@@ -329,6 +342,7 @@ ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALs
dst = (ALbyte*)dst + DstFrameSize*DstSize;
pos += DstSize;
}
+ END_MIXER_MODE();
return pos;
}
diff --git a/Alc/converter.h b/Alc/converter.h
index db3f1da..9934fa4 100644
--- a/Alc/converter.h
+++ b/Alc/converter.h
@@ -19,6 +19,7 @@ typedef struct SampleConverter {
ALsizei mFracOffset;
ALsizei mIncrement;
+ InterpState mState;
ResamplerFunc mResample;
alignas(16) ALfloat mSrcSamples[BUFFERSIZE];
diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c
index 62f2e53..f4383aa 100644
--- a/Alc/effects/chorus.c
+++ b/Alc/effects/chorus.c
@@ -91,7 +91,7 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev
ALsizei maxlen;
ALsizei it;
- maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 2.0f * Device->Frequency) + 1;
+ maxlen = fastf2i(AL_CHORUS_MAX_DELAY * 2.0f * Device->Frequency) + 1;
maxlen = NextPowerOf2(maxlen);
if(maxlen != state->BufferLength)
@@ -172,107 +172,99 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device
}
}
-static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
+static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
+ const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
+ const ALsizei todo)
{
- ALfloat lfo_value;
-
- lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_left = fastf2i(lfo_value) + state->delay;
-
- offset += state->lfo_disp;
- lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_right = fastf2i(lfo_value) + state->delay;
+ ALsizei i;
+ for(i = 0;i < todo;i++)
+ {
+ delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay;
+ offset = (offset+1)%lfo_range;
+ }
}
-static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
+static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
+ const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
+ const ALsizei todo)
{
- ALfloat lfo_value;
-
- lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_left = fastf2i(lfo_value) + state->delay;
-
- offset += state->lfo_disp;
- lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_right = fastf2i(lfo_value) + state->delay;
-}
-
-#define DECL_TEMPLATE(Func) \
-static void Process##Func(ALchorusState *state, const ALsizei SamplesToDo, \
- const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
-{ \
- const ALsizei bufmask = state->BufferLength-1; \
- ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
- ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
- ALsizei offset = state->offset; \
- const ALfloat feedback = state->feedback; \
- ALsizei it; \
- \
- for(it = 0;it < SamplesToDo;it++) \
- { \
- ALint delay_left, delay_right; \
- Func(&delay_left, &delay_right, offset, state); \
- \
- leftbuf[offset&bufmask] = SamplesIn[it]; \
- out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
- leftbuf[offset&bufmask] += out[it][0] * feedback; \
- \
- rightbuf[offset&bufmask] = SamplesIn[it]; \
- out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
- rightbuf[offset&bufmask] += out[it][1] * feedback; \
- \
- offset++; \
- } \
- state->offset = offset; \
+ ALsizei i;
+ for(i = 0;i < todo;i++)
+ {
+ delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
+ offset = (offset+1)%lfo_range;
+ }
}
-DECL_TEMPLATE(Triangle)
-DECL_TEMPLATE(Sinusoid)
-
-#undef DECL_TEMPLATE
static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
- ALsizei it, kt;
+ ALfloat *restrict leftbuf = state->SampleBuffer[0];
+ ALfloat *restrict rightbuf = state->SampleBuffer[1];
+ const ALsizei bufmask = state->BufferLength-1;
+ const ALfloat feedback = state->feedback;
+ ALsizei offset = state->offset;
+ ALsizei i, c;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
+ const ALsizei todo = mini(128, SamplesToDo-base);
ALfloat temps[128][2];
- ALsizei td = mini(128, SamplesToDo-base);
+ ALint moddelays[2][128];
switch(state->waveform)
{
case CWF_Triangle:
- ProcessTriangle(state, td, SamplesIn[0]+base, temps);
+ GetTriangleDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
+ state->lfo_scale, state->depth, state->delay, todo);
+ GetTriangleDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
+ state->lfo_range, state->lfo_scale, state->depth, state->delay,
+ todo);
break;
case CWF_Sinusoid:
- ProcessSinusoid(state, td, SamplesIn[0]+base, temps);
+ GetSinusoidDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
+ state->lfo_scale, state->depth, state->delay, todo);
+ GetSinusoidDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
+ state->lfo_range, state->lfo_scale, state->depth, state->delay,
+ todo);
break;
}
- for(kt = 0;kt < NumChannels;kt++)
+ for(i = 0;i < todo;i++)
+ {
+ leftbuf[offset&bufmask] = SamplesIn[0][base+i];
+ temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback;
+ leftbuf[offset&bufmask] += temps[i][0];
+
+ rightbuf[offset&bufmask] = SamplesIn[0][base+i];
+ temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback;
+ rightbuf[offset&bufmask] += temps[i][1];
+
+ offset++;
+ }
+
+ for(c = 0;c < NumChannels;c++)
{
- ALfloat gain = state->Gain[0][kt];
+ ALfloat gain = state->Gain[0][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
- for(it = 0;it < td;it++)
- SamplesOut[kt][it+base] += temps[it][0] * gain;
+ for(i = 0;i < todo;i++)
+ SamplesOut[c][i+base] += temps[i][0] * gain;
}
- gain = state->Gain[1][kt];
+ gain = state->Gain[1][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
- for(it = 0;it < td;it++)
- SamplesOut[kt][it+base] += temps[it][1] * gain;
+ for(i = 0;i < todo;i++)
+ SamplesOut[c][i+base] += temps[i][1] * gain;
}
}
- base += td;
+ base += todo;
}
+
+ state->offset = offset;
}
diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c
index d330511..b25b95c 100644
--- a/Alc/effects/flanger.c
+++ b/Alc/effects/flanger.c
@@ -172,107 +172,98 @@ static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Devi
}
}
-static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
+static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
+ const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
+ const ALsizei todo)
{
- ALfloat lfo_value;
-
- lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_left = fastf2i(lfo_value) + state->delay;
-
- offset += state->lfo_disp;
- lfo_value = 1.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_right = fastf2i(lfo_value) + state->delay;
+ ALsizei i;
+ for(i = 0;i < todo;i++)
+ {
+ delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay;
+ offset = (offset+1)%lfo_range;
+ }
}
-static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
+static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
+ const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
+ const ALsizei todo)
{
- ALfloat lfo_value;
-
- lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_left = fastf2i(lfo_value) + state->delay;
-
- offset += state->lfo_disp;
- lfo_value = sinf(state->lfo_scale*(offset%state->lfo_range));
- lfo_value *= state->depth;
- *delay_right = fastf2i(lfo_value) + state->delay;
-}
-
-#define DECL_TEMPLATE(Func) \
-static void Process##Func(ALflangerState *state, const ALsizei SamplesToDo, \
- const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2]) \
-{ \
- const ALsizei bufmask = state->BufferLength-1; \
- ALfloat *restrict leftbuf = state->SampleBuffer[0]; \
- ALfloat *restrict rightbuf = state->SampleBuffer[1]; \
- ALsizei offset = state->offset; \
- const ALfloat feedback = state->feedback; \
- ALsizei it; \
- \
- for(it = 0;it < SamplesToDo;it++) \
- { \
- ALint delay_left, delay_right; \
- Func(&delay_left, &delay_right, offset, state); \
- \
- leftbuf[offset&bufmask] = SamplesIn[it]; \
- out[it][0] = leftbuf[(offset-delay_left)&bufmask]; \
- leftbuf[offset&bufmask] += out[it][0] * feedback; \
- \
- rightbuf[offset&bufmask] = SamplesIn[it]; \
- out[it][1] = rightbuf[(offset-delay_right)&bufmask]; \
- rightbuf[offset&bufmask] += out[it][1] * feedback; \
- \
- offset++; \
- } \
- state->offset = offset; \
+ ALsizei i;
+ for(i = 0;i < todo;i++)
+ {
+ delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
+ offset = (offset+1)%lfo_range;
+ }
}
-DECL_TEMPLATE(Triangle)
-DECL_TEMPLATE(Sinusoid)
-
-#undef DECL_TEMPLATE
-
static ALvoid ALflangerState_process(ALflangerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
{
- ALsizei it, kt;
+ ALfloat *restrict leftbuf = state->SampleBuffer[0];
+ ALfloat *restrict rightbuf = state->SampleBuffer[1];
+ const ALsizei bufmask = state->BufferLength-1;
+ const ALfloat feedback = state->feedback;
+ ALsizei offset = state->offset;
+ ALsizei i, c;
ALsizei base;
for(base = 0;base < SamplesToDo;)
{
+ const ALsizei todo = mini(128, SamplesToDo-base);
ALfloat temps[128][2];
- ALsizei td = mini(128, SamplesToDo-base);
+ ALint moddelays[2][128];
switch(state->waveform)
{
case FWF_Triangle:
- ProcessTriangle(state, td, SamplesIn[0]+base, temps);
+ GetTriangleDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
+ state->lfo_scale, state->depth, state->delay, todo);
+ GetTriangleDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
+ state->lfo_range, state->lfo_scale, state->depth, state->delay,
+ todo);
break;
case FWF_Sinusoid:
- ProcessSinusoid(state, td, SamplesIn[0]+base, temps);
+ GetSinusoidDelays(moddelays[0], offset%state->lfo_range, state->lfo_range,
+ state->lfo_scale, state->depth, state->delay, todo);
+ GetSinusoidDelays(moddelays[1], (offset+state->lfo_disp)%state->lfo_range,
+ state->lfo_range, state->lfo_scale, state->depth, state->delay,
+ todo);
break;
}
- for(kt = 0;kt < NumChannels;kt++)
+ for(i = 0;i < todo;i++)
{
- ALfloat gain = state->Gain[0][kt];
+ leftbuf[offset&bufmask] = SamplesIn[0][base+i];
+ temps[i][0] = leftbuf[(offset-moddelays[0][i])&bufmask] * feedback;
+ leftbuf[offset&bufmask] += temps[i][0];
+
+ rightbuf[offset&bufmask] = SamplesIn[0][base+i];
+ temps[i][1] = rightbuf[(offset-moddelays[1][i])&bufmask] * feedback;
+ rightbuf[offset&bufmask] += temps[i][1];
+
+ offset++;
+ }
+
+ for(c = 0;c < NumChannels;c++)
+ {
+ ALfloat gain = state->Gain[0][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
- for(it = 0;it < td;it++)
- SamplesOut[kt][it+base] += temps[it][0] * gain;
+ for(i = 0;i < todo;i++)
+ SamplesOut[c][i+base] += temps[i][0] * gain;
}
- gain = state->Gain[1][kt];
+ gain = state->Gain[1][c];
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
- for(it = 0;it < td;it++)
- SamplesOut[kt][it+base] += temps[it][1] * gain;
+ for(i = 0;i < todo;i++)
+ SamplesOut[c][i+base] += temps[i][1] * gain;
}
}
- base += td;
+ base += todo;
}
+
+ state->offset = offset;
}
diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c
index e9026a6..5de88fc 100644
--- a/Alc/effects/modulator.c
+++ b/Alc/effects/modulator.c
@@ -127,7 +127,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *
else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
state->Process = ModulateSquare;
- state->step = fastf2u(props->Modulator.Frequency*WAVEFORM_FRACONE /
+ state->step = fastf2i(props->Modulator.Frequency*WAVEFORM_FRACONE /
Device->Frequency);
if(state->step == 0) state->step = 1;
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c
index f5d32d9..867abbc 100644
--- a/Alc/effects/reverb.c
+++ b/Alc/effects/reverb.c
@@ -331,21 +331,6 @@ ALfloat ReverbBoost = 1.0f;
*/
ALboolean EmulateEAXReverb = AL_FALSE;
-/* This coefficient is used to define the sinus depth according to the
- * modulation depth property. This value must be below 1, which would cause the
- * sampler to stall on the downswing, and above 1 it will cause it to sample
- * backwards.
- */
-static const ALfloat MODULATION_DEPTH_COEFF = 1.0f / 2048.0f;
-
-/* A filter is used to avoid the terrible distortion caused by changing
- * modulation time and/or depth. To be consistent across different sample
- * rates, the coefficient must be raised to a constant divided by the sample
- * rate: coeff^(constant / rate).
- */
-static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
-static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
-
/* The all-pass and delay lines have a variable length dependent on the
* effect's density parameter. The resulting density multiplier is:
*
@@ -473,20 +458,33 @@ static const ALfloat LATE_LINE_LENGTHS[4] =
9.709681e-3f, 1.223343e-2f, 1.689561e-2f, 1.941936e-2f
};
-/* HACK: Workaround for a modff bug in 32-bit Windows, which attempts to write
- * a 64-bit double to the 32-bit float parameter.
+/* This coefficient is used to define the sinus depth according to the
+ * modulation depth property. This value must be below half the shortest late
+ * line length (0.0097/2 = ~0.0048), otherwise with certain parameters (high
+ * mod time, low density) the downswing can sample before the input.
*/
-#if defined(_WIN32) && !defined (_M_X64) && !defined(_M_ARM)
-static inline float hack_modff(float x, float *y)
+static const ALfloat MODULATION_DEPTH_COEFF = 1.0f / 4096.0f;
+
+/* A filter is used to avoid the terrible distortion caused by changing
+ * modulation time and/or depth. To be consistent across different sample
+ * rates, the coefficient must be raised to a constant divided by the sample
+ * rate: coeff^(constant / rate).
+ */
+static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
+static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
+
+
+/* Prior to VS2013, MSVC lacks the round() family of functions. */
+#if defined(_MSC_VER) && _MSC_VER < 1800
+static inline long lroundf(float val)
{
- double di;
- double df = modf((double)x, &di);
- *y = (float)di;
- return (float)df;
+ if(val < 0.0)
+ return fastf2i(ceilf(val-0.5f));
+ return fastf2i(floorf(val+0.5f));
}
-#define modff hack_modff
#endif
+
/**************************************
* Device Update *
**************************************/
@@ -513,7 +511,7 @@ static ALuint CalcLineLength(const ALfloat length, const ptrdiff_t offset, const
/* All line lengths are powers of 2, calculated from their lengths in
* seconds, rounded up.
*/
- samples = fastf2u(ceilf(length*frequency));
+ samples = fastf2i(ceilf(length*frequency));
samples = NextPowerOf2(samples + extra);
/* All lines share a single sample buffer. */
@@ -629,7 +627,7 @@ static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Dev
/* The late feed taps are set a fixed position past the latest delay tap. */
for(i = 0;i < 4;i++)
- State->LateFeedTap = fastf2u((AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
+ State->LateFeedTap = fastf2i((AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
EARLY_TAP_LENGTHS[3]*multiplier) *
frequency);
@@ -752,7 +750,7 @@ static inline void CalcHighpassCoeffs(const ALfloat gain, const ALfloat w, ALflo
g = maxf(0.001f, gain);
g2 = g * g;
cw = cosf(w);
- p = g / (g*cw + sqrt((cw - 1.0f) * (g2*cw + g2 - 2.0f)));
+ p = g / (g*cw + sqrtf((cw - 1.0f) * (g2*cw + g2 - 2.0f)));
coeffs[0] = p;
coeffs[1] = -p;
@@ -1057,7 +1055,7 @@ static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth,
* (1 sample) and when the timing changes, the index is rescaled to the new
* range to keep the sinus consistent.
*/
- range = maxu(fastf2u(modTime*frequency), 1);
+ range = maxi(fastf2i(modTime*frequency), 1);
State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range /
State->Mod.Range);
State->Mod.Range = range;
@@ -1067,12 +1065,12 @@ static ALvoid UpdateModulator(const ALfloat modTime, const ALfloat modDepth,
* time changes the pitch, creating the modulation effect. The scale needs
* to be multiplied by the modulation time so that a given depth produces a
* consistent shift in frequency over all ranges of time. Since the depth
- * is applied to a sinus value, it needs to be halved once for the sinus
- * range (-1...+1 to 0...1) and again for the sinus swing in time (half of
- * it is spent decreasing the frequency, half is spent increasing it).
+ * is applied to a sinus value, it needs to be halved for the sinus swing
+ * in time (half of it is spent decreasing the frequency, half is spent
+ * increasing it).
*/
- State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f /
- 2.0f * frequency;
+ State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f *
+ frequency;
}
/* Update the offsets for the main effect delay line. */
@@ -1096,13 +1094,13 @@ static ALvoid UpdateDelayLine(const ALfloat earlyDelay, const ALfloat lateDelay,
for(i = 0;i < 4;i++)
{
length = earlyDelay + EARLY_TAP_LENGTHS[i]*multiplier;
- State->EarlyDelayTap[i][1] = fastf2u(length * frequency);
+ State->EarlyDelayTap[i][1] = fastf2i(length * frequency);
length = EARLY_TAP_LENGTHS[i]*multiplier;
State->EarlyDelayCoeff[i] = CalcDecayCoeff(length, decayTime);
length = lateDelay + (LATE_LINE_LENGTHS[i] - LATE_LINE_LENGTHS[0])*0.25f*multiplier;
- State->LateDelayTap[i][1] = State->LateFeedTap + fastf2u(length * frequency);
+ State->LateDelayTap[i][1] = State->LateFeedTap + fastf2i(length * frequency);
}
}
@@ -1126,7 +1124,7 @@ static ALvoid UpdateEarlyLines(const ALfloat density, const ALfloat decayTime, c
length = EARLY_LINE_LENGTHS[i] * multiplier;
/* Calculate the delay offset for each delay line. */
- State->Early.Offset[i][1] = fastf2u(length * frequency);
+ State->Early.Offset[i][1] = fastf2i(length * frequency);
/* Calculate the gain (coefficient) for each line. */
State->Early.Coeff[i] = CalcDecayCoeff(length, decayTime);
@@ -1183,7 +1181,7 @@ static ALvoid UpdateLateLines(const ALfloat density, const ALfloat diffusion, co
length = lerp(LATE_LINE_LENGTHS[i] * multiplier, echoTime, echoDepth);
/* Calculate the delay offset for each delay line. */
- State->Late.Offset[i][1] = fastf2u(length * frequency);
+ State->Late.Offset[i][1] = fastf2i(length * frequency);
/* Approximate the absorption that the vector all-pass would exhibit
* given the current diffusion so we don't have to process a full T60
@@ -1446,7 +1444,7 @@ static inline ALvoid DelayLineIn4Rev(DelayLineI *Delay, ALsizei offset, const AL
Delay->Line[offset][i] = in[3-i];
}
-static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays, const ALsizei todo)
+static void CalcModulationDelays(ALreverbState *State, ALint *restrict delays, const ALsizei todo)
{
ALfloat sinus, range;
ALsizei index, i;
@@ -1456,10 +1454,9 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays,
for(i = 0;i < todo;i++)
{
/* Calculate the sinus rhythm (dependent on modulation time and the
- * sampling rate). The center of the sinus is moved to reduce the
- * delay of the effect when the time or depth are low.
+ * sampling rate).
*/
- sinus = 1.0f - cosf(F_TAU * index / State->Mod.Range);
+ sinus = sinf(F_TAU * index / State->Mod.Range);
/* Step the modulation index forward, keeping it bound to its range. */
index = (index+1) % State->Mod.Range;
@@ -1470,8 +1467,8 @@ static void CalcModulationDelays(ALreverbState *State, ALfloat *restrict delays,
*/
range = lerp(range, State->Mod.Depth, State->Mod.Coeff);
- /* Calculate the read offset with fraction. */
- delays[i] = range*sinus;
+ /* Calculate the read offset. */
+ delays[i] = lroundf(range*sinus);
}
State->Mod.Index = index;
State->Mod.Filter = range;
@@ -1686,14 +1683,13 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \
const ALfloat apFeedCoeff = State->ApFeedCoeff; \
const ALfloat mixX = State->MixX; \
const ALfloat mixY = State->MixY; \
- ALfloat fdelay, frac; \
+ ALint moddelay[MAX_UPDATE_SAMPLES]; \
ALsizei delay; \
ALsizei offset; \
ALsizei i, j; \
ALfloat f[4]; \
\
- /* Calculations modulation delays, uing the output as temp storage. */ \
- CalcModulationDelays(State, &out[0][0], todo); \
+ CalcModulationDelays(State, moddelay, todo); \
\
offset = State->Offset; \
for(i = 0;i < todo;i++) \
@@ -1704,31 +1700,12 @@ static ALvoid LateReverb_##T(ALreverbState *State, const ALsizei todo, \
offset-State->LateDelayTap[j][1], j, fade \
) * State->Late.DensityGain; \
\
- /* Separate the integer offset and fraction between it and the next \
- * sample. \
- */ \
- frac = modff(out[0][i], &fdelay); \
- delay = offset - fastf2i(fdelay); \
- \
+ delay = offset - moddelay[i]; \
for(j = 0;j < 4;j++) \
- { \
- ALfloat out0, out1; \
- \
- /* Get the two samples crossed by the offset delay. */ \
- out0 = DELAY_OUT_##T(&State->Late.Delay, \
+ f[j] += DELAY_OUT_##T(&State->Late.Delay, \
delay-State->Late.Offset[j][0], \
delay-State->Late.Offset[j][1], j, fade \
); \
- out1 = DELAY_OUT_##T(&State->Late.Delay, \
- delay-State->Late.Offset[j][0]-1, \
- delay-State->Late.Offset[j][1]-1, j, fade \
- ); \
- \
- /* The modulated result is obtained by linearly interpolating the \
- * two samples that were acquired above. \
- */ \
- f[j] += lerp(out0, out1, frac); \
- } \
\
for(j = 0;j < 4;j++) \
f[j] = LateT60Filter(j, f[j], State); \
diff --git a/Alc/helpers.c b/Alc/helpers.c
index 8e685c7..7f6349b 100644
--- a/Alc/helpers.c
+++ b/Alc/helpers.c
@@ -40,6 +40,11 @@
#include <dirent.h>
#endif
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
#ifndef AL_NO_UID_DEFS
#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
#define INITGUID
@@ -113,8 +118,10 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x
extern inline ALuint NextPowerOf2(ALuint value);
extern inline size_t RoundUp(size_t value, size_t r);
+extern inline ALuint64 ScaleRound(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale);
+extern inline ALuint64 ScaleFloor(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale);
+extern inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale);
extern inline ALint fastf2i(ALfloat f);
-extern inline ALuint fastf2u(ALfloat f);
ALuint CPUCapFlags = 0;
@@ -289,6 +296,13 @@ void SetMixerFPUMode(FPUCtl *ctl)
{
#ifdef HAVE_FENV_H
fegetenv(STATIC_CAST(fenv_t, ctl));
+#ifdef _WIN32
+ /* HACK: A nasty bug in MinGW-W64 causes fegetenv and fesetenv to not save
+ * and restore the FPU rounding mode, so we have to do it manually. Don't
+ * know if this also applies to MSVC.
+ */
+ ctl->round_mode = fegetround();
+#endif
#if defined(__GNUC__) && defined(HAVE_SSE)
/* FIXME: Some fegetenv implementations can get the SSE environment too?
* How to tell when it does? */
@@ -335,6 +349,9 @@ void RestoreFPUMode(const FPUCtl *ctl)
{
#ifdef HAVE_FENV_H
fesetenv(STATIC_CAST(fenv_t, ctl));
+#ifdef _WIN32
+ fesetround(ctl->round_mode);
+#endif
#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state));
@@ -707,9 +724,22 @@ void UnmapFileMem(const struct FileMapping *mapping)
al_string GetProcPath(void)
{
al_string ret = AL_STRING_INIT_STATIC();
- const char *fname;
char *pathname, *sep;
size_t pathlen;
+
+#ifdef __FreeBSD__
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ mib[3] = getpid();
+ if (sysctl(mib, 4, NULL, &pathlen, NULL, 0) == -1) {
+ WARN("Failed to sysctl kern.proc.pathname.%d: %s\n", mib[3], strerror(errno));
+ return ret;
+ }
+
+ pathname = malloc(pathlen + 1);
+ sysctl(mib, 4, (void*)pathname, &pathlen, NULL, 0);
+ pathname[pathlen] = 0;
+#else
+ const char *fname;
ssize_t len;
pathlen = 256;
@@ -738,6 +768,8 @@ al_string GetProcPath(void)
}
pathname[len] = 0;
+#endif
+
sep = strrchr(pathname, '/');
if(sep)
alstr_copy_range(&ret, pathname, sep);
diff --git a/Alc/hrtf.c b/Alc/hrtf.c
index 3017113..d996815 100644
--- a/Alc/hrtf.c
+++ b/Alc/hrtf.c
@@ -37,7 +37,7 @@
/* Current data set limits defined by the makehrtf utility. */
#define MIN_IR_SIZE (8)
-#define MAX_IR_SIZE (128)
+#define MAX_IR_SIZE (512)
#define MOD_IR_SIZE (8)
#define MIN_EV_COUNT (5)
@@ -284,8 +284,10 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize
}
}
}
- TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length);
+ /* Round up to the next IR size multiple. */
+ max_length = RoundUp(max_length, MOD_IR_SIZE);
+ TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length);
return max_length;
#undef NUM_BANDS
}
@@ -360,6 +362,41 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount
return Hrtf;
}
+static ALubyte GetLE_ALubyte(const ALubyte **data, size_t *len)
+{
+ ALubyte ret = (*data)[0];
+ *data += 1; *len -= 1;
+ return ret;
+}
+
+static ALshort GetLE_ALshort(const ALubyte **data, size_t *len)
+{
+ ALshort ret = (*data)[0] | ((*data)[1]<<8);
+ *data += 2; *len -= 2;
+ return ret;
+}
+
+static ALushort GetLE_ALushort(const ALubyte **data, size_t *len)
+{
+ ALushort ret = (*data)[0] | ((*data)[1]<<8);
+ *data += 2; *len -= 2;
+ return ret;
+}
+
+static ALint GetLE_ALuint(const ALubyte **data, size_t *len)
+{
+ ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24);
+ *data += 4; *len -= 4;
+ return ret;
+}
+
+static const ALubyte *Get_ALubytePtr(const ALubyte **data, size_t *len, size_t size)
+{
+ const ALubyte *ret = *data;
+ *data += size; *len -= size;
+ return ret;
+}
+
static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename)
{
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
@@ -381,22 +418,13 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *
return NULL;
}
- rate = *(data++);
- rate |= *(data++)<<8;
- rate |= *(data++)<<16;
- rate |= *(data++)<<24;
- datalen -= 4;
+ rate = GetLE_ALuint(&data, &datalen);
- irCount = *(data++);
- irCount |= *(data++)<<8;
- datalen -= 2;
+ irCount = GetLE_ALushort(&data, &datalen);
- irSize = *(data++);
- irSize |= *(data++)<<8;
- datalen -= 2;
+ irSize = GetLE_ALushort(&data, &datalen);
- evCount = *(data++);
- datalen -= 1;
+ evCount = GetLE_ALubyte(&data, &datalen);
if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
{
@@ -429,14 +457,10 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *
if(!failed)
{
- evOffset[0] = *(data++);
- evOffset[0] |= *(data++)<<8;
- datalen -= 2;
+ evOffset[0] = GetLE_ALushort(&data, &datalen);
for(i = 1;i < evCount;i++)
{
- evOffset[i] = *(data++);
- evOffset[i] |= *(data++)<<8;
- datalen -= 2;
+ evOffset[i] = GetLE_ALushort(&data, &datalen);
if(evOffset[i] <= evOffset[i-1])
{
ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n",
@@ -492,22 +516,15 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *
if(!failed)
{
- for(i = 0;i < irCount*irSize;i+=irSize)
+ for(i = 0;i < irCount;i++)
{
for(j = 0;j < irSize;j++)
- {
- ALshort coeff;
- coeff = *(data++);
- coeff |= *(data++)<<8;
- datalen -= 2;
- coeffs[i+j][0] = coeff / 32768.0f;
- }
+ coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
}
for(i = 0;i < irCount;i++)
{
- delays[i][0] = *(data++);
- datalen -= 1;
+ delays[i][0] = GetLE_ALubyte(&data, &datalen);
if(delays[i][0] > maxDelay)
{
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay);
@@ -567,17 +584,11 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *
return NULL;
}
- rate = *(data++);
- rate |= *(data++)<<8;
- rate |= *(data++)<<16;
- rate |= *(data++)<<24;
- datalen -= 4;
+ rate = GetLE_ALuint(&data, &datalen);
- irSize = *(data++);
- datalen -= 1;
+ irSize = GetLE_ALubyte(&data, &datalen);
- evCount = *(data++);
- datalen -= 1;
+ evCount = GetLE_ALubyte(&data, &datalen);
if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
{
@@ -600,9 +611,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *
return NULL;
}
- azCount = data;
- data += evCount;
- datalen -= evCount;
+ azCount = Get_ALubytePtr(&data, &datalen, evCount);
evOffset = malloc(sizeof(evOffset[0])*evCount);
if(azCount == NULL || evOffset == NULL)
@@ -656,22 +665,15 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *
if(!failed)
{
- for(i = 0;i < irCount*irSize;i+=irSize)
+ for(i = 0;i < irCount;i++)
{
for(j = 0;j < irSize;j++)
- {
- ALshort coeff;
- coeff = *(data++);
- coeff |= *(data++)<<8;
- datalen -= 2;
- coeffs[i+j][0] = coeff / 32768.0f;
- }
+ coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
}
for(i = 0;i < irCount;i++)
{
- delays[i][0] = *(data++);
- datalen -= 1;
+ delays[i][0] = GetLE_ALubyte(&data, &datalen);
if(delays[i][0] > maxDelay)
{
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay);
diff --git a/Alc/hrtf.h b/Alc/hrtf.h
index 186ba3b..5de28f9 100644
--- a/Alc/hrtf.h
+++ b/Alc/hrtf.h
@@ -9,10 +9,6 @@
#include "atomic.h"
-#define HRTFDELAY_BITS (20)
-#define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
-#define HRTFDELAY_MASK (HRTFDELAY_FRACONE-1)
-
/* The maximum number of virtual speakers used to generate HRTF coefficients
* for decoding B-Format.
*/
diff --git a/Alc/mastering.c b/Alc/mastering.c
index c9f5beb..9de5fd5 100644
--- a/Alc/mastering.c
+++ b/Alc/mastering.c
@@ -89,7 +89,7 @@ static void RmsDetection(Compressor *Comp, const ALsizei SamplesToDo)
ALfloat sig = Comp->Envelope[i];
sum -= window[index];
- window[index] = fastf2u(minf(sig * sig * 65536.0f, RMS_VALUE_MAX));
+ window[index] = fastf2i(minf(sig * sig * 65536.0f, RMS_VALUE_MAX));
sum += window[index];
index = (index + 1) & RMS_WINDOW_MASK;
diff --git a/Alc/mixer.c b/Alc/mixer.c
index 56d6520..b5c4605 100644
--- a/Alc/mixer.c
+++ b/Alc/mixer.c
@@ -471,13 +471,8 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei
);
else
{
- static void (*const NfcUpdate[MAX_AMBI_ORDER])(
- NfcFilter*,float*,const float*,const int
- ) = {
- NfcFilterUpdate1, NfcFilterUpdate2, NfcFilterUpdate3
- };
ALfloat *nfcsamples = Device->NFCtrlData;
- ALsizei ord, chanoffset = 0;
+ ALsizei chanoffset = 0;
MixSamples(samples,
voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer,
@@ -485,18 +480,21 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei
DstBufferSize
);
chanoffset += voice->Direct.ChannelsPerOrder[0];
- for(ord = 1;ord < MAX_AMBI_ORDER+1;ord++)
- {
- if(voice->Direct.ChannelsPerOrder[ord] <= 0)
- break;
- NfcUpdate[ord-1](&parms->NFCtrlFilter[ord-1], nfcsamples, samples,
- DstBufferSize);
- MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[ord],
- voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset,
- parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize
- );
- chanoffset += voice->Direct.ChannelsPerOrder[ord];
- }
+#define APPLY_NFC_MIX(order) \
+ if(voice->Direct.ChannelsPerOrder[order] > 0) \
+ { \
+ NfcFilterUpdate##order(&parms->NFCtrlFilter[order-1], nfcsamples, \
+ samples, DstBufferSize); \
+ MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \
+ voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \
+ parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \
+ ); \
+ chanoffset += voice->Direct.ChannelsPerOrder[order]; \
+ }
+ APPLY_NFC_MIX(1)
+ APPLY_NFC_MIX(2)
+ APPLY_NFC_MIX(3)
+#undef APPLY_NFC_MIX
}
}
else
diff --git a/Alc/panning.c b/Alc/panning.c
index c00421c..0abf18d 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -152,8 +152,7 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MA
* ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1);
*
* The gain of the source is compensated for size, so that the
- * loundness doesn't depend on the spread. That is, the factors are
- * scaled so that ZH0 remains 1 regardless of the spread. Thus:
+ * loundness doesn't depend on the spread. Thus:
*
* ZH0 = 1.0f;
* ZH1 = 0.5f * (ca+1.0f);
@@ -163,11 +162,13 @@ void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MA
* ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f);
*/
ALfloat ca = cosf(spread * 0.5f);
+ /* Increase the source volume by up to +3dB for a full spread. */
+ ALfloat scale = sqrtf(1.0f + spread/F_TAU);
- ALfloat ZH0_norm = 1.0f;
- ALfloat ZH1_norm = 0.5f * (ca+1.f);
- ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca;
- ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f);
+ ALfloat ZH0_norm = scale;
+ ALfloat ZH1_norm = 0.5f * (ca+1.f) * scale;
+ ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca * scale;
+ ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f) * scale;
/* Zeroth-order */
coeffs[0] *= ZH0_norm;
@@ -963,9 +964,6 @@ static void InitHrtfPanning(ALCdevice *device)
device->Hrtf, device->Dry.NumChannels,
AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints)
);
-
- /* Round up to the nearest multiple of 8 */
- device->Hrtf->IrSize = (device->Hrtf->IrSize+7)&~7;
}
static void InitUhjPanning(ALCdevice *device)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6fcdb96..a871f4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,6 +65,8 @@ endif()
IF(WIN32)
ADD_DEFINITIONS("-D_WIN32 -D_WIN32_WINNT=0x0502")
+ OPTION(ALSOFT_BUILD_ROUTER "Build the router (EXPERIMENTAL; creates OpenAL32.dll and soft_oal.dll)" OFF)
+
# This option is mainly for static linking OpenAL Soft into another project
# that already defines the IDs. It is up to that project to ensure all
# required IDs are defined.
@@ -98,7 +100,7 @@ ENDIF()
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "18")
-SET(LIB_REVISION "0")
+SET(LIB_REVISION "2")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}")
SET(EXPORT_DECL "")
@@ -417,27 +419,26 @@ SET(SSE2_SWITCH "")
SET(SSE3_SWITCH "")
SET(SSE4_1_SWITCH "")
SET(FPU_NEON_SWITCH "")
-IF(NOT MSVC)
- CHECK_C_COMPILER_FLAG(-msse HAVE_MSSE_SWITCH)
- IF(HAVE_MSSE_SWITCH)
- SET(SSE_SWITCH "-msse")
- ENDIF()
- CHECK_C_COMPILER_FLAG(-msse2 HAVE_MSSE2_SWITCH)
- IF(HAVE_MSSE2_SWITCH)
- SET(SSE2_SWITCH "-msse2")
- ENDIF()
- CHECK_C_COMPILER_FLAG(-msse3 HAVE_MSSE3_SWITCH)
- IF(HAVE_MSSE3_SWITCH)
- SET(SSE3_SWITCH "-msse3")
- ENDIF()
- CHECK_C_COMPILER_FLAG(-msse4.1 HAVE_MSSE4_1_SWITCH)
- IF(HAVE_MSSE4_1_SWITCH)
- SET(SSE4_1_SWITCH "-msse4.1")
- ENDIF()
- CHECK_C_COMPILER_FLAG(-mfpu=neon HAVE_MFPU_NEON_SWITCH)
- IF(HAVE_MFPU_NEON_SWITCH)
- SET(FPU_NEON_SWITCH "-mfpu=neon")
- ENDIF()
+
+CHECK_C_COMPILER_FLAG(-msse HAVE_MSSE_SWITCH)
+IF(HAVE_MSSE_SWITCH)
+ SET(SSE_SWITCH "-msse")
+ENDIF()
+CHECK_C_COMPILER_FLAG(-msse2 HAVE_MSSE2_SWITCH)
+IF(HAVE_MSSE2_SWITCH)
+ SET(SSE2_SWITCH "-msse2")
+ENDIF()
+CHECK_C_COMPILER_FLAG(-msse3 HAVE_MSSE3_SWITCH)
+IF(HAVE_MSSE3_SWITCH)
+ SET(SSE3_SWITCH "-msse3")
+ENDIF()
+CHECK_C_COMPILER_FLAG(-msse4.1 HAVE_MSSE4_1_SWITCH)
+IF(HAVE_MSSE4_1_SWITCH)
+ SET(SSE4_1_SWITCH "-msse4.1")
+ENDIF()
+CHECK_C_COMPILER_FLAG(-mfpu=neon HAVE_MFPU_NEON_SWITCH)
+IF(HAVE_MFPU_NEON_SWITCH)
+ SET(FPU_NEON_SWITCH "-mfpu=neon")
ENDIF()
CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(printf, 1, 2)));
@@ -501,6 +502,7 @@ CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC)
CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF)
CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF)
+CHECK_SYMBOL_EXISTS(log2f math.h HAVE_LOG2F)
IF(NOT HAVE_C99_VLA)
CHECK_SYMBOL_EXISTS(alloca malloc.h HAVE_ALLOCA)
IF(NOT HAVE_ALLOCA)
@@ -621,6 +623,16 @@ int main()
}"
PTHREAD_SETNAME_NP_ONE_PARAM
)
+ CHECK_C_SOURCE_COMPILES("
+#include <pthread.h>
+#include <pthread_np.h>
+int main()
+{
+ pthread_setname_np(pthread_self(), \"%s\", \"testname\");
+ return 0;
+}"
+ PTHREAD_SETNAME_NP_THREE_PARAMS
+ )
ENDIF()
CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np "pthread.h;pthread_np.h" HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
ELSE()
@@ -637,6 +649,15 @@ int main()
}"
PTHREAD_SETNAME_NP_ONE_PARAM
)
+ CHECK_C_SOURCE_COMPILES("
+#include <pthread.h>
+int main()
+{
+ pthread_setname_np(pthread_self(), \"%s\", \"testname\");
+ return 0;
+}"
+ PTHREAD_SETNAME_NP_THREE_PARAMS
+ )
ENDIF()
CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np pthread.h HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
ENDIF()
@@ -882,6 +903,9 @@ IF(OSS_FOUND)
SET(HAVE_OSS 1)
SET(BACKENDS "${BACKENDS} OSS,")
SET(ALC_OBJS ${ALC_OBJS} Alc/backends/oss.c)
+ IF(OSS_LIBRARIES)
+ SET(EXTRA_LIBS ${OSS_LIBRARIES} ${EXTRA_LIBS})
+ ENDIF()
ENDIF()
ENDIF()
IF(ALSOFT_REQUIRE_OSS AND NOT HAVE_OSS)
@@ -1192,91 +1216,111 @@ CONFIGURE_FILE(
"${OpenAL_BINARY_DIR}/openal.pc"
@ONLY)
+MACRO(ADD_INCLUDE_DIRS TRGT TESTVAR INCVAR)
+ IF(${TESTVAR})
+ SET_PROPERTY(TARGET ${TRGT} APPEND PROPERTY INCLUDE_DIRECTORIES ${${INCVAR}})
+ ENDIF()
+ENDMACRO()
+
+UNSET(HAS_ROUTER)
+SET(IMPL_TARGET OpenAL)
+
# Build main library
IF(LIBTYPE STREQUAL "STATIC")
ADD_LIBRARY(OpenAL STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS})
ELSE()
- ADD_LIBRARY(OpenAL SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS})
+ IF(WIN32 AND ALSOFT_BUILD_ROUTER)
+ ADD_LIBRARY(OpenAL SHARED router/router.c router/alc.c router/al.c ${COMMON_OBJS})
+ SET_PROPERTY(TARGET OpenAL APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS})
+ SET_PROPERTY(TARGET OpenAL APPEND PROPERTY
+ COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES
+ )
+ SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS ${EXTRA_LDFLAGS})
+ IF(MSVC)
+ SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS")
+ ELSEIF(CMAKE_COMPILER_IS_GNUCC)
+ SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " -mwindows")
+ ENDIF()
+ SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "")
+ SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME})
+ IF(TARGET build_version)
+ ADD_DEPENDENCIES(OpenAL build_version)
+ ENDIF()
+ SET(HAS_ROUTER 1)
+
+ SET(LIBNAME "soft_oal")
+ SET(IMPL_TARGET soft_oal)
+ ENDIF()
+
+ ADD_LIBRARY(${IMPL_TARGET} SHARED ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS})
+ IF(WIN32)
+ SET_TARGET_PROPERTIES(${IMPL_TARGET} PROPERTIES PREFIX "")
+ ENDIF()
ENDIF()
-SET_PROPERTY(TARGET OpenAL APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS})
-SET_PROPERTY(TARGET OpenAL APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES)
+SET_TARGET_PROPERTIES(${IMPL_TARGET} PROPERTIES OUTPUT_NAME ${LIBNAME}
+ VERSION ${LIB_VERSION}
+ SOVERSION ${LIB_MAJOR_VERSION}
+)
+SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND PROPERTY INCLUDE_DIRECTORIES
+ "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc"
+)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_ALSA ALSA_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_OSS OSS_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_SOLARIS AUDIOIO_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_SNDIO SOUNDIO_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_QSA QSA_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_DSOUND DSOUND_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_PORTAUDIO PORTAUDIO_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_PULSEAUDIO PULSEAUDIO_INCLUDE_DIRS)
+ADD_INCLUDE_DIRS(${IMPL_TARGET} HAVE_JACK JACK_INCLUDE_DIRS)
+SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND PROPERTY
+ COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES
+)
IF(WIN32 AND ALSOFT_NO_UID_DEFS)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS)
+ SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS)
ENDIF()
-SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc")
-IF(HAVE_ALSA)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_OSS)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${OSS_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_SOLARIS)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${AUDIOIO_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_SNDIO)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${SOUNDIO_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_QSA)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${QSA_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_DSOUND)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${DSOUND_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_PORTAUDIO)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${PORTAUDIO_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_PULSEAUDIO)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS})
-ENDIF()
-IF(HAVE_JACK)
- SET_PROPERTY(TARGET OpenAL APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS})
+SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS})
+SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY LINK_FLAGS ${EXTRA_LDFLAGS})
+
+TARGET_LINK_LIBRARIES(${IMPL_TARGET} ${EXTRA_LIBS})
+IF(TARGET build_version)
+ ADD_DEPENDENCIES(${IMPL_TARGET} build_version)
ENDIF()
+
IF(WIN32)
IF(MSVC)
- SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS")
+ SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS")
ELSEIF(CMAKE_COMPILER_IS_GNUCC)
- SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS " -mwindows")
- ENDIF()
-ENDIF()
-
-SET_TARGET_PROPERTIES(OpenAL PROPERTIES VERSION ${LIB_VERSION}
- SOVERSION ${LIB_MAJOR_VERSION})
-SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME})
-
-if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
- SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "")
-
- IF(MINGW AND ALSOFT_BUILD_IMPORT_LIB)
- FIND_PROGRAM(SED_EXECUTABLE NAMES sed DOC "sed executable")
- FIND_PROGRAM(DLLTOOL_EXECUTABLE NAMES "${DLLTOOL}" DOC "dlltool executable")
- IF(NOT SED_EXECUTABLE OR NOT DLLTOOL_EXECUTABLE)
- MESSAGE(STATUS "")
- IF(NOT SED_EXECUTABLE)
- MESSAGE(STATUS "WARNING: Cannot find sed, disabling .def/.lib generation")
- ENDIF()
- IF(NOT DLLTOOL_EXECUTABLE)
- MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation")
+ SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -mwindows")
+ ENDIF()
+
+ if(NOT LIBTYPE STREQUAL "STATIC")
+ IF(MINGW AND ALSOFT_BUILD_IMPORT_LIB)
+ FIND_PROGRAM(SED_EXECUTABLE NAMES sed DOC "sed executable")
+ FIND_PROGRAM(DLLTOOL_EXECUTABLE NAMES "${DLLTOOL}" DOC "dlltool executable")
+ IF(NOT SED_EXECUTABLE OR NOT DLLTOOL_EXECUTABLE)
+ MESSAGE(STATUS "")
+ IF(NOT SED_EXECUTABLE)
+ MESSAGE(STATUS "WARNING: Cannot find sed, disabling .def/.lib generation")
+ ENDIF()
+ IF(NOT DLLTOOL_EXECUTABLE)
+ MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation")
+ ENDIF()
+ ELSE()
+ SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS
+ " -Wl,--output-def,OpenAL32.def")
+ ADD_CUSTOM_COMMAND(TARGET OpenAL POST_BUILD
+ COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" OpenAL32.def
+ COMMAND "${DLLTOOL_EXECUTABLE}" -d OpenAL32.def -l OpenAL32.lib -D OpenAL32.dll
+ COMMENT "Stripping ordinals from OpenAL32.def and generating OpenAL32.lib..."
+ VERBATIM
+ )
ENDIF()
- ELSE()
- SET(EXTRA_LDFLAGS "${EXTRA_LDFLAGS} -Wl,--output-def,OpenAL32.def")
- ADD_CUSTOM_COMMAND(TARGET OpenAL POST_BUILD
- COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" OpenAL32.def
- COMMAND "${DLLTOOL_EXECUTABLE}" -d OpenAL32.def -l OpenAL32.lib -D OpenAL32.dll
- COMMENT "Stripping ordinals from OpenAL32.def and generating OpenAL32.lib..."
- VERBATIM
- )
ENDIF()
ENDIF()
ENDIF()
-SET_PROPERTY(TARGET OpenAL APPEND_STRING PROPERTY LINK_FLAGS ${EXTRA_LDFLAGS})
-TARGET_LINK_LIBRARIES(OpenAL ${EXTRA_LIBS})
-IF(TARGET build_version)
- ADD_DEPENDENCIES(OpenAL build_version)
-ENDIF()
-
IF(ALSOFT_INSTALL)
- # Add an install target here
INSTALL(TARGETS OpenAL EXPORT OpenAL
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -1300,9 +1344,19 @@ IF(ALSOFT_INSTALL)
)
INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+ IF(TARGET soft_oal)
+ INSTALL(TARGETS soft_oal
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ )
+ ENDIF()
ENDIF()
+if(HAS_ROUTER)
+ message(STATUS "")
+ message(STATUS "Building DLL router")
+endif()
+
MESSAGE(STATUS "")
MESSAGE(STATUS "Building OpenAL with support for the following backends:")
MESSAGE(STATUS " ${BACKENDS}")
@@ -1409,6 +1463,20 @@ IF(ALSOFT_TESTS)
ENDIF()
IF(ALSOFT_EXAMPLES)
+ ADD_EXECUTABLE(alrecord examples/alrecord.c ${COMMON_OBJS})
+ TARGET_LINK_LIBRARIES(alrecord OpenAL)
+ SET_PROPERTY(TARGET alrecord APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS})
+
+ IF(ALSOFT_INSTALL)
+ INSTALL(TARGETS alrecord
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+ ENDIF()
+
+ MESSAGE(STATUS "Building example programs")
+
IF(SDL2_FOUND)
IF(SDL_SOUND_FOUND)
SET(EX_COMMON_OBJS examples/common/alhelpers.c)
@@ -1485,7 +1553,7 @@ IF(ALSOFT_EXAMPLES)
ENDIF()
IF(FFVER_OK)
ADD_EXECUTABLE(alffplay examples/alffplay.cpp ${COMMON_OBJS})
- TARGET_LINK_LIBRARIES(alffplay ${SDL2_LIBRARY} OpenAL ${FFMPEG_LIBRARIES})
+ TARGET_LINK_LIBRARIES(alffplay ${SDL2_LIBRARY} ${FFMPEG_LIBRARIES} OpenAL)
SET_PROPERTY(TARGET alffplay APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS})
SET_PROPERTY(TARGET alffplay APPEND PROPERTY
INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS}
diff --git a/ChangeLog b/ChangeLog
index 44afc3f..5300be1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+openal-soft-1.18.2:
+
+ Fixed resetting the FPU rounding mode after certain function calls on
+ Windows.
+
+ Fixed use of SSE intrinsics when building with Clang on Windows.
+
+ Fixed a crash with the JACK backend when using JACK1.
+
+ Fixed use of pthread_setnane_np on NetBSD.
+
+ Fixed building on FreeBSD with an older freebsd-lib.
+
+ OSS now links with libossaudio if found at build time (for NetBSD).
+
+openal-soft-1.18.1:
+
+ Fixed an issue where resuming a source might not restart playing it.
+
+ Fixed PulseAudio playback when the configured stream length is much less
+ than the requested length.
+
+ Fixed MMDevAPI capture with sample rates not matching the backing device.
+
+ Fixed int32 output for the Wave Writer.
+
+ Fixed enumeration of OSS devices that are missing device files.
+
+ Added correct retrieval of the executable's path on FreeBSD.
+
+ Added a config option to specify the dithering depth.
+
+ Added a 5.1 decoder preset that excludes front-center output.
+
openal-soft-1.18.0:
Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions.
diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h
index 9a7f9d4..f1a92b0 100644
--- a/OpenAL32/Include/alListener.h
+++ b/OpenAL32/Include/alListener.h
@@ -26,7 +26,7 @@ struct ALlistenerProps {
};
typedef struct ALlistener {
- ALfloat Position[3];
+ alignas(16) ALfloat Position[3];
ALfloat Velocity[3];
ALfloat Forward[3];
ALfloat Up[3];
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 6e17651..b14d674 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -409,6 +409,24 @@ inline size_t RoundUp(size_t value, size_t r)
return value - (value%r);
}
+/* Scales the given value using 64-bit integer math, rounding the result. */
+inline ALuint64 ScaleRound(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
+{
+ return (val*new_scale + old_scale/2) / old_scale;
+}
+
+/* Scales the given value using 64-bit integer math, flooring the result. */
+inline ALuint64 ScaleFloor(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
+{
+ return val * new_scale / old_scale;
+}
+
+/* Scales the given value using 64-bit integer math, ceiling the result. */
+inline ALuint64 ScaleCeil(ALuint64 val, ALuint64 new_scale, ALuint64 old_scale)
+{
+ return (val*new_scale + old_scale-1) / old_scale;
+}
+
/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero
* mode. */
inline ALint fastf2i(ALfloat f)
@@ -425,36 +443,12 @@ inline ALint fastf2i(ALfloat f)
#endif
}
-/* Fast float-to-uint conversion. Assumes the FPU is already in round-to-zero
- * mode. */
-inline ALuint fastf2u(ALfloat f)
-{ return fastf2i(f); }
-
enum DevProbe {
ALL_DEVICE_PROBE,
CAPTURE_DEVICE_PROBE
};
-typedef struct {
- ALCenum (*OpenPlayback)(ALCdevice*, const ALCchar*);
- void (*ClosePlayback)(ALCdevice*);
- ALCboolean (*ResetPlayback)(ALCdevice*);
- ALCboolean (*StartPlayback)(ALCdevice*);
- void (*StopPlayback)(ALCdevice*);
-
- ALCenum (*OpenCapture)(ALCdevice*, const ALCchar*);
- void (*CloseCapture)(ALCdevice*);
- void (*StartCapture)(ALCdevice*);
- void (*StopCapture)(ALCdevice*);
- ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint);
- ALCuint (*AvailableSamples)(ALCdevice*);
-} BackendFuncs;
-
-ALCboolean alc_qsa_init(BackendFuncs *func_list);
-void alc_qsa_deinit(void);
-void alc_qsa_probe(enum DevProbe type);
-
struct ALCbackend;
@@ -794,7 +788,7 @@ struct ALCdevice_struct
DistanceComp ChannelDelay[MAX_OUTPUT_CHANNELS];
/* Dithering control. */
- bool DitherEnabled;
+ ALfloat DitherDepth;
ALuint DitherSeed;
/* Running count of the mixer invocations, in 31.1 fixed point. This
@@ -804,21 +798,13 @@ struct ALCdevice_struct
*/
RefCount MixCount;
- /* Default effect slot */
- struct ALeffectslot *DefaultSlot;
-
// Contexts created on this device
ATOMIC(ALCcontext*) ContextList;
almtx_t BackendLock;
struct ALCbackend *Backend;
- void *ExtraData; // For the backend's use
-
ALCdevice *volatile next;
-
- /* Memory space used by the default slot (Playback devices only) */
- alignas(16) ALCbyte _slot_mem[];
};
// Frequency was requested by the app or config file
@@ -880,12 +866,15 @@ struct ALCcontext_struct {
ATOMIC(struct ALeffectslotArray*) ActiveAuxSlots;
+ /* Default effect slot */
+ struct ALeffectslot *DefaultSlot;
+
ALCdevice *Device;
const ALCchar *ExtensionList;
ALCcontext *volatile next;
- /* Memory space used by the listener */
+ /* Memory space used by the listener (and possibly default effect slot) */
alignas(16) ALCbyte _listener_mem[];
};
@@ -909,6 +898,9 @@ void ALCcontext_ProcessUpdates(ALCcontext *context);
typedef struct {
#ifdef HAVE_FENV_H
DERIVE_FROM_TYPE(fenv_t);
+#ifdef _WIN32
+ int round_mode;
+#endif
#else
int state;
#endif
@@ -918,6 +910,17 @@ typedef struct {
} FPUCtl;
void SetMixerFPUMode(FPUCtl *ctl);
void RestoreFPUMode(const FPUCtl *ctl);
+#ifdef __GNUC__
+/* Use an alternate macro set with GCC to avoid accidental continue or break
+ * statements within the mixer mode.
+ */
+#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode);
+#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); })
+#else
+#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode);
+#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0)
+#endif
+#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode)
typedef struct ll_ringbuffer ll_ringbuffer_t;
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index 0b3799c..794bdec 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -85,6 +85,8 @@ typedef union InterpState {
BsincState bsinc;
} InterpState;
+ALboolean BsincPrepare(const ALuint increment, BsincState *state);
+
typedef const ALfloat* (*ResamplerFunc)(const InterpState *state,
const ALfloat *restrict src, ALsizei frac, ALint increment,
ALfloat *restrict dst, ALsizei dstlen
@@ -500,7 +502,7 @@ void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans,
ALboolean MixSource(struct ALvoice *voice, struct ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo);
-void aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
+void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
/* Caller must lock the device. */
void aluHandleDisconnect(ALCdevice *device);
diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c
index cd2c1e0..02288a3 100644
--- a/OpenAL32/alAuxEffectSlot.c
+++ b/OpenAL32/alAuxEffectSlot.c
@@ -506,7 +506,6 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
if(newtype != EffectSlot->Effect.Type)
{
ALeffectStateFactory *factory;
- FPUCtl oldMode;
factory = getFactoryByType(newtype);
if(!factory)
@@ -517,19 +516,19 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
State = V0(factory,create)();
if(!State) return AL_OUT_OF_MEMORY;
- SetMixerFPUMode(&oldMode);
+ START_MIXER_MODE();
almtx_lock(&Device->BackendLock);
State->OutBuffer = Device->Dry.Buffer;
State->OutChannels = Device->Dry.NumChannels;
if(V(State,deviceUpdate)(Device) == AL_FALSE)
{
almtx_unlock(&Device->BackendLock);
- RestoreFPUMode(&oldMode);
+ LEAVE_MIXER_MODE();
ALeffectState_DecRef(State);
return AL_OUT_OF_MEMORY;
}
almtx_unlock(&Device->BackendLock);
- RestoreFPUMode(&oldMode);
+ END_MIXER_MODE();
if(!effect)
{
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c
index 46f23a7..be191fd 100644
--- a/OpenAL32/alSource.c
+++ b/OpenAL32/alSource.c
@@ -2502,17 +2502,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
case AL_PAUSED:
assert(voice != NULL);
- /* A source that's paused simply resumes. Clear its mixing
- * parameters and mark it as 'fading' so it fades in from
- * silence.
- */
- voice->Step = 0;
- voice->Flags |= VOICE_IS_FADING;
- memset(voice->Direct.Params, 0, sizeof(voice->Direct.Params[0])*
- voice->NumChannels);
- for(s = 0;s < device->NumAuxSends;s++)
- memset(voice->Send[s].Params, 0, sizeof(voice->Send[s].Params[0])*
- voice->NumChannels);
+ /* A source that's paused simply resumes. */
ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
goto finish_play;
diff --git a/alsoftrc.sample b/alsoftrc.sample
index 26d494f..3e7d0ee 100644
--- a/alsoftrc.sample
+++ b/alsoftrc.sample
@@ -188,11 +188,18 @@
#output-limiter = true
## dither:
-# Applies dithering on the final mix for 8- and 16-bit output. This replaces
-# the distortion created by nearest-value quantization with low-level
-# whitenoise.
+# Applies dithering on the final mix, for 8- and 16-bit output by default.
+# This replaces the distortion created by nearest-value quantization with low-
+# level whitenoise.
#dither = true
+## dither-depth:
+# Quantization bit-depth for dithered output. A value of 0 (or less) will
+# match the output sample depth. For int32, uint32, and float32 output, 0 will
+# disable dithering because they're at or beyond the rendered precision. The
+# maximum dither depth is 24.
+#dither-depth = 0
+
## volume-adjust:
# A global volume adjustment for source output, expressed in decibels. The
# value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will
diff --git a/appveyor.yml b/appveyor.yml
index 9c12535..eab4f39 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 1.18.0.{build}
+version: 1.18.2.{build}
environment:
matrix:
diff --git a/cmake/FindOSS.cmake b/cmake/FindOSS.cmake
index 88ee66a..feffb45 100644
--- a/cmake/FindOSS.cmake
+++ b/cmake/FindOSS.cmake
@@ -2,8 +2,10 @@
#
# OSS_FOUND - True if OSS_INCLUDE_DIR is found
# OSS_INCLUDE_DIRS - Set when OSS_INCLUDE_DIR is found
+# OSS_LIBRARIES - Set when OSS_LIBRARY is found
#
# OSS_INCLUDE_DIR - where to find sys/soundcard.h, etc.
+# OSS_LIBRARY - where to find libossaudio (optional).
#
find_path(OSS_INCLUDE_DIR
@@ -11,11 +13,21 @@ find_path(OSS_INCLUDE_DIR
DOC "The OSS include directory"
)
+find_library(OSS_LIBRARY
+ NAMES ossaudio
+ DOC "Optional OSS library"
+)
+
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OSS REQUIRED_VARS OSS_INCLUDE_DIR)
if(OSS_FOUND)
set(OSS_INCLUDE_DIRS ${OSS_INCLUDE_DIR})
+ if(OSS_LIBRARY)
+ set(OSS_LIBRARIES ${OSS_LIBRARY})
+ else()
+ unset(OSS_LIBRARIES)
+ endif()
endif()
-mark_as_advanced(OSS_INCLUDE_DIR)
+mark_as_advanced(OSS_INCLUDE_DIR OSS_LIBRARY)
diff --git a/common/math_defs.h b/common/math_defs.h
index 8756488..cbe9091 100644
--- a/common/math_defs.h
+++ b/common/math_defs.h
@@ -15,7 +15,18 @@
#endif
#ifndef HUGE_VALF
-#define HUGE_VALF (1.0f/0.0f)
+static const union msvc_inf_hack {
+ unsigned char b[4];
+ float f;
+} msvc_inf_union = {{ 0x00, 0x00, 0x80, 0x7F }};
+#define HUGE_VALF (msvc_inf_union.f)
+#endif
+
+#ifndef HAVE_LOG2F
+static inline float log2f(float f)
+{
+ return logf(f) / logf(2.0f);
+}
#endif
#define DEG2RAD(x) ((float)(x) * (F_PI/180.0f))
diff --git a/common/threads.c b/common/threads.c
index 0a019d0..dbd196e 100644
--- a/common/threads.c
+++ b/common/threads.c
@@ -257,7 +257,7 @@ int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_poi
else
{
sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000;
- sleeptime += (time_point->tv_sec - curtime.tv_sec)*1000;
+ sleeptime += (DWORD)(time_point->tv_sec - curtime.tv_sec)*1000;
if(SleepConditionVariableCS(cond, mtx, sleeptime) != 0)
return althrd_success;
}
@@ -364,7 +364,7 @@ int alcnd_timedwait(alcnd_t *cond, almtx_t *mtx, const struct timespec *time_poi
else
{
sleeptime = (time_point->tv_nsec - curtime.tv_nsec + 999999)/1000000;
- sleeptime += (time_point->tv_sec - curtime.tv_sec)*1000;
+ sleeptime += (DWORD)(time_point->tv_sec - curtime.tv_sec)*1000;
}
IncrementRef(&icond->wait_count);
@@ -500,6 +500,8 @@ void althrd_setname(althrd_t thr, const char *name)
#if defined(PTHREAD_SETNAME_NP_ONE_PARAM)
if(althrd_equal(thr, althrd_current()))
pthread_setname_np(name);
+#elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS)
+ pthread_setname_np(thr, "%s", (void*)name);
#else
pthread_setname_np(thr, name);
#endif
diff --git a/config.h.in b/config.h.in
index a71b54f..b0fc5d2 100644
--- a/config.h.in
+++ b/config.h.in
@@ -80,6 +80,9 @@
/* Define if we have the modff function */
#cmakedefine HAVE_MODFF
+/* Define if we have the log2f function */
+#cmakedefine HAVE_LOG2F
+
/* Define if we have the strtof function */
#cmakedefine HAVE_STRTOF
@@ -191,6 +194,9 @@
/* Define if pthread_setname_np() only accepts one parameter */
#cmakedefine PTHREAD_SETNAME_NP_ONE_PARAM
+/* Define if pthread_setname_np() accepts three parameters */
+#cmakedefine PTHREAD_SETNAME_NP_THREE_PARAMS
+
/* Define if we have pthread_set_name_np() */
#cmakedefine HAVE_PTHREAD_SET_NAME_NP
diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp
index b2033b9..10c0055 100644
--- a/examples/alffplay.cpp
+++ b/examples/alffplay.cpp
@@ -16,6 +16,7 @@
#include <atomic>
#include <mutex>
#include <deque>
+#include <array>
extern "C" {
#include "libavcodec/avcodec.h"
@@ -40,6 +41,7 @@ namespace
static const std::string AppName("alffplay");
+static bool do_direct_out = false;
static bool has_latency_check = false;
static LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
@@ -730,6 +732,17 @@ int AudioState::handler()
alGenBuffers(AUDIO_BUFFER_QUEUE_SIZE, mBuffers);
alGenSources(1, &mSource);
+ if(do_direct_out)
+ {
+ if(!alIsExtensionPresent("AL_SOFT_direct_channels"))
+ std::cerr<< "AL_SOFT_direct_channels not supported for direct output" <<std::endl;
+ else
+ {
+ alSourcei(mSource, AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
+ std::cout<< "Direct out enabled" <<std::endl;
+ }
+ }
+
while(alGetError() == AL_NO_ERROR && !mMovie->mQuit.load())
{
/* First remove any processed buffers. */
@@ -1358,7 +1371,7 @@ int main(int argc, char *argv[])
if(argc < 2)
{
- std::cerr<< "Usage: "<<argv[0]<<" [-device <device name>] <files...>" <<std::endl;
+ std::cerr<< "Usage: "<<argv[0]<<" [-device <device name>] [-direct] <files...>" <<std::endl;
return 1;
}
/* Register all formats and codecs */
@@ -1418,12 +1431,9 @@ int main(int argc, char *argv[])
ALCdevice *dev = NULL;
if(argc > 3 && strcmp(argv[1], "-device") == 0)
{
+ fileidx = 3;
dev = alcOpenDevice(argv[2]);
- if(dev)
- {
- fileidx = 3;
- return dev;
- }
+ if(dev) return dev;
std::cerr<< "Failed to open \""<<argv[2]<<"\" - trying default" <<std::endl;
}
return alcOpenDevice(nullptr);
@@ -1437,6 +1447,19 @@ int main(int argc, char *argv[])
return 1;
}
+ const ALCchar *name = nullptr;
+ if(alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT"))
+ name = alcGetString(device, ALC_ALL_DEVICES_SPECIFIER);
+ if(!name || alcGetError(device) != AL_NO_ERROR)
+ name = alcGetString(device, ALC_DEVICE_SPECIFIER);
+ std::cout<< "Opened \""<<name<<"\"" <<std::endl;
+
+ if(fileidx < argc && strcmp(argv[fileidx], "-direct") == 0)
+ {
+ ++fileidx;
+ do_direct_out = true;
+ }
+
while(fileidx < argc && !movState)
{
movState = std::unique_ptr<MovieState>(new MovieState(argv[fileidx++]));
diff --git a/examples/alrecord.c b/examples/alrecord.c
new file mode 100644
index 0000000..0835b46
--- /dev/null
+++ b/examples/alrecord.c
@@ -0,0 +1,386 @@
+/*
+ * OpenAL Recording Example
+ *
+ * Copyright (c) 2017 by Chris Robinson <chris.kcat at 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 recorder. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include "common/alhelpers.h"
+
+
+#if defined(_WIN64)
+#define SZFMT "%I64u"
+#elif defined(_WIN32)
+#define SZFMT "%u"
+#else
+#define SZFMT "%zu"
+#endif
+
+
+static void fwrite16le(ALushort val, FILE *f)
+{
+ ALubyte data[2] = { val&0xff, (val>>8)&0xff };
+ fwrite(data, 1, 2, f);
+}
+
+static void fwrite32le(ALuint val, FILE *f)
+{
+ ALubyte data[4] = { val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff };
+ fwrite(data, 1, 4, f);
+}
+
+
+typedef struct Recorder {
+ ALCdevice *mDevice;
+
+ FILE *mFile;
+ long mDataSizeOffset;
+ size_t mDataSize;
+ float mRecTime;
+
+ int mChannels;
+ int mBits;
+ int mSampleRate;
+ size_t mFrameSize;
+ ALbyte *mBuffer;
+ ALsizei mBufferSize;
+} Recorder;
+
+int main(int argc, char **argv)
+{
+ static const char optlist[] =
+" --channels/-c <channels> Set channel count (1 or 2)\n"
+" --bits/-b <bits> Set channel count (8, 16, or 32)\n"
+" --rate/-r <rate> Set sample rate (8000 to 96000)\n"
+" --time/-t <time> Time in seconds to record (1 to 10)\n"
+" --outfile/-o <filename> Output filename (default: record.wav)";
+ const char *fname = "record.wav";
+ const char *devname = NULL;
+ const char *progname;
+ Recorder recorder;
+ long total_size;
+ ALenum format;
+ ALCenum err;
+
+ progname = argv[0];
+ if(argc < 2)
+ {
+ fprintf(stderr, "Record from a device to a wav file.\n\n"
+ "Usage: %s [-device <name>] [options...]\n\n"
+ "Available options:\n%s\n", progname, optlist);
+ return 0;
+ }
+
+ recorder.mDevice = NULL;
+ recorder.mFile = NULL;
+ recorder.mDataSizeOffset = 0;
+ recorder.mDataSize = 0;
+ recorder.mRecTime = 4.0f;
+ recorder.mChannels = 1;
+ recorder.mBits = 16;
+ recorder.mSampleRate = 44100;
+ recorder.mFrameSize = recorder.mChannels * recorder.mBits / 8;
+ recorder.mBuffer = NULL;
+ recorder.mBufferSize = 0;
+
+ argv++; argc--;
+ if(argc > 1 && strcmp(argv[0], "-device") == 0)
+ {
+ devname = argv[1];
+ argv += 2;
+ argc -= 2;
+ }
+
+ while(argc > 0)
+ {
+ char *end;
+ if(strcmp(argv[0], "--") == 0)
+ break;
+ else if(strcmp(argv[0], "--channels") == 0 || strcmp(argv[0], "-c") == 0)
+ {
+ if(!(argc > 1))
+ {
+ fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
+ return 1;
+ }
+
+ recorder.mChannels = strtol(argv[1], &end, 0);
+ if((recorder.mChannels != 1 && recorder.mChannels != 2) || (end && *end != '\0'))
+ {
+ fprintf(stderr, "Invalid channels: %s\n", argv[1]);
+ return 1;
+ }
+ argv += 2;
+ argc -= 2;
+ }
+ else if(strcmp(argv[0], "--bits") == 0 || strcmp(argv[0], "-b") == 0)
+ {
+ if(!(argc > 1))
+ {
+ fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
+ return 1;
+ }
+
+ recorder.mBits = strtol(argv[1], &end, 0);
+ if((recorder.mBits != 8 && recorder.mBits != 16 && recorder.mBits != 32) ||
+ (end && *end != '\0'))
+ {
+ fprintf(stderr, "Invalid bit count: %s\n", argv[1]);
+ return 1;
+ }
+ argv += 2;
+ argc -= 2;
+ }
+ else if(strcmp(argv[0], "--rate") == 0 || strcmp(argv[0], "-r") == 0)
+ {
+ if(!(argc > 1))
+ {
+ fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
+ return 1;
+ }
+
+ recorder.mSampleRate = strtol(argv[1], &end, 0);
+ if(!(recorder.mSampleRate >= 8000 && recorder.mSampleRate <= 96000) || (end && *end != '\0'))
+ {
+ fprintf(stderr, "Invalid sample rate: %s\n", argv[1]);
+ return 1;
+ }
+ argv += 2;
+ argc -= 2;
+ }
+ else if(strcmp(argv[0], "--time") == 0 || strcmp(argv[0], "-t") == 0)
+ {
+ if(!(argc > 1))
+ {
+ fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
+ return 1;
+ }
+
+ recorder.mRecTime = strtod(argv[1], &end);
+ if(!(recorder.mRecTime >= 1.0f && recorder.mRecTime <= 10.0f) || (end && *end != '\0'))
+ {
+ fprintf(stderr, "Invalid record time: %s\n", argv[1]);
+ return 1;
+ }
+ argv += 2;
+ argc -= 2;
+ }
+ else if(strcmp(argv[0], "--outfile") == 0 || strcmp(argv[0], "-o") == 0)
+ {
+ if(!(argc > 1))
+ {
+ fprintf(stderr, "Missing argument for option: %s\n", argv[0]);
+ return 1;
+ }
+
+ fname = argv[1];
+ argv += 2;
+ argc -= 2;
+ }
+ else if(strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-h") == 0)
+ {
+ fprintf(stderr, "Record from a device to a wav file.\n\n"
+ "Usage: %s [-device <name>] [options...]\n\n"
+ "Available options:\n%s\n", progname, optlist);
+ return 0;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid option '%s'.\n\n"
+ "Usage: %s [-device <name>] [options...]\n\n"
+ "Available options:\n%s\n", argv[0], progname, optlist);
+ return 0;
+ }
+ }
+
+ recorder.mFrameSize = recorder.mChannels * recorder.mBits / 8;
+
+ format = AL_NONE;
+ if(recorder.mChannels == 1)
+ {
+ if(recorder.mBits == 8)
+ format = AL_FORMAT_MONO8;
+ else if(recorder.mBits == 16)
+ format = AL_FORMAT_MONO16;
+ else if(recorder.mBits == 32)
+ format = AL_FORMAT_MONO_FLOAT32;
+ }
+ else if(recorder.mChannels == 2)
+ {
+ if(recorder.mBits == 8)
+ format = AL_FORMAT_STEREO8;
+ else if(recorder.mBits == 16)
+ format = AL_FORMAT_STEREO16;
+ else if(recorder.mBits == 32)
+ format = AL_FORMAT_STEREO_FLOAT32;
+ }
+
+ recorder.mDevice = alcCaptureOpenDevice(devname, recorder.mSampleRate, format, 32768);
+ if(!recorder.mDevice)
+ {
+ fprintf(stderr, "Failed to open %s, %s %d-bit, %s, %dhz (%d samples)\n",
+ devname ? devname : "default device",
+ (recorder.mBits == 32) ? "Float" :
+ (recorder.mBits != 8) ? "Signed" : "Unsigned", recorder.mBits,
+ (recorder.mChannels == 1) ? "Mono" : "Stereo", recorder.mSampleRate,
+ 32768
+ );
+ return 1;
+ }
+ fprintf(stderr, "Opened \"%s\"\n", alcGetString(
+ recorder.mDevice, ALC_CAPTURE_DEVICE_SPECIFIER
+ ));
+
+ recorder.mFile = fopen(fname, "wb");
+ if(!recorder.mFile)
+ {
+ fprintf(stderr, "Failed to open '%s' for writing\n", fname);
+ alcCaptureCloseDevice(recorder.mDevice);
+ return 1;
+ }
+
+ fputs("RIFF", recorder.mFile);
+ fwrite32le(0xFFFFFFFF, recorder.mFile); // 'RIFF' header len; filled in at close
+
+ fputs("WAVE", recorder.mFile);
+
+ fputs("fmt ", recorder.mFile);
+ fwrite32le(18, recorder.mFile); // 'fmt ' header len
+
+ // 16-bit val, format type id (1 = integer PCM, 3 = float PCM)
+ fwrite16le((recorder.mBits == 32) ? 0x0003 : 0x0001, recorder.mFile);
+ // 16-bit val, channel count
+ fwrite16le(recorder.mChannels, recorder.mFile);
+ // 32-bit val, frequency
+ fwrite32le(recorder.mSampleRate, recorder.mFile);
+ // 32-bit val, bytes per second
+ fwrite32le(recorder.mSampleRate * recorder.mFrameSize, recorder.mFile);
+ // 16-bit val, frame size
+ fwrite16le(recorder.mFrameSize, recorder.mFile);
+ // 16-bit val, bits per sample
+ fwrite16le(recorder.mBits, recorder.mFile);
+ // 16-bit val, extra byte count
+ fwrite16le(0, recorder.mFile);
+
+ fputs("data", recorder.mFile);
+ fwrite32le(0xFFFFFFFF, recorder.mFile); // 'data' header len; filled in at close
+
+ recorder.mDataSizeOffset = ftell(recorder.mFile) - 4;
+ if(ferror(recorder.mFile) || recorder.mDataSizeOffset < 0)
+ {
+ fprintf(stderr, "Error writing header: %s\n", strerror(errno));
+ fclose(recorder.mFile);
+ alcCaptureCloseDevice(recorder.mDevice);
+ return 1;
+ }
+
+ fprintf(stderr, "Recording '%s', %s %d-bit, %s, %dhz (%g second%s)\n", fname,
+ (recorder.mBits == 32) ? "Float" :
+ (recorder.mBits != 8) ? "Signed" : "Unsigned", recorder.mBits,
+ (recorder.mChannels == 1) ? "Mono" : "Stereo", recorder.mSampleRate,
+ recorder.mRecTime, (recorder.mRecTime != 1.0f) ? "s" : ""
+ );
+
+ alcCaptureStart(recorder.mDevice);
+ while((double)recorder.mDataSize/(double)recorder.mSampleRate < recorder.mRecTime &&
+ (err=alcGetError(recorder.mDevice)) == ALC_NO_ERROR && !ferror(recorder.mFile))
+ {
+ ALCint count = 0;
+ fprintf(stderr, "\rCaptured "SZFMT" samples", recorder.mDataSize);
+ alcGetIntegerv(recorder.mDevice, ALC_CAPTURE_SAMPLES, 1, &count);
+ if(count < 1)
+ {
+ al_nssleep(10000000);
+ continue;
+ }
+ if(count > recorder.mBufferSize)
+ {
+ ALbyte *data = calloc(recorder.mFrameSize, count);
+ free(recorder.mBuffer);
+ recorder.mBuffer = data;
+ recorder.mBufferSize = count;
+ }
+ alcCaptureSamples(recorder.mDevice, recorder.mBuffer, count);
+#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
+ /* Byteswap multibyte samples on big-endian systems (wav needs little-
+ * endian, and OpenAL gives the system's native-endian).
+ */
+ if(recorder.mBits == 16)
+ {
+ ALCint i;
+ for(i = 0;i < count*recorder.mChannels;i++)
+ {
+ ALbyte b = recorder.mBuffer[i*2 + 0];
+ recorder.mBuffer[i*2 + 0] = recorder.mBuffer[i*2 + 1];
+ recorder.mBuffer[i*2 + 1] = b;
+ }
+ }
+ else if(recorder.mBits == 32)
+ {
+ ALCint i;
+ for(i = 0;i < count*recorder.mChannels;i++)
+ {
+ ALbyte b0 = recorder.mBuffer[i*4 + 0];
+ ALbyte b1 = recorder.mBuffer[i*4 + 1];
+ recorder.mBuffer[i*4 + 0] = recorder.mBuffer[i*4 + 3];
+ recorder.mBuffer[i*4 + 1] = recorder.mBuffer[i*4 + 2];
+ recorder.mBuffer[i*4 + 2] = b1;
+ recorder.mBuffer[i*4 + 3] = b0;
+ }
+ }
+#endif
+ recorder.mDataSize += fwrite(recorder.mBuffer, recorder.mFrameSize, count, recorder.mFile);
+ }
+ alcCaptureStop(recorder.mDevice);
+ fprintf(stderr, "\rCaptured "SZFMT" samples\n", recorder.mDataSize);
+ if(err != ALC_NO_ERROR)
+ fprintf(stderr, "Got device error 0x%04x: %s\n", err, alcGetString(recorder.mDevice, err));
+
+ alcCaptureCloseDevice(recorder.mDevice);
+ recorder.mDevice = NULL;
+
+ free(recorder.mBuffer);
+ recorder.mBuffer = NULL;
+ recorder.mBufferSize = 0;
+
+ total_size = ftell(recorder.mFile);
+ if(fseek(recorder.mFile, recorder.mDataSizeOffset, SEEK_SET) == 0)
+ {
+ fwrite32le(recorder.mDataSize*recorder.mFrameSize, recorder.mFile);
+ if(fseek(recorder.mFile, 4, SEEK_SET) == 0)
+ fwrite32le(total_size - 8, recorder.mFile);
+ }
+
+ fclose(recorder.mFile);
+ recorder.mFile = NULL;
+
+ return 0;
+}
diff --git a/examples/altonegen.c b/examples/altonegen.c
index 422e6d6..628e695 100644
--- a/examples/altonegen.c
+++ b/examples/altonegen.c
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
+#include <limits.h>
#include <math.h>
#include "AL/al.h"
@@ -53,6 +54,7 @@ enum WaveType {
WT_Sawtooth,
WT_Triangle,
WT_Impulse,
+ WT_WhiteNoise,
};
static const char *GetWaveTypeName(enum WaveType type)
@@ -64,10 +66,17 @@ static const char *GetWaveTypeName(enum WaveType type)
case WT_Sawtooth: return "sawtooth";
case WT_Triangle: return "triangle";
case WT_Impulse: return "impulse";
+ case WT_WhiteNoise: return "noise";
}
return "(unknown)";
}
+static inline ALuint dither_rng(ALuint *seed)
+{
+ *seed = (*seed * 96314165) + 907633515;
+ return *seed;
+}
+
static void ApplySin(ALfloat *data, ALdouble g, ALuint srate, ALuint freq)
{
ALdouble smps_per_cycle = (ALdouble)srate / freq;
@@ -81,6 +90,7 @@ static void ApplySin(ALfloat *data, ALdouble g, ALuint srate, ALuint freq)
*/
static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate)
{
+ ALuint seed = 22222;
ALint data_size;
ALfloat *data;
ALuint buffer;
@@ -89,25 +99,44 @@ static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate)
data_size = srate * sizeof(ALfloat);
data = calloc(1, data_size);
- if(type == WT_Sine)
- ApplySin(data, 1.0, srate, freq);
- else if(type == WT_Square)
- for(i = 1;freq*i < srate/2;i+=2)
- ApplySin(data, 4.0/M_PI * 1.0/i, srate, freq*i);
- else if(type == WT_Sawtooth)
- for(i = 1;freq*i < srate/2;i++)
- ApplySin(data, 2.0/M_PI * ((i&1)*2 - 1.0) / i, srate, freq*i);
- else if(type == WT_Triangle)
- for(i = 1;freq*i < srate/2;i+=2)
- ApplySin(data, 8.0/(M_PI*M_PI) * (1.0 - (i&2)) / (i*i), srate, freq*i);
- else if(type == WT_Impulse)
+ switch(type)
{
- /* NOTE: Impulse isn't really a waveform, but it can still be useful to
- * test (other than resampling, the ALSOFT_DEFAULT_REVERB environment
- * variable can prove useful here to test the reverb response).
- */
- for(i = 0;i < srate;i++)
- data[i] = (i%(srate/freq)) ? 0.0f : 1.0f;
+ case WT_Sine:
+ ApplySin(data, 1.0, srate, freq);
+ break;
+ case WT_Square:
+ for(i = 1;freq*i < srate/2;i+=2)
+ ApplySin(data, 4.0/M_PI * 1.0/i, srate, freq*i);
+ break;
+ case WT_Sawtooth:
+ for(i = 1;freq*i < srate/2;i++)
+ ApplySin(data, 2.0/M_PI * ((i&1)*2 - 1.0) / i, srate, freq*i);
+ break;
+ case WT_Triangle:
+ for(i = 1;freq*i < srate/2;i+=2)
+ ApplySin(data, 8.0/(M_PI*M_PI) * (1.0 - (i&2)) / (i*i), srate, freq*i);
+ break;
+ case WT_Impulse:
+ /* NOTE: Impulse isn't handled using additive synthesis, and is
+ * instead just a non-0 sample at a given rate. This can still be
+ * useful to test (other than resampling, the ALSOFT_DEFAULT_REVERB
+ * environment variable can prove useful here to test the reverb
+ * response).
+ */
+ for(i = 0;i < srate;i++)
+ data[i] = (i%(srate/freq)) ? 0.0f : 1.0f;
+ break;
+ case WT_WhiteNoise:
+ /* NOTE: WhiteNoise is just uniform set of uncorrelated values, and
+ * is not influenced by the waveform frequency.
+ */
+ for(i = 0;i < srate;i++)
+ {
+ ALuint rng0 = dither_rng(&seed);
+ ALuint rng1 = dither_rng(&seed);
+ data[i] = (ALfloat)(rng0*(1.0/UINT_MAX) - rng1*(1.0/UINT_MAX));
+ }
+ break;
}
/* Buffer the audio data into a new buffer object. */
@@ -166,7 +195,7 @@ int main(int argc, char *argv[])
" --help/-h This help text\n"
" -t <seconds> Time to play a tone (default 5 seconds)\n"
" --waveform/-w <type> Waveform type: sine (default), square, sawtooth,\n"
-" triangle, impulse\n"
+" triangle, impulse, noise\n"
" --freq/-f <hz> Tone frequency (default 1000 hz)\n"
" --srate/-s <sample rate> Sampling rate (default output rate)\n",
appname
@@ -192,6 +221,8 @@ int main(int argc, char *argv[])
wavetype = WT_Triangle;
else if(strcmp(argv[i], "impulse") == 0)
wavetype = WT_Impulse;
+ else if(strcmp(argv[i], "noise") == 0)
+ wavetype = WT_WhiteNoise;
else
fprintf(stderr, "Unhandled waveform: %s\n", argv[i]);
}
diff --git a/hrtf/default-44100.mhr b/hrtf/default-44100.mhr
index e0d0bf4..7150159 100644
Binary files a/hrtf/default-44100.mhr and b/hrtf/default-44100.mhr differ
diff --git a/hrtf/default-48000.mhr b/hrtf/default-48000.mhr
index 7addfa7..cee0971 100644
Binary files a/hrtf/default-48000.mhr and b/hrtf/default-48000.mhr differ
diff --git a/presets/itu5.1-nocenter.ambdec b/presets/itu5.1-nocenter.ambdec
new file mode 100644
index 0000000..23839d0
--- /dev/null
+++ b/presets/itu5.1-nocenter.ambdec
@@ -0,0 +1,46 @@
+# AmbDec configuration
+# Written by Ambisonic Decoder Toolbox, version 8.0
+
+# input channel order: WYXVU
+
+/description itu50-noCenter_2h0p_allrad_5200_rE_max_1_band
+
+# Although unused in this configuration, the front-center is declared here so
+# that an appropriate distance may be set (for proper delaying or attenuating
+# of dialog and such which feed it directly). It otherwise does not contribute
+# to positional sound output.
+
+/version 3
+
+/dec/chan_mask 11b
+/dec/freq_bands 1
+/dec/speakers 5
+/dec/coeff_scale fuma
+
+/opt/input_scale fuma
+/opt/nfeff_comp input
+/opt/delay_comp on
+/opt/level_comp on
+/opt/xover_freq 400.000000
+/opt/xover_ratio 0.000000
+
+/speakers/{
+# id dist azim elev conn
+#-----------------------------------------------------------------------
+add_spkr LS 1.000000 110.000000 0.000000 system:playback_3
+add_spkr LF 1.000000 30.000000 0.000000 system:playback_1
+add_spkr CE 1.000000 0.000000 0.000000 system:playback_5
+add_spkr RF 1.000000 -30.000000 0.000000 system:playback_2
+add_spkr RS 1.000000 -110.000000 0.000000 system:playback_4
+/}
+
+/matrix/{
+order_gain 1.00000000e+00 8.66025404e-01 5.00000000e-01 0.000000
+add_row 4.70934222e-01 3.78169605e-01 -4.00084750e-01 -8.22264454e-02 -4.43765986e-02
+add_row 2.66639870e-01 2.55418584e-01 3.32591390e-01 2.82949132e-01 8.16816772e-02
+add_row 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
+add_row 2.66634915e-01 -2.55421639e-01 3.32586482e-01 -2.82947688e-01 8.16782588e-02
+add_row 4.70935891e-01 -3.78173080e-01 -4.00080588e-01 8.22279700e-02 -4.43716394e-02
+/}
+
+/end
diff --git a/router/al.c b/router/al.c
new file mode 100644
index 0000000..3349ad1
--- /dev/null
+++ b/router/al.c
@@ -0,0 +1,132 @@
+
+#include "config.h"
+
+#include <stddef.h>
+
+#include "AL/al.h"
+#include "router.h"
+
+
+ATOMIC(DriverIface*) CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL);
+
+#define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) \
+{ \
+ DriverIface *iface = altss_get(ThreadCtxDriver); \
+ if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\
+ return iface->n(a); \
+}
+#define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) \
+{ \
+ DriverIface *iface = altss_get(ThreadCtxDriver); \
+ if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\
+ return iface->n(a, b); \
+}
+#define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) \
+{ \
+ DriverIface *iface = altss_get(ThreadCtxDriver); \
+ if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\
+ return iface->n(a, b, c); \
+}
+#define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) \
+{ \
+ DriverIface *iface = altss_get(ThreadCtxDriver); \
+ if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\
+ return iface->n(a, b, c, d); \
+}
+#define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) \
+{ \
+ DriverIface *iface = altss_get(ThreadCtxDriver); \
+ if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\
+ return iface->n(a, b, c, d, e); \
+}
+
+
+/* Ugly hack for some apps calling alGetError without a current context, and
+ * expecting it to be AL_NO_ERROR.
+ */
+AL_API ALenum AL_APIENTRY alGetError(void)
+{
+ DriverIface *iface = altss_get(ThreadCtxDriver);
+ if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);
+ return iface ? iface->alGetError() : AL_NO_ERROR;
+}
+
+
+DECL_THUNK1(void, alDopplerFactor, ALfloat)
+DECL_THUNK1(void, alDopplerVelocity, ALfloat)
+DECL_THUNK1(void, alSpeedOfSound, ALfloat)
+DECL_THUNK1(void, alDistanceModel, ALenum)
+
+DECL_THUNK1(void, alEnable, ALenum)
+DECL_THUNK1(void, alDisable, ALenum)
+DECL_THUNK1(ALboolean, alIsEnabled, ALenum)
+
+DECL_THUNK1(const ALchar*, alGetString, ALenum)
+DECL_THUNK2(void, alGetBooleanv, ALenum, ALboolean*)
+DECL_THUNK2(void, alGetIntegerv, ALenum, ALint*)
+DECL_THUNK2(void, alGetFloatv, ALenum, ALfloat*)
+DECL_THUNK2(void, alGetDoublev, ALenum, ALdouble*)
+DECL_THUNK1(ALboolean, alGetBoolean, ALenum)
+DECL_THUNK1(ALint, alGetInteger, ALenum)
+DECL_THUNK1(ALfloat, alGetFloat, ALenum)
+DECL_THUNK1(ALdouble, alGetDouble, ALenum)
+
+DECL_THUNK1(ALboolean, alIsExtensionPresent, const ALchar*)
+DECL_THUNK1(void*, alGetProcAddress, const ALchar*)
+DECL_THUNK1(ALenum, alGetEnumValue, const ALchar*)
+
+DECL_THUNK2(void, alListenerf, ALenum, ALfloat)
+DECL_THUNK4(void, alListener3f, ALenum, ALfloat, ALfloat, ALfloat)
+DECL_THUNK2(void, alListenerfv, ALenum, const ALfloat*)
+DECL_THUNK2(void, alListeneri, ALenum, ALint)
+DECL_THUNK4(void, alListener3i, ALenum, ALint, ALint, ALint)
+DECL_THUNK2(void, alListeneriv, ALenum, const ALint*)
+DECL_THUNK2(void, alGetListenerf, ALenum, ALfloat*)
+DECL_THUNK4(void, alGetListener3f, ALenum, ALfloat*, ALfloat*, ALfloat*)
+DECL_THUNK2(void, alGetListenerfv, ALenum, ALfloat*)
+DECL_THUNK2(void, alGetListeneri, ALenum, ALint*)
+DECL_THUNK4(void, alGetListener3i, ALenum, ALint*, ALint*, ALint*)
+DECL_THUNK2(void, alGetListeneriv, ALenum, ALint*)
+
+DECL_THUNK2(void, alGenSources, ALsizei, ALuint*)
+DECL_THUNK2(void, alDeleteSources, ALsizei, const ALuint*)
+DECL_THUNK1(ALboolean, alIsSource, ALuint)
+DECL_THUNK3(void, alSourcef, ALuint, ALenum, ALfloat)
+DECL_THUNK5(void, alSource3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat)
+DECL_THUNK3(void, alSourcefv, ALuint, ALenum, const ALfloat*)
+DECL_THUNK3(void, alSourcei, ALuint, ALenum, ALint)
+DECL_THUNK5(void, alSource3i, ALuint, ALenum, ALint, ALint, ALint)
+DECL_THUNK3(void, alSourceiv, ALuint, ALenum, const ALint*)
+DECL_THUNK3(void, alGetSourcef, ALuint, ALenum, ALfloat*)
+DECL_THUNK5(void, alGetSource3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*)
+DECL_THUNK3(void, alGetSourcefv, ALuint, ALenum, ALfloat*)
+DECL_THUNK3(void, alGetSourcei, ALuint, ALenum, ALint*)
+DECL_THUNK5(void, alGetSource3i, ALuint, ALenum, ALint*, ALint*, ALint*)
+DECL_THUNK3(void, alGetSourceiv, ALuint, ALenum, ALint*)
+DECL_THUNK2(void, alSourcePlayv, ALsizei, const ALuint*)
+DECL_THUNK2(void, alSourceStopv, ALsizei, const ALuint*)
+DECL_THUNK2(void, alSourceRewindv, ALsizei, const ALuint*)
+DECL_THUNK2(void, alSourcePausev, ALsizei, const ALuint*)
+DECL_THUNK1(void, alSourcePlay, ALuint)
+DECL_THUNK1(void, alSourceStop, ALuint)
+DECL_THUNK1(void, alSourceRewind, ALuint)
+DECL_THUNK1(void, alSourcePause, ALuint)
+DECL_THUNK3(void, alSourceQueueBuffers, ALuint, ALsizei, const ALuint*)
+DECL_THUNK3(void, alSourceUnqueueBuffers, ALuint, ALsizei, ALuint*)
+
+DECL_THUNK2(void, alGenBuffers, ALsizei, ALuint*)
+DECL_THUNK2(void, alDeleteBuffers, ALsizei, const ALuint*)
+DECL_THUNK1(ALboolean, alIsBuffer, ALuint)
+DECL_THUNK3(void, alBufferf, ALuint, ALenum, ALfloat)
+DECL_THUNK5(void, alBuffer3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat)
+DECL_THUNK3(void, alBufferfv, ALuint, ALenum, const ALfloat*)
+DECL_THUNK3(void, alBufferi, ALuint, ALenum, ALint)
+DECL_THUNK5(void, alBuffer3i, ALuint, ALenum, ALint, ALint, ALint)
+DECL_THUNK3(void, alBufferiv, ALuint, ALenum, const ALint*)
+DECL_THUNK3(void, alGetBufferf, ALuint, ALenum, ALfloat*)
+DECL_THUNK5(void, alGetBuffer3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*)
+DECL_THUNK3(void, alGetBufferfv, ALuint, ALenum, ALfloat*)
+DECL_THUNK3(void, alGetBufferi, ALuint, ALenum, ALint*)
+DECL_THUNK5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*)
+DECL_THUNK3(void, alGetBufferiv, ALuint, ALenum, ALint*)
+DECL_THUNK5(void, alBufferData, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei)
diff --git a/router/alc.c b/router/alc.c
new file mode 100644
index 0000000..946c7d4
--- /dev/null
+++ b/router/alc.c
@@ -0,0 +1,956 @@
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "AL/alc.h"
+#include "router.h"
+#include "almalloc.h"
+
+
+#define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
+
+#define DECL(x) { #x, (ALCvoid*)(x) }
+static const struct {
+ const ALCchar *funcName;
+ ALCvoid *address;
+} alcFunctions[] = {
+ DECL(alcCreateContext),
+ DECL(alcMakeContextCurrent),
+ DECL(alcProcessContext),
+ DECL(alcSuspendContext),
+ DECL(alcDestroyContext),
+ DECL(alcGetCurrentContext),
+ DECL(alcGetContextsDevice),
+ DECL(alcOpenDevice),
+ DECL(alcCloseDevice),
+ DECL(alcGetError),
+ DECL(alcIsExtensionPresent),
+ DECL(alcGetProcAddress),
+ DECL(alcGetEnumValue),
+ DECL(alcGetString),
+ DECL(alcGetIntegerv),
+ DECL(alcCaptureOpenDevice),
+ DECL(alcCaptureCloseDevice),
+ DECL(alcCaptureStart),
+ DECL(alcCaptureStop),
+ DECL(alcCaptureSamples),
+
+ DECL(alcSetThreadContext),
+ DECL(alcGetThreadContext),
+
+ DECL(alEnable),
+ DECL(alDisable),
+ DECL(alIsEnabled),
+ DECL(alGetString),
+ DECL(alGetBooleanv),
+ DECL(alGetIntegerv),
+ DECL(alGetFloatv),
+ DECL(alGetDoublev),
+ DECL(alGetBoolean),
+ DECL(alGetInteger),
+ DECL(alGetFloat),
+ DECL(alGetDouble),
+ DECL(alGetError),
+ DECL(alIsExtensionPresent),
+ DECL(alGetProcAddress),
+ DECL(alGetEnumValue),
+ DECL(alListenerf),
+ DECL(alListener3f),
+ DECL(alListenerfv),
+ DECL(alListeneri),
+ DECL(alListener3i),
+ DECL(alListeneriv),
+ DECL(alGetListenerf),
+ DECL(alGetListener3f),
+ DECL(alGetListenerfv),
+ DECL(alGetListeneri),
+ DECL(alGetListener3i),
+ DECL(alGetListeneriv),
+ DECL(alGenSources),
+ DECL(alDeleteSources),
+ DECL(alIsSource),
+ DECL(alSourcef),
+ DECL(alSource3f),
+ DECL(alSourcefv),
+ DECL(alSourcei),
+ DECL(alSource3i),
+ DECL(alSourceiv),
+ DECL(alGetSourcef),
+ DECL(alGetSource3f),
+ DECL(alGetSourcefv),
+ DECL(alGetSourcei),
+ DECL(alGetSource3i),
+ DECL(alGetSourceiv),
+ DECL(alSourcePlayv),
+ DECL(alSourceStopv),
+ DECL(alSourceRewindv),
+ DECL(alSourcePausev),
+ DECL(alSourcePlay),
+ DECL(alSourceStop),
+ DECL(alSourceRewind),
+ DECL(alSourcePause),
+ DECL(alSourceQueueBuffers),
+ DECL(alSourceUnqueueBuffers),
+ DECL(alGenBuffers),
+ DECL(alDeleteBuffers),
+ DECL(alIsBuffer),
+ DECL(alBufferData),
+ DECL(alBufferf),
+ DECL(alBuffer3f),
+ DECL(alBufferfv),
+ DECL(alBufferi),
+ DECL(alBuffer3i),
+ DECL(alBufferiv),
+ DECL(alGetBufferf),
+ DECL(alGetBuffer3f),
+ DECL(alGetBufferfv),
+ DECL(alGetBufferi),
+ DECL(alGetBuffer3i),
+ DECL(alGetBufferiv),
+ DECL(alDopplerFactor),
+ DECL(alDopplerVelocity),
+ DECL(alSpeedOfSound),
+ DECL(alDistanceModel),
+};
+#undef DECL
+
+#define DECL(x) { #x, (x) }
+static const struct {
+ const ALCchar *enumName;
+ ALCenum value;
+} alcEnumerations[] = {
+ DECL(ALC_INVALID),
+ DECL(ALC_FALSE),
+ DECL(ALC_TRUE),
+
+ DECL(ALC_MAJOR_VERSION),
+ DECL(ALC_MINOR_VERSION),
+ DECL(ALC_ATTRIBUTES_SIZE),
+ DECL(ALC_ALL_ATTRIBUTES),
+ DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
+ DECL(ALC_DEVICE_SPECIFIER),
+ DECL(ALC_ALL_DEVICES_SPECIFIER),
+ DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
+ DECL(ALC_EXTENSIONS),
+ DECL(ALC_FREQUENCY),
+ DECL(ALC_REFRESH),
+ DECL(ALC_SYNC),
+ DECL(ALC_MONO_SOURCES),
+ DECL(ALC_STEREO_SOURCES),
+ DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
+ DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
+ DECL(ALC_CAPTURE_SAMPLES),
+
+ DECL(ALC_NO_ERROR),
+ DECL(ALC_INVALID_DEVICE),
+ DECL(ALC_INVALID_CONTEXT),
+ DECL(ALC_INVALID_ENUM),
+ DECL(ALC_INVALID_VALUE),
+ DECL(ALC_OUT_OF_MEMORY),
+
+ DECL(AL_INVALID),
+ DECL(AL_NONE),
+ DECL(AL_FALSE),
+ DECL(AL_TRUE),
+
+ DECL(AL_SOURCE_RELATIVE),
+ DECL(AL_CONE_INNER_ANGLE),
+ DECL(AL_CONE_OUTER_ANGLE),
+ DECL(AL_PITCH),
+ DECL(AL_POSITION),
+ DECL(AL_DIRECTION),
+ DECL(AL_VELOCITY),
+ DECL(AL_LOOPING),
+ DECL(AL_BUFFER),
+ DECL(AL_GAIN),
+ DECL(AL_MIN_GAIN),
+ DECL(AL_MAX_GAIN),
+ DECL(AL_ORIENTATION),
+ DECL(AL_REFERENCE_DISTANCE),
+ DECL(AL_ROLLOFF_FACTOR),
+ DECL(AL_CONE_OUTER_GAIN),
+ DECL(AL_MAX_DISTANCE),
+ DECL(AL_SEC_OFFSET),
+ DECL(AL_SAMPLE_OFFSET),
+ DECL(AL_BYTE_OFFSET),
+ DECL(AL_SOURCE_TYPE),
+ DECL(AL_STATIC),
+ DECL(AL_STREAMING),
+ DECL(AL_UNDETERMINED),
+
+ DECL(AL_SOURCE_STATE),
+ DECL(AL_INITIAL),
+ DECL(AL_PLAYING),
+ DECL(AL_PAUSED),
+ DECL(AL_STOPPED),
+
+ DECL(AL_BUFFERS_QUEUED),
+ DECL(AL_BUFFERS_PROCESSED),
+
+ DECL(AL_FORMAT_MONO8),
+ DECL(AL_FORMAT_MONO16),
+ DECL(AL_FORMAT_STEREO8),
+ DECL(AL_FORMAT_STEREO16),
+
+ DECL(AL_FREQUENCY),
+ DECL(AL_BITS),
+ DECL(AL_CHANNELS),
+ DECL(AL_SIZE),
+
+ DECL(AL_UNUSED),
+ DECL(AL_PENDING),
+ DECL(AL_PROCESSED),
+
+ DECL(AL_NO_ERROR),
+ DECL(AL_INVALID_NAME),
+ DECL(AL_INVALID_ENUM),
+ DECL(AL_INVALID_VALUE),
+ DECL(AL_INVALID_OPERATION),
+ DECL(AL_OUT_OF_MEMORY),
+
+ DECL(AL_VENDOR),
+ DECL(AL_VERSION),
+ DECL(AL_RENDERER),
+ DECL(AL_EXTENSIONS),
+
+ DECL(AL_DOPPLER_FACTOR),
+ DECL(AL_DOPPLER_VELOCITY),
+ DECL(AL_DISTANCE_MODEL),
+ DECL(AL_SPEED_OF_SOUND),
+
+ DECL(AL_INVERSE_DISTANCE),
+ DECL(AL_INVERSE_DISTANCE_CLAMPED),
+ DECL(AL_LINEAR_DISTANCE),
+ DECL(AL_LINEAR_DISTANCE_CLAMPED),
+ DECL(AL_EXPONENT_DISTANCE),
+ DECL(AL_EXPONENT_DISTANCE_CLAMPED),
+};
+#undef DECL
+
+static const ALCchar alcNoError[] = "No Error";
+static const ALCchar alcErrInvalidDevice[] = "Invalid Device";
+static const ALCchar alcErrInvalidContext[] = "Invalid Context";
+static const ALCchar alcErrInvalidEnum[] = "Invalid Enum";
+static const ALCchar alcErrInvalidValue[] = "Invalid Value";
+static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
+static const ALCchar alcExtensionList[] =
+ "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
+ "ALC_EXT_thread_local_context";
+
+static const ALCint alcMajorVersion = 1;
+static const ALCint alcMinorVersion = 1;
+
+
+static almtx_t EnumerationLock;
+static almtx_t ContextSwitchLock;
+
+static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR);
+static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE;
+static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE;
+
+
+typedef struct EnumeratedList {
+ ALCchar *Names;
+ ALCchar *NamesEnd;
+ ALCint *Indicies;
+ ALCsizei IndexSize;
+} EnumeratedList;
+static EnumeratedList DevicesList = { NULL, NULL, NULL, 0 };
+static EnumeratedList AllDevicesList = { NULL, NULL, NULL, 0 };
+static EnumeratedList CaptureDevicesList = { NULL, NULL, NULL, 0 };
+
+static void ClearDeviceList(EnumeratedList *list)
+{
+ al_free(list->Names);
+ list->Names = NULL;
+ list->NamesEnd = NULL;
+
+ al_free(list->Indicies);
+ list->Indicies = NULL;
+ list->IndexSize = 0;
+}
+
+static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx)
+{
+ const ALCchar *name_end = names;
+ ALCsizei count = 0;
+ ALCchar *new_list;
+ ALCint *new_indicies;
+ size_t len;
+ ALCsizei i;
+
+ if(!name_end)
+ return;
+ while(*name_end)
+ {
+ TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
+ count++;
+ name_end += strlen(name_end)+1;
+ }
+ if(names == name_end)
+ return;
+
+ len = (list->NamesEnd - list->Names) + (name_end - names);
+ new_list = al_calloc(DEF_ALIGN, len + 1);
+ memcpy(new_list, list->Names, list->NamesEnd - list->Names);
+ memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names);
+ al_free(list->Names);
+ list->Names = new_list;
+ list->NamesEnd = list->Names + len;
+
+ new_indicies = al_calloc(16, sizeof(ALCint)*(list->IndexSize + count));
+ for(i = 0;i < list->IndexSize;i++)
+ new_indicies[i] = list->Indicies[i];
+ for(i = 0;i < count;i++)
+ new_indicies[list->IndexSize+i] = idx;
+ al_free(list->Indicies);
+ list->Indicies = new_indicies;
+ list->IndexSize += count;
+}
+
+static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name)
+{
+ const ALCchar *devnames = list->Names;
+ const ALCint *index = list->Indicies;
+
+ while(devnames && *devnames)
+ {
+ if(strcmp(name, devnames) == 0)
+ return *index;
+ devnames += strlen(devnames)+1;
+ index++;
+ }
+ return -1;
+}
+
+void InitALC(void)
+{
+ almtx_init(&EnumerationLock, almtx_recursive);
+ almtx_init(&ContextSwitchLock, almtx_plain);
+}
+
+void ReleaseALC(void)
+{
+ ClearDeviceList(&DevicesList);
+ ClearDeviceList(&AllDevicesList);
+ ClearDeviceList(&CaptureDevicesList);
+
+ ResetPtrIntMap(&ContextIfaceMap);
+ ResetPtrIntMap(&DeviceIfaceMap);
+
+ almtx_destroy(&ContextSwitchLock);
+ almtx_destroy(&EnumerationLock);
+}
+
+
+ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename)
+{
+ ALCdevice *device = NULL;
+ ALint idx;
+
+ /* Prior to the enumeration extension, apps would hardcode these names as a
+ * quality hint for the wrapper driver. Ignore them since there's no sane
+ * way to map them.
+ */
+ if(devicename && (devicename[0] == '\0' ||
+ strcmp(devicename, "DirectSound3D") == 0 ||
+ strcmp(devicename, "DirectSound") == 0 ||
+ strcmp(devicename, "MMSYSTEM") == 0))
+ devicename = NULL;
+ if(devicename)
+ {
+ almtx_lock(&EnumerationLock);
+ if(!DevicesList.Names)
+ (void)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+ idx = GetDriverIndexForName(&DevicesList, devicename);
+ if(idx < 0)
+ {
+ if(!AllDevicesList.Names)
+ (void)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
+ idx = GetDriverIndexForName(&AllDevicesList, devicename);
+ }
+ almtx_unlock(&EnumerationLock);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
+ TRACE("Failed to find driver for name \"%s\"\n", devicename);
+ return NULL;
+ }
+ TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
+ device = DriverList[idx].alcOpenDevice(devicename);
+ }
+ else
+ {
+ int i;
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
+ DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
+ {
+ idx = i;
+ TRACE("Using default device from driver %d\n", idx);
+ device = DriverList[idx].alcOpenDevice(NULL);
+ break;
+ }
+ }
+ }
+
+ if(device)
+ {
+ if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR)
+ {
+ DriverList[idx].alcCloseDevice(device);
+ device = NULL;
+ }
+ }
+
+ return device;
+}
+
+ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
+{
+ ALint idx;
+
+ if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return ALC_FALSE;
+ }
+ if(!DriverList[idx].alcCloseDevice(device))
+ return ALC_FALSE;
+ RemovePtrIntMapKey(&DeviceIfaceMap, device);
+ return ALC_TRUE;
+}
+
+
+ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
+{
+ ALCcontext *context;
+ ALint idx;
+
+ if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return ALC_FALSE;
+ }
+ context = DriverList[idx].alcCreateContext(device, attrlist);
+ if(context)
+ {
+ if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR)
+ {
+ DriverList[idx].alcDestroyContext(context);
+ context = NULL;
+ }
+ }
+
+ return context;
+}
+
+ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
+{
+ ALint idx = -1;
+
+ almtx_lock(&ContextSwitchLock);
+ if(context)
+ {
+ idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
+ almtx_unlock(&ContextSwitchLock);
+ return ALC_FALSE;
+ }
+ if(!DriverList[idx].alcMakeContextCurrent(context))
+ {
+ almtx_unlock(&ContextSwitchLock);
+ return ALC_FALSE;
+ }
+ }
+
+ /* Unset the context from the old driver if it's different from the new
+ * current one.
+ */
+ if(idx < 0)
+ {
+ DriverIface *oldiface = altss_get(ThreadCtxDriver);
+ if(oldiface) oldiface->alcSetThreadContext(NULL);
+ oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, NULL);
+ if(oldiface) oldiface->alcMakeContextCurrent(NULL);
+ }
+ else
+ {
+ DriverIface *oldiface = altss_get(ThreadCtxDriver);
+ if(oldiface && oldiface != &DriverList[idx])
+ oldiface->alcSetThreadContext(NULL);
+ oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx]);
+ if(oldiface && oldiface != &DriverList[idx])
+ oldiface->alcMakeContextCurrent(NULL);
+ }
+ almtx_unlock(&ContextSwitchLock);
+ altss_set(ThreadCtxDriver, NULL);
+
+ return ALC_TRUE;
+}
+
+ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
+{
+ if(context)
+ {
+ ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
+ if(idx >= 0)
+ return DriverList[idx].alcProcessContext(context);
+ }
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
+}
+
+ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
+{
+ if(context)
+ {
+ ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
+ if(idx >= 0)
+ return DriverList[idx].alcSuspendContext(context);
+ }
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
+}
+
+ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
+{
+ ALint idx;
+
+ if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
+ return;
+ }
+
+ DriverList[idx].alcDestroyContext(context);
+ RemovePtrIntMapKey(&ContextIfaceMap, context);
+}
+
+ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
+{
+ DriverIface *iface = altss_get(ThreadCtxDriver);
+ if(!iface) iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver);
+ return iface ? iface->alcGetCurrentContext() : NULL;
+}
+
+ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
+{
+ if(context)
+ {
+ ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
+ if(idx >= 0)
+ return DriverList[idx].alcGetContextsDevice(context);
+ }
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
+ return NULL;
+}
+
+
+ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
+{
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx < 0) return ALC_INVALID_DEVICE;
+ return DriverList[idx].alcGetError(device);
+ }
+ return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR);
+}
+
+ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
+{
+ const char *ptr;
+ size_t len;
+
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return ALC_FALSE;
+ }
+ return DriverList[idx].alcIsExtensionPresent(device, extname);
+ }
+
+ len = strlen(extname);
+ ptr = alcExtensionList;
+ while(ptr && *ptr)
+ {
+ if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
+ return ALC_TRUE;
+ if((ptr=strchr(ptr, ' ')) != NULL)
+ {
+ do {
+ ++ptr;
+ } while(isspace(*ptr));
+ }
+ }
+ return ALC_FALSE;
+}
+
+ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
+{
+ size_t i;
+
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return NULL;
+ }
+ return DriverList[idx].alcGetProcAddress(device, funcname);
+ }
+
+ for(i = 0;i < COUNTOF(alcFunctions);i++)
+ {
+ if(strcmp(funcname, alcFunctions[i].funcName) == 0)
+ return alcFunctions[i].address;
+ }
+ return NULL;
+}
+
+ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
+{
+ size_t i;
+
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return 0;
+ }
+ return DriverList[idx].alcGetEnumValue(device, enumname);
+ }
+
+ for(i = 0;i < COUNTOF(alcEnumerations);i++)
+ {
+ if(strcmp(enumname, alcEnumerations[i].enumName) == 0)
+ return alcEnumerations[i].value;
+ }
+ return 0;
+}
+
+ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
+{
+ ALsizei i = 0;
+
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return NULL;
+ }
+ return DriverList[idx].alcGetString(device, param);
+ }
+
+ switch(param)
+ {
+ case ALC_NO_ERROR:
+ return alcNoError;
+ case ALC_INVALID_ENUM:
+ return alcErrInvalidEnum;
+ case ALC_INVALID_VALUE:
+ return alcErrInvalidValue;
+ case ALC_INVALID_DEVICE:
+ return alcErrInvalidDevice;
+ case ALC_INVALID_CONTEXT:
+ return alcErrInvalidContext;
+ case ALC_OUT_OF_MEMORY:
+ return alcErrOutOfMemory;
+ case ALC_EXTENSIONS:
+ return alcExtensionList;
+
+ case ALC_DEVICE_SPECIFIER:
+ almtx_lock(&EnumerationLock);
+ ClearDeviceList(&DevicesList);
+ for(i = 0;i < DriverListSize;i++)
+ {
+ /* Only enumerate names from drivers that support it. */
+ if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
+ DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
+ AppendDeviceList(&DevicesList,
+ DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i
+ );
+ }
+ almtx_unlock(&EnumerationLock);
+ return DevicesList.Names;
+
+ case ALC_ALL_DEVICES_SPECIFIER:
+ almtx_lock(&EnumerationLock);
+ ClearDeviceList(&AllDevicesList);
+ for(i = 0;i < DriverListSize;i++)
+ {
+ /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
+ * standard enumeration.
+ */
+ if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
+ AppendDeviceList(&AllDevicesList,
+ DriverList[i].alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER), i
+ );
+ else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
+ DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
+ AppendDeviceList(&AllDevicesList,
+ DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i
+ );
+ }
+ almtx_unlock(&EnumerationLock);
+ return AllDevicesList.Names;
+
+ case ALC_CAPTURE_DEVICE_SPECIFIER:
+ almtx_lock(&EnumerationLock);
+ ClearDeviceList(&CaptureDevicesList);
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
+ DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
+ AppendDeviceList(&CaptureDevicesList,
+ DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER), i
+ );
+ }
+ almtx_unlock(&EnumerationLock);
+ return CaptureDevicesList.Names;
+
+ case ALC_DEFAULT_DEVICE_SPECIFIER:
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
+ DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
+ return DriverList[i].alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+ }
+ return "";
+
+ case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
+ return DriverList[i].alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
+ }
+ return "";
+
+ case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
+ DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
+ return DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
+ }
+ return "";
+
+ default:
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM);
+ break;
+ }
+ return NULL;
+}
+
+ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
+{
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return;
+ }
+ return DriverList[idx].alcGetIntegerv(device, param, size, values);
+ }
+
+ if(size <= 0 || values == NULL)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
+ return;
+ }
+
+ switch(param)
+ {
+ case ALC_MAJOR_VERSION:
+ if(size >= 1)
+ {
+ values[0] = alcMajorVersion;
+ return;
+ }
+ /*fall-through*/
+ case ALC_MINOR_VERSION:
+ if(size >= 1)
+ {
+ values[0] = alcMinorVersion;
+ return;
+ }
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
+ return;
+
+ case ALC_ATTRIBUTES_SIZE:
+ case ALC_ALL_ATTRIBUTES:
+ case ALC_FREQUENCY:
+ case ALC_REFRESH:
+ case ALC_SYNC:
+ case ALC_MONO_SOURCES:
+ case ALC_STEREO_SOURCES:
+ case ALC_CAPTURE_SAMPLES:
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return;
+
+ default:
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM);
+ return;
+ }
+}
+
+
+ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
+{
+ ALCdevice *device = NULL;
+ ALint idx;
+
+ if(devicename && devicename[0] == '\0')
+ devicename = NULL;
+ if(devicename)
+ {
+ almtx_lock(&EnumerationLock);
+ if(!CaptureDevicesList.Names)
+ (void)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
+ idx = GetDriverIndexForName(&CaptureDevicesList, devicename);
+ almtx_unlock(&EnumerationLock);
+ if(idx < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
+ TRACE("Failed to find driver for name \"%s\"\n", devicename);
+ return NULL;
+ }
+ TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
+ device = DriverList[idx].alcCaptureOpenDevice(
+ devicename, frequency, format, buffersize
+ );
+ }
+ else
+ {
+ int i;
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
+ DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
+ {
+ idx = i;
+ TRACE("Using default capture device from driver %d\n", idx);
+ device = DriverList[idx].alcCaptureOpenDevice(
+ NULL, frequency, format, buffersize
+ );
+ break;
+ }
+ }
+ }
+
+ if(device)
+ {
+ if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR)
+ {
+ DriverList[idx].alcCaptureCloseDevice(device);
+ device = NULL;
+ }
+ }
+
+ return device;
+}
+
+ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
+{
+ ALint idx;
+
+ if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
+ {
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+ return ALC_FALSE;
+ }
+ if(!DriverList[idx].alcCaptureCloseDevice(device))
+ return ALC_FALSE;
+ RemovePtrIntMapKey(&DeviceIfaceMap, device);
+ return ALC_TRUE;
+}
+
+ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
+{
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx >= 0)
+ return DriverList[idx].alcCaptureStart(device);
+ }
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+}
+
+ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
+{
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx >= 0)
+ return DriverList[idx].alcCaptureStop(device);
+ }
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+}
+
+ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
+{
+ if(device)
+ {
+ ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
+ if(idx >= 0)
+ return DriverList[idx].alcCaptureSamples(device, buffer, samples);
+ }
+ ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
+}
+
+
+ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
+{
+ ALCenum err = ALC_INVALID_CONTEXT;
+ ALint idx;
+
+ if(!context)
+ {
+ DriverIface *oldiface = altss_get(ThreadCtxDriver);
+ if(oldiface && !oldiface->alcSetThreadContext(NULL))
+ return ALC_FALSE;
+ altss_set(ThreadCtxDriver, NULL);
+ return ALC_TRUE;
+ }
+
+ idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
+ if(idx >= 0)
+ {
+ if(DriverList[idx].alcSetThreadContext(context))
+ {
+ DriverIface *oldiface = altss_get(ThreadCtxDriver);
+ if(oldiface != &DriverList[idx])
+ {
+ altss_set(ThreadCtxDriver, &DriverList[idx]);
+ if(oldiface) oldiface->alcSetThreadContext(NULL);
+ }
+ return ALC_TRUE;
+ }
+ err = DriverList[idx].alcGetError(NULL);
+ }
+ ATOMIC_STORE_SEQ(&LastError, err);
+ return ALC_FALSE;
+}
+
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
+{
+ DriverIface *iface = altss_get(ThreadCtxDriver);
+ if(iface) return iface->alcGetThreadContext();
+ return NULL;
+}
diff --git a/router/router.c b/router/router.c
new file mode 100644
index 0000000..0497a1d
--- /dev/null
+++ b/router/router.c
@@ -0,0 +1,512 @@
+
+#include "config.h"
+
+#include "router.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "almalloc.h"
+
+#include "version.h"
+
+
+DriverIface *DriverList = NULL;
+int DriverListSize = 0;
+static int DriverListSizeMax = 0;
+
+altss_t ThreadCtxDriver;
+
+enum LogLevel LogLevel = LogLevel_Error;
+FILE *LogFile;
+
+static void LoadDriverList(void);
+
+
+BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved))
+{
+ const char *str;
+ int i;
+
+ switch(reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ LogFile = stderr;
+ str = getenv("ALROUTER_LOGFILE");
+ if(str && *str != '\0')
+ {
+ FILE *f = fopen(str, "w");
+ if(f == NULL)
+ ERR("Could not open log file: %s\n", str);
+ else
+ LogFile = f;
+ }
+ str = getenv("ALROUTER_LOGLEVEL");
+ if(str && *str != '\0')
+ {
+ char *end = NULL;
+ long l = strtol(str, &end, 0);
+ if(!end || *end != '\0')
+ ERR("Invalid log level value: %s\n", str);
+ else if(l < LogLevel_None || l > LogLevel_Trace)
+ ERR("Log level out of range: %s\n", str);
+ else
+ LogLevel = l;
+ }
+ TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH);
+ LoadDriverList();
+
+ altss_create(&ThreadCtxDriver, NULL);
+ InitALC();
+ break;
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+
+ case DLL_PROCESS_DETACH:
+ ReleaseALC();
+ altss_delete(ThreadCtxDriver);
+
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].Module)
+ FreeLibrary(DriverList[i].Module);
+ }
+ al_free(DriverList);
+ DriverList = NULL;
+ DriverListSize = 0;
+ DriverListSizeMax = 0;
+
+ if(LogFile && LogFile != stderr)
+ fclose(LogFile);
+ LogFile = NULL;
+ break;
+ }
+ return TRUE;
+}
+
+
+#ifdef __GNUC__
+#define CAST_FUNC(x) (__typeof(x))
+#else
+#define CAST_FUNC(x) (void*)
+#endif
+
+static void AddModule(HMODULE module, const WCHAR *name)
+{
+ DriverIface newdrv;
+ int err = 0;
+ int i;
+
+ for(i = 0;i < DriverListSize;i++)
+ {
+ if(DriverList[i].Module == module)
+ {
+ TRACE("Skipping already-loaded module %p\n", module);
+ FreeLibrary(module);
+ return;
+ }
+ if(wcscmp(DriverList[i].Name, name) == 0)
+ {
+ TRACE("Skipping similarly-named module %ls\n", name);
+ FreeLibrary(module);
+ return;
+ }
+ }
+
+ if(DriverListSize == DriverListSizeMax)
+ {
+ int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4;
+ void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax);
+ if(!newlist) return;
+
+ memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0]));
+ al_free(DriverList);
+ DriverList = newlist;
+ DriverListSizeMax = newmax;
+ }
+
+ memset(&newdrv, 0, sizeof(newdrv));
+ /* Load required functions. */
+#define LOAD_PROC(x) do { \
+ newdrv.x = CAST_FUNC(newdrv.x) GetProcAddress(module, #x); \
+ if(!newdrv.x) \
+ { \
+ ERR("Failed to find entry point for %s in %ls\n", #x, name); \
+ err = 1; \
+ } \
+} while(0)
+ LOAD_PROC(alcCreateContext);
+ LOAD_PROC(alcMakeContextCurrent);
+ LOAD_PROC(alcProcessContext);
+ LOAD_PROC(alcSuspendContext);
+ LOAD_PROC(alcDestroyContext);
+ LOAD_PROC(alcGetCurrentContext);
+ LOAD_PROC(alcGetContextsDevice);
+ LOAD_PROC(alcOpenDevice);
+ LOAD_PROC(alcCloseDevice);
+ LOAD_PROC(alcGetError);
+ LOAD_PROC(alcIsExtensionPresent);
+ LOAD_PROC(alcGetProcAddress);
+ LOAD_PROC(alcGetEnumValue);
+ LOAD_PROC(alcGetString);
+ LOAD_PROC(alcGetIntegerv);
+ LOAD_PROC(alcCaptureOpenDevice);
+ LOAD_PROC(alcCaptureCloseDevice);
+ LOAD_PROC(alcCaptureStart);
+ LOAD_PROC(alcCaptureStop);
+ LOAD_PROC(alcCaptureSamples);
+
+ LOAD_PROC(alEnable);
+ LOAD_PROC(alDisable);
+ LOAD_PROC(alIsEnabled);
+ LOAD_PROC(alGetString);
+ LOAD_PROC(alGetBooleanv);
+ LOAD_PROC(alGetIntegerv);
+ LOAD_PROC(alGetFloatv);
+ LOAD_PROC(alGetDoublev);
+ LOAD_PROC(alGetBoolean);
+ LOAD_PROC(alGetInteger);
+ LOAD_PROC(alGetFloat);
+ LOAD_PROC(alGetDouble);
+ LOAD_PROC(alGetError);
+ LOAD_PROC(alIsExtensionPresent);
+ LOAD_PROC(alGetProcAddress);
+ LOAD_PROC(alGetEnumValue);
+ LOAD_PROC(alListenerf);
+ LOAD_PROC(alListener3f);
+ LOAD_PROC(alListenerfv);
+ LOAD_PROC(alListeneri);
+ LOAD_PROC(alListener3i);
+ LOAD_PROC(alListeneriv);
+ LOAD_PROC(alGetListenerf);
+ LOAD_PROC(alGetListener3f);
+ LOAD_PROC(alGetListenerfv);
+ LOAD_PROC(alGetListeneri);
+ LOAD_PROC(alGetListener3i);
+ LOAD_PROC(alGetListeneriv);
+ LOAD_PROC(alGenSources);
+ LOAD_PROC(alDeleteSources);
+ LOAD_PROC(alIsSource);
+ LOAD_PROC(alSourcef);
+ LOAD_PROC(alSource3f);
+ LOAD_PROC(alSourcefv);
+ LOAD_PROC(alSourcei);
+ LOAD_PROC(alSource3i);
+ LOAD_PROC(alSourceiv);
+ LOAD_PROC(alGetSourcef);
+ LOAD_PROC(alGetSource3f);
+ LOAD_PROC(alGetSourcefv);
+ LOAD_PROC(alGetSourcei);
+ LOAD_PROC(alGetSource3i);
+ LOAD_PROC(alGetSourceiv);
+ LOAD_PROC(alSourcePlayv);
+ LOAD_PROC(alSourceStopv);
+ LOAD_PROC(alSourceRewindv);
+ LOAD_PROC(alSourcePausev);
+ LOAD_PROC(alSourcePlay);
+ LOAD_PROC(alSourceStop);
+ LOAD_PROC(alSourceRewind);
+ LOAD_PROC(alSourcePause);
+ LOAD_PROC(alSourceQueueBuffers);
+ LOAD_PROC(alSourceUnqueueBuffers);
+ LOAD_PROC(alGenBuffers);
+ LOAD_PROC(alDeleteBuffers);
+ LOAD_PROC(alIsBuffer);
+ LOAD_PROC(alBufferf);
+ LOAD_PROC(alBuffer3f);
+ LOAD_PROC(alBufferfv);
+ LOAD_PROC(alBufferi);
+ LOAD_PROC(alBuffer3i);
+ LOAD_PROC(alBufferiv);
+ LOAD_PROC(alGetBufferf);
+ LOAD_PROC(alGetBuffer3f);
+ LOAD_PROC(alGetBufferfv);
+ LOAD_PROC(alGetBufferi);
+ LOAD_PROC(alGetBuffer3i);
+ LOAD_PROC(alGetBufferiv);
+ LOAD_PROC(alBufferData);
+ LOAD_PROC(alDopplerFactor);
+ LOAD_PROC(alDopplerVelocity);
+ LOAD_PROC(alSpeedOfSound);
+ LOAD_PROC(alDistanceModel);
+ if(!err)
+ {
+ ALCint alc_ver[2] = { 0, 0 };
+ wcsncpy(newdrv.Name, name, 32);
+ newdrv.Module = module;
+ newdrv.alcGetIntegerv(NULL, ALC_MAJOR_VERSION, 1, &alc_ver[0]);
+ newdrv.alcGetIntegerv(NULL, ALC_MINOR_VERSION, 1, &alc_ver[1]);
+ if(newdrv.alcGetError(NULL) == ALC_NO_ERROR)
+ newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]);
+ else
+ newdrv.ALCVer = MAKE_ALC_VER(1, 0);
+
+#undef LOAD_PROC
+#define LOAD_PROC(x) do { \
+ newdrv.x = CAST_FUNC(newdrv.x) newdrv.alcGetProcAddress(NULL, #x); \
+ if(!newdrv.x) \
+ { \
+ ERR("Failed to find entry point for %s in %ls\n", #x, name); \
+ err = 1; \
+ } \
+} while(0)
+ if(newdrv.alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context"))
+ {
+ LOAD_PROC(alcSetThreadContext);
+ LOAD_PROC(alcGetThreadContext);
+ }
+ }
+
+ if(!err)
+ {
+ TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name,
+ newdrv.ALCVer>>8, newdrv.ALCVer&255);
+ DriverList[DriverListSize++] = newdrv;
+ }
+#undef LOAD_PROC
+}
+
+static void SearchDrivers(WCHAR *path)
+{
+ WCHAR srchPath[MAX_PATH+1] = L"";
+ WIN32_FIND_DATAW fdata;
+ HANDLE srchHdl;
+
+ TRACE("Searching for drivers in %ls...\n", path);
+ wcsncpy(srchPath, path, MAX_PATH);
+ wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath));
+ srchHdl = FindFirstFileW(srchPath, &fdata);
+ if(srchHdl != INVALID_HANDLE_VALUE)
+ {
+ do {
+ HMODULE mod;
+
+ wcsncpy(srchPath, path, MAX_PATH);
+ wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath));
+ wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath));
+ TRACE("Found %ls\n", srchPath);
+
+ mod = LoadLibraryW(srchPath);
+ if(!mod)
+ WARN("Could not load %ls\n", srchPath);
+ else
+ AddModule(mod, fdata.cFileName);
+ } while(FindNextFileW(srchHdl, &fdata));
+ FindClose(srchHdl);
+ }
+}
+
+static WCHAR *strrchrW(WCHAR *str, WCHAR ch)
+{
+ WCHAR *res = NULL;
+ while(str && *str != '\0')
+ {
+ if(*str == ch)
+ res = str;
+ ++str;
+ }
+ return res;
+}
+
+static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length)
+{
+ HMODULE module = NULL;
+ WCHAR *sep0, *sep1;
+
+ if(name)
+ {
+ module = GetModuleHandleW(name);
+ if(!module) return 0;
+ }
+
+ if(GetModuleFileNameW(module, moddir, length) == 0)
+ return 0;
+
+ sep0 = strrchrW(moddir, '/');
+ if(sep0) sep1 = strrchrW(sep0+1, '\\');
+ else sep1 = strrchrW(moddir, '\\');
+
+ if(sep1) *sep1 = '\0';
+ else if(sep0) *sep0 = '\0';
+ else *moddir = '\0';
+
+ return 1;
+}
+
+void LoadDriverList(void)
+{
+ WCHAR path[MAX_PATH+1] = L"";
+ int len;
+
+ if(GetLoadedModuleDirectory(L"OpenAL32.dll", path, MAX_PATH))
+ SearchDrivers(path);
+
+ GetCurrentDirectoryW(MAX_PATH, path);
+ len = lstrlenW(path);
+ if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/'))
+ path[len-1] = '\0';
+ SearchDrivers(path);
+
+ if(GetLoadedModuleDirectory(NULL, path, MAX_PATH))
+ SearchDrivers(path);
+
+ GetSystemDirectoryW(path, MAX_PATH);
+ len = lstrlenW(path);
+ if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/'))
+ path[len-1] = '\0';
+ SearchDrivers(path);
+}
+
+
+void InitPtrIntMap(PtrIntMap *map)
+{
+ map->keys = NULL;
+ map->values = NULL;
+ map->size = 0;
+ map->capacity = 0;
+ RWLockInit(&map->lock);
+}
+
+void ResetPtrIntMap(PtrIntMap *map)
+{
+ WriteLock(&map->lock);
+ al_free(map->keys);
+ map->keys = NULL;
+ map->values = NULL;
+ map->size = 0;
+ map->capacity = 0;
+ WriteUnlock(&map->lock);
+}
+
+ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value)
+{
+ ALsizei pos = 0;
+
+ WriteLock(&map->lock);
+ if(map->size > 0)
+ {
+ ALsizei count = map->size;
+ do {
+ ALsizei step = count>>1;
+ ALsizei i = pos+step;
+ if(!(map->keys[i] < key))
+ count = step;
+ else
+ {
+ pos = i+1;
+ count -= step+1;
+ }
+ } while(count > 0);
+ }
+
+ if(pos == map->size || map->keys[pos] != key)
+ {
+ if(map->size == map->capacity)
+ {
+ ALvoid **keys = NULL;
+ ALint *values;
+ ALsizei newcap;
+
+ newcap = (map->capacity ? (map->capacity<<1) : 4);
+ if(newcap > map->capacity)
+ keys = al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap);
+ if(!keys)
+ {
+ WriteUnlock(&map->lock);
+ return AL_OUT_OF_MEMORY;
+ }
+ values = (ALint*)&keys[newcap];
+
+ if(map->keys)
+ {
+ memcpy(keys, map->keys, map->size*sizeof(map->keys[0]));
+ memcpy(values, map->values, map->size*sizeof(map->values[0]));
+ }
+ al_free(map->keys);
+ map->keys = keys;
+ map->values = values;
+ map->capacity = newcap;
+ }
+
+ if(pos < map->size)
+ {
+ memmove(&map->keys[pos+1], &map->keys[pos],
+ (map->size-pos)*sizeof(map->keys[0]));
+ memmove(&map->values[pos+1], &map->values[pos],
+ (map->size-pos)*sizeof(map->values[0]));
+ }
+ map->size++;
+ }
+ map->keys[pos] = key;
+ map->values[pos] = value;
+ WriteUnlock(&map->lock);
+
+ return AL_NO_ERROR;
+}
+
+ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key)
+{
+ ALint ret = -1;
+ WriteLock(&map->lock);
+ if(map->size > 0)
+ {
+ ALsizei pos = 0;
+ ALsizei count = map->size;
+ do {
+ ALsizei step = count>>1;
+ ALsizei i = pos+step;
+ if(!(map->keys[i] < key))
+ count = step;
+ else
+ {
+ pos = i+1;
+ count -= step+1;
+ }
+ } while(count > 0);
+ if(pos < map->size && map->keys[pos] == key)
+ {
+ ret = map->values[pos];
+ if(pos < map->size-1)
+ {
+ memmove(&map->keys[pos], &map->keys[pos+1],
+ (map->size-1-pos)*sizeof(map->keys[0]));
+ memmove(&map->values[pos], &map->values[pos+1],
+ (map->size-1-pos)*sizeof(map->values[0]));
+ }
+ map->size--;
+ }
+ }
+ WriteUnlock(&map->lock);
+ return ret;
+}
+
+ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key)
+{
+ ALint ret = -1;
+ ReadLock(&map->lock);
+ if(map->size > 0)
+ {
+ ALsizei pos = 0;
+ ALsizei count = map->size;
+ do {
+ ALsizei step = count>>1;
+ ALsizei i = pos+step;
+ if(!(map->keys[i] < key))
+ count = step;
+ else
+ {
+ pos = i+1;
+ count -= step+1;
+ }
+ } while(count > 0);
+ if(pos < map->size && map->keys[pos] == key)
+ ret = map->values[pos];
+ }
+ ReadUnlock(&map->lock);
+ return ret;
+}
diff --git a/router/router.h b/router/router.h
new file mode 100644
index 0000000..ee885d8
--- /dev/null
+++ b/router/router.h
@@ -0,0 +1,196 @@
+#ifndef ROUTER_ROUTER_H
+#define ROUTER_ROUTER_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winnt.h>
+
+#include <stdio.h>
+
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "AL/alext.h"
+#include "atomic.h"
+#include "rwlock.h"
+#include "threads.h"
+
+
+#ifndef UNUSED
+#if defined(__cplusplus)
+#define UNUSED(x)
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_##x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#else
+#define UNUSED(x) x
+#endif
+#endif
+
+#define MAKE_ALC_VER(major, minor) (((major)<<8) | (minor))
+
+typedef struct DriverIface {
+ WCHAR Name[32];
+ HMODULE Module;
+ int ALCVer;
+
+ LPALCCREATECONTEXT alcCreateContext;
+ LPALCMAKECONTEXTCURRENT alcMakeContextCurrent;
+ LPALCPROCESSCONTEXT alcProcessContext;
+ LPALCSUSPENDCONTEXT alcSuspendContext;
+ LPALCDESTROYCONTEXT alcDestroyContext;
+ LPALCGETCURRENTCONTEXT alcGetCurrentContext;
+ LPALCGETCONTEXTSDEVICE alcGetContextsDevice;
+ LPALCOPENDEVICE alcOpenDevice;
+ LPALCCLOSEDEVICE alcCloseDevice;
+ LPALCGETERROR alcGetError;
+ LPALCISEXTENSIONPRESENT alcIsExtensionPresent;
+ LPALCGETPROCADDRESS alcGetProcAddress;
+ LPALCGETENUMVALUE alcGetEnumValue;
+ LPALCGETSTRING alcGetString;
+ LPALCGETINTEGERV alcGetIntegerv;
+ LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice;
+ LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice;
+ LPALCCAPTURESTART alcCaptureStart;
+ LPALCCAPTURESTOP alcCaptureStop;
+ LPALCCAPTURESAMPLES alcCaptureSamples;
+
+ PFNALCSETTHREADCONTEXTPROC alcSetThreadContext;
+ PFNALCGETTHREADCONTEXTPROC alcGetThreadContext;
+
+ LPALENABLE alEnable;
+ LPALDISABLE alDisable;
+ LPALISENABLED alIsEnabled;
+ LPALGETSTRING alGetString;
+ LPALGETBOOLEANV alGetBooleanv;
+ LPALGETINTEGERV alGetIntegerv;
+ LPALGETFLOATV alGetFloatv;
+ LPALGETDOUBLEV alGetDoublev;
+ LPALGETBOOLEAN alGetBoolean;
+ LPALGETINTEGER alGetInteger;
+ LPALGETFLOAT alGetFloat;
+ LPALGETDOUBLE alGetDouble;
+ LPALGETERROR alGetError;
+ LPALISEXTENSIONPRESENT alIsExtensionPresent;
+ LPALGETPROCADDRESS alGetProcAddress;
+ LPALGETENUMVALUE alGetEnumValue;
+ LPALLISTENERF alListenerf;
+ LPALLISTENER3F alListener3f;
+ LPALLISTENERFV alListenerfv;
+ LPALLISTENERI alListeneri;
+ LPALLISTENER3I alListener3i;
+ LPALLISTENERIV alListeneriv;
+ LPALGETLISTENERF alGetListenerf;
+ LPALGETLISTENER3F alGetListener3f;
+ LPALGETLISTENERFV alGetListenerfv;
+ LPALGETLISTENERI alGetListeneri;
+ LPALGETLISTENER3I alGetListener3i;
+ LPALGETLISTENERIV alGetListeneriv;
+ LPALGENSOURCES alGenSources;
+ LPALDELETESOURCES alDeleteSources;
+ LPALISSOURCE alIsSource;
+ LPALSOURCEF alSourcef;
+ LPALSOURCE3F alSource3f;
+ LPALSOURCEFV alSourcefv;
+ LPALSOURCEI alSourcei;
+ LPALSOURCE3I alSource3i;
+ LPALSOURCEIV alSourceiv;
+ LPALGETSOURCEF alGetSourcef;
+ LPALGETSOURCE3F alGetSource3f;
+ LPALGETSOURCEFV alGetSourcefv;
+ LPALGETSOURCEI alGetSourcei;
+ LPALGETSOURCE3I alGetSource3i;
+ LPALGETSOURCEIV alGetSourceiv;
+ LPALSOURCEPLAYV alSourcePlayv;
+ LPALSOURCESTOPV alSourceStopv;
+ LPALSOURCEREWINDV alSourceRewindv;
+ LPALSOURCEPAUSEV alSourcePausev;
+ LPALSOURCEPLAY alSourcePlay;
+ LPALSOURCESTOP alSourceStop;
+ LPALSOURCEREWIND alSourceRewind;
+ LPALSOURCEPAUSE alSourcePause;
+ LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers;
+ LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers;
+ LPALGENBUFFERS alGenBuffers;
+ LPALDELETEBUFFERS alDeleteBuffers;
+ LPALISBUFFER alIsBuffer;
+ LPALBUFFERF alBufferf;
+ LPALBUFFER3F alBuffer3f;
+ LPALBUFFERFV alBufferfv;
+ LPALBUFFERI alBufferi;
+ LPALBUFFER3I alBuffer3i;
+ LPALBUFFERIV alBufferiv;
+ LPALGETBUFFERF alGetBufferf;
+ LPALGETBUFFER3F alGetBuffer3f;
+ LPALGETBUFFERFV alGetBufferfv;
+ LPALGETBUFFERI alGetBufferi;
+ LPALGETBUFFER3I alGetBuffer3i;
+ LPALGETBUFFERIV alGetBufferiv;
+ LPALBUFFERDATA alBufferData;
+ LPALDOPPLERFACTOR alDopplerFactor;
+ LPALDOPPLERVELOCITY alDopplerVelocity;
+ LPALSPEEDOFSOUND alSpeedOfSound;
+ LPALDISTANCEMODEL alDistanceModel;
+} DriverIface;
+
+extern DriverIface *DriverList;
+extern int DriverListSize;
+
+extern altss_t ThreadCtxDriver;
+extern ATOMIC(DriverIface*) CurrentCtxDriver;
+
+
+typedef struct PtrIntMap {
+ ALvoid **keys;
+ /* Shares memory with keys. */
+ ALint *values;
+
+ ALsizei size;
+ ALsizei capacity;
+ RWLock lock;
+} PtrIntMap;
+#define PTRINTMAP_STATIC_INITIALIZE { NULL, NULL, 0, 0, RWLOCK_STATIC_INITIALIZE }
+
+void InitPtrIntMap(PtrIntMap *map);
+void ResetPtrIntMap(PtrIntMap *map);
+ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value);
+ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key);
+ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key);
+
+
+void InitALC(void);
+void ReleaseALC(void);
+
+
+enum LogLevel {
+ LogLevel_None = 0,
+ LogLevel_Error = 1,
+ LogLevel_Warn = 2,
+ LogLevel_Trace = 3,
+};
+extern enum LogLevel LogLevel;
+extern FILE *LogFile;
+
+#define TRACE(...) do { \
+ if(LogLevel >= LogLevel_Trace) \
+ { \
+ fprintf(LogFile, "AL Router (II): " __VA_ARGS__); \
+ fflush(LogFile); \
+ } \
+} while(0)
+#define WARN(...) do { \
+ if(LogLevel >= LogLevel_Warn) \
+ { \
+ fprintf(LogFile, "AL Router (WW): " __VA_ARGS__); \
+ fflush(LogFile); \
+ } \
+} while(0)
+#define ERR(...) do { \
+ if(LogLevel >= LogLevel_Error) \
+ { \
+ fprintf(LogFile, "AL Router (EE): " __VA_ARGS__); \
+ fflush(LogFile); \
+ } \
+} while(0)
+
+#endif /* ROUTER_ROUTER_H */
diff --git a/utils/makehrtf.c b/utils/makehrtf.c
index 704bf62..547c80d 100644
--- a/utils/makehrtf.c
+++ b/utils/makehrtf.c
@@ -2,7 +2,7 @@
* HRTF utility for producing and demonstrating the process of creating an
* OpenAL Soft compatible HRIR data set.
*
- * Copyright (C) 2011-2014 Christopher Fitzgerald
+ * Copyright (C) 2011-2017 Christopher Fitzgerald
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -83,7 +83,7 @@
#endif
// The epsilon used to maintain signal stability.
-#define EPSILON (1e-15)
+#define EPSILON (1e-9)
// Constants for accessing the token reader's ring buffer.
#define TR_RING_BITS (16)
@@ -145,16 +145,16 @@
#define MAX_ASCII_BITS (32)
// The limits to the FFT window size override on the command line.
-#define MIN_FFTSIZE (512)
-#define MAX_FFTSIZE (16384)
+#define MIN_FFTSIZE (65536)
+#define MAX_FFTSIZE (131072)
// The limits to the equalization range limit on the command line.
#define MIN_LIMIT (2.0)
#define MAX_LIMIT (120.0)
// The limits to the truncation window size on the command line.
-#define MIN_TRUNCSIZE (8)
-#define MAX_TRUNCSIZE (128)
+#define MIN_TRUNCSIZE (16)
+#define MAX_TRUNCSIZE (512)
// The limits to the custom head radius on the command line.
#define MIN_CUSTOM_RADIUS (0.05)
@@ -165,6 +165,7 @@
#define MOD_TRUNCSIZE (8)
// The defaults for the command line options.
+#define DEFAULT_FFTSIZE (65536)
#define DEFAULT_EQUALIZE (1)
#define DEFAULT_SURFACE (1)
#define DEFAULT_LIMIT (24.0)
@@ -985,10 +986,10 @@ static void FftInverse(const uint n, const double *inR, const double *inI, doubl
}
}
-/* Calculate the complex helical sequence (or discrete-time analytical
- * signal) of the given input using the Hilbert transform. Given the
- * negative natural logarithm of a signal's magnitude response, the imaginary
- * components can be used as the angles for minimum-phase reconstruction.
+/* Calculate the complex helical sequence (or discrete-time analytical signal)
+ * of the given input using the Hilbert transform. Given the natural logarithm
+ * of a signal's magnitude response, the imaginary components can be used as
+ * the angles for minimum-phase reconstruction.
*/
static void Hilbert(const uint n, const double *in, double *outR, double *outI)
{
@@ -1009,24 +1010,20 @@ static void Hilbert(const uint n, const double *in, double *outR, double *outI)
outI[i] = 0.0;
}
}
- FftForward(n, outR, outI, outR, outI);
- /* Currently the Fourier routines operate only on point counts that are
- * powers of two. If that changes and n is odd, the following conditional
- * should be: i < (n + 1) / 2.
- */
- for(i = 1;i < (n/2);i++)
+ FftInverse(n, outR, outI, outR, outI);
+ for(i = 1;i < (n+1)/2;i++)
{
outR[i] *= 2.0;
outI[i] *= 2.0;
}
- // If n is odd, the following increment should be skipped.
- i++;
+ /* Increment i if n is even. */
+ i += (n&1)^1;
for(;i < n;i++)
{
outR[i] = 0.0;
outI[i] = 0.0;
}
- FftInverse(n, outR, outI, outR, outI);
+ FftForward(n, outR, outI, outR, outI);
}
/* Calculate the magnitude response of the given input. This is used in
@@ -1080,15 +1077,15 @@ static void LimitMagnitudeResponse(const uint n, const double limit, const doubl
static void MinimumPhase(const uint n, const double *in, double *outR, double *outI)
{
const uint m = 1 + (n / 2);
- double aR, aI;
double *mags;
+ double aR, aI;
uint i;
mags = CreateArray(n);
for(i = 0;i < m;i++)
{
- mags[i] = fmax(in[i], EPSILON);
- outR[i] = -log(mags[i]);
+ mags[i] = fmax(EPSILON, in[i]);
+ outR[i] = log(mags[i]);
}
for(;i < n;i++)
{
@@ -1097,9 +1094,8 @@ static void MinimumPhase(const uint n, const double *in, double *outR, double *o
}
Hilbert(n, outR, outR, outI);
// Remove any DC offset the filter has.
- outR[0] = 0.0;
- outI[0] = 0.0;
- for(i = 1;i < n;i++)
+ mags[0] = EPSILON;
+ for(i = 0;i < n;i++)
{
ComplexExp(0.0, outI[i], &aR, &aI);
ComplexMul(mags[i], 0.0, aR, aI, &outR[i], &outI[i]);
@@ -1272,13 +1268,13 @@ static void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRat
*/
if(rs->mP > rs->mQ)
{
- cutoff = 0.45 / rs->mP;
- width = 0.1 / rs->mP;
+ cutoff = 0.475 / rs->mP;
+ width = 0.05 / rs->mP;
}
else
{
- cutoff = 0.45 / rs->mQ;
- width = 0.1 / rs->mQ;
+ cutoff = 0.475 / rs->mQ;
+ width = 0.05 / rs->mQ;
}
// A rejection of -180 dB is used for the stop band.
l = CalcKaiserOrder(180.0, width) / 2;
@@ -1923,12 +1919,13 @@ static int StoreMhr(const HrirDataT *hData, const char *filename)
// Calculate the onset time of an HRIR and average it with any existing
// timing for its elevation and azimuth.
-static void AverageHrirOnset(const double *hrir, const uint n, const double f, const uint ei, const uint ai, const HrirDataT *hData)
+static void AverageHrirOnset(const double *hrir, const double f, const uint ei, const uint ai, const HrirDataT *hData)
{
double mag;
- uint i, j;
+ uint n, i, j;
mag = 0.0;
+ n = hData->mIrPoints;
for(i = 0;i < n;i++)
mag = fmax(fabs(hrir[i]), mag);
mag *= 0.15;
@@ -1943,7 +1940,7 @@ static void AverageHrirOnset(const double *hrir, const uint n, const double f, c
// Calculate the magnitude response of an HRIR and average it with any
// existing responses for its elevation and azimuth.
-static void AverageHrirMagnitude(const double *hrir, const uint npoints, const double f, const uint ei, const uint ai, const HrirDataT *hData)
+static void AverageHrirMagnitude(const double *hrir, const double f, const uint ei, const uint ai, const HrirDataT *hData)
{
double *re, *im;
uint n, m, i, j;
@@ -1951,7 +1948,7 @@ static void AverageHrirMagnitude(const double *hrir, const uint npoints, const d
n = hData->mFftSize;
re = CreateArray(n);
im = CreateArray(n);
- for(i = 0;i < npoints;i++)
+ for(i = 0;i < hData->mIrPoints;i++)
{
re[i] = hrir[i];
im[i] = 0.0;
@@ -2107,6 +2104,23 @@ static void ReconstructHrirs(const HrirDataT *hData)
DestroyArray (re);
}
+// Resamples the HRIRs for use at the given sampling rate.
+static void ResampleHrirs(const uint rate, HrirDataT *hData)
+{
+ uint n, step, start, end, j;
+ ResamplerT rs;
+
+ ResamplerSetup(&rs, hData->mIrRate, rate);
+ n = hData->mIrPoints;
+ step = hData->mIrSize;
+ start = hData->mEvOffset[hData->mEvStart] * step;
+ end = hData->mIrCount * step;
+ for(j = start;j < end;j += step)
+ ResamplerRun(&rs, n, &hData->mHrirs[j], n, &hData->mHrirs[j]);
+ ResamplerClear(&rs);
+ hData->mIrRate = rate;
+}
+
/* Given an elevation index and an azimuth, calculate the indices of the two
* HRIRs that bound the coordinate along with a factor for calculating the
* continous HRIR using interpolation.
@@ -2343,14 +2357,10 @@ static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint trunc
return 0;
}
hData->mIrPoints = points;
- hData->mFftSize = fftSize;
if(fftSize <= 0)
{
- points = 1;
- while(points < (4 * hData->mIrPoints))
- points <<= 1;
- hData->mFftSize = points;
- hData->mIrSize = 1 + (points / 2);
+ hData->mFftSize = DEFAULT_FFTSIZE;
+ hData->mIrSize = 1 + (DEFAULT_FFTSIZE / 2);
}
else
{
@@ -2596,37 +2606,17 @@ static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src)
}
// Process the list of sources in the data set definition.
-static int ProcessSources(const HeadModelT model, const uint dstRate, TokenReaderT *tr, HrirDataT *hData)
+static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *hData)
{
uint *setCount, *setFlag;
uint line, col, ei, ai;
- uint res_points;
SourceRefT src;
double factor;
double *hrir;
- ResamplerT rs;
-
- ResamplerSetup(&rs, hData->mIrRate, dstRate);
- /* Scale the number of IR points for resampling. This could be improved by
- * also including space for the resampler build-up and fall-off (rs.mL*2),
- * instead of clipping them off, but that could affect the HRTDs. It's not
- * a big deal to exclude them for sources that aren't already minimum-
- * phase).
- */
- res_points = (uint)(((uint64)hData->mIrPoints*dstRate + hData->mIrRate-1) /
- hData->mIrRate);
- /* Clamp to the IR size to prevent overflow, and don't go less than the
- * original point count.
- */
- if(res_points > hData->mIrSize)
- res_points = hData->mIrSize;
- else if(res_points < hData->mIrPoints)
- res_points = hData->mIrPoints;
setCount = (uint*)calloc(hData->mEvCount, sizeof(uint));
setFlag = (uint*)calloc(hData->mIrCount, sizeof(uint));
- hrir = CreateArray(res_points);
-
+ hrir = CreateArray(hData->mIrPoints);
while(TrIsOperator(tr, "["))
{
TrIndication(tr, & line, & col);
@@ -2651,13 +2641,9 @@ static int ProcessSources(const HeadModelT model, const uint dstRate, TokenReade
if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir))
goto error;
- if(hData->mIrRate != dstRate)
- ResamplerRun(&rs, hData->mIrPoints, hrir,
- res_points, hrir);
-
if(model == HM_DATASET)
- AverageHrirOnset(hrir, res_points, 1.0 / factor, ei, ai, hData);
- AverageHrirMagnitude(hrir, res_points, 1.0 / factor, ei, ai, hData);
+ AverageHrirOnset(hrir, 1.0 / factor, ei, ai, hData);
+ AverageHrirMagnitude(hrir, 1.0 / factor, ei, ai, hData);
factor += 1.0;
if(!TrIsOperator(tr, "+"))
break;
@@ -2666,8 +2652,6 @@ static int ProcessSources(const HeadModelT model, const uint dstRate, TokenReade
setFlag[hData->mEvOffset[ei] + ai] = 1;
setCount[ei]++;
}
- hData->mIrPoints = res_points;
- hData->mIrRate = dstRate;
ei = 0;
while(ei < hData->mEvCount && setCount[ei] < 1)
@@ -2681,7 +2665,6 @@ static int ProcessSources(const HeadModelT model, const uint dstRate, TokenReade
{
if(!TrLoad(tr))
{
- ResamplerClear(&rs);
DestroyArray(hrir);
free(setFlag);
free(setCount);
@@ -2696,7 +2679,6 @@ static int ProcessSources(const HeadModelT model, const uint dstRate, TokenReade
TrError(tr, "Missing source references.\n");
error:
- ResamplerClear(&rs);
DestroyArray(hrir);
free(setFlag);
free(setCount);
@@ -2747,7 +2729,7 @@ static int ProcessDefinition(const char *inName, const uint outRate, const uint
}
hData.mHrirs = CreateArray(hData.mIrCount * hData.mIrSize);
hData.mHrtds = CreateArray(hData.mIrCount);
- if(!ProcessSources(model, outRate ? outRate : hData.mIrRate, &tr, &hData))
+ if(!ProcessSources(model, &tr, &hData))
{
DestroyArray(hData.mHrtds);
DestroyArray(hData.mHrirs);
@@ -2768,6 +2750,11 @@ static int ProcessDefinition(const char *inName, const uint outRate, const uint
}
fprintf(stdout, "Performing minimum phase reconstruction...\n");
ReconstructHrirs(&hData);
+ if(outRate != 0 && outRate != hData.mIrRate)
+ {
+ fprintf(stdout, "Resampling HRIRs...\n");
+ ResampleHrirs(outRate, &hData);
+ }
fprintf(stdout, "Truncating minimum-phase HRIRs...\n");
hData.mIrPoints = truncSize;
fprintf(stdout, "Synthesizing missing elevations...\n");
@@ -2809,8 +2796,7 @@ static void PrintHelp(const char *argv0, FILE *ofile)
fprintf(ofile, "Options:\n");
fprintf(ofile, " -r=<rate> Change the data set sample rate to the specified value and\n");
fprintf(ofile, " resample the HRIRs accordingly.\n");
- fprintf(ofile, " -f=<points> Override the FFT window size (defaults to the first power-\n");
- fprintf(ofile, " of-two that fits four times the number of HRIR points).\n");
+ fprintf(ofile, " -f=<points> Override the FFT window size (default: %u).\n", DEFAULT_FFTSIZE);
fprintf(ofile, " -e={on|off} Toggle diffuse-field equalization (default: %s).\n", (DEFAULT_EQUALIZE ? "on" : "off"));
fprintf(ofile, " -s={on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DEFAULT_SURFACE ? "on" : "off"));
fprintf(ofile, " -l={<dB>|none} Specify a limit to the magnitude range of the diffuse-field\n");
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/openal-soft.git
More information about the Pkg-games-commits
mailing list