Compare commits

...

104 Commits

Author SHA1 Message Date
Chris Robinson bf9c36408a Release 1.18.1 2017-07-29 22:09:21 -07:00
Chris Robinson 12db67f548 Cleanup output write functions 2017-07-27 19:07:02 -07:00
Chris Robinson e25ba747e6 Remove unused macros 2017-07-25 17:42:16 -07:00
Chris Robinson 11b44d29e6 Update default HRTFs 2017-07-25 17:11:44 -07:00
Chris Robinson 75841642bf Update makehrtf to use a larger FFT by default
Also fixes DC offset removal and increases the max IR size.
2017-07-25 16:17:46 -07:00
Chris Robinson 1ab082caaf Update ChangeLog with OSS enumeration fix 2017-07-23 22:10:13 -07:00
Chris Robinson 82a990e08e Downgrade some ERRs to TRACEs
These don't exist outside OSSv4, e.g. with OSS/Free, padsp, or aoss, so no need
to be concerned.
2017-07-23 16:43:39 -07:00
Chris Robinson 5ab4e584ee Make sure OSS device files exist before adding them 2017-07-23 16:38:54 -07:00
Chris Robinson 4ec67e6226 Add missing include for std::array 2017-07-23 00:18:32 -07:00
Chris Robinson 21b71b2fd2 Update ChangeLog 2017-07-19 18:54:12 -07:00
Chris Robinson f91445029d Fix default effect initialization 2017-07-19 18:26:46 -07:00
Chris Robinson fea74124c8 Add an all-pass filter that replicates the band splitter's phase shift 2017-07-19 02:48:01 -07:00
Chris Robinson 0135ddc2e5 Scale the source volume by +3dB for a full spread
This effectively turns a full spread source into an ambient response,
preventing such sources from being unexpectedly quiet.
2017-07-18 22:15:32 -07:00
Chris Robinson 5f7268c0cc Add a 5.1 preset that excludes the front-center speaker
On some speaker setups, the front-center speaker is not designed for full-range
content and should be used exclusively for dialog. Consequently it should not
be used for positional sounds, only the dedicated dialog effect.
2017-07-18 20:30:45 -07:00
Chris Robinson c484935542 Apply the output buffer offset before writing to it 2017-07-15 23:13:08 -07:00
Chris Robinson ff696bc1fe Set the float PCM GUID for wave files only when outputting float 2017-07-15 01:45:48 -07:00
Chris Robinson 8fa3f6da64 Add the default auxiliary slot to the active slot array 2017-07-13 23:13:02 -07:00
Chris Robinson 249afde5f9 Initialize the default effect after device update 2017-07-13 22:35:37 -07:00
Chris Robinson a535169bbd Use macros to set and restore the mixer FPU mode 2017-07-13 22:30:39 -07:00
Chris Robinson 22d77b87a3 Store the default effect slot in the context 2017-07-13 21:44:25 -07:00
Chris Robinson 67ab9ec466 Don't trace for every GetDriverIndexForName call 2017-07-11 22:43:22 -07:00
Chris Robinson 0da55fd912 Trace a version for the router 2017-07-11 00:43:15 -07:00
Chris Robinson 5048322fff Update alffplay's command line message 2017-07-11 00:38:52 -07:00
Chris Robinson f313f9c117 Rename the OpenAL target if also building the router
This is rather ugly, but it's necessary to get a proper export configuration.
The issue was that the main OpenAL target library name is set to soft_oal when
the router is being built, which is incorrect for the exported config library.
Exporting the router would have the incorrect name of OpenAL::Router.

So this change has the router use the OpenAL target name when it's built, which
is good since it will have the standard OpenAL lib name for apps to link to and
get the OpenAL::OpenAL export name. The main library's target name is changed
in this case to avoid conflicts.
2017-07-10 01:57:22 -07:00
Chris Robinson d6326c1791 Generate the def and lib files from the router when built 2017-07-09 23:14:31 -07:00
Chris Robinson d050af7eeb Reorganize some Windows-only CMake commands 2017-07-09 22:19:34 -07:00
Chris Robinson 2be4c93f9f Use a macro to add backend include dirs 2017-07-08 22:58:16 -07:00
Chris Robinson 09826cc684 Set the proper ldflags for the router 2017-07-07 18:48:19 -07:00
Chris Robinson e4e240fa9b Support ALC_EXT_thread_local_context in the router
Note that a given context's device must also support the extension to work. The
router's support simply lets a driver's capabilities through.
2017-07-07 18:41:03 -07:00
Chris Robinson 6be752a9b1 Add methods for thread-local contexts to the router 2017-07-07 18:33:54 -07:00
Chris Robinson faefa1d554 Revert "Try all drivers for an unknown device name"
This reverts commit dadf7a4cf2.
2017-07-05 14:18:16 -07:00
Chris Robinson 56a33ef955 Print the opened device in alffplay 2017-07-05 12:32:19 -07:00
Chris Robinson dadf7a4cf2 Try all drivers for an unknown device name 2017-07-05 12:23:08 -07:00
Chris Robinson 3af2ff7b25 Trace if a driver was found for a device name 2017-07-05 12:16:28 -07:00
Chris Robinson 72ce0d1e9c Open a device only when a driver index is found 2017-07-03 22:14:15 -07:00
Chris Robinson 3cd4cfe73d Don't add --output-def to EXTRA_LDFLAGS 2017-07-01 20:48:17 -07:00
Chris Robinson 74139c914d Skip past the -device switch even if the device doesn't open 2017-07-01 20:44:56 -07:00
Chris Robinson cb83f48105 Add an option to enable direct channels for alffplay 2017-07-01 19:18:57 -07:00
Chris Robinson a14f651034 Flush the log file after writing 2017-07-01 15:34:42 -07:00
Chris Robinson 958fa34272 Use a weaker memory order for the current context iface 2017-07-01 15:25:39 -07:00
Chris Robinson af626fdded Initialize ALC resources in the file they're used in 2017-07-01 15:25:11 -07:00
Chris Robinson 7daefd4e77 Use the al alloc functions instead of standard 2017-07-01 12:22:25 -07:00
Chris Robinson 32bda7b94c Add tracing capabilities to the router 2017-06-30 17:22:15 -07:00
Chris Robinson 77e317609b Add special handling for alGerError in the router 2017-06-30 17:21:26 -07:00
Chris Robinson ce9222b686 Clear initial ALC version vars before querying it 2017-06-29 23:21:07 -07:00
Chris Robinson 8a0d1e5191 Store the QSA backend's ExtraData in the wrapper struct 2017-06-29 17:38:38 -07:00
Chris Robinson d874b6bb27 Don't assume the first driver has the default device 2017-06-29 15:59:16 -07:00
Chris Robinson 00694826ef Protect context switches with a lock in the router 2017-06-29 10:56:32 -07:00
Chris Robinson 058d57ef03 Protect device enumeration in the router with a mutex 2017-06-29 10:39:27 -07:00
Chris Robinson e8ce8924d1 Use sqrtf for single-precision square roots 2017-06-29 10:28:37 -07:00
Chris Robinson ec13cf6c9c Add casts to silence MSVC 2017-06-29 10:28:22 -07:00
Chris Robinson a69d608a1e Define a backup log2f if the compiler doesn't have it 2017-06-29 10:11:31 -07:00
Chris Robinson aefa11b6ad Workaround for MSVC not liking 1.0f/0.0f for float infinity 2017-06-29 09:57:19 -07:00
Chris Robinson cee2d226d2 Return the extension list in the router 2017-06-29 08:55:44 -07:00
Chris Robinson f08a7b341f Prepare the new driver in a local variable 2017-06-29 08:46:06 -07:00
Chris Robinson 15e6821147 Avoid unnecessary reenumeration in the router 2017-06-29 08:35:21 -07:00
Chris Robinson 3a16fed279 Handle the ALC version for some extension capabilities
Also fix some improper parenthesis.
2017-06-28 23:18:39 -07:00
Chris Robinson ef7eced7a7 Properly clean up allocated memory at exit 2017-06-28 22:39:11 -07:00
Chris Robinson a729007887 Implement setting a context current in the router 2017-06-28 21:54:44 -07:00
Chris Robinson 323162c49f Implement creating and destroying contexts 2017-06-28 21:15:30 -07:00
Chris Robinson ea4379c5b7 Implement opening and closing devices in the router 2017-06-28 21:10:02 -07:00
Chris Robinson 6124f447cd Implement enumeration in the router 2017-06-28 20:45:23 -07:00
Chris Robinson 47f1db36a7 Partially implement ALC functions in the router 2017-06-28 20:03:36 -07:00
Chris Robinson b88b57868a Add a ptr-to-int map 2017-06-28 19:09:38 -07:00
Chris Robinson 9fd7349220 Add forwarding for the AL functions 2017-06-28 17:02:43 -07:00
Chris Robinson cfec20830b Load driver dlls in the router 2017-06-28 16:41:38 -07:00
Chris Robinson ebee8da05c Start a router DLL
Experimental, Windows only. This is intended as an alternative to Creative's
router DLL, fixing a few issues with it (falsely reporting extensions that
aren't supported, not being able to query the ALC version without a device, and
not being able to use ALC extension functions).

When enabled OpenAL Soft's DLL is built as soft_oal.dll, while the router is
OpenAL32.dll.
2017-06-28 12:42:20 -07:00
Chris Robinson 7cadbebe9f Calculate the converter stepping value using floating point 2017-06-28 10:17:36 -07:00
Chris Robinson e9a7218a06 Remove the fastf2u conversion function 2017-06-27 07:25:08 -07:00
Chris Robinson 8f2bbc434c Use a macro to apply NFC filtered mixes instead of a loop 2017-06-26 11:19:27 -07:00
Chris Robinson b13fead555 Round the converter's stepping value 2017-06-26 11:04:23 -07:00
Chris Robinson 2f2d941edb Trace the message name in the message handler loop 2017-06-26 08:57:29 -07:00
Chris Robinson 740e7d979c Convert all input samples in the loop
Instead of potentially leaving 1 sample that requires another loop iteration.
2017-06-26 08:55:22 -07:00
Chris Robinson 464a7c0545 Update ChangeLog for mmdevapi fix 2017-06-26 07:09:17 -07:00
Chris Robinson 55c329b462 Clean up some messy rounding code 2017-06-26 06:54:45 -07:00
Chris Robinson 5d5eff7502 Ensure the mmdevapi capture buffer is at least 100ms 2017-06-26 06:14:11 -07:00
Chris Robinson 4b7cbb50ab Add a whitenoise generator to altonegen 2017-06-25 08:00:55 -07:00
Chris Robinson be552a35e6 Support 32-bit float with the recording example 2017-06-25 06:10:20 -07:00
Chris Robinson 1deb8b6160 Clean up some loop variables 2017-06-25 05:42:35 -07:00
Chris Robinson c465718ddd Use the bsinc resampler for the converter 2017-06-25 04:07:06 -07:00
Chris Robinson d1bb04d588 Improve traces for the mmdevapi capture conversions 2017-06-23 09:54:26 -07:00
Chris Robinson d70a98fe03 Use the correct destination channel offset 2017-06-23 08:25:47 -07:00
Chris Robinson 9d01ac440d Don't report any output samples for no input samples 2017-06-23 08:13:42 -07:00
Chris Robinson 44a940d8d6 Forward Sample_ALuint to Sample_ALint 2017-06-23 05:34:43 -07:00
Chris Robinson e07166e93c Add a recording example app 2017-06-23 05:19:24 -07:00
Chris Robinson d1077795de Stop conversion when no more source samples are available 2017-06-22 15:07:24 -07:00
Chris Robinson 31b02e044f Trace the capture converter formats for mmdevapi 2017-06-22 13:58:32 -07:00
Chris Robinson 552d3a85af Workaround log2f missing on Android 2017-06-21 23:05:11 -07:00
Chris Robinson 6fcbb7c738 Remove an unnecessary variable 2017-06-21 11:34:26 -07:00
Chris Robinson e09468cdca Trace if dithering is enabled 2017-06-19 00:17:11 -07:00
Chris Robinson 36edd80073 Update ChangeLog for the dither-depth config option 2017-06-18 04:14:56 -07:00
Chris Robinson 0a361fa9e2 "Convert" the QSA backend to the new API
I say "convert" because it takes the lazy way and essentially just embeds the
wrappers into the backend. It's done this way because I lack the means to check
any changes, even syntactically. This also means the device's ExtraData field
is still needed.

However, this does mean all the backends are now using the new API. Code
related to the old interface can now be removed.
2017-06-18 03:07:02 -07:00
Chris Robinson 2b013fc54e Make the dithering depth configurable 2017-06-17 23:09:51 -07:00
Chris Robinson e3a825b37c Apply dither separately from output 2017-06-17 02:42:01 -07:00
Chris Robinson 9fc01934c2 Use helpers to get data from byte streams 2017-06-16 22:58:13 -07:00
Chris Robinson 879b79740f Round the B-Format HRTF response where the multiple is defined 2017-06-16 19:00:00 -07:00
Chris Robinson e18f7ca3e4 Update ChangeLog with the PulseAudio fix 2017-06-15 23:13:25 -07:00
Chris Robinson d4f3490a88 Limit device buffer based on PulseAudio's tlength
Unfortunately PulseAudio has a habit of limiting tlength, and trying to
calculate the device's buffer length to write regardless of tlength could
result in some amount always being writable.
2017-06-15 21:39:09 -07:00
Chris Robinson 1e8feeff03 Update ChangeLog with recent fixes 2017-06-11 16:38:51 -07:00
Chris Robinson a35b9bbd3e Don't force a fade-in when resuming a paused source
This needs to be handled more automatically by the mixer to work correctly.
Otherwise, requiring a property update on resume can put the source into a
playing state with the mixer never playing it, due to not having valid mixing
parameters and the mixing parameters not getting calculated because no updates
are specified by the app (and forcing an update can break deferred updates).
2017-06-09 13:32:34 -07:00
kcat ba0644254c Merge pull request #123 from rdb/master
Implement GetProcPath for FreeBSD
2017-06-09 12:14:56 -07:00
rdb 39e4756b37 Implement GetProcPath for FreeBSD 2017-06-09 15:19:03 +02:00
Chris Robinson b4aea294c3 Calculate chorus and flanger mod delays separately from feedback 2017-06-07 12:42:54 -07:00
Chris Robinson 10ff6cba9c Make the late lines' delay the delay average for modulation
Similar to the recent chorus and flanger changes, the modulation delay now
swings between -n to +n, where n is less than the delay length. This brings up
a slight issue with the linear interpolation, as modff doesn't produce the
correct fraction value for interpolation (it's inverted, with 0 being closer to
the next sample and 1 being closer to the base). So it's using nearest
interpolation for now.
2017-06-07 10:39:19 -07:00
46 changed files with 3407 additions and 1072 deletions
+123 -133
View File
@@ -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);
{
+101 -173
View File
@@ -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;
/* NOTE: Non-dithered conversions have unused extra parameters. */
static inline ALfloat aluF2F(ALfloat val, ...)
/* 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;
}
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;
if(device->DitherDepth > 0.0f)
ApplyDither(Buffer, &device->DitherSeed, device->DitherDepth, SamplesToDo,
Channels);
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;
#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;
}
}
-154
View File
@@ -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;
}
+1 -2
View File
@@ -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 */
+34 -11
View File
@@ -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,
+12 -4
View File
@@ -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;
+9 -10
View File
@@ -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);
+201 -47
View File
@@ -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)
{
*func_list = qsa_funcs;
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;
}
void alc_qsa_deinit(void)
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))
{
return ALC_TRUE;
}
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);
}
+3 -2
View File
@@ -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);
+39
View File
@@ -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
+12
View File
@@ -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 */
+30 -16
View File
@@ -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;
}
+1
View File
@@ -19,6 +19,7 @@ typedef struct SampleConverter {
ALsizei mFracOffset;
ALsizei mIncrement;
InterpState mState;
ResamplerFunc mResample;
alignas(16) ALfloat mSrcSamples[BUFFERSIZE];
+60 -68
View File
@@ -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;
ALsizei i;
for(i = 0;i < todo;i++)
{
delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
offset = (offset+1)%lfo_range;
}
}
#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; \
}
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++)
{
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;
}
+59 -68
View File
@@ -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;
ALsizei i;
for(i = 0;i < todo;i++)
{
delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
offset = (offset+1)%lfo_range;
}
}
#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; \
}
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;
}
+1 -1
View File
@@ -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;
+44 -67
View File
@@ -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); \
+23 -2
View File
@@ -40,6 +40,10 @@
#include <dirent.h>
#endif
#ifdef __FreeBSD__
#include <sys/sysctl.h>
#endif
#ifndef AL_NO_UID_DEFS
#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
#define INITGUID
@@ -113,8 +117,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;
@@ -707,9 +713,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 +757,8 @@ al_string GetProcPath(void)
}
pathname[len] = 0;
#endif
sep = strrchr(pathname, '/');
if(sep)
alstr_copy_range(&ret, pathname, sep);
+55 -53
View File
@@ -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);
-4
View File
@@ -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.
*/
+1 -1
View File
@@ -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;
+16 -18
View File
@@ -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
+7 -9
View File
@@ -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)
+119 -72
View File
@@ -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 "1")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}")
SET(EXPORT_DECL "")
@@ -501,6 +503,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)
@@ -1192,91 +1195,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})
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)
IF(WIN32 AND ALSOFT_NO_UID_DEFS)
SET_PROPERTY(TARGET OpenAL 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})
ENDIF()
IF(WIN32)
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")
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_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 ${IMPL_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS)
ENDIF()
SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS})
SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY LINK_FLAGS ${EXTRA_LDFLAGS})
SET_TARGET_PROPERTIES(OpenAL PROPERTIES VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION})
SET_TARGET_PROPERTIES(OpenAL PROPERTIES OUTPUT_NAME ${LIBNAME})
TARGET_LINK_LIBRARIES(${IMPL_TARGET} ${EXTRA_LIBS})
IF(TARGET build_version)
ADD_DEPENDENCIES(${IMPL_TARGET} build_version)
ENDIF()
if(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
SET_TARGET_PROPERTIES(OpenAL PROPERTIES PREFIX "")
IF(WIN32)
IF(MSVC)
SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " /SUBSYSTEM:WINDOWS")
ELSEIF(CMAKE_COMPILER_IS_GNUCC)
SET_PROPERTY(TARGET ${IMPL_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -mwindows")
ENDIF()
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")
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()
IF(NOT DLLTOOL_EXECUTABLE)
MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation")
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 +1323,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 +1442,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 +1532,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}
+19
View File
@@ -1,3 +1,22 @@
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.
+1 -1
View File
@@ -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];
+34 -34
View File
@@ -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[];
};
@@ -918,6 +907,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;
+3 -1
View File
@@ -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);
+3 -4
View File
@@ -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)
{
+1 -11
View File
@@ -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;
+10 -3
View File
@@ -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
+1 -1
View File
@@ -1,4 +1,4 @@
version: 1.18.0.{build}
version: 1.18.1.{build}
environment:
matrix:
+12 -1
View File
@@ -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))
+2 -2
View File
@@ -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);
+3
View File
@@ -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
+29 -6
View File
@@ -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++]));
+386
View File
@@ -0,0 +1,386 @@
/*
* OpenAL Recording Example
*
* Copyright (c) 2017 by Chris Robinson <chris.kcat@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* This file contains a relatively simple 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;
}
+50 -19
View File
@@ -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]);
}
Binary file not shown.
Binary file not shown.
+46
View File
@@ -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
+132
View File
@@ -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)
+956
View File
@@ -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;
}
+512
View File
@@ -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;
}
+196
View File
@@ -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 */
+60 -74
View File
@@ -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");