--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <ctype.h>
+
+#include "alMain.h"
+#include "alSource.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alThunk.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alAuxEffectSlot.h"
+#include "alDatabuffer.h"
+#include "bs2b.h"
+#include "alu.h"
+#if defined(USE_DLOG)
+#include <dlog.h>
+#endif
+
+#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+typedef struct BackendInfo {
+ const char *name;
+ void (*Init)(BackendFuncs*);
+ void (*Deinit)(void);
+ void (*Probe)(int);
+ BackendFuncs Funcs;
+} BackendInfo;
+static BackendInfo BackendList[] = {
+#ifdef HAVE_PULSEAUDIO
+ { "pulse", alc_pulse_init, alc_pulse_deinit, alc_pulse_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_ALSA
+ { "alsa", alc_alsa_init, alc_alsa_deinit, alc_alsa_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_OSS
+ { "oss", alc_oss_init, alc_oss_deinit, alc_oss_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_SOLARIS
+ { "solaris", alc_solaris_init, alc_solaris_deinit, alc_solaris_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_DSOUND
+ { "dsound", alcDSoundInit, alcDSoundDeinit, alcDSoundProbe, EmptyFuncs },
+#endif
+#ifdef HAVE_WINMM
+ { "winmm", alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs },
+#endif
+#ifdef HAVE_PORTAUDIO
+ { "port", alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs },
+#endif
+
+ { "null", alc_null_init, alc_null_deinit, alc_null_probe, EmptyFuncs },
+#ifdef HAVE_WAVE
+ { "wave", alc_wave_init, alc_wave_deinit, alc_wave_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_AVSYSTEM
+ { "avsystem", alc_avsystem_init, alc_avsystem_deinit, alc_avsystem_probe, EmptyFuncs },
+#endif
+
+ { NULL, NULL, NULL, NULL, EmptyFuncs }
+};
+#undef EmptyFuncs
+
+///////////////////////////////////////////////////////
+
+#define ALC_EFX_MAJOR_VERSION 0x20001
+#define ALC_EFX_MINOR_VERSION 0x20002
+#define ALC_MAX_AUXILIARY_SENDS 0x20003
+
+///////////////////////////////////////////////////////
+// STRING and EXTENSIONS
+
+typedef struct ALCfunction {
+ const ALCchar *funcName;
+ ALCvoid *address;
+} ALCfunction;
+
+typedef struct ALCenums {
+ const ALCchar *enumName;
+ ALCenum value;
+} ALCenums;
+
+
+static const ALCfunction alcFunctions[] = {
+ { "alcCreateContext", (ALCvoid *) alcCreateContext },
+ { "alcMakeContextCurrent", (ALCvoid *) alcMakeContextCurrent },
+ { "alcProcessContext", (ALCvoid *) alcProcessContext },
+ { "alcSuspendContext", (ALCvoid *) alcSuspendContext },
+ { "alcDestroyContext", (ALCvoid *) alcDestroyContext },
+ { "alcGetCurrentContext", (ALCvoid *) alcGetCurrentContext },
+ { "alcGetContextsDevice", (ALCvoid *) alcGetContextsDevice },
+ { "alcOpenDevice", (ALCvoid *) alcOpenDevice },
+ { "alcCloseDevice", (ALCvoid *) alcCloseDevice },
+ { "alcGetError", (ALCvoid *) alcGetError },
+ { "alcIsExtensionPresent", (ALCvoid *) alcIsExtensionPresent },
+ { "alcGetProcAddress", (ALCvoid *) alcGetProcAddress },
+ { "alcGetEnumValue", (ALCvoid *) alcGetEnumValue },
+ { "alcGetString", (ALCvoid *) alcGetString },
+ { "alcGetIntegerv", (ALCvoid *) alcGetIntegerv },
+ { "alcCaptureOpenDevice", (ALCvoid *) alcCaptureOpenDevice },
+ { "alcCaptureCloseDevice", (ALCvoid *) alcCaptureCloseDevice },
+ { "alcCaptureStart", (ALCvoid *) alcCaptureStart },
+ { "alcCaptureStop", (ALCvoid *) alcCaptureStop },
+ { "alcCaptureSamples", (ALCvoid *) alcCaptureSamples },
+
+ { "alcSetThreadContext", (ALCvoid *) alcSetThreadContext },
+ { "alcGetThreadContext", (ALCvoid *) alcGetThreadContext },
+
+ { "alEnable", (ALCvoid *) alEnable },
+ { "alDisable", (ALCvoid *) alDisable },
+ { "alIsEnabled", (ALCvoid *) alIsEnabled },
+ { "alGetString", (ALCvoid *) alGetString },
+ { "alGetBooleanv", (ALCvoid *) alGetBooleanv },
+ { "alGetIntegerv", (ALCvoid *) alGetIntegerv },
+ { "alGetFloatv", (ALCvoid *) alGetFloatv },
+ { "alGetDoublev", (ALCvoid *) alGetDoublev },
+ { "alGetBoolean", (ALCvoid *) alGetBoolean },
+ { "alGetInteger", (ALCvoid *) alGetInteger },
+ { "alGetFloat", (ALCvoid *) alGetFloat },
+ { "alGetDouble", (ALCvoid *) alGetDouble },
+ { "alGetError", (ALCvoid *) alGetError },
+ { "alIsExtensionPresent", (ALCvoid *) alIsExtensionPresent },
+ { "alGetProcAddress", (ALCvoid *) alGetProcAddress },
+ { "alGetEnumValue", (ALCvoid *) alGetEnumValue },
+ { "alListenerf", (ALCvoid *) alListenerf },
+ { "alListener3f", (ALCvoid *) alListener3f },
+ { "alListenerfv", (ALCvoid *) alListenerfv },
+ { "alListeneri", (ALCvoid *) alListeneri },
+ { "alListener3i", (ALCvoid *) alListener3i },
+ { "alListeneriv", (ALCvoid *) alListeneriv },
+ { "alGetListenerf", (ALCvoid *) alGetListenerf },
+ { "alGetListener3f", (ALCvoid *) alGetListener3f },
+ { "alGetListenerfv", (ALCvoid *) alGetListenerfv },
+ { "alGetListeneri", (ALCvoid *) alGetListeneri },
+ { "alGetListener3i", (ALCvoid *) alGetListener3i },
+ { "alGetListeneriv", (ALCvoid *) alGetListeneriv },
+ { "alGenSources", (ALCvoid *) alGenSources },
+ { "alDeleteSources", (ALCvoid *) alDeleteSources },
+ { "alIsSource", (ALCvoid *) alIsSource },
+ { "alSourcef", (ALCvoid *) alSourcef },
+ { "alSource3f", (ALCvoid *) alSource3f },
+ { "alSourcefv", (ALCvoid *) alSourcefv },
+ { "alSourcei", (ALCvoid *) alSourcei },
+ { "alSource3i", (ALCvoid *) alSource3i },
+ { "alSourceiv", (ALCvoid *) alSourceiv },
+ { "alGetSourcef", (ALCvoid *) alGetSourcef },
+ { "alGetSource3f", (ALCvoid *) alGetSource3f },
+ { "alGetSourcefv", (ALCvoid *) alGetSourcefv },
+ { "alGetSourcei", (ALCvoid *) alGetSourcei },
+ { "alGetSource3i", (ALCvoid *) alGetSource3i },
+ { "alGetSourceiv", (ALCvoid *) alGetSourceiv },
+ { "alSourcePlayv", (ALCvoid *) alSourcePlayv },
+ { "alSourceStopv", (ALCvoid *) alSourceStopv },
+ { "alSourceRewindv", (ALCvoid *) alSourceRewindv },
+ { "alSourcePausev", (ALCvoid *) alSourcePausev },
+ { "alSourcePlay", (ALCvoid *) alSourcePlay },
+ { "alSourceStop", (ALCvoid *) alSourceStop },
+ { "alSourceRewind", (ALCvoid *) alSourceRewind },
+ { "alSourcePause", (ALCvoid *) alSourcePause },
+ { "alSourceQueueBuffers", (ALCvoid *) alSourceQueueBuffers },
+ { "alSourceUnqueueBuffers", (ALCvoid *) alSourceUnqueueBuffers },
+ { "alGenBuffers", (ALCvoid *) alGenBuffers },
+ { "alDeleteBuffers", (ALCvoid *) alDeleteBuffers },
+ { "alIsBuffer", (ALCvoid *) alIsBuffer },
+ { "alBufferData", (ALCvoid *) alBufferData },
+ { "alBufferf", (ALCvoid *) alBufferf },
+ { "alBuffer3f", (ALCvoid *) alBuffer3f },
+ { "alBufferfv", (ALCvoid *) alBufferfv },
+ { "alBufferi", (ALCvoid *) alBufferi },
+ { "alBuffer3i", (ALCvoid *) alBuffer3i },
+ { "alBufferiv", (ALCvoid *) alBufferiv },
+ { "alGetBufferf", (ALCvoid *) alGetBufferf },
+ { "alGetBuffer3f", (ALCvoid *) alGetBuffer3f },
+ { "alGetBufferfv", (ALCvoid *) alGetBufferfv },
+ { "alGetBufferi", (ALCvoid *) alGetBufferi },
+ { "alGetBuffer3i", (ALCvoid *) alGetBuffer3i },
+ { "alGetBufferiv", (ALCvoid *) alGetBufferiv },
+ { "alDopplerFactor", (ALCvoid *) alDopplerFactor },
+ { "alDopplerVelocity", (ALCvoid *) alDopplerVelocity },
+ { "alSpeedOfSound", (ALCvoid *) alSpeedOfSound },
+ { "alDistanceModel", (ALCvoid *) alDistanceModel },
+
+ { "alGenFilters", (ALCvoid *) alGenFilters },
+ { "alDeleteFilters", (ALCvoid *) alDeleteFilters },
+ { "alIsFilter", (ALCvoid *) alIsFilter },
+ { "alFilteri", (ALCvoid *) alFilteri },
+ { "alFilteriv", (ALCvoid *) alFilteriv },
+ { "alFilterf", (ALCvoid *) alFilterf },
+ { "alFilterfv", (ALCvoid *) alFilterfv },
+ { "alGetFilteri", (ALCvoid *) alGetFilteri },
+ { "alGetFilteriv", (ALCvoid *) alGetFilteriv },
+ { "alGetFilterf", (ALCvoid *) alGetFilterf },
+ { "alGetFilterfv", (ALCvoid *) alGetFilterfv },
+
+ { "alGenEffects", (ALCvoid *) alGenEffects },
+ { "alDeleteEffects", (ALCvoid *) alDeleteEffects },
+ { "alIsEffect", (ALCvoid *) alIsEffect },
+ { "alEffecti", (ALCvoid *) alEffecti },
+ { "alEffectiv", (ALCvoid *) alEffectiv },
+ { "alEffectf", (ALCvoid *) alEffectf },
+ { "alEffectfv", (ALCvoid *) alEffectfv },
+ { "alGetEffecti", (ALCvoid *) alGetEffecti },
+ { "alGetEffectiv", (ALCvoid *) alGetEffectiv },
+ { "alGetEffectf", (ALCvoid *) alGetEffectf },
+ { "alGetEffectfv", (ALCvoid *) alGetEffectfv },
+
+ { "alGenAuxiliaryEffectSlots", (ALCvoid *) alGenAuxiliaryEffectSlots},
+ { "alDeleteAuxiliaryEffectSlots",(ALCvoid *) alDeleteAuxiliaryEffectSlots},
+ { "alIsAuxiliaryEffectSlot", (ALCvoid *) alIsAuxiliaryEffectSlot },
+ { "alAuxiliaryEffectSloti", (ALCvoid *) alAuxiliaryEffectSloti },
+ { "alAuxiliaryEffectSlotiv", (ALCvoid *) alAuxiliaryEffectSlotiv },
+ { "alAuxiliaryEffectSlotf", (ALCvoid *) alAuxiliaryEffectSlotf },
+ { "alAuxiliaryEffectSlotfv", (ALCvoid *) alAuxiliaryEffectSlotfv },
+ { "alGetAuxiliaryEffectSloti", (ALCvoid *) alGetAuxiliaryEffectSloti},
+ { "alGetAuxiliaryEffectSlotiv", (ALCvoid *) alGetAuxiliaryEffectSlotiv},
+ { "alGetAuxiliaryEffectSlotf", (ALCvoid *) alGetAuxiliaryEffectSlotf},
+ { "alGetAuxiliaryEffectSlotfv", (ALCvoid *) alGetAuxiliaryEffectSlotfv},
+
+ { "alBufferSubDataSOFT", (ALCvoid *) alBufferSubDataSOFT },
+#if 0
+ { "alGenDatabuffersEXT", (ALCvoid *) alGenDatabuffersEXT },
+ { "alDeleteDatabuffersEXT", (ALCvoid *) alDeleteDatabuffersEXT },
+ { "alIsDatabufferEXT", (ALCvoid *) alIsDatabufferEXT },
+ { "alDatabufferDataEXT", (ALCvoid *) alDatabufferDataEXT },
+ { "alDatabufferSubDataEXT", (ALCvoid *) alDatabufferSubDataEXT },
+ { "alGetDatabufferSubDataEXT", (ALCvoid *) alGetDatabufferSubDataEXT},
+ { "alDatabufferfEXT", (ALCvoid *) alDatabufferfEXT },
+ { "alDatabufferfvEXT", (ALCvoid *) alDatabufferfvEXT },
+ { "alDatabufferiEXT", (ALCvoid *) alDatabufferiEXT },
+ { "alDatabufferivEXT", (ALCvoid *) alDatabufferivEXT },
+ { "alGetDatabufferfEXT", (ALCvoid *) alGetDatabufferfEXT },
+ { "alGetDatabufferfvEXT", (ALCvoid *) alGetDatabufferfvEXT },
+ { "alGetDatabufferiEXT", (ALCvoid *) alGetDatabufferiEXT },
+ { "alGetDatabufferivEXT", (ALCvoid *) alGetDatabufferivEXT },
+ { "alSelectDatabufferEXT", (ALCvoid *) alSelectDatabufferEXT },
+ { "alMapDatabufferEXT", (ALCvoid *) alMapDatabufferEXT },
+ { "alUnmapDatabufferEXT", (ALCvoid *) alUnmapDatabufferEXT },
+#endif
+ { NULL, (ALCvoid *) NULL }
+};
+
+static const ALCenums enumeration[] = {
+ // Types
+ { "ALC_INVALID", ALC_INVALID },
+ { "ALC_FALSE", ALC_FALSE },
+ { "ALC_TRUE", ALC_TRUE },
+
+ // ALC Properties
+ { "ALC_MAJOR_VERSION", ALC_MAJOR_VERSION },
+ { "ALC_MINOR_VERSION", ALC_MINOR_VERSION },
+ { "ALC_ATTRIBUTES_SIZE", ALC_ATTRIBUTES_SIZE },
+ { "ALC_ALL_ATTRIBUTES", ALC_ALL_ATTRIBUTES },
+ { "ALC_DEFAULT_DEVICE_SPECIFIER", ALC_DEFAULT_DEVICE_SPECIFIER },
+ { "ALC_DEVICE_SPECIFIER", ALC_DEVICE_SPECIFIER },
+ { "ALC_ALL_DEVICES_SPECIFIER", ALC_ALL_DEVICES_SPECIFIER },
+ { "ALC_DEFAULT_ALL_DEVICES_SPECIFIER", ALC_DEFAULT_ALL_DEVICES_SPECIFIER },
+ { "ALC_EXTENSIONS", ALC_EXTENSIONS },
+ { "ALC_FREQUENCY", ALC_FREQUENCY },
+ { "ALC_REFRESH", ALC_REFRESH },
+ { "ALC_SYNC", ALC_SYNC },
+ { "ALC_MONO_SOURCES", ALC_MONO_SOURCES },
+ { "ALC_STEREO_SOURCES", ALC_STEREO_SOURCES },
+ { "ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER },
+ { "ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER},
+ { "ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES },
+ { "ALC_CONNECTED", ALC_CONNECTED },
+
+ // EFX Properties
+ { "ALC_EFX_MAJOR_VERSION", ALC_EFX_MAJOR_VERSION },
+ { "ALC_EFX_MINOR_VERSION", ALC_EFX_MINOR_VERSION },
+ { "ALC_MAX_AUXILIARY_SENDS", ALC_MAX_AUXILIARY_SENDS },
+
+ // ALC Error Message
+ { "ALC_NO_ERROR", ALC_NO_ERROR },
+ { "ALC_INVALID_DEVICE", ALC_INVALID_DEVICE },
+ { "ALC_INVALID_CONTEXT", ALC_INVALID_CONTEXT },
+ { "ALC_INVALID_ENUM", ALC_INVALID_ENUM },
+ { "ALC_INVALID_VALUE", ALC_INVALID_VALUE },
+ { "ALC_OUT_OF_MEMORY", ALC_OUT_OF_MEMORY },
+ { NULL, (ALCenum)0 }
+};
+// Error strings
+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";
+
+/* Device lists. Sizes only include the first ending null character, not the
+ * second */
+static ALCchar *alcDeviceList;
+static size_t alcDeviceListSize;
+static ALCchar *alcAllDeviceList;
+static size_t alcAllDeviceListSize;
+static ALCchar *alcCaptureDeviceList;
+static size_t alcCaptureDeviceListSize;
+// Default is always the first in the list
+static ALCchar *alcDefaultDeviceSpecifier;
+static ALCchar *alcDefaultAllDeviceSpecifier;
+static ALCchar *alcCaptureDefaultDeviceSpecifier;
+
+
+static const ALCchar alcNoDeviceExtList[] =
+ "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
+ "ALC_EXT_thread_local_context";
+static const ALCchar alcExtensionList[] =
+ "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
+ "ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context";
+static const ALCint alcMajorVersion = 1;
+static const ALCint alcMinorVersion = 1;
+
+static const ALCint alcEFXMajorVersion = 1;
+static const ALCint alcEFXMinorVersion = 0;
+
+///////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////
+// Global Variables
+
+static ALCdevice *g_pDeviceList = NULL;
+static ALCuint g_ulDeviceCount = 0;
+
+static CRITICAL_SECTION g_csMutex;
+
+// Context List
+static ALCcontext *g_pContextList = NULL;
+static ALCuint g_ulContextCount = 0;
+
+// Thread-local current context
+static tls_type LocalContext;
+// Process-wide current context
+static ALCcontext *GlobalContext;
+
+// Context Error
+static ALCenum g_eLastNullDeviceError = ALC_NO_ERROR;
+
+// Default context extensions
+static const ALchar alExtList[] =
+ "AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 "
+ "AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW "
+ "AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model "
+ "AL_LOKI_quadriphonic AL_SOFT_buffer_sub_data AL_SOFT_loop_points";
+
+// Mixing Priority Level
+static ALint RTPrioLevel;
+
+// Output Log File
+static FILE *LogFile;
+
+///////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////
+// ALC Related helper functions
+static void ReleaseALC(void);
+
+#ifdef HAVE_GCC_DESTRUCTOR
+static void alc_init(void) __attribute__((constructor));
+static void alc_deinit(void) __attribute__((destructor));
+#else
+#ifdef _WIN32
+static void alc_init(void);
+static void alc_deinit(void);
+
+BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
+{
+ (void)lpReserved;
+
+ // Perform actions based on the reason for calling.
+ switch(ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hModule);
+ alc_init();
+ break;
+
+ case DLL_PROCESS_DETACH:
+ alc_deinit();
+ break;
+ }
+ return TRUE;
+}
+#endif
+#endif
+
+static void alc_init(void)
+{
+ int i;
+ const char *devs, *str;
+
+ str = getenv("ALSOFT_LOGFILE");
+ if(str && str[0])
+ {
+ LogFile = fopen(str, "w");
+ if(!LogFile)
+ fprintf(stderr, "AL lib: Failed to open log file '%s'\n", str);
+ }
+ if(!LogFile)
+ LogFile = stderr;
+
+ InitializeCriticalSection(&g_csMutex);
+ ALTHUNK_INIT();
+ ReadALConfig();
+
+ tls_create(&LocalContext);
+
+ RTPrioLevel = GetConfigValueInt(NULL, "rt-prio", 0);
+
+ DefaultResampler = GetConfigValueInt(NULL, "resampler", RESAMPLER_DEFAULT);
+ if(DefaultResampler >= RESAMPLER_MAX || DefaultResampler <= RESAMPLER_MIN)
+ DefaultResampler = RESAMPLER_DEFAULT;
+
+ devs = GetConfigValue(NULL, "drivers", "");
+ if(devs[0])
+ {
+ int n;
+ size_t len;
+ const char *next = devs;
+ int endlist, delitem;
+
+ i = 0;
+ do {
+ devs = next;
+ next = strchr(devs, ',');
+
+ delitem = (devs[0] == '-');
+ if(devs[0] == '-') devs++;
+
+ if(!devs[0] || devs[0] == ',')
+ {
+ endlist = 0;
+ continue;
+ }
+ endlist = 1;
+
+ len = (next ? ((size_t)(next-devs)) : strlen(devs));
+ for(n = i;BackendList[n].Init;n++)
+ {
+ if(len == strlen(BackendList[n].name) &&
+ strncmp(BackendList[n].name, devs, len) == 0)
+ {
+ if(delitem)
+ {
+ do {
+ BackendList[n] = BackendList[n+1];
+ ++n;
+ } while(BackendList[n].Init);
+ }
+ else
+ {
+ BackendInfo Bkp = BackendList[n];
+ while(n > i)
+ {
+ BackendList[n] = BackendList[n-1];
+ --n;
+ }
+ BackendList[n] = Bkp;
+
+ i++;
+ }
+ break;
+ }
+ }
+ } while(next++);
+
+ if(endlist)
+ {
+ BackendList[i].name = NULL;
+ BackendList[i].Init = NULL;
+ BackendList[i].Deinit = NULL;
+ BackendList[i].Probe = NULL;
+ }
+ }
+
+ for(i = 0;BackendList[i].Init;i++)
+ BackendList[i].Init(&BackendList[i].Funcs);
+
+ str = GetConfigValue(NULL, "excludefx", "");
+ if(str[0])
+ {
+ const struct {
+ const char *name;
+ int type;
+ } EffectList[] = {
+ { "eaxreverb", EAXREVERB },
+ { "reverb", REVERB },
+ { "echo", ECHO },
+ { "modulator", MODULATOR },
+ { NULL, 0 }
+ };
+ int n;
+ size_t len;
+ const char *next = str;
+
+ do {
+ str = next;
+ next = strchr(str, ',');
+
+ if(!str[0] || next == str)
+ continue;
+
+ len = (next ? ((size_t)(next-str)) : strlen(str));
+ for(n = 0;EffectList[n].name;n++)
+ {
+ if(len == strlen(EffectList[n].name) &&
+ strncmp(EffectList[n].name, str, len) == 0)
+ DisabledEffects[EffectList[n].type] = AL_TRUE;
+ }
+ } while(next++);
+ }
+}
+
+static void alc_deinit(void)
+{
+ int i;
+
+ ReleaseALC();
+
+ for(i = 0;BackendList[i].Deinit;i++)
+ BackendList[i].Deinit();
+
+ tls_delete(LocalContext);
+
+ FreeALConfig();
+ ALTHUNK_EXIT();
+ DeleteCriticalSection(&g_csMutex);
+
+ if(LogFile != stderr)
+ fclose(LogFile);
+ LogFile = NULL;
+}
+
+
+static void ProbeDeviceList()
+{
+ ALint i;
+
+ free(alcDeviceList); alcDeviceList = NULL;
+ alcDeviceListSize = 0;
+
+ for(i = 0;BackendList[i].Probe;i++)
+ BackendList[i].Probe(DEVICE_PROBE);
+}
+
+static void ProbeAllDeviceList()
+{
+ ALint i;
+
+ free(alcAllDeviceList); alcAllDeviceList = NULL;
+ alcAllDeviceListSize = 0;
+
+ for(i = 0;BackendList[i].Probe;i++)
+ BackendList[i].Probe(ALL_DEVICE_PROBE);
+}
+
+static void ProbeCaptureDeviceList()
+{
+ ALint i;
+
+ free(alcCaptureDeviceList); alcCaptureDeviceList = NULL;
+ alcCaptureDeviceListSize = 0;
+
+ for(i = 0;BackendList[i].Probe;i++)
+ BackendList[i].Probe(CAPTURE_DEVICE_PROBE);
+}
+
+
+static void AppendList(const ALCchar *name, ALCchar **List, size_t *ListSize)
+{
+ size_t len = strlen(name);
+ void *temp;
+
+ if(len == 0)
+ return;
+
+ temp = realloc(*List, (*ListSize) + len + 2);
+ if(!temp)
+ {
+ AL_PRINT("Realloc failed to add %s!\n", name);
+ return;
+ }
+ *List = temp;
+
+ memcpy((*List)+(*ListSize), name, len+1);
+ *ListSize += len+1;
+ (*List)[*ListSize] = 0;
+}
+
+#define DECL_APPEND_LIST_FUNC(type) \
+void Append##type##List(const ALCchar *name) \
+{ AppendList(name, &alc##type##List, &alc##type##ListSize); }
+
+DECL_APPEND_LIST_FUNC(Device)
+DECL_APPEND_LIST_FUNC(AllDevice)
+DECL_APPEND_LIST_FUNC(CaptureDevice)
+
+#undef DECL_APPEND_LIST_FUNC
+
+
+void al_print(const char *fname, unsigned int line, const char *fmt, ...)
+{
+ const char *fn;
+ char str[256];
+ int i;
+
+ fn = strrchr(fname, '/');
+ if(!fn) fn = strrchr(fname, '\\');;
+ if(!fn) fn = fname;
+ else fn += 1;
+
+ i = snprintf(str, sizeof(str), "AL lib: %s:%d: ", fn, line);
+ if(i < (int)sizeof(str) && i > 0)
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(str+i, sizeof(str)-i, fmt, ap);
+ va_end(ap);
+ }
+ str[sizeof(str)-1] = 0;
+#if defined(USE_DLOG)
+ SLOG(LOG_WARN, "MMFW_OPENAL", "%s", str);
+#else
+ fprintf(LogFile, "%s", str);
+#endif
+ fflush(LogFile);
+}
+
+void SetRTPriority(void)
+{
+ ALboolean failed;
+
+#ifdef _WIN32
+ if(RTPrioLevel > 0)
+ failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ else
+ failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+#elif defined(HAVE_PTHREAD_SETSCHEDPARAM)
+ struct sched_param param;
+
+ if(RTPrioLevel > 0)
+ {
+ /* Use the minimum real-time priority possible for now (on Linux this
+ * should be 1 for SCHED_RR) */
+ param.sched_priority = sched_get_priority_min(SCHED_RR);
+ failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, ¶m);
+ }
+ else
+ {
+ param.sched_priority = 0;
+ failed = !!pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m);
+ }
+#else
+ /* Real-time priority not available */
+ failed = (RTPrioLevel>0);
+#endif
+ if(failed)
+ AL_PRINT("Failed to set priority level for thread\n");
+}
+
+
+void InitUIntMap(UIntMap *map)
+{
+ map->array = NULL;
+ map->size = 0;
+ map->maxsize = 0;
+}
+
+void ResetUIntMap(UIntMap *map)
+{
+ free(map->array);
+ map->array = NULL;
+ map->size = 0;
+ map->maxsize = 0;
+}
+
+ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value)
+{
+ ALsizei pos = 0;
+
+ if(map->size > 0)
+ {
+ ALsizei low = 0;
+ ALsizei high = map->size - 1;
+ while(low < high)
+ {
+ ALsizei mid = low + (high-low)/2;
+ if(map->array[mid].key < key)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+ if(map->array[low].key < key)
+ low++;
+ pos = low;
+ }
+
+ if(pos == map->size || map->array[pos].key != key)
+ {
+ if(map->size == map->maxsize)
+ {
+ ALvoid *temp;
+ ALsizei newsize;
+
+ newsize = (map->maxsize ? (map->maxsize<<1) : 4);
+ if(newsize < map->maxsize)
+ return AL_OUT_OF_MEMORY;
+
+ temp = realloc(map->array, newsize*sizeof(map->array[0]));
+ if(!temp) return AL_OUT_OF_MEMORY;
+ map->array = temp;
+ map->maxsize = newsize;
+ }
+
+ map->size++;
+ if(pos < map->size-1)
+ memmove(&map->array[pos+1], &map->array[pos],
+ (map->size-1-pos)*sizeof(map->array[0]));
+ }
+ map->array[pos].key = key;
+ map->array[pos].value = value;
+
+ return AL_NO_ERROR;
+}
+
+void RemoveUIntMapKey(UIntMap *map, ALuint key)
+{
+ if(map->size > 0)
+ {
+ ALsizei low = 0;
+ ALsizei high = map->size - 1;
+ while(low < high)
+ {
+ ALsizei mid = low + (high-low)/2;
+ if(map->array[mid].key < key)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+ if(map->array[low].key == key)
+ {
+ if(low < map->size-1)
+ memmove(&map->array[low], &map->array[low+1],
+ (map->size-1-low)*sizeof(map->array[0]));
+ map->size--;
+ }
+ }
+}
+
+ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key)
+{
+ if(map->size > 0)
+ {
+ ALsizei low = 0;
+ ALsizei high = map->size - 1;
+ while(low < high)
+ {
+ ALsizei mid = low + (high-low)/2;
+ if(map->array[mid].key < key)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+ if(map->array[low].key == key)
+ return map->array[low].value;
+ }
+ return NULL;
+}
+
+
+ALuint BytesFromDevFmt(enum DevFmtType type)
+{
+ switch(type)
+ {
+ case DevFmtByte: return sizeof(ALbyte);
+ case DevFmtUByte: return sizeof(ALubyte);
+ case DevFmtShort: return sizeof(ALshort);
+ case DevFmtUShort: return sizeof(ALushort);
+ case DevFmtFloat: return sizeof(ALfloat);
+ }
+ return 0;
+}
+ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
+{
+ switch(chans)
+ {
+ case DevFmtMono: return 1;
+ case DevFmtStereo: return 2;
+ case DevFmtQuad: return 4;
+ case DevFmtX51: return 6;
+ case DevFmtX61: return 7;
+ case DevFmtX71: return 8;
+ }
+ return 0;
+}
+ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans,
+ enum DevFmtType *type)
+{
+ switch(format)
+ {
+ case AL_FORMAT_MONO8:
+ *chans = DevFmtMono;
+ *type = DevFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_MONO16:
+ *chans = DevFmtMono;
+ *type = DevFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_MONO_FLOAT32:
+ *chans = DevFmtMono;
+ *type = DevFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO8:
+ *chans = DevFmtStereo;
+ *type = DevFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO16:
+ *chans = DevFmtStereo;
+ *type = DevFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO_FLOAT32:
+ *chans = DevFmtStereo;
+ *type = DevFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD8:
+ *chans = DevFmtQuad;
+ *type = DevFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD16:
+ *chans = DevFmtQuad;
+ *type = DevFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD32:
+ *chans = DevFmtQuad;
+ *type = DevFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN8:
+ *chans = DevFmtX51;
+ *type = DevFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN16:
+ *chans = DevFmtX51;
+ *type = DevFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN32:
+ *chans = DevFmtX51;
+ *type = DevFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN8:
+ *chans = DevFmtX61;
+ *type = DevFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN16:
+ *chans = DevFmtX61;
+ *type = DevFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN32:
+ *chans = DevFmtX61;
+ *type = DevFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN8:
+ *chans = DevFmtX71;
+ *type = DevFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN16:
+ *chans = DevFmtX71;
+ *type = DevFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN32:
+ *chans = DevFmtX71;
+ *type = DevFmtFloat;
+ return AL_TRUE;
+ }
+ return AL_FALSE;
+}
+
+/*
+ IsDevice
+
+ Check pDevice is a valid Device pointer
+*/
+static ALCboolean IsDevice(ALCdevice *pDevice)
+{
+ ALCdevice *pTempDevice;
+
+ SuspendContext(NULL);
+
+ pTempDevice = g_pDeviceList;
+ while(pTempDevice && pTempDevice != pDevice)
+ pTempDevice = pTempDevice->next;
+
+ ProcessContext(NULL);
+
+ return (pTempDevice ? ALC_TRUE : ALC_FALSE);
+}
+
+/*
+ IsContext
+
+ Check pContext is a valid Context pointer
+*/
+static ALCboolean IsContext(ALCcontext *pContext)
+{
+ ALCcontext *pTempContext;
+
+ SuspendContext(NULL);
+
+ pTempContext = g_pContextList;
+ while (pTempContext && pTempContext != pContext)
+ pTempContext = pTempContext->next;
+
+ ProcessContext(NULL);
+
+ return (pTempContext ? ALC_TRUE : ALC_FALSE);
+}
+
+
+/*
+ alcSetError
+
+ Store latest ALC Error
+*/
+ALCvoid alcSetError(ALCdevice *device, ALenum errorCode)
+{
+ if(IsDevice(device))
+ device->LastError = errorCode;
+ else
+ g_eLastNullDeviceError = errorCode;
+}
+
+
+/* UpdateDeviceParams:
+ *
+ * Updates device parameters according to the attribute list.
+ */
+static ALCboolean UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
+{
+ ALCuint freq, numMono, numStereo, numSends;
+ ALboolean running;
+ ALuint oldRate;
+ ALuint attrIdx;
+ ALuint i;
+
+ running = ((device->NumContexts > 0) ? AL_TRUE : AL_FALSE);
+ oldRate = device->Frequency;
+
+ // Check for attributes
+ if(attrList && attrList[0])
+ {
+ // If a context is already running on the device, stop playback so the
+ // device attributes can be updated
+ if(running)
+ {
+ ProcessContext(NULL);
+ ALCdevice_StopPlayback(device);
+ SuspendContext(NULL);
+ running = AL_FALSE;
+ }
+
+ freq = device->Frequency;
+ numMono = device->NumMonoSources;
+ numStereo = device->NumStereoSources;
+ numSends = device->NumAuxSends;
+
+ attrIdx = 0;
+ while(attrList[attrIdx])
+ {
+ if(attrList[attrIdx] == ALC_FREQUENCY &&
+ !ConfigValueExists(NULL, "frequency"))
+ {
+ freq = attrList[attrIdx + 1];
+ if(freq < 8000)
+ freq = 8000;
+ }
+
+ if(attrList[attrIdx] == ALC_STEREO_SOURCES)
+ {
+ numStereo = attrList[attrIdx + 1];
+ if(numStereo > device->MaxNoOfSources)
+ numStereo = device->MaxNoOfSources;
+
+ numMono = device->MaxNoOfSources - numStereo;
+ }
+
+ if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS &&
+ !ConfigValueExists(NULL, "sends"))
+ {
+ numSends = attrList[attrIdx + 1];
+ if(numSends > MAX_SENDS)
+ numSends = MAX_SENDS;
+ }
+
+ attrIdx += 2;
+ }
+
+ device->UpdateSize = (ALuint64)device->UpdateSize * freq /
+ device->Frequency;
+
+ device->Frequency = freq;
+ device->NumMonoSources = numMono;
+ device->NumStereoSources = numStereo;
+ device->NumAuxSends = numSends;
+ }
+
+ if(running)
+ return ALC_TRUE;
+
+ if(ALCdevice_ResetPlayback(device) == ALC_FALSE)
+ return ALC_FALSE;
+
+ aluInitPanning(device);
+
+ for(i = 0;i < MAXCHANNELS;i++)
+ {
+ device->ClickRemoval[i] = 0.0f;
+ device->PendingClicks[i] = 0.0f;
+ }
+
+ for(i = 0;i < device->NumContexts;i++)
+ {
+ ALCcontext *context = device->Contexts[i];
+ ALsizei pos;
+
+ SuspendContext(context);
+ for(pos = 0;pos < context->EffectSlotMap.size;pos++)
+ {
+ ALeffectslot *slot = context->EffectSlotMap.array[pos].value;
+
+ if(ALEffect_DeviceUpdate(slot->EffectState, device) == AL_FALSE)
+ {
+ ProcessContext(context);
+ return ALC_FALSE;
+ }
+ ALEffect_Update(slot->EffectState, context, &slot->effect);
+ }
+
+ for(pos = 0;pos < context->SourceMap.size;pos++)
+ {
+ ALsource *source = context->SourceMap.array[pos].value;
+ ALuint s = device->NumAuxSends;
+ while(s < MAX_SENDS)
+ {
+ if(source->Send[s].Slot)
+ source->Send[s].Slot->refcount--;
+ source->Send[s].Slot = NULL;
+ source->Send[s].WetFilter.type = 0;
+ source->Send[s].WetFilter.filter = 0;
+ s++;
+ }
+ source->NeedsUpdate = AL_TRUE;
+ }
+ ProcessContext(context);
+ }
+
+ if(device->Bs2bLevel > 0 && device->Bs2bLevel <= 6)
+ {
+ if(!device->Bs2b)
+ {
+ device->Bs2b = calloc(1, sizeof(*device->Bs2b));
+ bs2b_clear(device->Bs2b);
+ }
+ bs2b_set_srate(device->Bs2b, device->Frequency);
+ bs2b_set_level(device->Bs2b, device->Bs2bLevel);
+ }
+ else
+ {
+ free(device->Bs2b);
+ device->Bs2b = NULL;
+ }
+
+ if(ChannelsFromDevFmt(device->FmtChans) <= 2)
+ {
+ device->HeadDampen = GetConfigValueFloat(NULL, "head_dampen", DEFAULT_HEAD_DAMPEN);
+ device->HeadDampen = __min(device->HeadDampen, 1.0f);
+ device->HeadDampen = __max(device->HeadDampen, 0.0f);
+ }
+ else
+ device->HeadDampen = 0.0f;
+
+ return ALC_TRUE;
+}
+
+
+/*
+ SuspendContext
+
+ Thread-safe entry
+*/
+ALCvoid SuspendContext(ALCcontext *pContext)
+{
+ (void)pContext;
+ EnterCriticalSection(&g_csMutex);
+}
+
+
+/*
+ ProcessContext
+
+ Thread-safe exit
+*/
+ALCvoid ProcessContext(ALCcontext *pContext)
+{
+ (void)pContext;
+ LeaveCriticalSection(&g_csMutex);
+}
+
+
+/*
+ GetContextSuspended
+
+ Returns the currently active Context, in a locked state
+*/
+ALCcontext *GetContextSuspended(void)
+{
+ ALCcontext *pContext = NULL;
+
+ SuspendContext(NULL);
+
+ pContext = tls_get(LocalContext);
+ if(pContext && !IsContext(pContext))
+ {
+ tls_set(LocalContext, NULL);
+ pContext = NULL;
+ }
+ if(!pContext)
+ pContext = GlobalContext;
+
+ if(pContext)
+ SuspendContext(pContext);
+
+ ProcessContext(NULL);
+
+ return pContext;
+}
+
+
+/*
+ InitContext
+
+ Initialize Context variables
+*/
+static ALvoid InitContext(ALCcontext *pContext)
+{
+ //Initialise listener
+ pContext->Listener.Gain = 1.0f;
+ pContext->Listener.MetersPerUnit = 1.0f;
+ pContext->Listener.Position[0] = 0.0f;
+ pContext->Listener.Position[1] = 0.0f;
+ pContext->Listener.Position[2] = 0.0f;
+ pContext->Listener.Velocity[0] = 0.0f;
+ pContext->Listener.Velocity[1] = 0.0f;
+ pContext->Listener.Velocity[2] = 0.0f;
+ pContext->Listener.Forward[0] = 0.0f;
+ pContext->Listener.Forward[1] = 0.0f;
+ pContext->Listener.Forward[2] = -1.0f;
+ pContext->Listener.Up[0] = 0.0f;
+ pContext->Listener.Up[1] = 1.0f;
+ pContext->Listener.Up[2] = 0.0f;
+
+ //Validate pContext
+ pContext->LastError = AL_NO_ERROR;
+ pContext->Suspended = AL_FALSE;
+ pContext->ActiveSourceCount = 0;
+ InitUIntMap(&pContext->SourceMap);
+ InitUIntMap(&pContext->EffectSlotMap);
+
+ //Set globals
+ pContext->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
+ pContext->SourceDistanceModel = AL_FALSE;
+ pContext->DopplerFactor = 1.0f;
+ pContext->DopplerVelocity = 1.0f;
+ pContext->flSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC;
+
+ pContext->ExtensionList = alExtList;
+}
+
+
+/*
+ ExitContext
+
+ Clean up Context, destroy any remaining Sources
+*/
+static ALCvoid ExitContext(ALCcontext *pContext)
+{
+ //Invalidate context
+ pContext->LastError = AL_NO_ERROR;
+}
+
+///////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////
+// ALC Functions calls
+
+
+// This should probably move to another c file but for now ...
+ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
+{
+ ALCboolean DeviceFound = ALC_FALSE;
+ ALCdevice *device = NULL;
+ ALCint i;
+
+ if(SampleSize <= 0)
+ {
+ alcSetError(NULL, ALC_INVALID_VALUE);
+ return NULL;
+ }
+
+ if(deviceName && !deviceName[0])
+ deviceName = NULL;
+
+ device = calloc(1, sizeof(ALCdevice));
+ if(!device)
+ {
+ alcSetError(NULL, ALC_OUT_OF_MEMORY);
+ return NULL;
+ }
+
+ //Validate device
+ device->Connected = ALC_TRUE;
+ device->IsCaptureDevice = AL_TRUE;
+
+ device->szDeviceName = NULL;
+
+ device->Frequency = frequency;
+ if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE)
+ {
+ free(device);
+ alcSetError(NULL, ALC_INVALID_ENUM);
+ return NULL;
+ }
+
+ device->UpdateSize = SampleSize;
+ device->NumUpdates = 1;
+
+ SuspendContext(NULL);
+ for(i = 0;BackendList[i].Init;i++)
+ {
+ device->Funcs = &BackendList[i].Funcs;
+ if(ALCdevice_OpenCapture(device, deviceName))
+ {
+ device->next = g_pDeviceList;
+ g_pDeviceList = device;
+ g_ulDeviceCount++;
+
+ DeviceFound = ALC_TRUE;
+ break;
+ }
+ }
+ ProcessContext(NULL);
+
+ if(!DeviceFound)
+ {
+ alcSetError(NULL, ALC_INVALID_VALUE);
+ free(device);
+ device = NULL;
+ }
+
+ return device;
+}
+
+ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *pDevice)
+{
+ ALCdevice **list;
+
+ if(!IsDevice(pDevice) || !pDevice->IsCaptureDevice)
+ {
+ alcSetError(pDevice, ALC_INVALID_DEVICE);
+ return ALC_FALSE;
+ }
+
+ SuspendContext(NULL);
+
+ list = &g_pDeviceList;
+ while(*list != pDevice)
+ list = &(*list)->next;
+
+ *list = (*list)->next;
+ g_ulDeviceCount--;
+
+ ProcessContext(NULL);
+
+ ALCdevice_CloseCapture(pDevice);
+
+ free(pDevice->szDeviceName);
+ pDevice->szDeviceName = NULL;
+
+ free(pDevice);
+
+ return ALC_TRUE;
+}
+
+ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
+{
+ SuspendContext(NULL);
+ if(!IsDevice(device) || !device->IsCaptureDevice)
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else if(device->Connected)
+ ALCdevice_StartCapture(device);
+ ProcessContext(NULL);
+}
+
+ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
+{
+ SuspendContext(NULL);
+ if(!IsDevice(device) || !device->IsCaptureDevice)
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ ALCdevice_StopCapture(device);
+ ProcessContext(NULL);
+}
+
+ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
+{
+ SuspendContext(NULL);
+ if(!IsDevice(device) || !device->IsCaptureDevice)
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ ALCdevice_CaptureSamples(device, buffer, samples);
+ ProcessContext(NULL);
+}
+
+/*
+ alcGetError
+
+ Return last ALC generated error code
+*/
+ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
+{
+ ALCenum errorCode;
+
+ if(IsDevice(device))
+ {
+ errorCode = device->LastError;
+ device->LastError = ALC_NO_ERROR;
+ }
+ else
+ {
+ errorCode = g_eLastNullDeviceError;
+ g_eLastNullDeviceError = ALC_NO_ERROR;
+ }
+ return errorCode;
+}
+
+
+/*
+ alcSuspendContext
+
+ Not functional
+*/
+ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *pContext)
+{
+ SuspendContext(NULL);
+ if(IsContext(pContext))
+ pContext->Suspended = AL_TRUE;
+ ProcessContext(NULL);
+}
+
+
+/*
+ alcProcessContext
+
+ Not functional
+*/
+ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *pContext)
+{
+ SuspendContext(NULL);
+ if(IsContext(pContext))
+ pContext->Suspended = AL_FALSE;
+ ProcessContext(NULL);
+}
+
+
+/*
+ alcGetString
+
+ Returns information about the Device, and error strings
+*/
+ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *pDevice,ALCenum param)
+{
+ const ALCchar *value = NULL;
+
+ switch (param)
+ {
+ case ALC_NO_ERROR:
+ value = alcNoError;
+ break;
+
+ case ALC_INVALID_ENUM:
+ value = alcErrInvalidEnum;
+ break;
+
+ case ALC_INVALID_VALUE:
+ value = alcErrInvalidValue;
+ break;
+
+ case ALC_INVALID_DEVICE:
+ value = alcErrInvalidDevice;
+ break;
+
+ case ALC_INVALID_CONTEXT:
+ value = alcErrInvalidContext;
+ break;
+
+ case ALC_OUT_OF_MEMORY:
+ value = alcErrOutOfMemory;
+ break;
+
+ case ALC_DEVICE_SPECIFIER:
+ if(IsDevice(pDevice))
+ value = pDevice->szDeviceName;
+ else
+ {
+ ProbeDeviceList();
+ value = alcDeviceList;
+ }
+ break;
+
+ case ALC_ALL_DEVICES_SPECIFIER:
+ ProbeAllDeviceList();
+ value = alcAllDeviceList;
+ break;
+
+ case ALC_CAPTURE_DEVICE_SPECIFIER:
+ if(IsDevice(pDevice))
+ value = pDevice->szDeviceName;
+ else
+ {
+ ProbeCaptureDeviceList();
+ value = alcCaptureDeviceList;
+ }
+ break;
+
+ /* Default devices are always first in the list */
+ case ALC_DEFAULT_DEVICE_SPECIFIER:
+ if(!alcDeviceList)
+ ProbeDeviceList();
+
+ free(alcDefaultDeviceSpecifier);
+ alcDefaultDeviceSpecifier = strdup(alcDeviceList ? alcDeviceList : "");
+ if(!alcDefaultDeviceSpecifier)
+ alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+ value = alcDefaultDeviceSpecifier;
+ break;
+
+ case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
+ if(!alcAllDeviceList)
+ ProbeAllDeviceList();
+
+ free(alcDefaultAllDeviceSpecifier);
+ alcDefaultAllDeviceSpecifier = strdup(alcAllDeviceList ?
+ alcAllDeviceList : "");
+ if(!alcDefaultAllDeviceSpecifier)
+ alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+ value = alcDefaultAllDeviceSpecifier;
+ break;
+
+ case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
+ if(!alcCaptureDeviceList)
+ ProbeCaptureDeviceList();
+
+ free(alcCaptureDefaultDeviceSpecifier);
+ alcCaptureDefaultDeviceSpecifier = strdup(alcCaptureDeviceList ?
+ alcCaptureDeviceList : "");
+ if(!alcCaptureDefaultDeviceSpecifier)
+ alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+ value = alcCaptureDefaultDeviceSpecifier;
+ break;
+
+ case ALC_EXTENSIONS:
+ if(IsDevice(pDevice))
+ value = alcExtensionList;
+ else
+ value = alcNoDeviceExtList;
+ break;
+
+ default:
+ alcSetError(pDevice, ALC_INVALID_ENUM);
+ break;
+ }
+
+ return value;
+}
+
+
+/*
+ alcGetIntegerv
+
+ Returns information about the Device and the version of Open AL
+*/
+ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data)
+{
+ if(size == 0 || data == NULL)
+ {
+ alcSetError(device, ALC_INVALID_VALUE);
+ return;
+ }
+
+ if(IsDevice(device) && device->IsCaptureDevice)
+ {
+ SuspendContext(NULL);
+
+ // Capture device
+ switch (param)
+ {
+ case ALC_CAPTURE_SAMPLES:
+ *data = ALCdevice_AvailableSamples(device);
+ break;
+
+ case ALC_CONNECTED:
+ *data = device->Connected;
+ break;
+
+ default:
+ alcSetError(device, ALC_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(NULL);
+ return;
+ }
+
+ // Playback Device
+ switch (param)
+ {
+ case ALC_MAJOR_VERSION:
+ *data = alcMajorVersion;
+ break;
+
+ case ALC_MINOR_VERSION:
+ *data = alcMinorVersion;
+ break;
+
+ case ALC_EFX_MAJOR_VERSION:
+ *data = alcEFXMajorVersion;
+ break;
+
+ case ALC_EFX_MINOR_VERSION:
+ *data = alcEFXMinorVersion;
+ break;
+
+ case ALC_MAX_AUXILIARY_SENDS:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = device->NumAuxSends;
+ break;
+
+ case ALC_ATTRIBUTES_SIZE:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = 13;
+ break;
+
+ case ALC_ALL_ATTRIBUTES:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else if (size < 13)
+ alcSetError(device, ALC_INVALID_VALUE);
+ else
+ {
+ int i = 0;
+
+ SuspendContext(NULL);
+ data[i++] = ALC_FREQUENCY;
+ data[i++] = device->Frequency;
+
+ data[i++] = ALC_REFRESH;
+ data[i++] = device->Frequency / device->UpdateSize;
+
+ data[i++] = ALC_SYNC;
+ data[i++] = ALC_FALSE;
+
+ data[i++] = ALC_MONO_SOURCES;
+ data[i++] = device->NumMonoSources;
+
+ data[i++] = ALC_STEREO_SOURCES;
+ data[i++] = device->NumStereoSources;
+
+ data[i++] = ALC_MAX_AUXILIARY_SENDS;
+ data[i++] = device->NumAuxSends;
+
+ data[i++] = 0;
+ ProcessContext(NULL);
+ }
+ break;
+
+ case ALC_FREQUENCY:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = device->Frequency;
+ break;
+
+ case ALC_REFRESH:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = device->Frequency / device->UpdateSize;
+ break;
+
+ case ALC_SYNC:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = ALC_FALSE;
+ break;
+
+ case ALC_MONO_SOURCES:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = device->NumMonoSources;
+ break;
+
+ case ALC_STEREO_SOURCES:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = device->NumStereoSources;
+ break;
+
+ case ALC_CONNECTED:
+ if(!IsDevice(device))
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else
+ *data = device->Connected;
+ break;
+
+ default:
+ alcSetError(device, ALC_INVALID_ENUM);
+ break;
+ }
+}
+
+
+/*
+ alcIsExtensionPresent
+
+ Determines if there is support for a particular extension
+*/
+ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName)
+{
+ ALCboolean bResult = ALC_FALSE;
+ const char *ptr;
+ size_t len;
+
+ if(!extName)
+ {
+ alcSetError(device, ALC_INVALID_VALUE);
+ return ALC_FALSE;
+ }
+
+ len = strlen(extName);
+ ptr = (IsDevice(device) ? alcExtensionList : alcNoDeviceExtList);
+ while(ptr && *ptr)
+ {
+ if(strncasecmp(ptr, extName, len) == 0 &&
+ (ptr[len] == '\0' || isspace(ptr[len])))
+ {
+ bResult = ALC_TRUE;
+ break;
+ }
+ if((ptr=strchr(ptr, ' ')) != NULL)
+ {
+ do {
+ ++ptr;
+ } while(isspace(*ptr));
+ }
+ }
+
+ return bResult;
+}
+
+
+/*
+ alcGetProcAddress
+
+ Retrieves the function address for a particular extension function
+*/
+ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName)
+{
+ ALsizei i = 0;
+
+ if(!funcName)
+ {
+ alcSetError(device, ALC_INVALID_VALUE);
+ return NULL;
+ }
+
+ while(alcFunctions[i].funcName && strcmp(alcFunctions[i].funcName,funcName) != 0)
+ i++;
+ return alcFunctions[i].address;
+}
+
+
+/*
+ alcGetEnumValue
+
+ Get the value for a particular ALC Enumerated Value
+*/
+ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName)
+{
+ ALsizei i = 0;
+
+ if(!enumName)
+ {
+ alcSetError(device, ALC_INVALID_VALUE);
+ return (ALCenum)0;
+ }
+
+ while(enumeration[i].enumName && strcmp(enumeration[i].enumName,enumName) != 0)
+ i++;
+ return enumeration[i].value;
+}
+
+
+/*
+ alcCreateContext
+
+ Create and attach a Context to a particular Device.
+*/
+ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList)
+{
+ ALCcontext *ALContext;
+ void *temp;
+
+ SuspendContext(NULL);
+
+ if(!IsDevice(device) || device->IsCaptureDevice || !device->Connected)
+ {
+ alcSetError(device, ALC_INVALID_DEVICE);
+ ProcessContext(NULL);
+ return NULL;
+ }
+
+ // Reset Context Last Error code
+ device->LastError = ALC_NO_ERROR;
+
+ if(UpdateDeviceParams(device, attrList) == ALC_FALSE)
+ {
+ alcSetError(device, ALC_INVALID_DEVICE);
+ aluHandleDisconnect(device);
+ ProcessContext(NULL);
+ ALCdevice_StopPlayback(device);
+ return NULL;
+ }
+
+ ALContext = NULL;
+ temp = realloc(device->Contexts, (device->NumContexts+1) * sizeof(*device->Contexts));
+ if(temp)
+ {
+ device->Contexts = temp;
+
+ ALContext = calloc(1, sizeof(ALCcontext));
+ if(ALContext)
+ {
+ ALContext->MaxActiveSources = 256;
+ ALContext->ActiveSources = malloc(sizeof(ALContext->ActiveSources[0]) *
+ ALContext->MaxActiveSources);
+ }
+ }
+ if(!ALContext || !ALContext->ActiveSources)
+ {
+ free(ALContext);
+ alcSetError(device, ALC_OUT_OF_MEMORY);
+ ProcessContext(NULL);
+ if(device->NumContexts == 0)
+ ALCdevice_StopPlayback(device);
+ return NULL;
+ }
+
+ device->Contexts[device->NumContexts++] = ALContext;
+ ALContext->Device = device;
+
+ InitContext(ALContext);
+
+ ALContext->next = g_pContextList;
+ g_pContextList = ALContext;
+ g_ulContextCount++;
+
+ ProcessContext(NULL);
+
+ return ALContext;
+}
+
+
+/*
+ alcDestroyContext
+
+ Remove a Context
+*/
+ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
+{
+ ALCdevice *Device;
+ ALCcontext **list;
+ ALuint i;
+
+ if(!IsContext(context))
+ {
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ return;
+ }
+
+ Device = context->Device;
+
+ if(Device->NumContexts == 1)
+ ALCdevice_StopPlayback(Device);
+
+ SuspendContext(NULL);
+
+ if(context == GlobalContext)
+ GlobalContext = NULL;
+
+ for(i = 0;i < Device->NumContexts;i++)
+ {
+ if(Device->Contexts[i] == context)
+ {
+ Device->Contexts[i] = Device->Contexts[Device->NumContexts-1];
+ Device->NumContexts--;
+ break;
+ }
+ }
+
+ // Lock context
+ SuspendContext(context);
+
+ if(context->SourceMap.size > 0)
+ {
+#ifdef _DEBUG
+ AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", context->SourceMap.size);
+#endif
+ ReleaseALSources(context);
+ }
+ ResetUIntMap(&context->SourceMap);
+
+ if(context->EffectSlotMap.size > 0)
+ {
+#ifdef _DEBUG
+ AL_PRINT("alcDestroyContext(): deleting %d AuxiliaryEffectSlot(s)\n", context->EffectSlotMap.size);
+#endif
+ ReleaseALAuxiliaryEffectSlots(context);
+ }
+ ResetUIntMap(&context->EffectSlotMap);
+
+ free(context->ActiveSources);
+ context->ActiveSources = NULL;
+ context->MaxActiveSources = 0;
+ context->ActiveSourceCount = 0;
+
+ list = &g_pContextList;
+ while(*list != context)
+ list = &(*list)->next;
+
+ *list = (*list)->next;
+ g_ulContextCount--;
+
+ // Unlock context
+ ProcessContext(context);
+ ProcessContext(NULL);
+
+ ExitContext(context);
+
+ // Free memory (MUST do this after ProcessContext)
+ memset(context, 0, sizeof(ALCcontext));
+ free(context);
+}
+
+
+/*
+ alcGetCurrentContext
+
+ Returns the currently active Context
+*/
+ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(ALCvoid)
+{
+ ALCcontext *pContext;
+
+ if((pContext=GetContextSuspended()) != NULL)
+ ProcessContext(pContext);
+
+ return pContext;
+}
+
+/*
+ alcGetThreadContext
+
+ Returns the currently active thread-local Context
+*/
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
+{
+ ALCcontext *pContext = NULL;
+
+ SuspendContext(NULL);
+
+ pContext = tls_get(LocalContext);
+ if(pContext && !IsContext(pContext))
+ {
+ tls_set(LocalContext, NULL);
+ pContext = NULL;
+ }
+
+ ProcessContext(NULL);
+
+ return pContext;
+}
+
+
+/*
+ alcGetContextsDevice
+
+ Returns the Device that a particular Context is attached to
+*/
+ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *pContext)
+{
+ ALCdevice *pDevice = NULL;
+
+ SuspendContext(NULL);
+ if(IsContext(pContext))
+ pDevice = pContext->Device;
+ else
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ ProcessContext(NULL);
+
+ return pDevice;
+}
+
+
+/*
+ alcMakeContextCurrent
+
+ Makes the given Context the active Context
+*/
+ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
+{
+ ALboolean bReturn = AL_TRUE;
+
+ SuspendContext(NULL);
+
+ // context must be a valid Context or NULL
+ if(context == NULL || IsContext(context))
+ {
+ GlobalContext = context;
+ tls_set(LocalContext, NULL);
+ }
+ else
+ {
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ bReturn = AL_FALSE;
+ }
+
+ ProcessContext(NULL);
+
+ return bReturn;
+}
+
+/*
+ alcSetThreadContext
+
+ Makes the given Context the active Context for the current thread
+*/
+ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
+{
+ ALboolean bReturn = AL_TRUE;
+
+ SuspendContext(NULL);
+
+ // context must be a valid Context or NULL
+ if(context == NULL || IsContext(context))
+ tls_set(LocalContext, context);
+ else
+ {
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ bReturn = AL_FALSE;
+ }
+
+ ProcessContext(NULL);
+
+ return bReturn;
+}
+
+
+// Sets the default channel order used by most non-WaveFormatEx-based APIs
+void SetDefaultChannelOrder(ALCdevice *device)
+{
+ switch(device->FmtChans)
+ {
+ case DevFmtMono: device->DevChannels[FRONT_CENTER] = 0; break;
+
+ case DevFmtStereo: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1; break;
+
+ case DevFmtQuad: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[BACK_LEFT] = 2;
+ device->DevChannels[BACK_RIGHT] = 3; break;
+
+ case DevFmtX51: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[BACK_LEFT] = 2;
+ device->DevChannels[BACK_RIGHT] = 3;
+ device->DevChannels[FRONT_CENTER] = 4;
+ device->DevChannels[LFE] = 5; break;
+
+ case DevFmtX61: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[FRONT_CENTER] = 2;
+ device->DevChannels[LFE] = 3;
+ device->DevChannels[BACK_CENTER] = 4;
+ device->DevChannels[SIDE_LEFT] = 5;
+ device->DevChannels[SIDE_RIGHT] = 6; break;
+
+ case DevFmtX71: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[BACK_LEFT] = 2;
+ device->DevChannels[BACK_RIGHT] = 3;
+ device->DevChannels[FRONT_CENTER] = 4;
+ device->DevChannels[LFE] = 5;
+ device->DevChannels[SIDE_LEFT] = 6;
+ device->DevChannels[SIDE_RIGHT] = 7; break;
+ }
+}
+// Sets the default order used by WaveFormatEx
+void SetDefaultWFXChannelOrder(ALCdevice *device)
+{
+ switch(device->FmtChans)
+ {
+ case DevFmtMono: device->DevChannels[FRONT_CENTER] = 0; break;
+
+ case DevFmtStereo: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1; break;
+
+ case DevFmtQuad: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[BACK_LEFT] = 2;
+ device->DevChannels[BACK_RIGHT] = 3; break;
+
+ case DevFmtX51: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[FRONT_CENTER] = 2;
+ device->DevChannels[LFE] = 3;
+ device->DevChannels[BACK_LEFT] = 4;
+ device->DevChannels[BACK_RIGHT] = 5; break;
+
+ case DevFmtX61: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[FRONT_CENTER] = 2;
+ device->DevChannels[LFE] = 3;
+ device->DevChannels[BACK_CENTER] = 4;
+ device->DevChannels[SIDE_LEFT] = 5;
+ device->DevChannels[SIDE_RIGHT] = 6; break;
+
+ case DevFmtX71: device->DevChannels[FRONT_LEFT] = 0;
+ device->DevChannels[FRONT_RIGHT] = 1;
+ device->DevChannels[FRONT_CENTER] = 2;
+ device->DevChannels[LFE] = 3;
+ device->DevChannels[BACK_LEFT] = 4;
+ device->DevChannels[BACK_RIGHT] = 5;
+ device->DevChannels[SIDE_LEFT] = 6;
+ device->DevChannels[SIDE_RIGHT] = 7; break;
+ }
+}
+
+static ALenum GetFormatFromString(const char *str)
+{
+ if(strcasecmp(str, "AL_FORMAT_MONO32") == 0) return AL_FORMAT_MONO_FLOAT32;
+ if(strcasecmp(str, "AL_FORMAT_STEREO32") == 0) return AL_FORMAT_STEREO_FLOAT32;
+ if(strcasecmp(str, "AL_FORMAT_QUAD32") == 0) return AL_FORMAT_QUAD32;
+ if(strcasecmp(str, "AL_FORMAT_51CHN32") == 0) return AL_FORMAT_51CHN32;
+ if(strcasecmp(str, "AL_FORMAT_61CHN32") == 0) return AL_FORMAT_61CHN32;
+ if(strcasecmp(str, "AL_FORMAT_71CHN32") == 0) return AL_FORMAT_71CHN32;
+
+ if(strcasecmp(str, "AL_FORMAT_MONO16") == 0) return AL_FORMAT_MONO16;
+ if(strcasecmp(str, "AL_FORMAT_STEREO16") == 0) return AL_FORMAT_STEREO16;
+ if(strcasecmp(str, "AL_FORMAT_QUAD16") == 0) return AL_FORMAT_QUAD16;
+ if(strcasecmp(str, "AL_FORMAT_51CHN16") == 0) return AL_FORMAT_51CHN16;
+ if(strcasecmp(str, "AL_FORMAT_61CHN16") == 0) return AL_FORMAT_61CHN16;
+ if(strcasecmp(str, "AL_FORMAT_71CHN16") == 0) return AL_FORMAT_71CHN16;
+
+ if(strcasecmp(str, "AL_FORMAT_MONO8") == 0) return AL_FORMAT_MONO8;
+ if(strcasecmp(str, "AL_FORMAT_STEREO8") == 0) return AL_FORMAT_STEREO8;
+ if(strcasecmp(str, "AL_FORMAT_QUAD8") == 0) return AL_FORMAT_QUAD8;
+ if(strcasecmp(str, "AL_FORMAT_51CHN8") == 0) return AL_FORMAT_51CHN8;
+ if(strcasecmp(str, "AL_FORMAT_61CHN8") == 0) return AL_FORMAT_61CHN8;
+ if(strcasecmp(str, "AL_FORMAT_71CHN8") == 0) return AL_FORMAT_71CHN8;
+
+ AL_PRINT("Unknown format: \"%s\"\n", str);
+ return AL_FORMAT_STEREO16;
+}
+
+/*
+ alcOpenDevice
+
+ Open the Device specified.
+*/
+ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
+{
+ ALboolean bDeviceFound = AL_FALSE;
+ const ALCchar *fmt;
+ ALCdevice *device;
+ ALint i;
+
+ if(deviceName && !deviceName[0])
+ deviceName = NULL;
+
+ device = calloc(1, sizeof(ALCdevice));
+ if(!device)
+ {
+ alcSetError(NULL, ALC_OUT_OF_MEMORY);
+ return NULL;
+ }
+
+ //Validate device
+ device->Connected = ALC_TRUE;
+ device->IsCaptureDevice = AL_FALSE;
+ device->LastError = ALC_NO_ERROR;
+
+ device->Bs2b = NULL;
+ device->szDeviceName = NULL;
+
+ device->Contexts = NULL;
+ device->NumContexts = 0;
+
+ InitUIntMap(&device->BufferMap);
+ InitUIntMap(&device->EffectMap);
+ InitUIntMap(&device->FilterMap);
+ InitUIntMap(&device->DatabufferMap);
+
+ //Set output format
+ device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE);
+ if(device->Frequency < 8000)
+ device->Frequency = 8000;
+
+ fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16");
+ if(DecomposeDevFormat(GetFormatFromString(fmt),
+ &device->FmtChans, &device->FmtType) == AL_FALSE)
+ {
+ /* Should never happen... */
+ device->FmtChans = DevFmtStereo;
+ device->FmtType = DevFmtShort;
+ }
+
+ device->NumUpdates = GetConfigValueInt(NULL, "periods", 4);
+ if(device->NumUpdates < 2)
+ device->NumUpdates = 4;
+
+ device->UpdateSize = GetConfigValueInt(NULL, "period_size", 1024);
+ if(device->UpdateSize <= 0)
+ device->UpdateSize = 1024;
+
+ device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256);
+ if((ALint)device->MaxNoOfSources <= 0)
+ device->MaxNoOfSources = 256;
+
+ device->AuxiliaryEffectSlotMax = GetConfigValueInt(NULL, "slots", 4);
+ if((ALint)device->AuxiliaryEffectSlotMax <= 0)
+ device->AuxiliaryEffectSlotMax = 4;
+
+ device->NumStereoSources = 1;
+ device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources;
+
+ device->NumAuxSends = GetConfigValueInt(NULL, "sends", 1);
+ if(device->NumAuxSends > MAX_SENDS)
+ device->NumAuxSends = MAX_SENDS;
+
+ device->Bs2bLevel = GetConfigValueInt(NULL, "cf_level", 0);
+
+ device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 1);
+
+ device->HeadDampen = 0.0f;
+
+ // Find a playback device to open
+ SuspendContext(NULL);
+ for(i = 0;BackendList[i].Init;i++)
+ {
+ device->Funcs = &BackendList[i].Funcs;
+ if(ALCdevice_OpenPlayback(device, deviceName))
+ {
+ device->next = g_pDeviceList;
+ g_pDeviceList = device;
+ g_ulDeviceCount++;
+
+ bDeviceFound = AL_TRUE;
+ break;
+ }
+ }
+ ProcessContext(NULL);
+
+ if(!bDeviceFound)
+ {
+ // No suitable output device found
+ alcSetError(NULL, ALC_INVALID_VALUE);
+ free(device);
+ device = NULL;
+ }
+
+ return device;
+}
+
+
+/*
+ alcCloseDevice
+
+ Close the specified Device
+*/
+ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *pDevice)
+{
+ ALCdevice **list;
+
+ if(!IsDevice(pDevice) || pDevice->IsCaptureDevice)
+ {
+ alcSetError(pDevice, ALC_INVALID_DEVICE);
+ return ALC_FALSE;
+ }
+
+ SuspendContext(NULL);
+
+ list = &g_pDeviceList;
+ while(*list != pDevice)
+ list = &(*list)->next;
+
+ *list = (*list)->next;
+ g_ulDeviceCount--;
+
+ ProcessContext(NULL);
+
+ if(pDevice->NumContexts > 0)
+ {
+#ifdef _DEBUG
+ AL_PRINT("alcCloseDevice(): destroying %u Context(s)\n", pDevice->NumContexts);
+#endif
+ while(pDevice->NumContexts > 0)
+ alcDestroyContext(pDevice->Contexts[0]);
+ }
+ ALCdevice_ClosePlayback(pDevice);
+
+ if(pDevice->BufferMap.size > 0)
+ {
+#ifdef _DEBUG
+ AL_PRINT("alcCloseDevice(): deleting %d Buffer(s)\n", pDevice->BufferMap.size);
+#endif
+ ReleaseALBuffers(pDevice);
+ }
+ ResetUIntMap(&pDevice->BufferMap);
+
+ if(pDevice->EffectMap.size > 0)
+ {
+#ifdef _DEBUG
+ AL_PRINT("alcCloseDevice(): deleting %d Effect(s)\n", pDevice->EffectMap.size);
+#endif
+ ReleaseALEffects(pDevice);
+ }
+ ResetUIntMap(&pDevice->EffectMap);
+
+ if(pDevice->FilterMap.size > 0)
+ {
+#ifdef _DEBUG
+ AL_PRINT("alcCloseDevice(): deleting %d Filter(s)\n", pDevice->FilterMap.size);
+#endif
+ ReleaseALFilters(pDevice);
+ }
+ ResetUIntMap(&pDevice->FilterMap);
+
+ if(pDevice->DatabufferMap.size > 0)
+ {
+#ifdef _DEBUG
+ AL_PRINT("alcCloseDevice(): deleting %d Databuffer(s)\n", pDevice->DatabufferMap.size);
+#endif
+ ReleaseALDatabuffers(pDevice);
+ }
+ ResetUIntMap(&pDevice->DatabufferMap);
+
+ free(pDevice->Bs2b);
+ pDevice->Bs2b = NULL;
+
+ free(pDevice->szDeviceName);
+ pDevice->szDeviceName = NULL;
+
+ free(pDevice->Contexts);
+ pDevice->Contexts = NULL;
+
+ //Release device structure
+ memset(pDevice, 0, sizeof(ALCdevice));
+ free(pDevice);
+
+ return ALC_TRUE;
+}
+
+
+static void ReleaseALC(void)
+{
+ free(alcDeviceList); alcDeviceList = NULL;
+ alcDeviceListSize = 0;
+ free(alcAllDeviceList); alcAllDeviceList = NULL;
+ alcAllDeviceListSize = 0;
+ free(alcCaptureDeviceList); alcCaptureDeviceList = NULL;
+ alcCaptureDeviceListSize = 0;
+
+ free(alcDefaultDeviceSpecifier);
+ alcDefaultDeviceSpecifier = NULL;
+ free(alcDefaultAllDeviceSpecifier);
+ alcDefaultAllDeviceSpecifier = NULL;
+ free(alcCaptureDefaultDeviceSpecifier);
+ alcCaptureDefaultDeviceSpecifier = NULL;
+
+#ifdef _DEBUG
+ if(g_ulDeviceCount > 0)
+ AL_PRINT("exit(): closing %u Device%s\n", g_ulDeviceCount, (g_ulDeviceCount>1)?"s":"");
+#endif
+
+ while(g_pDeviceList)
+ {
+ if(g_pDeviceList->IsCaptureDevice)
+ alcCaptureCloseDevice(g_pDeviceList);
+ else
+ alcCloseDevice(g_pDeviceList);
+ }
+}
+
+///////////////////////////////////////////////////////
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alListener.h"
+#include "alAuxEffectSlot.h"
+#include "alu.h"
+#include "bs2b.h"
+
+
+static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
+{
+ outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
+ outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
+ outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
+}
+
+static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
+{
+ return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
+ inVector1[2]*inVector2[2];
+}
+
+static __inline ALvoid aluNormalize(ALfloat *inVector)
+{
+ ALfloat length, inverse_length;
+
+ length = aluSqrt(aluDotproduct(inVector, inVector));
+ if(length != 0.0f)
+ {
+ inverse_length = 1.0f/length;
+ inVector[0] *= inverse_length;
+ inVector[1] *= inverse_length;
+ inVector[2] *= inverse_length;
+ }
+}
+
+static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
+{
+ ALfloat temp[4] = {
+ vector[0], vector[1], vector[2], w
+ };
+
+ vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
+ vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
+ vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
+}
+
+
+ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+{
+ ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
+ ALbufferlistitem *BufferListItem;
+ enum DevFmtChannels DevChans;
+ enum FmtChannels Channels;
+ ALfloat DryGain, DryGainHF;
+ ALfloat WetGain[MAX_SENDS];
+ ALfloat WetGainHF[MAX_SENDS];
+ ALint NumSends, Frequency;
+ ALboolean DupStereo;
+ ALfloat Pitch;
+ ALfloat cw;
+ ALint i;
+
+ /* Get device properties */
+ DevChans = ALContext->Device->FmtChans;
+ DupStereo = ALContext->Device->DuplicateStereo;
+ NumSends = ALContext->Device->NumAuxSends;
+ Frequency = ALContext->Device->Frequency;
+
+ /* Get listener properties */
+ ListenerGain = ALContext->Listener.Gain;
+
+ /* Get source properties */
+ SourceVolume = ALSource->flGain;
+ MinVolume = ALSource->flMinGain;
+ MaxVolume = ALSource->flMaxGain;
+ Pitch = ALSource->flPitch;
+
+ /* Calculate the stepping value */
+ Channels = FmtMono;
+ BufferListItem = ALSource->queue;
+ while(BufferListItem != NULL)
+ {
+ ALbuffer *ALBuffer;
+ if((ALBuffer=BufferListItem->buffer) != NULL)
+ {
+ ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
+ ALBuffer->FmtType);
+ maxstep -= ResamplerPadding[ALSource->Resampler] +
+ ResamplerPrePadding[ALSource->Resampler] + 1;
+ maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
+
+ Pitch = Pitch * ALBuffer->Frequency / Frequency;
+ if(Pitch > (ALfloat)maxstep)
+ ALSource->Params.Step = maxstep<<FRACTIONBITS;
+ else
+ {
+ ALSource->Params.Step = Pitch*FRACTIONONE;
+ if(ALSource->Params.Step == 0)
+ ALSource->Params.Step = 1;
+ }
+
+ Channels = ALBuffer->FmtChannels;
+ break;
+ }
+ BufferListItem = BufferListItem->next;
+ }
+
+ /* Calculate gains */
+ DryGain = SourceVolume;
+ DryGain = __min(DryGain,MaxVolume);
+ DryGain = __max(DryGain,MinVolume);
+ DryGainHF = 1.0f;
+
+ switch(ALSource->DirectFilter.type)
+ {
+ case AL_FILTER_LOWPASS:
+ DryGain *= ALSource->DirectFilter.Gain;
+ DryGainHF *= ALSource->DirectFilter.GainHF;
+ break;
+ }
+
+ for(i = 0;i < MAXCHANNELS;i++)
+ {
+ ALuint i2;
+ for(i2 = 0;i2 < MAXCHANNELS;i2++)
+ ALSource->Params.DryGains[i][i2] = 0.0f;
+ }
+
+ switch(Channels)
+ {
+ case FmtMono:
+ ALSource->Params.DryGains[0][FRONT_CENTER] = DryGain * ListenerGain;
+ break;
+ case FmtStereo:
+ if(DupStereo == AL_FALSE)
+ {
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ }
+ else
+ {
+ switch(DevChans)
+ {
+ case DevFmtMono:
+ case DevFmtStereo:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ break;
+
+ case DevFmtQuad:
+ case DevFmtX51:
+ DryGain *= aluSqrt(2.0f/4.0f);
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[0][BACK_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][BACK_RIGHT] = DryGain * ListenerGain;
+ break;
+
+ case DevFmtX61:
+ DryGain *= aluSqrt(2.0f/4.0f);
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[0][SIDE_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][SIDE_RIGHT] = DryGain * ListenerGain;
+ break;
+
+ case DevFmtX71:
+ DryGain *= aluSqrt(2.0f/6.0f);
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[0][BACK_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][BACK_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[0][SIDE_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][SIDE_RIGHT] = DryGain * ListenerGain;
+ break;
+ }
+ }
+ break;
+
+ case FmtRear:
+ ALSource->Params.DryGains[0][BACK_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][BACK_RIGHT] = DryGain * ListenerGain;
+ break;
+
+ case FmtQuad:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[2][BACK_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[3][BACK_RIGHT] = DryGain * ListenerGain;
+ break;
+
+ case FmtX51:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[3][LFE] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[4][BACK_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[5][BACK_RIGHT] = DryGain * ListenerGain;
+ break;
+
+ case FmtX61:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[3][LFE] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[4][BACK_CENTER] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[5][SIDE_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[6][SIDE_RIGHT] = DryGain * ListenerGain;
+ break;
+
+ case FmtX71:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[3][LFE] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[4][BACK_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[5][BACK_RIGHT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[6][SIDE_LEFT] = DryGain * ListenerGain;
+ ALSource->Params.DryGains[7][SIDE_RIGHT] = DryGain * ListenerGain;
+ break;
+ }
+
+ for(i = 0;i < NumSends;i++)
+ {
+ WetGain[i] = SourceVolume;
+ WetGain[i] = __min(WetGain[i],MaxVolume);
+ WetGain[i] = __max(WetGain[i],MinVolume);
+ WetGainHF[i] = 1.0f;
+
+ switch(ALSource->Send[i].WetFilter.type)
+ {
+ case AL_FILTER_LOWPASS:
+ WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
+ WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
+ break;
+ }
+
+ ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
+ }
+
+ /* Update filter coefficients. Calculations based on the I3DL2
+ * spec. */
+ cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
+
+ /* We use two chained one-pole filters, so we need to take the
+ * square root of the squared gain, which is the same as the base
+ * gain. */
+ ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
+
+ for(i = 0;i < NumSends;i++)
+ {
+ /* We use a one-pole filter, so we need to take the squared gain */
+ ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
+ ALSource->Params.Send[i].iirFilter.coeff = a;
+ }
+}
+
+ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+{
+ const ALCdevice *Device = ALContext->Device;
+ ALfloat InnerAngle,OuterAngle,Angle,Distance,OrigDist;
+ ALfloat Direction[3],Position[3],SourceToListener[3];
+ ALfloat Velocity[3],ListenerVel[3];
+ ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
+ ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
+ ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;
+ ALfloat AirAbsorptionFactor;
+ ALbufferlistitem *BufferListItem;
+ ALfloat Attenuation, EffectiveDist;
+ ALfloat RoomAttenuation[MAX_SENDS];
+ ALfloat MetersPerUnit;
+ ALfloat RoomRolloff[MAX_SENDS];
+ ALfloat DryGain;
+ ALfloat DryGainHF;
+ ALfloat WetGain[MAX_SENDS];
+ ALfloat WetGainHF[MAX_SENDS];
+ ALfloat DirGain, AmbientGain;
+ const ALfloat *SpeakerGain;
+ ALfloat Pitch;
+ ALfloat length;
+ ALuint Frequency;
+ ALint NumSends;
+ ALint pos, s, i;
+ ALfloat cw;
+
+ DryGainHF = 1.0f;
+ for(i = 0;i < MAX_SENDS;i++)
+ WetGainHF[i] = 1.0f;
+
+ //Get context properties
+ DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
+ DopplerVelocity = ALContext->DopplerVelocity;
+ SpeedOfSound = ALContext->flSpeedOfSound;
+ NumSends = Device->NumAuxSends;
+ Frequency = Device->Frequency;
+
+ //Get listener properties
+ ListenerGain = ALContext->Listener.Gain;
+ MetersPerUnit = ALContext->Listener.MetersPerUnit;
+ memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
+
+ //Get source properties
+ SourceVolume = ALSource->flGain;
+ memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
+ memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
+ memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
+ MinVolume = ALSource->flMinGain;
+ MaxVolume = ALSource->flMaxGain;
+ MinDist = ALSource->flRefDistance;
+ MaxDist = ALSource->flMaxDistance;
+ Rolloff = ALSource->flRollOffFactor;
+ InnerAngle = ALSource->flInnerAngle;
+ OuterAngle = ALSource->flOuterAngle;
+ OuterGainHF = ALSource->OuterGainHF;
+ AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
+
+ //1. Translate Listener to origin (convert to head relative)
+ if(ALSource->bHeadRelative == AL_FALSE)
+ {
+ ALfloat U[3],V[3],N[3];
+ ALfloat Matrix[4][4];
+
+ // Build transform matrix
+ memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
+ aluNormalize(N); // Normalized At-vector
+ memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
+ aluNormalize(V); // Normalized Up-vector
+ aluCrossproduct(N, V, U); // Right-vector
+ aluNormalize(U); // Normalized Right-vector
+ Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
+ Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
+ Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
+ Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
+
+ // Translate position
+ Position[0] -= ALContext->Listener.Position[0];
+ Position[1] -= ALContext->Listener.Position[1];
+ Position[2] -= ALContext->Listener.Position[2];
+
+ // Transform source position and direction into listener space
+ aluMatrixVector(Position, 1.0f, Matrix);
+ aluMatrixVector(Direction, 0.0f, Matrix);
+ // Transform source and listener velocity into listener space
+ aluMatrixVector(Velocity, 0.0f, Matrix);
+ aluMatrixVector(ListenerVel, 0.0f, Matrix);
+ }
+ else
+ ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
+
+ SourceToListener[0] = -Position[0];
+ SourceToListener[1] = -Position[1];
+ SourceToListener[2] = -Position[2];
+ aluNormalize(SourceToListener);
+ aluNormalize(Direction);
+
+ //2. Calculate distance attenuation
+ Distance = aluSqrt(aluDotproduct(Position, Position));
+ OrigDist = Distance;
+
+ Attenuation = 1.0f;
+ for(i = 0;i < NumSends;i++)
+ {
+ RoomAttenuation[i] = 1.0f;
+
+ RoomRolloff[i] = ALSource->RoomRolloffFactor;
+ if(ALSource->Send[i].Slot &&
+ (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
+ ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
+ RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
+ }
+
+ switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
+ ALContext->DistanceModel)
+ {
+ case AL_INVERSE_DISTANCE_CLAMPED:
+ Distance=__max(Distance,MinDist);
+ Distance=__min(Distance,MaxDist);
+ if(MaxDist < MinDist)
+ break;
+ //fall-through
+ case AL_INVERSE_DISTANCE:
+ if(MinDist > 0.0f)
+ {
+ if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
+ Attenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
+ for(i = 0;i < NumSends;i++)
+ {
+ if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
+ RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
+ }
+ }
+ break;
+
+ case AL_LINEAR_DISTANCE_CLAMPED:
+ Distance=__max(Distance,MinDist);
+ Distance=__min(Distance,MaxDist);
+ if(MaxDist < MinDist)
+ break;
+ //fall-through
+ case AL_LINEAR_DISTANCE:
+ if(MaxDist != MinDist)
+ {
+ Attenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
+ Attenuation = __max(Attenuation, 0.0f);
+ for(i = 0;i < NumSends;i++)
+ {
+ RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
+ RoomAttenuation[i] = __max(RoomAttenuation[i], 0.0f);
+ }
+ }
+ break;
+
+ case AL_EXPONENT_DISTANCE_CLAMPED:
+ Distance=__max(Distance,MinDist);
+ Distance=__min(Distance,MaxDist);
+ if(MaxDist < MinDist)
+ break;
+ //fall-through
+ case AL_EXPONENT_DISTANCE:
+ if(Distance > 0.0f && MinDist > 0.0f)
+ {
+ Attenuation = aluPow(Distance/MinDist, -Rolloff);
+ for(i = 0;i < NumSends;i++)
+ RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
+ }
+ break;
+
+ case AL_NONE:
+ break;
+ }
+
+ // Source Gain + Attenuation
+ DryGain = SourceVolume * Attenuation;
+ for(i = 0;i < NumSends;i++)
+ WetGain[i] = SourceVolume * RoomAttenuation[i];
+
+ EffectiveDist = 0.0f;
+ if(MinDist > 0.0f && Attenuation < 1.0f)
+ EffectiveDist = (MinDist/Attenuation - MinDist)*MetersPerUnit;
+
+ // Distance-based air absorption
+ if(AirAbsorptionFactor > 0.0f && EffectiveDist > 0.0f)
+ {
+ ALfloat absorb;
+
+ // Absorption calculation is done in dB
+ absorb = (AirAbsorptionFactor*AIRABSORBGAINDBHF) *
+ EffectiveDist;
+ // Convert dB to linear gain before applying
+ absorb = aluPow(10.0f, absorb/20.0f);
+
+ DryGainHF *= absorb;
+ }
+
+ //3. Apply directional soundcones
+ Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
+ if(Angle >= InnerAngle && Angle <= OuterAngle)
+ {
+ ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
+ ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
+ ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
+ }
+ else if(Angle > OuterAngle)
+ {
+ ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
+ ConeHF = (1.0f+(OuterGainHF-1.0f));
+ }
+ else
+ {
+ ConeVolume = 1.0f;
+ ConeHF = 1.0f;
+ }
+
+ // Apply some high-frequency attenuation for sources behind the listener
+ // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
+ // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
+ // the same as SourceToListener[2]
+ Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
+ // Sources within the minimum distance attenuate less
+ if(OrigDist < MinDist)
+ Angle *= OrigDist/MinDist;
+ if(Angle > 90.0f)
+ {
+ ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
+ ConeHF *= 1.0f - (Device->HeadDampen*scale);
+ }
+
+ DryGain *= ConeVolume;
+ if(ALSource->DryGainHFAuto)
+ DryGainHF *= ConeHF;
+
+ // Clamp to Min/Max Gain
+ DryGain = __min(DryGain,MaxVolume);
+ DryGain = __max(DryGain,MinVolume);
+
+ for(i = 0;i < NumSends;i++)
+ {
+ ALeffectslot *Slot = ALSource->Send[i].Slot;
+
+ if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
+ {
+ ALSource->Params.Send[i].WetGain = 0.0f;
+ WetGainHF[i] = 1.0f;
+ continue;
+ }
+
+ if(Slot->AuxSendAuto)
+ {
+ if(ALSource->WetGainAuto)
+ WetGain[i] *= ConeVolume;
+ if(ALSource->WetGainHFAuto)
+ WetGainHF[i] *= ConeHF;
+
+ // Clamp to Min/Max Gain
+ WetGain[i] = __min(WetGain[i],MaxVolume);
+ WetGain[i] = __max(WetGain[i],MinVolume);
+
+ if(Slot->effect.type == AL_EFFECT_REVERB ||
+ Slot->effect.type == AL_EFFECT_EAXREVERB)
+ {
+ /* Apply a decay-time transformation to the wet path, based on
+ * the attenuation of the dry path.
+ *
+ * Using the approximate (effective) source to listener
+ * distance, the initial decay of the reverb effect is
+ * calculated and applied to the wet path.
+ */
+ WetGain[i] *= aluPow(10.0f, EffectiveDist /
+ (SPEEDOFSOUNDMETRESPERSEC *
+ Slot->effect.Reverb.DecayTime) *
+ -60.0 / 20.0);
+
+ WetGainHF[i] *= aluPow(Slot->effect.Reverb.AirAbsorptionGainHF,
+ AirAbsorptionFactor * EffectiveDist);
+ }
+ }
+ else
+ {
+ /* If the slot's auxiliary send auto is off, the data sent to the
+ * effect slot is the same as the dry path, sans filter effects */
+ WetGain[i] = DryGain;
+ WetGainHF[i] = DryGainHF;
+ }
+
+ switch(ALSource->Send[i].WetFilter.type)
+ {
+ case AL_FILTER_LOWPASS:
+ WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
+ WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
+ break;
+ }
+ ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
+ }
+
+ // Apply filter gains and filters
+ switch(ALSource->DirectFilter.type)
+ {
+ case AL_FILTER_LOWPASS:
+ DryGain *= ALSource->DirectFilter.Gain;
+ DryGainHF *= ALSource->DirectFilter.GainHF;
+ break;
+ }
+ DryGain *= ListenerGain;
+
+ // Calculate Velocity
+ Pitch = ALSource->flPitch;
+ if(DopplerFactor != 0.0f)
+ {
+ ALfloat VSS, VLS;
+ ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
+ DopplerFactor;
+
+ VSS = aluDotproduct(Velocity, SourceToListener);
+ if(VSS >= MaxVelocity)
+ VSS = (MaxVelocity - 1.0f);
+ else if(VSS <= -MaxVelocity)
+ VSS = -MaxVelocity + 1.0f;
+
+ VLS = aluDotproduct(ListenerVel, SourceToListener);
+ if(VLS >= MaxVelocity)
+ VLS = (MaxVelocity - 1.0f);
+ else if(VLS <= -MaxVelocity)
+ VLS = -MaxVelocity + 1.0f;
+
+ Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
+ ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
+ }
+
+ BufferListItem = ALSource->queue;
+ while(BufferListItem != NULL)
+ {
+ ALbuffer *ALBuffer;
+ if((ALBuffer=BufferListItem->buffer) != NULL)
+ {
+ ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
+ ALBuffer->FmtType);
+ maxstep -= ResamplerPadding[ALSource->Resampler] +
+ ResamplerPrePadding[ALSource->Resampler] + 1;
+ maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
+
+ Pitch = Pitch * ALBuffer->Frequency / Frequency;
+ if(Pitch > (ALfloat)maxstep)
+ ALSource->Params.Step = maxstep<<FRACTIONBITS;
+ else
+ {
+ ALSource->Params.Step = Pitch*FRACTIONONE;
+ if(ALSource->Params.Step == 0)
+ ALSource->Params.Step = 1;
+ }
+ break;
+ }
+ BufferListItem = BufferListItem->next;
+ }
+
+ // Use energy-preserving panning algorithm for multi-speaker playback
+ length = __max(OrigDist, MinDist);
+ if(length > 0.0f)
+ {
+ ALfloat invlen = 1.0f/length;
+ Position[0] *= invlen;
+ Position[1] *= invlen;
+ Position[2] *= invlen;
+ }
+
+ pos = aluCart2LUTpos(-Position[2], Position[0]);
+ SpeakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+
+ DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
+ // elevation adjustment for directional gain. this sucks, but
+ // has low complexity
+ AmbientGain = aluSqrt(1.0/Device->NumChan);
+ for(s = 0;s < MAXCHANNELS;s++)
+ {
+ ALuint s2;
+ for(s2 = 0;s2 < MAXCHANNELS;s2++)
+ ALSource->Params.DryGains[s][s2] = 0.0f;
+ }
+ for(s = 0;s < (ALsizei)Device->NumChan;s++)
+ {
+ Channel chan = Device->Speaker2Chan[s];
+ ALfloat gain = AmbientGain + (SpeakerGain[chan]-AmbientGain)*DirGain;
+ ALSource->Params.DryGains[0][chan] = DryGain * gain;
+ }
+
+ /* Update filter coefficients. */
+ cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
+
+ /* Spatialized sources use four chained one-pole filters, so we need to
+ * take the fourth root of the squared gain, which is the same as the
+ * square root of the base gain. */
+ ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
+
+ for(i = 0;i < NumSends;i++)
+ {
+ /* The wet path uses two chained one-pole filters, so take the
+ * base gain (square root of the squared gain) */
+ ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
+ }
+}
+
+
+static __inline ALfloat aluF2F(ALfloat val)
+{
+ return val;
+}
+static __inline ALushort aluF2US(ALfloat val)
+{
+ if(val > 1.0f) return 65535;
+ if(val < -1.0f) return 0;
+ return (ALint)(val*32767.0f) + 32768;
+}
+static __inline ALshort aluF2S(ALfloat val)
+{
+ if(val > 1.0f) return 32767;
+ if(val < -1.0f) return -32768;
+ return (ALint)(val*32767.0f);
+}
+static __inline ALubyte aluF2UB(ALfloat val)
+{
+ ALushort i = aluF2US(val);
+ return i>>8;
+}
+static __inline ALbyte aluF2B(ALfloat val)
+{
+ ALshort i = aluF2S(val);
+ return i>>8;
+}
+
+static const Channel MonoChans[] = { FRONT_CENTER };
+static const Channel StereoChans[] = { FRONT_LEFT, FRONT_RIGHT };
+static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
+ BACK_LEFT, BACK_RIGHT };
+static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
+ FRONT_CENTER, LFE,
+ BACK_LEFT, BACK_RIGHT };
+static const Channel X61Chans[] = { FRONT_LEFT, FRONT_LEFT,
+ FRONT_CENTER, LFE, BACK_CENTER,
+ SIDE_LEFT, SIDE_RIGHT };
+static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
+ FRONT_CENTER, LFE,
+ BACK_LEFT, BACK_RIGHT,
+ SIDE_LEFT, SIDE_RIGHT };
+
+#define DECL_TEMPLATE(T, chans,N, func) \
+static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
+{ \
+ ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
+ ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
+ const ALuint *ChanMap = device->DevChannels; \
+ ALuint i, j, c; \
+ \
+ for(i = 0;i < SamplesToDo;i++) \
+ { \
+ for(j = 0;j < N;j++) \
+ { \
+ ALfloat samp = 0.0f; \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
+ ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
+ } \
+ buffer = ((T*)buffer) + N; \
+ } \
+}
+
+DECL_TEMPLATE(ALfloat, MonoChans,1, aluF2F)
+DECL_TEMPLATE(ALfloat, QuadChans,4, aluF2F)
+DECL_TEMPLATE(ALfloat, X51Chans,6, aluF2F)
+DECL_TEMPLATE(ALfloat, X61Chans,7, aluF2F)
+DECL_TEMPLATE(ALfloat, X71Chans,8, aluF2F)
+
+DECL_TEMPLATE(ALushort, MonoChans,1, aluF2US)
+DECL_TEMPLATE(ALushort, QuadChans,4, aluF2US)
+DECL_TEMPLATE(ALushort, X51Chans,6, aluF2US)
+DECL_TEMPLATE(ALushort, X61Chans,7, aluF2US)
+DECL_TEMPLATE(ALushort, X71Chans,8, aluF2US)
+
+DECL_TEMPLATE(ALshort, MonoChans,1, aluF2S)
+DECL_TEMPLATE(ALshort, QuadChans,4, aluF2S)
+DECL_TEMPLATE(ALshort, X51Chans,6, aluF2S)
+DECL_TEMPLATE(ALshort, X61Chans,7, aluF2S)
+DECL_TEMPLATE(ALshort, X71Chans,8, aluF2S)
+
+DECL_TEMPLATE(ALubyte, MonoChans,1, aluF2UB)
+DECL_TEMPLATE(ALubyte, QuadChans,4, aluF2UB)
+DECL_TEMPLATE(ALubyte, X51Chans,6, aluF2UB)
+DECL_TEMPLATE(ALubyte, X61Chans,7, aluF2UB)
+DECL_TEMPLATE(ALubyte, X71Chans,8, aluF2UB)
+
+DECL_TEMPLATE(ALbyte, MonoChans,1, aluF2B)
+DECL_TEMPLATE(ALbyte, QuadChans,4, aluF2B)
+DECL_TEMPLATE(ALbyte, X51Chans,6, aluF2B)
+DECL_TEMPLATE(ALbyte, X61Chans,7, aluF2B)
+DECL_TEMPLATE(ALbyte, X71Chans,8, aluF2B)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T, chans,N, func) \
+static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
+{ \
+ ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
+ ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
+ const ALuint *ChanMap = device->DevChannels; \
+ ALuint i, j, c; \
+ \
+ if(device->Bs2b) \
+ { \
+ for(i = 0;i < SamplesToDo;i++) \
+ { \
+ float samples[2] = { 0.0f, 0.0f }; \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ { \
+ samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
+ samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
+ } \
+ bs2b_cross_feed(device->Bs2b, samples); \
+ ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
+ ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
+ buffer = ((T*)buffer) + 2; \
+ } \
+ } \
+ else \
+ { \
+ for(i = 0;i < SamplesToDo;i++) \
+ { \
+ for(j = 0;j < N;j++) \
+ { \
+ ALfloat samp = 0.0f; \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
+ ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
+ } \
+ buffer = ((T*)buffer) + N; \
+ } \
+ } \
+}
+
+DECL_TEMPLATE(ALfloat, StereoChans,2, aluF2F)
+DECL_TEMPLATE(ALushort, StereoChans,2, aluF2US)
+DECL_TEMPLATE(ALshort, StereoChans,2, aluF2S)
+DECL_TEMPLATE(ALubyte, StereoChans,2, aluF2UB)
+DECL_TEMPLATE(ALbyte, StereoChans,2, aluF2B)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T, func) \
+static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
+{ \
+ switch(device->FmtChans) \
+ { \
+ case DevFmtMono: \
+ Write_##T##_MonoChans(device, buffer, SamplesToDo); \
+ break; \
+ case DevFmtStereo: \
+ Write_##T##_StereoChans(device, buffer, SamplesToDo); \
+ break; \
+ case DevFmtQuad: \
+ Write_##T##_QuadChans(device, buffer, SamplesToDo); \
+ break; \
+ case DevFmtX51: \
+ Write_##T##_X51Chans(device, buffer, SamplesToDo); \
+ break; \
+ case DevFmtX61: \
+ Write_##T##_X61Chans(device, buffer, SamplesToDo); \
+ break; \
+ case DevFmtX71: \
+ Write_##T##_X71Chans(device, buffer, SamplesToDo); \
+ break; \
+ } \
+}
+
+DECL_TEMPLATE(ALfloat, aluF2F)
+DECL_TEMPLATE(ALushort, aluF2US)
+DECL_TEMPLATE(ALshort, aluF2S)
+DECL_TEMPLATE(ALubyte, aluF2UB)
+DECL_TEMPLATE(ALbyte, aluF2B)
+
+#undef DECL_TEMPLATE
+
+ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
+{
+ ALuint SamplesToDo;
+ ALeffectslot *ALEffectSlot;
+ ALCcontext **ctx, **ctx_end;
+ ALsource **src, **src_end;
+ int fpuState;
+ ALuint i, c;
+ ALsizei e;
+
+#if defined(HAVE_FESETROUND)
+ fpuState = fegetround();
+ fesetround(FE_TOWARDZERO);
+#elif defined(HAVE__CONTROLFP)
+ fpuState = _controlfp(_RC_CHOP, _MCW_RC);
+#else
+ (void)fpuState;
+#endif
+
+ while(size > 0)
+ {
+ /* Setup variables */
+ SamplesToDo = min(size, BUFFERSIZE);
+
+ /* Clear mixing buffer */
+ memset(device->DryBuffer, 0, SamplesToDo*MAXCHANNELS*sizeof(ALfloat));
+
+ SuspendContext(NULL);
+ ctx = device->Contexts;
+ ctx_end = ctx + device->NumContexts;
+ while(ctx != ctx_end)
+ {
+ SuspendContext(*ctx);
+
+ src = (*ctx)->ActiveSources;
+ src_end = src + (*ctx)->ActiveSourceCount;
+ while(src != src_end)
+ {
+ if((*src)->state != AL_PLAYING)
+ {
+ --((*ctx)->ActiveSourceCount);
+ *src = *(--src_end);
+ continue;
+ }
+
+ if((*src)->NeedsUpdate)
+ {
+ ALsource_Update(*src, *ctx);
+ (*src)->NeedsUpdate = AL_FALSE;
+ }
+
+ MixSource(*src, device, SamplesToDo);
+ src++;
+ }
+
+ /* effect slot processing */
+ for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
+ {
+ ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
+
+ for(i = 0;i < SamplesToDo;i++)
+ {
+ ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;
+ ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
+ }
+ for(i = 0;i < 1;i++)
+ {
+ ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
+ ALEffectSlot->PendingClicks[i] = 0.0f;
+ }
+
+ ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
+ SamplesToDo, ALEffectSlot->WetBuffer,
+ device->DryBuffer);
+
+ for(i = 0;i < SamplesToDo;i++)
+ ALEffectSlot->WetBuffer[i] = 0.0f;
+ }
+
+ ProcessContext(*ctx);
+ ctx++;
+ }
+ ProcessContext(NULL);
+
+ //Post processing loop
+ for(i = 0;i < SamplesToDo;i++)
+ {
+ for(c = 0;c < MAXCHANNELS;c++)
+ {
+ device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;
+ device->DryBuffer[i][c] += device->ClickRemoval[c];
+ }
+ }
+ for(i = 0;i < MAXCHANNELS;i++)
+ {
+ device->ClickRemoval[i] += device->PendingClicks[i];
+ device->PendingClicks[i] = 0.0f;
+ }
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ Write_ALbyte(device, buffer, SamplesToDo);
+ break;
+ case DevFmtUByte:
+ Write_ALubyte(device, buffer, SamplesToDo);
+ break;
+ case DevFmtShort:
+ Write_ALshort(device, buffer, SamplesToDo);
+ break;
+ case DevFmtUShort:
+ Write_ALushort(device, buffer, SamplesToDo);
+ break;
+ case DevFmtFloat:
+ Write_ALfloat(device, buffer, SamplesToDo);
+ break;
+ }
+
+ size -= SamplesToDo;
+ }
+
+#if defined(HAVE_FESETROUND)
+ fesetround(fpuState);
+#elif defined(HAVE__CONTROLFP)
+ _controlfp(fpuState, _MCW_RC);
+#endif
+}
+
+
+ALvoid aluHandleDisconnect(ALCdevice *device)
+{
+ ALuint i;
+
+ SuspendContext(NULL);
+ for(i = 0;i < device->NumContexts;i++)
+ {
+ ALCcontext *Context = device->Contexts[i];
+ ALsource *source;
+ ALsizei pos;
+
+ SuspendContext(Context);
+
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ source = Context->SourceMap.array[pos].value;
+ if(source->state == AL_PLAYING)
+ {
+ source->state = AL_STOPPED;
+ source->BuffersPlayed = source->BuffersInQueue;
+ source->position = 0;
+ source->position_fraction = 0;
+ }
+ }
+ ProcessContext(Context);
+ }
+
+ device->Connected = ALC_FALSE;
+ ProcessContext(NULL);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifdef _WIN32
+#ifdef __MINGW64__
+#define _WIN32_IE 0x501
+#else
+#define _WIN32_IE 0x400
+#endif
+#endif
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "alMain.h"
+
+#ifdef _WIN32_IE
+#include <shlobj.h>
+#endif
+
+typedef struct ConfigEntry {
+ char *key;
+ char *value;
+} ConfigEntry;
+
+typedef struct ConfigBlock {
+ char *name;
+ ConfigEntry *entries;
+ size_t entryCount;
+} ConfigBlock;
+
+static ConfigBlock *cfgBlocks;
+static size_t cfgCount;
+
+static char buffer[1024];
+
+static void LoadConfigFromFile(FILE *f)
+{
+ ConfigBlock *curBlock = cfgBlocks;
+ ConfigEntry *ent;
+
+ while(fgets(buffer, sizeof(buffer), f))
+ {
+ size_t i = 0;
+
+ while(isspace(buffer[i]))
+ i++;
+ if(!buffer[i] || buffer[i] == '#')
+ continue;
+
+ memmove(buffer, buffer+i, strlen(buffer+i)+1);
+
+ if(buffer[0] == '[')
+ {
+ ConfigBlock *nextBlock;
+
+ i = 1;
+ while(buffer[i] && buffer[i] != ']')
+ i++;
+
+ if(!buffer[i])
+ {
+ AL_PRINT("config parse error: bad line \"%s\"\n", buffer);
+ continue;
+ }
+ buffer[i] = 0;
+
+ do {
+ i++;
+ if(buffer[i] && !isspace(buffer[i]))
+ {
+ if(buffer[i] != '#')
+ AL_PRINT("config warning: extra data after block: \"%s\"\n", buffer+i);
+ break;
+ }
+ } while(buffer[i]);
+
+ nextBlock = NULL;
+ for(i = 0;i < cfgCount;i++)
+ {
+ if(strcasecmp(cfgBlocks[i].name, buffer+1) == 0)
+ {
+ nextBlock = cfgBlocks+i;
+// AL_PRINT("found block '%s'\n", nextBlock->name);
+ break;
+ }
+ }
+
+ if(!nextBlock)
+ {
+ nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock));
+ if(!nextBlock)
+ {
+ AL_PRINT("config parse error: error reallocating config blocks\n");
+ continue;
+ }
+ cfgBlocks = nextBlock;
+ nextBlock = cfgBlocks+cfgCount;
+ cfgCount++;
+
+ nextBlock->name = strdup(buffer+1);
+ nextBlock->entries = NULL;
+ nextBlock->entryCount = 0;
+
+// AL_PRINT("found new block '%s'\n", nextBlock->name);
+ }
+ curBlock = nextBlock;
+ continue;
+ }
+
+ /* Look for the option name */
+ i = 0;
+ while(buffer[i] && buffer[i] != '#' && buffer[i] != '=' &&
+ !isspace(buffer[i]))
+ i++;
+
+ if(!buffer[i] || buffer[i] == '#' || i == 0)
+ {
+ AL_PRINT("config parse error: malformed option line: \"%s\"\n", buffer);
+ continue;
+ }
+
+ /* Seperate the option */
+ if(buffer[i] != '=')
+ {
+ buffer[i++] = 0;
+
+ while(isspace(buffer[i]))
+ i++;
+ if(buffer[i] != '=')
+ {
+ AL_PRINT("config parse error: option without a value: \"%s\"\n", buffer);
+ continue;
+ }
+ }
+ /* Find the start of the value */
+ buffer[i++] = 0;
+ while(isspace(buffer[i]))
+ i++;
+
+ /* Check if we already have this option set */
+ ent = curBlock->entries;
+ while((size_t)(ent-curBlock->entries) < curBlock->entryCount)
+ {
+ if(strcasecmp(ent->key, buffer) == 0)
+ break;
+ ent++;
+ }
+
+ if((size_t)(ent-curBlock->entries) >= curBlock->entryCount)
+ {
+ /* Allocate a new option entry */
+ ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry));
+ if(!ent)
+ {
+ AL_PRINT("config parse error: error reallocating config entries\n");
+ continue;
+ }
+ curBlock->entries = ent;
+ ent = curBlock->entries + curBlock->entryCount;
+ curBlock->entryCount++;
+
+ ent->key = strdup(buffer);
+ ent->value = NULL;
+ }
+
+ /* Look for the end of the line (Null term, new-line, or #-symbol) and
+ eat up the trailing whitespace */
+ memmove(buffer, buffer+i, strlen(buffer+i)+1);
+
+ i = 0;
+ while(buffer[i] && buffer[i] != '#' && buffer[i] != '\n')
+ i++;
+ do {
+ i--;
+ } while(isspace(buffer[i]));
+ buffer[++i] = 0;
+
+ free(ent->value);
+ ent->value = strdup(buffer);
+
+// AL_PRINT("found '%s' = '%s'\n", ent->key, ent->value);
+ }
+}
+
+void ReadALConfig(void)
+{
+ FILE *f;
+
+ cfgBlocks = calloc(1, sizeof(ConfigBlock));
+ cfgBlocks->name = strdup("general");
+ cfgCount = 1;
+
+#ifdef _WIN32
+ if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
+ {
+ size_t p = strlen(buffer);
+ snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini");
+ f = fopen(buffer, "rt");
+ if(f)
+ {
+ LoadConfigFromFile(f);
+ fclose(f);
+ }
+ }
+#else
+ f = fopen("/etc/openal/alsoft.conf", "r");
+ if(f)
+ {
+ LoadConfigFromFile(f);
+ fclose(f);
+ }
+ if(getenv("HOME") && *(getenv("HOME")))
+ {
+ snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", getenv("HOME"));
+ f = fopen(buffer, "r");
+ if(f)
+ {
+ LoadConfigFromFile(f);
+ fclose(f);
+ }
+ }
+#endif
+ if(getenv("ALSOFT_CONF"))
+ {
+ f = fopen(getenv("ALSOFT_CONF"), "r");
+ if(f)
+ {
+ LoadConfigFromFile(f);
+ fclose(f);
+ }
+ }
+}
+
+void FreeALConfig(void)
+{
+ size_t i;
+
+ for(i = 0;i < cfgCount;i++)
+ {
+ size_t j;
+ for(j = 0;j < cfgBlocks[i].entryCount;j++)
+ {
+ free(cfgBlocks[i].entries[j].key);
+ free(cfgBlocks[i].entries[j].value);
+ }
+ free(cfgBlocks[i].entries);
+ free(cfgBlocks[i].name);
+ }
+ free(cfgBlocks);
+ cfgBlocks = NULL;
+ cfgCount = 0;
+}
+
+const char *GetConfigValue(const char *blockName, const char *keyName, const char *def)
+{
+ size_t i, j;
+
+ if(!keyName)
+ return def;
+
+ if(!blockName)
+ blockName = "general";
+
+ for(i = 0;i < cfgCount;i++)
+ {
+ if(strcasecmp(cfgBlocks[i].name, blockName) != 0)
+ continue;
+
+ for(j = 0;j < cfgBlocks[i].entryCount;j++)
+ {
+ if(strcasecmp(cfgBlocks[i].entries[j].key, keyName) == 0)
+ {
+ if(cfgBlocks[i].entries[j].value[0])
+ return cfgBlocks[i].entries[j].value;
+ return def;
+ }
+ }
+ }
+
+ return def;
+}
+
+int ConfigValueExists(const char *blockName, const char *keyName)
+{
+ const char *val = GetConfigValue(blockName, keyName, "");
+ return !!val[0];
+}
+
+int GetConfigValueInt(const char *blockName, const char *keyName, int def)
+{
+ const char *val = GetConfigValue(blockName, keyName, "");
+
+ if(!val[0]) return def;
+ return strtol(val, NULL, 0);
+}
+
+float GetConfigValueFloat(const char *blockName, const char *keyName, float def)
+{
+ const char *val = GetConfigValue(blockName, keyName, "");
+
+ if(!val[0]) return def;
+#ifdef HAVE_STRTOF
+ return strtof(val, NULL);
+#else
+ return (float)strtod(val, NULL);
+#endif
+}
+
+int GetConfigValueBool(const char *blockName, const char *keyName, int def)
+{
+ const char *val = GetConfigValue(blockName, keyName, "");
+
+ if(!val[0]) return !!def;
+ return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
+ strcasecmp(val, "on") == 0 || atoi(val) != 0);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Chris Robinson.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALechoState {
+ // Must be first in all effects!
+ ALeffectState state;
+
+ ALfloat *SampleBuffer;
+ ALuint BufferLength;
+
+ // The echo is two tap. The delay is the number of samples from before the
+ // current offset
+ struct {
+ ALuint delay;
+ } Tap[2];
+ ALuint Offset;
+ // The LR gains for the first tap. The second tap uses the reverse
+ ALfloat GainL;
+ ALfloat GainR;
+
+ ALfloat FeedGain;
+
+ ALfloat Gain[MAXCHANNELS];
+
+ FILTER iirFilter;
+ ALfloat history[2];
+} ALechoState;
+
+static ALvoid EchoDestroy(ALeffectState *effect)
+{
+ ALechoState *state = (ALechoState*)effect;
+ if(state)
+ {
+ free(state->SampleBuffer);
+ state->SampleBuffer = NULL;
+ free(state);
+ }
+}
+
+static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+ ALechoState *state = (ALechoState*)effect;
+ ALuint maxlen, i;
+
+ // Use the next power of 2 for the buffer length, so the tap offsets can be
+ // wrapped using a mask instead of a modulo
+ maxlen = (ALuint)(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
+ maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
+ maxlen = NextPowerOf2(maxlen);
+
+ if(maxlen != state->BufferLength)
+ {
+ void *temp;
+
+ temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat));
+ if(!temp)
+ return AL_FALSE;
+ state->SampleBuffer = temp;
+ state->BufferLength = maxlen;
+ }
+ for(i = 0;i < state->BufferLength;i++)
+ state->SampleBuffer[i] = 0.0f;
+
+ for(i = 0;i < MAXCHANNELS;i++)
+ state->Gain[i] = 0.0f;
+ for(i = 0;i < Device->NumChan;i++)
+ {
+ Channel chan = Device->Speaker2Chan[i];
+ state->Gain[chan] = 1.0f;
+ }
+
+ return AL_TRUE;
+}
+
+static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+ ALechoState *state = (ALechoState*)effect;
+ ALuint frequency = Context->Device->Frequency;
+ ALfloat lrpan, cw, a, g;
+
+ state->Tap[0].delay = (ALuint)(Effect->Echo.Delay * frequency) + 1;
+ state->Tap[1].delay = (ALuint)(Effect->Echo.LRDelay * frequency);
+ state->Tap[1].delay += state->Tap[0].delay;
+
+ lrpan = Effect->Echo.Spread*0.5f + 0.5f;
+ state->GainL = aluSqrt( lrpan);
+ state->GainR = aluSqrt(1.0f-lrpan);
+
+ state->FeedGain = Effect->Echo.Feedback;
+
+ cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / frequency);
+ g = 1.0f - Effect->Echo.Damping;
+ a = 0.0f;
+ if(g < 0.9999f) // 1-epsilon
+ a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
+ state->iirFilter.coeff = a;
+}
+
+static ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+ ALechoState *state = (ALechoState*)effect;
+ const ALuint mask = state->BufferLength-1;
+ const ALuint tap1 = state->Tap[0].delay;
+ const ALuint tap2 = state->Tap[1].delay;
+ ALuint offset = state->Offset;
+ const ALfloat gain = Slot->Gain;
+ ALfloat samp[2], smp;
+ ALuint i;
+
+ for(i = 0;i < SamplesToDo;i++,offset++)
+ {
+ // Sample first tap
+ smp = state->SampleBuffer[(offset-tap1) & mask];
+ samp[0] = smp * state->GainL;
+ samp[1] = smp * state->GainR;
+ // Sample second tap. Reverse LR panning
+ smp = state->SampleBuffer[(offset-tap2) & mask];
+ samp[0] += smp * state->GainR;
+ samp[1] += smp * state->GainL;
+
+ // Apply damping and feedback gain to the second tap, and mix in the
+ // new sample
+ smp = lpFilter2P(&state->iirFilter, 0, smp+SamplesIn[i]);
+ state->SampleBuffer[offset&mask] = smp * state->FeedGain;
+
+ // Apply slot gain
+ samp[0] *= gain;
+ samp[1] *= gain;
+
+ SamplesOut[i][FRONT_LEFT] += state->Gain[FRONT_LEFT] * samp[0];
+ SamplesOut[i][FRONT_RIGHT] += state->Gain[FRONT_RIGHT] * samp[1];
+ SamplesOut[i][SIDE_LEFT] += state->Gain[SIDE_LEFT] * samp[0];
+ SamplesOut[i][SIDE_RIGHT] += state->Gain[SIDE_RIGHT] * samp[1];
+ SamplesOut[i][BACK_LEFT] += state->Gain[BACK_LEFT] * samp[0];
+ SamplesOut[i][BACK_RIGHT] += state->Gain[BACK_RIGHT] * samp[1];
+ }
+ state->Offset = offset;
+}
+
+ALeffectState *EchoCreate(void)
+{
+ ALechoState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state)
+ return NULL;
+
+ state->state.Destroy = EchoDestroy;
+ state->state.DeviceUpdate = EchoDeviceUpdate;
+ state->state.Update = EchoUpdate;
+ state->state.Process = EchoProcess;
+
+ state->BufferLength = 0;
+ state->SampleBuffer = NULL;
+
+ state->Tap[0].delay = 0;
+ state->Tap[1].delay = 0;
+ state->Offset = 0;
+ state->GainL = 0.0f;
+ state->GainR = 0.0f;
+
+ state->iirFilter.coeff = 0.0f;
+ state->iirFilter.history[0] = 0.0f;
+ state->iirFilter.history[1] = 0.0f;
+
+ return &state->state;
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Chris Robinson.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALmodulatorState {
+ // Must be first in all effects!
+ ALeffectState state;
+
+ enum {
+ SINUSOID,
+ SAWTOOTH,
+ SQUARE
+ } Waveform;
+
+ ALuint index;
+ ALuint step;
+
+ ALfloat Gain[MAXCHANNELS];
+
+ FILTER iirFilter;
+ ALfloat history[1];
+} ALmodulatorState;
+
+#define WAVEFORM_FRACBITS 16
+#define WAVEFORM_FRACMASK ((1<<WAVEFORM_FRACBITS)-1)
+
+static __inline ALfloat sin_func(ALuint index)
+{
+ return sin(index / (double)(1<<WAVEFORM_FRACBITS) * M_PI * 2.0f);
+}
+
+static __inline ALfloat saw_func(ALuint index)
+{
+ return index*2.0f/(1<<WAVEFORM_FRACBITS) - 1.0f;
+}
+
+static __inline ALfloat square_func(ALuint index)
+{
+ return ((index>>(WAVEFORM_FRACBITS-1))&1) ? -1.0f : 1.0f;
+}
+
+
+static __inline ALfloat hpFilter1P(FILTER *iir, ALuint offset, ALfloat input)
+{
+ ALfloat *history = &iir->history[offset];
+ ALfloat a = iir->coeff;
+ ALfloat output = input;
+
+ output = output + (history[0]-output)*a;
+ history[0] = output;
+
+ return input - output;
+}
+
+
+static ALvoid ModulatorDestroy(ALeffectState *effect)
+{
+ ALmodulatorState *state = (ALmodulatorState*)effect;
+ free(state);
+}
+
+static ALboolean ModulatorDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+ ALmodulatorState *state = (ALmodulatorState*)effect;
+ ALuint index;
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ state->Gain[index] = 0.0f;
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ state->Gain[chan] = 1.0f;
+ }
+
+ return AL_TRUE;
+}
+
+static ALvoid ModulatorUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+ ALmodulatorState *state = (ALmodulatorState*)effect;
+ ALfloat cw, a = 0.0f;
+
+ if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
+ state->Waveform = SINUSOID;
+ else if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
+ state->Waveform = SAWTOOTH;
+ else if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SQUARE)
+ state->Waveform = SQUARE;
+
+ state->step = Effect->Modulator.Frequency*(1<<WAVEFORM_FRACBITS) /
+ Context->Device->Frequency;
+ if(!state->step)
+ state->step = 1;
+
+ cw = cos(2.0*M_PI * Effect->Modulator.HighPassCutoff / Context->Device->Frequency);
+ a = (2.0f-cw) - aluSqrt(aluPow(2.0f-cw, 2.0f) - 1.0f);
+ state->iirFilter.coeff = a;
+}
+
+static ALvoid ModulatorProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+ ALmodulatorState *state = (ALmodulatorState*)effect;
+ const ALfloat gain = Slot->Gain;
+ const ALuint step = state->step;
+ ALuint index = state->index;
+ ALfloat samp;
+ ALuint i;
+
+ switch(state->Waveform)
+ {
+ case SINUSOID:
+ for(i = 0;i < SamplesToDo;i++)
+ {
+#define FILTER_OUT(func) do { \
+ samp = SamplesIn[i]; \
+ \
+ index += step; \
+ index &= WAVEFORM_FRACMASK; \
+ samp *= func(index); \
+ \
+ samp = hpFilter1P(&state->iirFilter, 0, samp); \
+ \
+ /* Apply slot gain */ \
+ samp *= gain; \
+ \
+ SamplesOut[i][FRONT_LEFT] += state->Gain[FRONT_LEFT] * samp; \
+ SamplesOut[i][FRONT_RIGHT] += state->Gain[FRONT_RIGHT] * samp; \
+ SamplesOut[i][FRONT_CENTER] += state->Gain[FRONT_CENTER] * samp; \
+ SamplesOut[i][SIDE_LEFT] += state->Gain[SIDE_LEFT] * samp; \
+ SamplesOut[i][SIDE_RIGHT] += state->Gain[SIDE_RIGHT] * samp; \
+ SamplesOut[i][BACK_LEFT] += state->Gain[BACK_LEFT] * samp; \
+ SamplesOut[i][BACK_RIGHT] += state->Gain[BACK_RIGHT] * samp; \
+ SamplesOut[i][BACK_CENTER] += state->Gain[BACK_CENTER] * samp; \
+} while(0)
+ FILTER_OUT(sin_func);
+ }
+ break;
+
+ case SAWTOOTH:
+ for(i = 0;i < SamplesToDo;i++)
+ {
+ FILTER_OUT(saw_func);
+ }
+ break;
+
+ case SQUARE:
+ for(i = 0;i < SamplesToDo;i++)
+ {
+ FILTER_OUT(square_func);
+#undef FILTER_OUT
+ }
+ break;
+ }
+ state->index = index;
+}
+
+ALeffectState *ModulatorCreate(void)
+{
+ ALmodulatorState *state;
+
+ state = malloc(sizeof(*state));
+ if(!state)
+ return NULL;
+
+ state->state.Destroy = ModulatorDestroy;
+ state->state.DeviceUpdate = ModulatorDeviceUpdate;
+ state->state.Update = ModulatorUpdate;
+ state->state.Process = ModulatorProcess;
+
+ state->index = 0.0f;
+ state->step = 1.0f;
+
+ state->iirFilter.coeff = 0.0f;
+ state->iirFilter.history[0] = 0.0f;
+
+ return &state->state;
+}
--- /dev/null
+/**
+ * Reverb for the OpenAL cross platform audio library
+ * Copyright (C) 2008-2009 by Christopher Fitzgerald.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+#include "alEffect.h"
+#include "alError.h"
+#include "alu.h"
+
+typedef struct DelayLine
+{
+ // The delay lines use sample lengths that are powers of 2 to allow the
+ // use of bit-masking instead of a modulus for wrapping.
+ ALuint Mask;
+ ALfloat *Line;
+} DelayLine;
+
+typedef struct ALverbState {
+ // Must be first in all effects!
+ ALeffectState state;
+
+ // All delay lines are allocated as a single buffer to reduce memory
+ // fragmentation and management code.
+ ALfloat *SampleBuffer;
+ ALuint TotalSamples;
+ // Master effect low-pass filter (2 chained 1-pole filters).
+ FILTER LpFilter;
+ ALfloat LpHistory[2];
+ struct {
+ // Modulator delay line.
+ DelayLine Delay;
+ // The vibrato time is tracked with an index over a modulus-wrapped
+ // range (in samples).
+ ALuint Index;
+ ALuint Range;
+ // The depth of frequency change (also in samples) and its filter.
+ ALfloat Depth;
+ ALfloat Coeff;
+ ALfloat Filter;
+ } Mod;
+ // Initial effect delay.
+ DelayLine Delay;
+ // The tap points for the initial delay. First tap goes to early
+ // reflections, the last to late reverb.
+ ALuint DelayTap[2];
+ struct {
+ // Output gain for early reflections.
+ ALfloat Gain;
+ // Early reflections are done with 4 delay lines.
+ ALfloat Coeff[4];
+ DelayLine Delay[4];
+ ALuint Offset[4];
+ // The gain for each output channel based on 3D panning (only for the
+ // EAX path).
+ ALfloat PanGain[MAXCHANNELS];
+ } Early;
+ // Decorrelator delay line.
+ DelayLine Decorrelator;
+ // There are actually 4 decorrelator taps, but the first occurs at the
+ // initial sample.
+ ALuint DecoTap[3];
+ struct {
+ // Output gain for late reverb.
+ ALfloat Gain;
+ // Attenuation to compensate for the modal density and decay rate of
+ // the late lines.
+ ALfloat DensityGain;
+ // The feed-back and feed-forward all-pass coefficient.
+ ALfloat ApFeedCoeff;
+ // Mixing matrix coefficient.
+ ALfloat MixCoeff;
+ // Late reverb has 4 parallel all-pass filters.
+ ALfloat ApCoeff[4];
+ DelayLine ApDelay[4];
+ ALuint ApOffset[4];
+ // In addition to 4 cyclical delay lines.
+ ALfloat Coeff[4];
+ DelayLine Delay[4];
+ ALuint Offset[4];
+ // The cyclical delay lines are 1-pole low-pass filtered.
+ ALfloat LpCoeff[4];
+ ALfloat LpSample[4];
+ // The gain for each output channel based on 3D panning (only for the
+ // EAX path).
+ ALfloat PanGain[MAXCHANNELS];
+ } Late;
+ struct {
+ // Attenuation to compensate for the modal density and decay rate of
+ // the echo line.
+ ALfloat DensityGain;
+ // Echo delay and all-pass lines.
+ DelayLine Delay;
+ DelayLine ApDelay;
+ ALfloat Coeff;
+ ALfloat ApFeedCoeff;
+ ALfloat ApCoeff;
+ ALuint Offset;
+ ALuint ApOffset;
+ // The echo line is 1-pole low-pass filtered.
+ ALfloat LpCoeff;
+ ALfloat LpSample;
+ // Echo mixing coefficients.
+ ALfloat MixCoeff[2];
+ } Echo;
+ // The current read offset for all delay lines.
+ ALuint Offset;
+
+ // The gain for each output channel (non-EAX path only; aliased from
+ // Late.PanGain)
+ ALfloat *Gain;
+} ALverbState;
+
+/* This coefficient is used to define the maximum frequency range controlled
+ * by the modulation depth. The current value of 0.1 will allow it to swing
+ * from 0.9x to 1.1x. This value must be below 1. At 1 it will cause the
+ * sampler to stall on the downswing, and above 1 it will cause it to sample
+ * backwards.
+ */
+static const ALfloat MODULATION_DEPTH_COEFF = 0.1f;
+
+/* 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;
+
+// When diffusion is above 0, an all-pass filter is used to take the edge off
+// the echo effect. It uses the following line length (in seconds).
+static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f;
+
+// Input into the late reverb is decorrelated between four channels. Their
+// timings are dependent on a fraction and multiplier. See the
+// UpdateDecorrelator() routine for the calculations involved.
+static const ALfloat DECO_FRACTION = 0.15f;
+static const ALfloat DECO_MULTIPLIER = 2.0f;
+
+// All delay line lengths are specified in seconds.
+
+// The lengths of the early delay lines.
+static const ALfloat EARLY_LINE_LENGTH[4] =
+{
+ 0.0015f, 0.0045f, 0.0135f, 0.0405f
+};
+
+// The lengths of the late all-pass delay lines.
+static const ALfloat ALLPASS_LINE_LENGTH[4] =
+{
+ 0.0151f, 0.0167f, 0.0183f, 0.0200f,
+};
+
+// The lengths of the late cyclical delay lines.
+static const ALfloat LATE_LINE_LENGTH[4] =
+{
+ 0.0211f, 0.0311f, 0.0461f, 0.0680f
+};
+
+// The late cyclical delay lines have a variable length dependent on the
+// effect's density parameter (inverted for some reason) and this multiplier.
+static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
+
+// Calculate the length of a delay line and store its mask and offset.
+static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay)
+{
+ ALuint samples;
+
+ // All line lengths are powers of 2, calculated from their lengths, with
+ // an additional sample in case of rounding errors.
+ samples = NextPowerOf2((ALuint)(length * frequency) + 1);
+ // All lines share a single sample buffer.
+ Delay->Mask = samples - 1;
+ Delay->Line = (ALfloat*)offset;
+ // Return the sample count for accumulation.
+ return samples;
+}
+
+// Given the allocated sample buffer, this function updates each delay line
+// offset.
+static __inline ALvoid RealizeLineOffset(ALfloat * sampleBuffer, DelayLine *Delay)
+{
+ Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line];
+}
+
+/* Calculates the delay line metrics and allocates the shared sample buffer
+ * for all lines given a flag indicating whether or not to allocate the EAX-
+ * related delays (eaxFlag) and the sample rate (frequency). If an
+ * allocation failure occurs, it returns AL_FALSE.
+ */
+static ALboolean AllocLines(ALboolean eaxFlag, ALuint frequency, ALverbState *State)
+{
+ ALuint totalSamples, index;
+ ALfloat length;
+ ALfloat *newBuffer = NULL;
+
+ // All delay line lengths are calculated to accomodate the full range of
+ // lengths given their respective paramters.
+ totalSamples = 0;
+ if(eaxFlag)
+ {
+ /* The modulator's line length is calculated from the maximum
+ * modulation time and depth coefficient, and halfed for the low-to-
+ * high frequency swing. An additional sample is added to keep it
+ * stable when there is no modulation.
+ */
+ length = (AL_EAXREVERB_MAX_MODULATION_TIME * MODULATION_DEPTH_COEFF /
+ 2.0f) + (1.0f / frequency);
+ totalSamples += CalcLineLength(length, totalSamples, frequency,
+ &State->Mod.Delay);
+ }
+
+ // The initial delay is the sum of the reflections and late reverb
+ // delays.
+ if(eaxFlag)
+ length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
+ AL_EAXREVERB_MAX_LATE_REVERB_DELAY;
+ else
+ length = AL_REVERB_MAX_REFLECTIONS_DELAY +
+ AL_REVERB_MAX_LATE_REVERB_DELAY;
+ totalSamples += CalcLineLength(length, totalSamples, frequency,
+ &State->Delay);
+
+ // The early reflection lines.
+ for(index = 0;index < 4;index++)
+ totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples,
+ frequency, &State->Early.Delay[index]);
+
+ // The decorrelator line is calculated from the lowest reverb density (a
+ // parameter value of 1).
+ length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) *
+ LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER);
+ totalSamples += CalcLineLength(length, totalSamples, frequency,
+ &State->Decorrelator);
+
+ // The late all-pass lines.
+ for(index = 0;index < 4;index++)
+ totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples,
+ frequency, &State->Late.ApDelay[index]);
+
+ // The late delay lines are calculated from the lowest reverb density.
+ for(index = 0;index < 4;index++)
+ {
+ length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER);
+ totalSamples += CalcLineLength(length, totalSamples, frequency,
+ &State->Late.Delay[index]);
+ }
+
+ if(eaxFlag)
+ {
+ // The echo all-pass and delay lines.
+ totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples,
+ frequency, &State->Echo.ApDelay);
+ totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples,
+ frequency, &State->Echo.Delay);
+ }
+
+ if(totalSamples != State->TotalSamples)
+ {
+ newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples);
+ if(newBuffer == NULL)
+ return AL_FALSE;
+ State->SampleBuffer = newBuffer;
+ State->TotalSamples = totalSamples;
+ }
+
+ // Update all delays to reflect the new sample buffer.
+ RealizeLineOffset(State->SampleBuffer, &State->Delay);
+ RealizeLineOffset(State->SampleBuffer, &State->Decorrelator);
+ for(index = 0;index < 4;index++)
+ {
+ RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]);
+ RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]);
+ RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]);
+ }
+ if(eaxFlag)
+ {
+ RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay);
+ RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay);
+ RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay);
+ }
+
+ // Clear the sample buffer.
+ for(index = 0;index < State->TotalSamples;index++)
+ State->SampleBuffer[index] = 0.0f;
+
+ return AL_TRUE;
+}
+
+// Calculate a decay coefficient given the length of each cycle and the time
+// until the decay reaches -60 dB.
+static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
+{
+ return aluPow(10.0f, length / decayTime * -60.0f / 20.0f);
+}
+
+// Calculate a decay length from a coefficient and the time until the decay
+// reaches -60 dB.
+static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
+{
+ return log10(coeff) / -60.0 * 20.0f * decayTime;
+}
+
+// Calculate the high frequency parameter for the I3DL2 coefficient
+// calculation.
+static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency)
+{
+ return cos(2.0f * M_PI * hfRef / frequency);
+}
+
+// Calculate an attenuation to be applied to the input of any echo models to
+// compensate for modal density and decay time.
+static __inline ALfloat CalcDensityGain(ALfloat a)
+{
+ /* The energy of a signal can be obtained by finding the area under the
+ * squared signal. This takes the form of Sum(x_n^2), where x is the
+ * amplitude for the sample n.
+ *
+ * Decaying feedback matches exponential decay of the form Sum(a^n),
+ * where a is the attenuation coefficient, and n is the sample. The area
+ * under this decay curve can be calculated as: 1 / (1 - a).
+ *
+ * Modifying the above equation to find the squared area under the curve
+ * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be
+ * calculated by inverting the square root of this approximation,
+ * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
+ */
+ return aluSqrt(1.0f - (a * a));
+}
+
+// Calculate the mixing matrix coefficients given a diffusion factor.
+static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
+{
+ ALfloat n, t;
+
+ // The matrix is of order 4, so n is sqrt (4 - 1).
+ n = aluSqrt(3.0f);
+ t = diffusion * atan(n);
+
+ // Calculate the first mixing matrix coefficient.
+ *x = cos(t);
+ // Calculate the second mixing matrix coefficient.
+ *y = sin(t) / n;
+}
+
+// Calculate the limited HF ratio for use with the late reverb low-pass
+// filters.
+static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime)
+{
+ ALfloat limitRatio;
+
+ /* Find the attenuation due to air absorption in dB (converting delay
+ * time to meters using the speed of sound). Then reversing the decay
+ * equation, solve for HF ratio. The delay length is cancelled out of
+ * the equation, so it can be calculated once for all lines.
+ */
+ limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) *
+ SPEEDOFSOUNDMETRESPERSEC);
+ // Need to limit the result to a minimum of 0.1, just like the HF ratio
+ // parameter.
+ limitRatio = __max(limitRatio, 0.1f);
+
+ // Using the limit calculated above, apply the upper bound to the HF
+ // ratio.
+ return __min(hfRatio, limitRatio);
+}
+
+// Calculate the coefficient for a HF (and eventually LF) decay damping
+// filter.
+static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
+{
+ ALfloat coeff, g;
+
+ // Eventually this should boost the high frequencies when the ratio
+ // exceeds 1.
+ coeff = 0.0f;
+ if (hfRatio < 1.0f)
+ {
+ // Calculate the low-pass coefficient by dividing the HF decay
+ // coefficient by the full decay coefficient.
+ g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff;
+
+ // Damping is done with a 1-pole filter, so g needs to be squared.
+ g *= g;
+ coeff = lpCoeffCalc(g, cw);
+
+ // Very low decay times will produce minimal output, so apply an
+ // upper bound to the coefficient.
+ coeff = __min(coeff, 0.98f);
+ }
+ return coeff;
+}
+
+// Update the EAX modulation index, range, and depth. Keep in mind that this
+// kind of vibrato is additive and not multiplicative as one may expect. The
+// downswing will sound stronger than the upswing.
+static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State)
+{
+ ALfloat length;
+
+ /* Modulation is calculated in two parts.
+ *
+ * The modulation time effects the sinus applied to the change in
+ * frequency. An index out of the current time range (both in samples)
+ * is incremented each sample. The range is bound to a reasonable
+ * minimum (1 sample) and when the timing changes, the index is rescaled
+ * to the new range (to keep the sinus consistent).
+ */
+ length = modTime * frequency;
+ if (length >= 1.0f) {
+ State->Mod.Index = (ALuint)(State->Mod.Index * length /
+ State->Mod.Range);
+ State->Mod.Range = (ALuint)length;
+ } else {
+ State->Mod.Index = 0;
+ State->Mod.Range = 1;
+ }
+
+ /* The modulation depth effects the amount of frequency change over the
+ * range of the sinus. It needs to be scaled by the modulation time so
+ * that a given depth produces a consistent change in frequency over all
+ * ranges of time. Since the depth is applied to a sinus value, it needs
+ * to be halfed once for the sinus range and again 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;
+}
+
+// Update the offsets for the initial effect delay line.
+static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State)
+{
+ // Calculate the initial delay taps.
+ State->DelayTap[0] = (ALuint)(earlyDelay * frequency);
+ State->DelayTap[1] = (ALuint)((earlyDelay + lateDelay) * frequency);
+}
+
+// Update the early reflections gain and line coefficients.
+static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State)
+{
+ ALuint index;
+
+ // Calculate the early reflections gain (from the master effect gain, and
+ // reflections gain parameters) with a constant attenuation of 0.5.
+ State->Early.Gain = 0.5f * reverbGain * earlyGain;
+
+ // Calculate the gain (coefficient) for each early delay line using the
+ // late delay time. This expands the early reflections to the start of
+ // the late reverb.
+ for(index = 0;index < 4;index++)
+ State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index],
+ lateDelay);
+}
+
+// Update the offsets for the decorrelator line.
+static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State)
+{
+ ALuint index;
+ ALfloat length;
+
+ /* The late reverb inputs are decorrelated to smooth the reverb tail and
+ * reduce harsh echos. The first tap occurs immediately, while the
+ * remaining taps are delayed by multiples of a fraction of the smallest
+ * cyclical delay time.
+ *
+ * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay
+ */
+ for(index = 0;index < 3;index++)
+ {
+ length = (DECO_FRACTION * aluPow(DECO_MULTIPLIER, (ALfloat)index)) *
+ LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER));
+ State->DecoTap[index] = (ALuint)(length * frequency);
+ }
+}
+
+// Update the late reverb gains, line lengths, and line coefficients.
+static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
+{
+ ALfloat length;
+ ALuint index;
+
+ /* Calculate the late reverb gain (from the master effect gain, and late
+ * reverb gain parameters). Since the output is tapped prior to the
+ * application of the next delay line coefficients, this gain needs to be
+ * attenuated by the 'x' mixing matrix coefficient as well.
+ */
+ State->Late.Gain = reverbGain * lateGain * xMix;
+
+ /* To compensate for changes in modal density and decay time of the late
+ * reverb signal, the input is attenuated based on the maximal energy of
+ * the outgoing signal. This approximation is used to keep the apparent
+ * energy of the signal equal for all ranges of density and decay time.
+ *
+ * The average length of the cyclcical delay lines is used to calculate
+ * the attenuation coefficient.
+ */
+ length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
+ LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f;
+ length *= 1.0f + (density * LATE_LINE_MULTIPLIER);
+ State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length,
+ decayTime));
+
+ // Calculate the all-pass feed-back and feed-forward coefficient.
+ State->Late.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
+
+ for(index = 0;index < 4;index++)
+ {
+ // Calculate the gain (coefficient) for each all-pass line.
+ State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index],
+ decayTime);
+
+ // Calculate the length (in seconds) of each cyclical delay line.
+ length = LATE_LINE_LENGTH[index] * (1.0f + (density *
+ LATE_LINE_MULTIPLIER));
+
+ // Calculate the delay offset for each cyclical delay line.
+ State->Late.Offset[index] = (ALuint)(length * frequency);
+
+ // Calculate the gain (coefficient) for each cyclical line.
+ State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime);
+
+ // Calculate the damping coefficient for each low-pass filter.
+ State->Late.LpCoeff[index] =
+ CalcDampingCoeff(hfRatio, length, decayTime,
+ State->Late.Coeff[index], cw);
+
+ // Attenuate the cyclical line coefficients by the mixing coefficient
+ // (x).
+ State->Late.Coeff[index] *= xMix;
+ }
+}
+
+// Update the echo gain, line offset, line coefficients, and mixing
+// coefficients.
+static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
+{
+ // Update the offset and coefficient for the echo delay line.
+ State->Echo.Offset = (ALuint)(echoTime * frequency);
+
+ // Calculate the decay coefficient for the echo line.
+ State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime);
+
+ // Calculate the energy-based attenuation coefficient for the echo delay
+ // line.
+ State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff);
+
+ // Calculate the echo all-pass feed coefficient.
+ State->Echo.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
+
+ // Calculate the echo all-pass attenuation coefficient.
+ State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime);
+
+ // Calculate the damping coefficient for each low-pass filter.
+ State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime,
+ State->Echo.Coeff, cw);
+
+ /* Calculate the echo mixing coefficients. The first is applied to the
+ * echo itself. The second is used to attenuate the late reverb when
+ * echo depth is high and diffusion is low, so the echo is slightly
+ * stronger than the decorrelated echos in the reverb tail.
+ */
+ State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth;
+ State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion));
+}
+
+// Update the early and late 3D panning gains.
+static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALverbState *State)
+{
+ ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
+ ReflectionsPan[2] };
+ ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
+ LateReverbPan[2] };
+ const ALfloat *speakerGain;
+ ALfloat dirGain;
+ ALfloat length;
+ ALuint index;
+ ALint pos;
+
+ // Calculate the 3D-panning gains for the early reflections and late
+ // reverb.
+ length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
+ if(length > 1.0f)
+ {
+ length = 1.0f / aluSqrt(length);
+ earlyPan[0] *= length;
+ earlyPan[1] *= length;
+ earlyPan[2] *= length;
+ }
+ length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
+ if(length > 1.0f)
+ {
+ length = 1.0f / aluSqrt(length);
+ latePan[0] *= length;
+ latePan[1] *= length;
+ latePan[2] *= length;
+ }
+
+ /* This code applies directional reverb just like the mixer applies
+ * directional sources. It diffuses the sound toward all speakers as the
+ * magnitude of the panning vector drops, which is only a rough
+ * approximation of the expansion of sound across the speakers from the
+ * panning direction.
+ */
+ pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]);
+ speakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+ dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ State->Early.PanGain[index] = 0.0f;
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ State->Early.PanGain[chan] = 1.0 + (speakerGain[chan]-1.0)*dirGain;
+ }
+
+
+ pos = aluCart2LUTpos(latePan[2], latePan[0]);
+ speakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+ dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ State->Late.PanGain[index] = 0.0f;
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ State->Late.PanGain[chan] = 1.0 + (speakerGain[chan]-1.0)*dirGain;
+ }
+}
+
+// Basic delay line input/output routines.
+static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
+{
+ return Delay->Line[offset&Delay->Mask];
+}
+
+static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
+{
+ Delay->Line[offset&Delay->Mask] = in;
+}
+
+// Attenuated delay line output routine.
+static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
+{
+ return coeff * Delay->Line[offset&Delay->Mask];
+}
+
+// Basic attenuated all-pass input/output routine.
+static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
+{
+ ALfloat out, feed;
+
+ out = DelayLineOut(Delay, outOffset);
+ feed = feedCoeff * in;
+ DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in);
+
+ // The time-based attenuation is only applied to the delay output to
+ // keep it from affecting the feed-back path (which is already controlled
+ // by the all-pass feed coefficient).
+ return (coeff * out) - feed;
+}
+
+// Given an input sample, this function produces modulation for the late
+// reverb.
+static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
+{
+ ALfloat sinus, frac;
+ ALuint offset;
+ ALfloat out0, out1;
+
+ // Calculate the sinus rythm (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.
+ sinus = 1.0f - cos(2.0f * M_PI * State->Mod.Index / State->Mod.Range);
+
+ // The depth determines the range over which to read the input samples
+ // from, so it must be filtered to reduce the distortion caused by even
+ // small parameter changes.
+ State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth,
+ State->Mod.Coeff);
+
+ // Calculate the read offset and fraction between it and the next sample.
+ frac = (1.0f + (State->Mod.Filter * sinus));
+ offset = (ALuint)frac;
+ frac -= offset;
+
+ // Get the two samples crossed by the offset, and feed the delay line
+ // with the next input sample.
+ out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset);
+ out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1);
+ DelayLineIn(&State->Mod.Delay, State->Offset, in);
+
+ // Step the modulation index forward, keeping it bound to its range.
+ State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range;
+
+ // The output is obtained by linearly interpolating the two samples that
+ // were acquired above.
+ return lerp(out0, out1, frac);
+}
+
+// Delay line output routine for early reflections.
+static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
+{
+ return AttenuatedDelayLineOut(&State->Early.Delay[index],
+ State->Offset - State->Early.Offset[index],
+ State->Early.Coeff[index]);
+}
+
+// Given an input sample, this function produces four-channel output for the
+// early reflections.
+static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
+{
+ ALfloat d[4], v, f[4];
+
+ // Obtain the decayed results of each early delay line.
+ d[0] = EarlyDelayLineOut(State, 0);
+ d[1] = EarlyDelayLineOut(State, 1);
+ d[2] = EarlyDelayLineOut(State, 2);
+ d[3] = EarlyDelayLineOut(State, 3);
+
+ /* The following uses a lossless scattering junction from waveguide
+ * theory. It actually amounts to a householder mixing matrix, which
+ * will produce a maximally diffuse response, and means this can probably
+ * be considered a simple feed-back delay network (FDN).
+ * N
+ * ---
+ * \
+ * v = 2/N / d_i
+ * ---
+ * i=1
+ */
+ v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
+ // The junction is loaded with the input here.
+ v += in;
+
+ // Calculate the feed values for the delay lines.
+ f[0] = v - d[0];
+ f[1] = v - d[1];
+ f[2] = v - d[2];
+ f[3] = v - d[3];
+
+ // Re-feed the delay lines.
+ DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
+ DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
+ DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
+ DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
+
+ // Output the results of the junction for all four channels.
+ out[0] = State->Early.Gain * f[0];
+ out[1] = State->Early.Gain * f[1];
+ out[2] = State->Early.Gain * f[2];
+ out[3] = State->Early.Gain * f[3];
+}
+
+// All-pass input/output routine for late reverb.
+static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
+{
+ return AllpassInOut(&State->Late.ApDelay[index],
+ State->Offset - State->Late.ApOffset[index],
+ State->Offset, in, State->Late.ApFeedCoeff,
+ State->Late.ApCoeff[index]);
+}
+
+// Delay line output routine for late reverb.
+static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
+{
+ return AttenuatedDelayLineOut(&State->Late.Delay[index],
+ State->Offset - State->Late.Offset[index],
+ State->Late.Coeff[index]);
+}
+
+// Low-pass filter input/output routine for late reverb.
+static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
+{
+ in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]);
+ State->Late.LpSample[index] = in;
+ return in;
+}
+
+// Given four decorrelated input samples, this function produces four-channel
+// output for the late reverb.
+static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
+{
+ ALfloat d[4], f[4];
+
+ // Obtain the decayed results of the cyclical delay lines, and add the
+ // corresponding input channels. Then pass the results through the
+ // low-pass filters.
+
+ // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back
+ // to 0.
+ d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2));
+ d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0));
+ d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3));
+ d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1));
+
+ // To help increase diffusion, run each line through an all-pass filter.
+ // When there is no diffusion, the shortest all-pass filter will feed the
+ // shortest delay line.
+ d[0] = LateAllPassInOut(State, 0, d[0]);
+ d[1] = LateAllPassInOut(State, 1, d[1]);
+ d[2] = LateAllPassInOut(State, 2, d[2]);
+ d[3] = LateAllPassInOut(State, 3, d[3]);
+
+ /* Late reverb is done with a modified feed-back delay network (FDN)
+ * topology. Four input lines are each fed through their own all-pass
+ * filter and then into the mixing matrix. The four outputs of the
+ * mixing matrix are then cycled back to the inputs. Each output feeds
+ * a different input to form a circlular feed cycle.
+ *
+ * The mixing matrix used is a 4D skew-symmetric rotation matrix derived
+ * using a single unitary rotational parameter:
+ *
+ * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
+ * [ -a, d, c, -b ]
+ * [ -b, -c, d, a ]
+ * [ -c, b, -a, d ]
+ *
+ * The rotation is constructed from the effect's diffusion parameter,
+ * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
+ * with differing signs, and d is the coefficient x. The matrix is thus:
+ *
+ * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
+ * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
+ * [ y, -y, x, y ] x = cos(t)
+ * [ -y, -y, -y, x ] y = sin(t) / n
+ *
+ * To reduce the number of multiplies, the x coefficient is applied with
+ * the cyclical delay line coefficients. Thus only the y coefficient is
+ * applied when mixing, and is modified to be: y / x.
+ */
+ f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3]));
+ f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
+ f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3]));
+ f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] ));
+
+ // Output the results of the matrix for all four channels, attenuated by
+ // the late reverb gain (which is attenuated by the 'x' mix coefficient).
+ out[0] = State->Late.Gain * f[0];
+ out[1] = State->Late.Gain * f[1];
+ out[2] = State->Late.Gain * f[2];
+ out[3] = State->Late.Gain * f[3];
+
+ // Re-feed the cyclical delay lines.
+ DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]);
+ DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]);
+ DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]);
+ DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]);
+}
+
+// Given an input sample, this function mixes echo into the four-channel late
+// reverb.
+static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *late)
+{
+ ALfloat out, feed;
+
+ // Get the latest attenuated echo sample for output.
+ feed = AttenuatedDelayLineOut(&State->Echo.Delay,
+ State->Offset - State->Echo.Offset,
+ State->Echo.Coeff);
+
+ // Mix the output into the late reverb channels.
+ out = State->Echo.MixCoeff[0] * feed;
+ late[0] = (State->Echo.MixCoeff[1] * late[0]) + out;
+ late[1] = (State->Echo.MixCoeff[1] * late[1]) + out;
+ late[2] = (State->Echo.MixCoeff[1] * late[2]) + out;
+ late[3] = (State->Echo.MixCoeff[1] * late[3]) + out;
+
+ // Mix the energy-attenuated input with the output and pass it through
+ // the echo low-pass filter.
+ feed += State->Echo.DensityGain * in;
+ feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff);
+ State->Echo.LpSample = feed;
+
+ // Then the echo all-pass filter.
+ feed = AllpassInOut(&State->Echo.ApDelay,
+ State->Offset - State->Echo.ApOffset,
+ State->Offset, feed, State->Echo.ApFeedCoeff,
+ State->Echo.ApCoeff);
+
+ // Feed the delay with the mixed and filtered sample.
+ DelayLineIn(&State->Echo.Delay, State->Offset, feed);
+}
+
+// Perform the non-EAX reverb pass on a given input sample, resulting in
+// four-channel output.
+static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
+{
+ ALfloat feed, taps[4];
+
+ // Low-pass filter the incoming sample.
+ in = lpFilter2P(&State->LpFilter, 0, in);
+
+ // Feed the initial delay line.
+ DelayLineIn(&State->Delay, State->Offset, in);
+
+ // Calculate the early reflection from the first delay tap.
+ in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
+ EarlyReflection(State, in, early);
+
+ // Feed the decorrelator from the energy-attenuated output of the second
+ // delay tap.
+ in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
+ feed = in * State->Late.DensityGain;
+ DelayLineIn(&State->Decorrelator, State->Offset, feed);
+
+ // Calculate the late reverb from the decorrelator taps.
+ taps[0] = feed;
+ taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
+ taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
+ taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
+ LateReverb(State, taps, late);
+
+ // Step all delays forward one sample.
+ State->Offset++;
+}
+
+// Perform the EAX reverb pass on a given input sample, resulting in four-
+// channel output.
+static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
+{
+ ALfloat feed, taps[4];
+
+ // Low-pass filter the incoming sample.
+ in = lpFilter2P(&State->LpFilter, 0, in);
+
+ // Perform any modulation on the input.
+ in = EAXModulation(State, in);
+
+ // Feed the initial delay line.
+ DelayLineIn(&State->Delay, State->Offset, in);
+
+ // Calculate the early reflection from the first delay tap.
+ in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
+ EarlyReflection(State, in, early);
+
+ // Feed the decorrelator from the energy-attenuated output of the second
+ // delay tap.
+ in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
+ feed = in * State->Late.DensityGain;
+ DelayLineIn(&State->Decorrelator, State->Offset, feed);
+
+ // Calculate the late reverb from the decorrelator taps.
+ taps[0] = feed;
+ taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
+ taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
+ taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
+ LateReverb(State, taps, late);
+
+ // Calculate and mix in any echo.
+ EAXEcho(State, in, late);
+
+ // Step all delays forward one sample.
+ State->Offset++;
+}
+
+// This destroys the reverb state. It should be called only when the effect
+// slot has a different (or no) effect loaded over the reverb effect.
+static ALvoid VerbDestroy(ALeffectState *effect)
+{
+ ALverbState *State = (ALverbState*)effect;
+ if(State)
+ {
+ free(State->SampleBuffer);
+ State->SampleBuffer = NULL;
+ free(State);
+ }
+}
+
+// This updates the device-dependant reverb state. This is called on
+// initialization and any time the device parameters (eg. playback frequency,
+// or format) have been changed.
+static ALboolean VerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint frequency = Device->Frequency;
+ ALuint index;
+
+ // Allocate the delay lines.
+ if(!AllocLines(AL_FALSE, frequency, State))
+ return AL_FALSE;
+
+ // The early reflection and late all-pass filter line lengths are static,
+ // so their offsets only need to be calculated once.
+ for(index = 0;index < 4;index++)
+ {
+ State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
+ frequency);
+ State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
+ frequency);
+ }
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ State->Gain[index] = 0.0f;
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ State->Gain[chan] = 1.0f;
+ }
+
+ return AL_TRUE;
+}
+
+// This updates the device-dependant EAX reverb state. This is called on
+// initialization and any time the device parameters (eg. playback frequency,
+// format) have been changed.
+static ALboolean EAXVerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint frequency = Device->Frequency, index;
+
+ // Allocate the delay lines.
+ if(!AllocLines(AL_TRUE, frequency, State))
+ return AL_FALSE;
+
+ // Calculate the modulation filter coefficient. Notice that the exponent
+ // is calculated given the current sample rate. This ensures that the
+ // resulting filter response over time is consistent across all sample
+ // rates.
+ State->Mod.Coeff = aluPow(MODULATION_FILTER_COEFF,
+ MODULATION_FILTER_CONST / frequency);
+
+ // The early reflection and late all-pass filter line lengths are static,
+ // so their offsets only need to be calculated once.
+ for(index = 0;index < 4;index++)
+ {
+ State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
+ frequency);
+ State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
+ frequency);
+ }
+
+ // The echo all-pass filter line length is static, so its offset only
+ // needs to be calculated once.
+ State->Echo.ApOffset = (ALuint)(ECHO_ALLPASS_LENGTH * frequency);
+
+ return AL_TRUE;
+}
+
+// This updates the reverb state. This is called any time the reverb effect
+// is loaded into a slot.
+static ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint frequency = Context->Device->Frequency;
+ ALfloat cw, x, y, hfRatio;
+
+ // Calculate the master low-pass filter (from the master effect HF gain).
+ cw = CalcI3DL2HFreq(Effect->Reverb.HFReference, frequency);
+ // This is done with 2 chained 1-pole filters, so no need to square g.
+ State->LpFilter.coeff = lpCoeffCalc(Effect->Reverb.GainHF, cw);
+
+ // Update the initial effect delay.
+ UpdateDelayLine(Effect->Reverb.ReflectionsDelay,
+ Effect->Reverb.LateReverbDelay, frequency, State);
+
+ // Update the early lines.
+ UpdateEarlyLines(Effect->Reverb.Gain, Effect->Reverb.ReflectionsGain,
+ Effect->Reverb.LateReverbDelay, State);
+
+ // Update the decorrelator.
+ UpdateDecorrelator(Effect->Reverb.Density, frequency, State);
+
+ // Get the mixing matrix coefficients (x and y).
+ CalcMatrixCoeffs(Effect->Reverb.Diffusion, &x, &y);
+ // Then divide x into y to simplify the matrix calculation.
+ State->Late.MixCoeff = y / x;
+
+ // If the HF limit parameter is flagged, calculate an appropriate limit
+ // based on the air absorption parameter.
+ hfRatio = Effect->Reverb.DecayHFRatio;
+ if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f)
+ hfRatio = CalcLimitedHfRatio(hfRatio, Effect->Reverb.AirAbsorptionGainHF,
+ Effect->Reverb.DecayTime);
+
+ // Update the late lines.
+ UpdateLateLines(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain,
+ x, Effect->Reverb.Density, Effect->Reverb.DecayTime,
+ Effect->Reverb.Diffusion, hfRatio, cw, frequency, State);
+}
+
+// This updates the EAX reverb state. This is called any time the EAX reverb
+// effect is loaded into a slot.
+static ALvoid EAXVerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint frequency = Context->Device->Frequency;
+ ALfloat cw, x, y, hfRatio;
+
+ // Calculate the master low-pass filter (from the master effect HF gain).
+ cw = CalcI3DL2HFreq(Effect->Reverb.HFReference, frequency);
+ // This is done with 2 chained 1-pole filters, so no need to square g.
+ State->LpFilter.coeff = lpCoeffCalc(Effect->Reverb.GainHF, cw);
+
+ // Update the modulator line.
+ UpdateModulator(Effect->Reverb.ModulationTime,
+ Effect->Reverb.ModulationDepth, frequency, State);
+
+ // Update the initial effect delay.
+ UpdateDelayLine(Effect->Reverb.ReflectionsDelay,
+ Effect->Reverb.LateReverbDelay, frequency, State);
+
+ // Update the early lines.
+ UpdateEarlyLines(Effect->Reverb.Gain, Effect->Reverb.ReflectionsGain,
+ Effect->Reverb.LateReverbDelay, State);
+
+ // Update the decorrelator.
+ UpdateDecorrelator(Effect->Reverb.Density, frequency, State);
+
+ // Get the mixing matrix coefficients (x and y).
+ CalcMatrixCoeffs(Effect->Reverb.Diffusion, &x, &y);
+ // Then divide x into y to simplify the matrix calculation.
+ State->Late.MixCoeff = y / x;
+
+ // If the HF limit parameter is flagged, calculate an appropriate limit
+ // based on the air absorption parameter.
+ hfRatio = Effect->Reverb.DecayHFRatio;
+ if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f)
+ hfRatio = CalcLimitedHfRatio(hfRatio, Effect->Reverb.AirAbsorptionGainHF,
+ Effect->Reverb.DecayTime);
+
+ // Update the late lines.
+ UpdateLateLines(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain,
+ x, Effect->Reverb.Density, Effect->Reverb.DecayTime,
+ Effect->Reverb.Diffusion, hfRatio, cw, frequency, State);
+
+ // Update the echo line.
+ UpdateEchoLine(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain,
+ Effect->Reverb.EchoTime, Effect->Reverb.DecayTime,
+ Effect->Reverb.Diffusion, Effect->Reverb.EchoDepth,
+ hfRatio, cw, frequency, State);
+
+ // Update early and late 3D panning.
+ Update3DPanning(Context->Device, Effect->Reverb.ReflectionsPan,
+ Effect->Reverb.LateReverbPan, State);
+}
+
+// This processes the reverb state, given the input samples and an output
+// buffer.
+static ALvoid VerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint index;
+ ALfloat early[4], late[4], out[4];
+ ALfloat gain = Slot->Gain;
+ const ALfloat *panGain = State->Gain;
+
+ for(index = 0;index < SamplesToDo;index++)
+ {
+ // Process reverb for this sample.
+ VerbPass(State, SamplesIn[index], early, late);
+
+ // Mix early reflections and late reverb.
+ out[0] = (early[0] + late[0]) * gain;
+ out[1] = (early[1] + late[1]) * gain;
+ out[2] = (early[2] + late[2]) * gain;
+ out[3] = (early[3] + late[3]) * gain;
+
+ // Output the results.
+ SamplesOut[index][FRONT_LEFT] += panGain[FRONT_LEFT] * out[0];
+ SamplesOut[index][FRONT_RIGHT] += panGain[FRONT_RIGHT] * out[1];
+ SamplesOut[index][FRONT_CENTER] += panGain[FRONT_CENTER] * out[3];
+ SamplesOut[index][SIDE_LEFT] += panGain[SIDE_LEFT] * out[0];
+ SamplesOut[index][SIDE_RIGHT] += panGain[SIDE_RIGHT] * out[1];
+ SamplesOut[index][BACK_LEFT] += panGain[BACK_LEFT] * out[0];
+ SamplesOut[index][BACK_RIGHT] += panGain[BACK_RIGHT] * out[1];
+ SamplesOut[index][BACK_CENTER] += panGain[BACK_CENTER] * out[2];
+ }
+}
+
+// This processes the EAX reverb state, given the input samples and an output
+// buffer.
+static ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint index;
+ ALfloat early[4], late[4];
+ ALfloat gain = Slot->Gain;
+
+ for(index = 0;index < SamplesToDo;index++)
+ {
+ // Process reverb for this sample.
+ EAXVerbPass(State, SamplesIn[index], early, late);
+
+ // Unfortunately, while the number and configuration of gains for
+ // panning adjust according to MAXCHANNELS, the output from the
+ // reverb engine is not so scalable.
+ SamplesOut[index][FRONT_LEFT] +=
+ (State->Early.PanGain[FRONT_LEFT]*early[0] +
+ State->Late.PanGain[FRONT_LEFT]*late[0]) * gain;
+ SamplesOut[index][FRONT_RIGHT] +=
+ (State->Early.PanGain[FRONT_RIGHT]*early[1] +
+ State->Late.PanGain[FRONT_RIGHT]*late[1]) * gain;
+ SamplesOut[index][FRONT_CENTER] +=
+ (State->Early.PanGain[FRONT_CENTER]*early[3] +
+ State->Late.PanGain[FRONT_CENTER]*late[3]) * gain;
+ SamplesOut[index][SIDE_LEFT] +=
+ (State->Early.PanGain[SIDE_LEFT]*early[0] +
+ State->Late.PanGain[SIDE_LEFT]*late[0]) * gain;
+ SamplesOut[index][SIDE_RIGHT] +=
+ (State->Early.PanGain[SIDE_RIGHT]*early[1] +
+ State->Late.PanGain[SIDE_RIGHT]*late[1]) * gain;
+ SamplesOut[index][BACK_LEFT] +=
+ (State->Early.PanGain[BACK_LEFT]*early[0] +
+ State->Late.PanGain[BACK_LEFT]*late[0]) * gain;
+ SamplesOut[index][BACK_RIGHT] +=
+ (State->Early.PanGain[BACK_RIGHT]*early[1] +
+ State->Late.PanGain[BACK_RIGHT]*late[1]) * gain;
+ SamplesOut[index][BACK_CENTER] +=
+ (State->Early.PanGain[BACK_CENTER]*early[2] +
+ State->Late.PanGain[BACK_CENTER]*late[2]) * gain;
+ }
+}
+
+// This creates the reverb state. It should be called only when the reverb
+// effect is loaded into a slot that doesn't already have a reverb effect.
+ALeffectState *VerbCreate(void)
+{
+ ALverbState *State = NULL;
+ ALuint index;
+
+ State = malloc(sizeof(ALverbState));
+ if(!State)
+ return NULL;
+
+ State->state.Destroy = VerbDestroy;
+ State->state.DeviceUpdate = VerbDeviceUpdate;
+ State->state.Update = VerbUpdate;
+ State->state.Process = VerbProcess;
+
+ State->TotalSamples = 0;
+ State->SampleBuffer = NULL;
+
+ State->LpFilter.coeff = 0.0f;
+ State->LpFilter.history[0] = 0.0f;
+ State->LpFilter.history[1] = 0.0f;
+
+ State->Mod.Delay.Mask = 0;
+ State->Mod.Delay.Line = NULL;
+ State->Mod.Index = 0;
+ State->Mod.Range = 1;
+ State->Mod.Depth = 0.0f;
+ State->Mod.Coeff = 0.0f;
+ State->Mod.Filter = 0.0f;
+
+ State->Delay.Mask = 0;
+ State->Delay.Line = NULL;
+ State->DelayTap[0] = 0;
+ State->DelayTap[1] = 0;
+
+ State->Early.Gain = 0.0f;
+ for(index = 0;index < 4;index++)
+ {
+ State->Early.Coeff[index] = 0.0f;
+ State->Early.Delay[index].Mask = 0;
+ State->Early.Delay[index].Line = NULL;
+ State->Early.Offset[index] = 0;
+ }
+
+ State->Decorrelator.Mask = 0;
+ State->Decorrelator.Line = NULL;
+ State->DecoTap[0] = 0;
+ State->DecoTap[1] = 0;
+ State->DecoTap[2] = 0;
+
+ State->Late.Gain = 0.0f;
+ State->Late.DensityGain = 0.0f;
+ State->Late.ApFeedCoeff = 0.0f;
+ State->Late.MixCoeff = 0.0f;
+ for(index = 0;index < 4;index++)
+ {
+ State->Late.ApCoeff[index] = 0.0f;
+ State->Late.ApDelay[index].Mask = 0;
+ State->Late.ApDelay[index].Line = NULL;
+ State->Late.ApOffset[index] = 0;
+
+ State->Late.Coeff[index] = 0.0f;
+ State->Late.Delay[index].Mask = 0;
+ State->Late.Delay[index].Line = NULL;
+ State->Late.Offset[index] = 0;
+
+ State->Late.LpCoeff[index] = 0.0f;
+ State->Late.LpSample[index] = 0.0f;
+ }
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ {
+ State->Early.PanGain[index] = 0.0f;
+ State->Late.PanGain[index] = 0.0f;
+ }
+
+ State->Echo.DensityGain = 0.0f;
+ State->Echo.Delay.Mask = 0;
+ State->Echo.Delay.Line = NULL;
+ State->Echo.ApDelay.Mask = 0;
+ State->Echo.ApDelay.Line = NULL;
+ State->Echo.Coeff = 0.0f;
+ State->Echo.ApFeedCoeff = 0.0f;
+ State->Echo.ApCoeff = 0.0f;
+ State->Echo.Offset = 0;
+ State->Echo.ApOffset = 0;
+ State->Echo.LpCoeff = 0.0f;
+ State->Echo.LpSample = 0.0f;
+ State->Echo.MixCoeff[0] = 0.0f;
+ State->Echo.MixCoeff[1] = 0.0f;
+
+ State->Offset = 0;
+
+ State->Gain = State->Late.PanGain;
+
+ return &State->state;
+}
+
+ALeffectState *EAXVerbCreate(void)
+{
+ ALeffectState *State = VerbCreate();
+ if(State)
+ {
+ State->DeviceUpdate = EAXVerbDeviceUpdate;
+ State->Update = EAXVerbUpdate;
+ State->Process = EAXVerbProcess;
+ }
+ return State;
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+
+
+struct RingBuffer {
+ ALubyte *mem;
+
+ ALsizei frame_size;
+ ALsizei length;
+ ALint read_pos;
+ ALint write_pos;
+
+ CRITICAL_SECTION cs;
+};
+
+
+RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length)
+{
+ RingBuffer *ring = calloc(1, sizeof(*ring));
+ if(ring)
+ {
+ ring->frame_size = frame_size;
+ ring->length = length+1;
+ ring->write_pos = 1;
+ ring->mem = malloc(ring->length * ring->frame_size);
+ if(!ring->mem)
+ {
+ free(ring);
+ ring = NULL;
+ }
+
+ InitializeCriticalSection(&ring->cs);
+ }
+ return ring;
+}
+
+void DestroyRingBuffer(RingBuffer *ring)
+{
+ if(ring)
+ {
+ DeleteCriticalSection(&ring->cs);
+ free(ring->mem);
+ free(ring);
+ }
+}
+
+ALsizei RingBufferSize(RingBuffer *ring)
+{
+ ALsizei s;
+
+ EnterCriticalSection(&ring->cs);
+ s = (ring->write_pos-ring->read_pos-1+ring->length) % ring->length;
+ LeaveCriticalSection(&ring->cs);
+
+ return s;
+}
+
+void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
+{
+ int remain;
+
+ EnterCriticalSection(&ring->cs);
+
+ remain = (ring->read_pos-ring->write_pos+ring->length) % ring->length;
+ if(remain < len) len = remain;
+
+ if(len > 0)
+ {
+ remain = ring->length - ring->write_pos;
+ if(remain < len)
+ {
+ memcpy(ring->mem+(ring->write_pos*ring->frame_size), data,
+ remain*ring->frame_size);
+ memcpy(ring->mem, data+(remain*ring->frame_size),
+ (len-remain)*ring->frame_size);
+ }
+ else
+ memcpy(ring->mem+(ring->write_pos*ring->frame_size), data,
+ len*ring->frame_size);
+
+ ring->write_pos += len;
+ ring->write_pos %= ring->length;
+ }
+
+ LeaveCriticalSection(&ring->cs);
+}
+
+void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
+{
+ int remain;
+
+ EnterCriticalSection(&ring->cs);
+
+ remain = ring->length - ring->read_pos;
+ if(remain < len)
+ {
+ memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), remain*ring->frame_size);
+ memcpy(data+(remain*ring->frame_size), ring->mem, (len-remain)*ring->frame_size);
+ }
+ else
+ memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), len*ring->frame_size);
+
+ ring->read_pos += len;
+ ring->read_pos %= ring->length;
+
+ LeaveCriticalSection(&ring->cs);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alThunk.h"
+
+
+#ifdef _WIN32
+
+typedef struct {
+ ALuint (*func)(ALvoid*);
+ ALvoid *ptr;
+ HANDLE thread;
+} ThreadInfo;
+
+static DWORD CALLBACK StarterFunc(void *ptr)
+{
+ ThreadInfo *inf = (ThreadInfo*)ptr;
+ ALint ret;
+
+ ret = inf->func(inf->ptr);
+ ExitThread((DWORD)ret);
+
+ return (DWORD)ret;
+}
+
+ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
+{
+ DWORD dummy;
+ ThreadInfo *inf = malloc(sizeof(ThreadInfo));
+ if(!inf) return 0;
+
+ inf->func = func;
+ inf->ptr = ptr;
+
+ inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, &dummy);
+ if(!inf->thread)
+ {
+ free(inf);
+ return NULL;
+ }
+
+ return inf;
+}
+
+ALuint StopThread(ALvoid *thread)
+{
+ ThreadInfo *inf = thread;
+ DWORD ret = 0;
+
+ WaitForSingleObject(inf->thread, INFINITE);
+ GetExitCodeThread(inf->thread, &ret);
+ CloseHandle(inf->thread);
+
+ free(inf);
+
+ return (ALuint)ret;
+}
+
+#else
+
+#include <pthread.h>
+
+typedef struct {
+ ALuint (*func)(ALvoid*);
+ ALvoid *ptr;
+ ALuint ret;
+ pthread_t thread;
+} ThreadInfo;
+
+static void *StarterFunc(void *ptr)
+{
+ ThreadInfo *inf = (ThreadInfo*)ptr;
+ inf->ret = inf->func(inf->ptr);
+ return NULL;
+}
+
+ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
+{
+ ThreadInfo *inf = malloc(sizeof(ThreadInfo));
+ if(!inf) return NULL;
+
+ inf->func = func;
+ inf->ptr = ptr;
+ if(pthread_create(&inf->thread, NULL, StarterFunc, inf) != 0)
+ {
+ free(inf);
+ return NULL;
+ }
+
+ return inf;
+}
+
+ALuint StopThread(ALvoid *thread)
+{
+ ThreadInfo *inf = thread;
+ ALuint ret;
+
+ pthread_join(inf->thread, NULL);
+ ret = inf->ret;
+
+ free(inf);
+
+ return ret;
+}
+
+#endif
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <alsa/asoundlib.h>
+
+
+typedef struct {
+ snd_pcm_t *pcmHandle;
+
+ ALvoid *buffer;
+ ALsizei size;
+
+ ALboolean doCapture;
+ RingBuffer *ring;
+
+ volatile int killNow;
+ ALvoid *thread;
+} alsa_data;
+
+typedef struct {
+ ALCchar *name;
+ int card, dev;
+} DevMap;
+
+static void *alsa_handle;
+#define MAKE_FUNC(f) static typeof(f) * p##f
+MAKE_FUNC(snd_strerror);
+MAKE_FUNC(snd_pcm_open);
+MAKE_FUNC(snd_pcm_close);
+MAKE_FUNC(snd_pcm_nonblock);
+MAKE_FUNC(snd_pcm_frames_to_bytes);
+MAKE_FUNC(snd_pcm_bytes_to_frames);
+MAKE_FUNC(snd_pcm_hw_params_malloc);
+MAKE_FUNC(snd_pcm_hw_params_free);
+MAKE_FUNC(snd_pcm_hw_params_any);
+MAKE_FUNC(snd_pcm_hw_params_set_access);
+MAKE_FUNC(snd_pcm_hw_params_set_format);
+MAKE_FUNC(snd_pcm_hw_params_set_channels);
+MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
+MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
+MAKE_FUNC(snd_pcm_hw_params_set_rate);
+MAKE_FUNC(snd_pcm_hw_params_set_rate_resample);
+MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
+MAKE_FUNC(snd_pcm_hw_params_set_period_time_near);
+MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
+MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
+MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
+MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
+MAKE_FUNC(snd_pcm_hw_params_get_period_size);
+MAKE_FUNC(snd_pcm_hw_params_get_access);
+MAKE_FUNC(snd_pcm_hw_params_get_periods);
+MAKE_FUNC(snd_pcm_hw_params);
+MAKE_FUNC(snd_pcm_sw_params_malloc);
+MAKE_FUNC(snd_pcm_sw_params_current);
+MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
+MAKE_FUNC(snd_pcm_sw_params);
+MAKE_FUNC(snd_pcm_sw_params_free);
+MAKE_FUNC(snd_pcm_prepare);
+MAKE_FUNC(snd_pcm_start);
+MAKE_FUNC(snd_pcm_resume);
+MAKE_FUNC(snd_pcm_wait);
+MAKE_FUNC(snd_pcm_state);
+MAKE_FUNC(snd_pcm_avail_update);
+MAKE_FUNC(snd_pcm_areas_silence);
+MAKE_FUNC(snd_pcm_mmap_begin);
+MAKE_FUNC(snd_pcm_mmap_commit);
+MAKE_FUNC(snd_pcm_readi);
+MAKE_FUNC(snd_pcm_writei);
+MAKE_FUNC(snd_pcm_drain);
+MAKE_FUNC(snd_pcm_recover);
+MAKE_FUNC(snd_pcm_info_malloc);
+MAKE_FUNC(snd_pcm_info_free);
+MAKE_FUNC(snd_pcm_info_set_device);
+MAKE_FUNC(snd_pcm_info_set_subdevice);
+MAKE_FUNC(snd_pcm_info_set_stream);
+MAKE_FUNC(snd_pcm_info_get_name);
+MAKE_FUNC(snd_ctl_pcm_next_device);
+MAKE_FUNC(snd_ctl_pcm_info);
+MAKE_FUNC(snd_ctl_open);
+MAKE_FUNC(snd_ctl_close);
+MAKE_FUNC(snd_ctl_card_info_malloc);
+MAKE_FUNC(snd_ctl_card_info_free);
+MAKE_FUNC(snd_ctl_card_info);
+MAKE_FUNC(snd_ctl_card_info_get_name);
+MAKE_FUNC(snd_card_next);
+#undef MAKE_FUNC
+
+
+static const ALCchar alsaDevice[] = "ALSA Default";
+static DevMap *allDevNameMap;
+static ALuint numDevNames;
+static DevMap *allCaptureDevNameMap;
+static ALuint numCaptureDevNames;
+
+
+void *alsa_load(void)
+{
+ if(!alsa_handle)
+ {
+ char *str;
+
+#ifdef HAVE_DLFCN_H
+ alsa_handle = dlopen("libasound.so.2", RTLD_NOW);
+ if(!alsa_handle)
+ return NULL;
+ dlerror();
+
+#define LOAD_FUNC(f) do { \
+ p##f = dlsym(alsa_handle, #f); \
+ if((str=dlerror()) != NULL) \
+ { \
+ dlclose(alsa_handle); \
+ alsa_handle = NULL; \
+ AL_PRINT("Could not load %s from libasound.so.2: %s\n", #f, str); \
+ return NULL; \
+ } \
+} while(0)
+#else
+ str = NULL;
+ alsa_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(f) p##f = f
+#endif
+
+LOAD_FUNC(snd_strerror);
+LOAD_FUNC(snd_pcm_open);
+LOAD_FUNC(snd_pcm_close);
+LOAD_FUNC(snd_pcm_nonblock);
+LOAD_FUNC(snd_pcm_frames_to_bytes);
+LOAD_FUNC(snd_pcm_bytes_to_frames);
+LOAD_FUNC(snd_pcm_hw_params_malloc);
+LOAD_FUNC(snd_pcm_hw_params_free);
+LOAD_FUNC(snd_pcm_hw_params_any);
+LOAD_FUNC(snd_pcm_hw_params_set_access);
+LOAD_FUNC(snd_pcm_hw_params_set_format);
+LOAD_FUNC(snd_pcm_hw_params_set_channels);
+LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
+LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
+LOAD_FUNC(snd_pcm_hw_params_set_rate);
+LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
+LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
+LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
+LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
+LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
+LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
+LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
+LOAD_FUNC(snd_pcm_hw_params_get_period_size);
+LOAD_FUNC(snd_pcm_hw_params_get_access);
+LOAD_FUNC(snd_pcm_hw_params_get_periods);
+LOAD_FUNC(snd_pcm_hw_params);
+LOAD_FUNC(snd_pcm_sw_params_malloc);
+LOAD_FUNC(snd_pcm_sw_params_current);
+LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
+LOAD_FUNC(snd_pcm_sw_params);
+LOAD_FUNC(snd_pcm_sw_params_free);
+LOAD_FUNC(snd_pcm_prepare);
+LOAD_FUNC(snd_pcm_start);
+LOAD_FUNC(snd_pcm_resume);
+LOAD_FUNC(snd_pcm_wait);
+LOAD_FUNC(snd_pcm_state);
+LOAD_FUNC(snd_pcm_avail_update);
+LOAD_FUNC(snd_pcm_areas_silence);
+LOAD_FUNC(snd_pcm_mmap_begin);
+LOAD_FUNC(snd_pcm_mmap_commit);
+LOAD_FUNC(snd_pcm_readi);
+LOAD_FUNC(snd_pcm_writei);
+LOAD_FUNC(snd_pcm_drain);
+LOAD_FUNC(snd_pcm_recover);
+
+LOAD_FUNC(snd_pcm_info_malloc);
+LOAD_FUNC(snd_pcm_info_free);
+LOAD_FUNC(snd_pcm_info_set_device);
+LOAD_FUNC(snd_pcm_info_set_subdevice);
+LOAD_FUNC(snd_pcm_info_set_stream);
+LOAD_FUNC(snd_pcm_info_get_name);
+LOAD_FUNC(snd_ctl_pcm_next_device);
+LOAD_FUNC(snd_ctl_pcm_info);
+LOAD_FUNC(snd_ctl_open);
+LOAD_FUNC(snd_ctl_close);
+LOAD_FUNC(snd_ctl_card_info_malloc);
+LOAD_FUNC(snd_ctl_card_info_free);
+LOAD_FUNC(snd_ctl_card_info);
+LOAD_FUNC(snd_ctl_card_info_get_name);
+LOAD_FUNC(snd_card_next);
+
+#undef LOAD_FUNC
+ }
+ return alsa_handle;
+}
+
+static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
+{
+ snd_ctl_t *handle;
+ int card, err, dev, idx;
+ snd_ctl_card_info_t *info;
+ snd_pcm_info_t *pcminfo;
+ DevMap *DevList;
+ char name[1024];
+
+ psnd_ctl_card_info_malloc(&info);
+ psnd_pcm_info_malloc(&pcminfo);
+
+ card = -1;
+ if((err=psnd_card_next(&card)) < 0)
+ AL_PRINT("Failed to find a card: %s\n", psnd_strerror(err));
+
+ DevList = malloc(sizeof(DevMap) * 1);
+ DevList[0].name = strdup("ALSA Default");
+ idx = 1;
+ while(card >= 0)
+ {
+ sprintf(name, "hw:%d", card);
+ if((err = psnd_ctl_open(&handle, name, 0)) < 0)
+ {
+ AL_PRINT("control open (%i): %s\n", card, psnd_strerror(err));
+ goto next_card;
+ }
+ if((err = psnd_ctl_card_info(handle, info)) < 0)
+ {
+ AL_PRINT("control hardware info (%i): %s\n", card, psnd_strerror(err));
+ psnd_ctl_close(handle);
+ goto next_card;
+ }
+
+ dev = -1;
+ while(1)
+ {
+ const char *cname, *dname;
+ void *temp;
+
+ if(psnd_ctl_pcm_next_device(handle, &dev) < 0)
+ AL_PRINT("snd_ctl_pcm_next_device failed\n");
+ if(dev < 0)
+ break;
+
+ psnd_pcm_info_set_device(pcminfo, dev);
+ psnd_pcm_info_set_subdevice(pcminfo, 0);
+ psnd_pcm_info_set_stream(pcminfo, stream);
+ if((err = psnd_ctl_pcm_info(handle, pcminfo)) < 0) {
+ if(err != -ENOENT)
+ AL_PRINT("control digital audio info (%i): %s\n", card, psnd_strerror(err));
+ continue;
+ }
+
+ temp = realloc(DevList, sizeof(DevMap) * (idx+1));
+ if(temp)
+ {
+ DevList = temp;
+ cname = psnd_ctl_card_info_get_name(info);
+ dname = psnd_pcm_info_get_name(pcminfo);
+ snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d) via ALSA",
+ cname, dname, card, dev);
+ DevList[idx].name = strdup(name);
+ DevList[idx].card = card;
+ DevList[idx].dev = dev;
+ idx++;
+ }
+ }
+ psnd_ctl_close(handle);
+ next_card:
+ if(psnd_card_next(&card) < 0) {
+ AL_PRINT("snd_card_next failed\n");
+ break;
+ }
+ }
+
+ psnd_pcm_info_free(pcminfo);
+ psnd_ctl_card_info_free(info);
+
+ *count = idx;
+ return DevList;
+}
+
+
+static int xrun_recovery(snd_pcm_t *handle, int err)
+{
+ err = psnd_pcm_recover(handle, err, 1);
+ if(err < 0)
+ AL_PRINT("recover failed: %s\n", psnd_strerror(err));
+ return err;
+}
+
+static int verify_state(snd_pcm_t *handle)
+{
+ snd_pcm_state_t state = psnd_pcm_state(handle);
+ if(state == SND_PCM_STATE_DISCONNECTED)
+ return -ENODEV;
+ if(state == SND_PCM_STATE_XRUN)
+ {
+ int err = xrun_recovery(handle, -EPIPE);
+ if(err < 0) return err;
+ }
+ else if(state == SND_PCM_STATE_SUSPENDED)
+ {
+ int err = xrun_recovery(handle, -ESTRPIPE);
+ if(err < 0) return err;
+ }
+
+ return state;
+}
+
+
+static ALuint ALSAProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ alsa_data *data = (alsa_data*)pDevice->ExtraData;
+ const snd_pcm_channel_area_t *areas = NULL;
+ snd_pcm_sframes_t avail, commitres;
+ snd_pcm_uframes_t offset, frames;
+ char *WritePtr;
+ int err;
+
+ SetRTPriority();
+
+ while(!data->killNow)
+ {
+ int state = verify_state(data->pcmHandle);
+ if(state < 0)
+ {
+ AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
+ aluHandleDisconnect(pDevice);
+ break;
+ }
+
+ avail = psnd_pcm_avail_update(data->pcmHandle);
+ if(avail < 0)
+ {
+ AL_PRINT("available update failed: %s\n", psnd_strerror(avail));
+ continue;
+ }
+
+ // make sure there's frames to process
+ if((snd_pcm_uframes_t)avail < pDevice->UpdateSize)
+ {
+ if(state != SND_PCM_STATE_RUNNING)
+ {
+ err = psnd_pcm_start(data->pcmHandle);
+ if(err < 0)
+ {
+ AL_PRINT("start failed: %s\n", psnd_strerror(err));
+ continue;
+ }
+ }
+ if(psnd_pcm_wait(data->pcmHandle, 1000) == 0)
+ AL_PRINT("Wait timeout... buffer size too low?\n");
+ continue;
+ }
+ avail -= avail%pDevice->UpdateSize;
+
+ // it is possible that contiguous areas are smaller, thus we use a loop
+ while(avail > 0)
+ {
+ frames = avail;
+
+ err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
+ if(err < 0)
+ {
+ AL_PRINT("mmap begin error: %s\n", psnd_strerror(err));
+ break;
+ }
+
+ WritePtr = (char*)areas->addr + (offset * areas->step / 8);
+ aluMixData(pDevice, WritePtr, frames);
+
+ commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames);
+ if(commitres < 0 || (commitres-frames) != 0)
+ {
+ AL_PRINT("mmap commit error: %s\n",
+ psnd_strerror(commitres >= 0 ? -EPIPE : commitres));
+ break;
+ }
+
+ avail -= frames;
+ }
+ }
+
+ return 0;
+}
+
+static ALuint ALSANoMMapProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ alsa_data *data = (alsa_data*)pDevice->ExtraData;
+ snd_pcm_sframes_t avail;
+ char *WritePtr;
+
+ SetRTPriority();
+
+ while(!data->killNow)
+ {
+ int state = verify_state(data->pcmHandle);
+ if(state < 0)
+ {
+ AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
+ aluHandleDisconnect(pDevice);
+ break;
+ }
+
+ WritePtr = data->buffer;
+ avail = data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
+ aluMixData(pDevice, WritePtr, avail);
+
+ while(avail > 0)
+ {
+ int ret = psnd_pcm_writei(data->pcmHandle, WritePtr, avail);
+ switch (ret)
+ {
+ case -EAGAIN:
+ continue;
+ case -ESTRPIPE:
+ case -EPIPE:
+ case -EINTR:
+ ret = psnd_pcm_recover(data->pcmHandle, ret, 1);
+ if(ret < 0)
+ avail = 0;
+ break;
+ default:
+ if (ret >= 0)
+ {
+ WritePtr += psnd_pcm_frames_to_bytes(data->pcmHandle, ret);
+ avail -= ret;
+ }
+ break;
+ }
+ if (ret < 0)
+ {
+ ret = psnd_pcm_prepare(data->pcmHandle);
+ if(ret < 0)
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ alsa_data *data;
+ char driver[64];
+ int i;
+
+ if(!alsa_load())
+ return ALC_FALSE;
+
+ strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1);
+ driver[sizeof(driver)-1] = 0;
+
+ if(!deviceName)
+ deviceName = alsaDevice;
+ else if(strcmp(deviceName, alsaDevice) != 0)
+ {
+ size_t idx;
+
+ if(!allDevNameMap)
+ allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
+
+ for(idx = 0;idx < numDevNames;idx++)
+ {
+ if(allDevNameMap[idx].name &&
+ strcmp(deviceName, allDevNameMap[idx].name) == 0)
+ {
+ if(idx > 0)
+ sprintf(driver, "hw:%d,%d", allDevNameMap[idx].card, allDevNameMap[idx].dev);
+ break;
+ }
+ }
+ if(idx == numDevNames)
+ return ALC_FALSE;
+ }
+
+ data = (alsa_data*)calloc(1, sizeof(alsa_data));
+
+ i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ if(i >= 0)
+ {
+ i = psnd_pcm_nonblock(data->pcmHandle, 0);
+ if(i < 0)
+ psnd_pcm_close(data->pcmHandle);
+ }
+ if(i < 0)
+ {
+ free(data);
+ AL_PRINT("Could not open playback device '%s': %s\n", driver, psnd_strerror(i));
+ return ALC_FALSE;
+ }
+
+ device->szDeviceName = strdup(deviceName);
+ device->ExtraData = data;
+ return ALC_TRUE;
+}
+
+static void alsa_close_playback(ALCdevice *device)
+{
+ alsa_data *data = (alsa_data*)device->ExtraData;
+
+ psnd_pcm_close(data->pcmHandle);
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean alsa_reset_playback(ALCdevice *device)
+{
+ alsa_data *data = (alsa_data*)device->ExtraData;
+ snd_pcm_uframes_t periodSizeInFrames;
+ unsigned int periodLen, bufferLen;
+ snd_pcm_sw_params_t *sp = NULL;
+ snd_pcm_hw_params_t *p = NULL;
+ snd_pcm_access_t access;
+ snd_pcm_format_t format;
+ unsigned int periods;
+ unsigned int rate;
+ int allowmmap;
+ char *err;
+ int i;
+
+
+ format = -1;
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ format = SND_PCM_FORMAT_S8;
+ break;
+ case DevFmtUByte:
+ format = SND_PCM_FORMAT_U8;
+ break;
+ case DevFmtShort:
+ format = SND_PCM_FORMAT_S16;
+ break;
+ case DevFmtUShort:
+ format = SND_PCM_FORMAT_U16;
+ break;
+ case DevFmtFloat:
+ format = SND_PCM_FORMAT_FLOAT;
+ break;
+ }
+
+ allowmmap = GetConfigValueBool("alsa", "mmap", 1);
+ periods = device->NumUpdates;
+ periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
+ bufferLen = periodLen * periods;
+ rate = device->Frequency;
+
+ err = NULL;
+ psnd_pcm_hw_params_malloc(&p);
+
+ if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
+ err = "any";
+ /* set interleaved access */
+ if(i >= 0 && (!allowmmap || (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
+ {
+ if(periods > 2)
+ {
+ periods--;
+ bufferLen = periodLen * periods;
+ }
+ if((i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+ err = "set access";
+ }
+ /* set format (implicitly sets sample bits) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
+ {
+ device->FmtType = DevFmtFloat;
+ if(format == SND_PCM_FORMAT_FLOAT ||
+ (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_FLOAT)) < 0)
+ {
+ device->FmtType = DevFmtShort;
+ if(format == SND_PCM_FORMAT_S16 ||
+ (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0)
+ {
+ device->FmtType = DevFmtUByte;
+ if(format == SND_PCM_FORMAT_U8 ||
+ (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0)
+ err = "set format";
+ }
+ }
+ }
+ /* set channels (implicitly sets frame bits) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0)
+ {
+ device->FmtChans = DevFmtStereo;
+ if((i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, 2)) < 0)
+ {
+ device->FmtChans = DevFmtMono;
+ if((i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0)
+ err = "set channels";
+ }
+ }
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0)
+ {
+ AL_PRINT("Failed to disable ALSA resampler\n");
+ i = 0;
+ }
+ /* set rate (implicitly constrains period/buffer parameters) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0)
+ err = "set rate near";
+ /* set buffer time (implicitly constrains period/buffer parameters) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0)
+ err = "set buffer time near";
+ /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0)
+ err = "set period time near";
+ /* install and prepare hardware configuration */
+ if(i >= 0 && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
+ err = "set params";
+ if(i >= 0 && (i=psnd_pcm_hw_params_get_access(p, &access)) < 0)
+ err = "get access";
+ if(i >= 0 && (i=psnd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0)
+ err = "get period size";
+ if(i >= 0 && (i=psnd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0)
+ err = "get periods";
+ if(i < 0)
+ {
+ AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
+ psnd_pcm_hw_params_free(p);
+ return ALC_FALSE;
+ }
+
+ psnd_pcm_hw_params_free(p);
+
+ err = NULL;
+ psnd_pcm_sw_params_malloc(&sp);
+
+ if((i=psnd_pcm_sw_params_current(data->pcmHandle, sp)) != 0)
+ err = "sw current";
+ if(i == 0 && (i=psnd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0)
+ err = "sw set avail min";
+ if(i == 0 && (i=psnd_pcm_sw_params(data->pcmHandle, sp)) != 0)
+ err = "sw set params";
+ if(i != 0)
+ {
+ AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
+ psnd_pcm_sw_params_free(sp);
+ return ALC_FALSE;
+ }
+
+ psnd_pcm_sw_params_free(sp);
+
+ device->Frequency = rate;
+
+ SetDefaultChannelOrder(device);
+
+ data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
+ if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
+ {
+ /* Increase periods by one, since the temp buffer counts as an extra
+ * period */
+ periods++;
+ data->buffer = malloc(data->size);
+ if(!data->buffer)
+ {
+ AL_PRINT("buffer malloc failed\n");
+ return ALC_FALSE;
+ }
+ device->UpdateSize = periodSizeInFrames;
+ device->NumUpdates = periods;
+ data->thread = StartThread(ALSANoMMapProc, device);
+ }
+ else
+ {
+ i = psnd_pcm_prepare(data->pcmHandle);
+ if(i < 0)
+ {
+ AL_PRINT("prepare error: %s\n", psnd_strerror(i));
+ return ALC_FALSE;
+ }
+ device->UpdateSize = periodSizeInFrames;
+ device->NumUpdates = periods;
+ data->thread = StartThread(ALSAProc, device);
+ }
+ if(data->thread == NULL)
+ {
+ AL_PRINT("Could not create playback thread\n");
+ free(data->buffer);
+ data->buffer = NULL;
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void alsa_stop_playback(ALCdevice *device)
+{
+ alsa_data *data = (alsa_data*)device->ExtraData;
+
+ if(data->thread)
+ {
+ data->killNow = 1;
+ StopThread(data->thread);
+ data->thread = NULL;
+ }
+ data->killNow = 0;
+ free(data->buffer);
+ data->buffer = NULL;
+}
+
+
+static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ snd_pcm_hw_params_t *p;
+ snd_pcm_uframes_t bufferSizeInFrames;
+ snd_pcm_format_t format;
+ ALuint frameSize;
+ alsa_data *data;
+ char driver[64];
+ char *err;
+ int i;
+
+ if(!alsa_load())
+ return ALC_FALSE;
+
+ strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1);
+ driver[sizeof(driver)-1] = 0;
+
+ if(!allCaptureDevNameMap)
+ allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
+
+ if(!deviceName)
+ deviceName = allCaptureDevNameMap[0].name;
+ else
+ {
+ size_t idx;
+
+ for(idx = 0;idx < numCaptureDevNames;idx++)
+ {
+ if(allCaptureDevNameMap[idx].name &&
+ strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
+ {
+ if(idx > 0)
+ sprintf(driver, "plughw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev);
+ break;
+ }
+ }
+ if(idx == numCaptureDevNames)
+ return ALC_FALSE;
+ }
+
+ data = (alsa_data*)calloc(1, sizeof(alsa_data));
+
+ i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+ if(i < 0)
+ {
+ AL_PRINT("Could not open capture device '%s': %s\n", driver, psnd_strerror(i));
+ free(data);
+ return ALC_FALSE;
+ }
+
+ format = -1;
+ switch(pDevice->FmtType)
+ {
+ case DevFmtByte:
+ format = SND_PCM_FORMAT_S8;
+ break;
+ case DevFmtUByte:
+ format = SND_PCM_FORMAT_U8;
+ break;
+ case DevFmtShort:
+ format = SND_PCM_FORMAT_S16;
+ break;
+ case DevFmtUShort:
+ format = SND_PCM_FORMAT_U16;
+ break;
+ case DevFmtFloat:
+ format = SND_PCM_FORMAT_FLOAT;
+ break;
+ }
+
+ err = NULL;
+ bufferSizeInFrames = pDevice->UpdateSize * pDevice->NumUpdates;
+ psnd_pcm_hw_params_malloc(&p);
+
+ if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
+ err = "any";
+ /* set interleaved access */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+ err = "set access";
+ /* set format (implicitly sets sample bits) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
+ err = "set format";
+ /* set channels (implicitly sets frame bits) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(pDevice->FmtChans))) < 0)
+ err = "set channels";
+ /* set rate (implicitly constrains period/buffer parameters) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0)
+ err = "set rate near";
+ /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
+ if(i >= 0 && (i=psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
+ err = "set buffer size near";
+ /* install and prepare hardware configuration */
+ if(i >= 0 && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
+ err = "set params";
+ if(i < 0)
+ {
+ AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
+ psnd_pcm_hw_params_free(p);
+ goto error;
+ }
+
+ if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
+ {
+ AL_PRINT("get size failed: %s\n", psnd_strerror(i));
+ psnd_pcm_hw_params_free(p);
+ goto error;
+ }
+
+ psnd_pcm_hw_params_free(p);
+
+ frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+ data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates);
+ if(!data->ring)
+ {
+ AL_PRINT("ring buffer create failed\n");
+ goto error;
+ }
+
+ data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
+ data->buffer = malloc(data->size);
+ if(!data->buffer)
+ {
+ AL_PRINT("buffer malloc failed\n");
+ goto error;
+ }
+
+ pDevice->szDeviceName = strdup(deviceName);
+
+ pDevice->ExtraData = data;
+ return ALC_TRUE;
+
+error:
+ free(data->buffer);
+ DestroyRingBuffer(data->ring);
+ psnd_pcm_close(data->pcmHandle);
+ free(data);
+
+ pDevice->ExtraData = NULL;
+ return ALC_FALSE;
+}
+
+static void alsa_close_capture(ALCdevice *pDevice)
+{
+ alsa_data *data = (alsa_data*)pDevice->ExtraData;
+
+ psnd_pcm_close(data->pcmHandle);
+ DestroyRingBuffer(data->ring);
+
+ free(data->buffer);
+ free(data);
+ pDevice->ExtraData = NULL;
+}
+
+static void alsa_start_capture(ALCdevice *Device)
+{
+ alsa_data *data = (alsa_data*)Device->ExtraData;
+ int err;
+
+ err = psnd_pcm_start(data->pcmHandle);
+ if(err < 0)
+ {
+ AL_PRINT("start failed: %s\n", psnd_strerror(err));
+ aluHandleDisconnect(Device);
+ }
+ else
+ data->doCapture = AL_TRUE;
+}
+
+static void alsa_stop_capture(ALCdevice *Device)
+{
+ alsa_data *data = (alsa_data*)Device->ExtraData;
+ psnd_pcm_drain(data->pcmHandle);
+ data->doCapture = AL_FALSE;
+}
+
+static ALCuint alsa_available_samples(ALCdevice *Device)
+{
+ alsa_data *data = (alsa_data*)Device->ExtraData;
+ snd_pcm_sframes_t avail;
+
+ avail = (Device->Connected ? psnd_pcm_avail_update(data->pcmHandle) : 0);
+ if(avail < 0)
+ {
+ AL_PRINT("avail update failed: %s\n", psnd_strerror(avail));
+
+ if((avail=psnd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
+ {
+ if(data->doCapture)
+ avail = psnd_pcm_start(data->pcmHandle);
+ if(avail >= 0)
+ avail = psnd_pcm_avail_update(data->pcmHandle);
+ }
+ if(avail < 0)
+ {
+ AL_PRINT("restore error: %s\n", psnd_strerror(avail));
+ aluHandleDisconnect(Device);
+ }
+ }
+ while(avail > 0)
+ {
+ snd_pcm_sframes_t amt;
+
+ amt = psnd_pcm_bytes_to_frames(data->pcmHandle, data->size);
+ if(avail < amt) amt = avail;
+
+ amt = psnd_pcm_readi(data->pcmHandle, data->buffer, amt);
+ if(amt < 0)
+ {
+ AL_PRINT("read error: %s\n", psnd_strerror(amt));
+
+ if(amt == -EAGAIN)
+ continue;
+ if((amt=psnd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
+ {
+ if(data->doCapture)
+ amt = psnd_pcm_start(data->pcmHandle);
+ if(amt >= 0)
+ amt = psnd_pcm_avail_update(data->pcmHandle);
+ }
+ if(amt < 0)
+ {
+ AL_PRINT("restore error: %s\n", psnd_strerror(amt));
+ aluHandleDisconnect(Device);
+ break;
+ }
+ avail = amt;
+ continue;
+ }
+
+ WriteRingBuffer(data->ring, data->buffer, amt);
+ avail -= amt;
+ }
+
+ return RingBufferSize(data->ring);
+}
+
+static void alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
+{
+ alsa_data *data = (alsa_data*)Device->ExtraData;
+
+ if(Samples <= alsa_available_samples(Device))
+ ReadRingBuffer(data->ring, Buffer, Samples);
+ else
+ alcSetError(Device, ALC_INVALID_VALUE);
+}
+
+
+BackendFuncs alsa_funcs = {
+ alsa_open_playback,
+ alsa_close_playback,
+ alsa_reset_playback,
+ alsa_stop_playback,
+ alsa_open_capture,
+ alsa_close_capture,
+ alsa_start_capture,
+ alsa_stop_capture,
+ alsa_capture_samples,
+ alsa_available_samples
+};
+
+void alc_alsa_init(BackendFuncs *func_list)
+{
+ *func_list = alsa_funcs;
+}
+
+void alc_alsa_deinit(void)
+{
+ ALuint i;
+
+ for(i = 0;i < numDevNames;++i)
+ free(allDevNameMap[i].name);
+ free(allDevNameMap);
+ allDevNameMap = NULL;
+ numDevNames = 0;
+
+ for(i = 0;i < numCaptureDevNames;++i)
+ free(allCaptureDevNameMap[i].name);
+ free(allCaptureDevNameMap);
+ allCaptureDevNameMap = NULL;
+ numCaptureDevNames = 0;
+
+ if(alsa_handle)
+ {
+#ifdef HAVE_DLFCN_H
+ dlclose(alsa_handle);
+#endif
+ alsa_handle = NULL;
+ }
+}
+
+void alc_alsa_probe(int type)
+{
+ ALuint i;
+
+ if(!alsa_load())
+ return;
+
+ if(type == DEVICE_PROBE)
+ AppendDeviceList(alsaDevice);
+ else if(type == ALL_DEVICE_PROBE)
+ {
+ for(i = 0;i < numDevNames;++i)
+ free(allDevNameMap[i].name);
+
+ free(allDevNameMap);
+ allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
+
+ for(i = 0;i < numDevNames;++i)
+ AppendAllDeviceList(allDevNameMap[i].name);
+ }
+ else if(type == CAPTURE_DEVICE_PROBE)
+ {
+ for(i = 0;i < numCaptureDevNames;++i)
+ free(allCaptureDevNameMap[i].name);
+
+ free(allCaptureDevNameMap);
+ allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
+
+ for(i = 0;i < numCaptureDevNames;++i)
+ AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <avsystem.h>
+#include <avsys-audio.h>
+#include <audio-session-manager.h>
+#include <mm_session.h>
+#include <mm_session_private.h>
+
+#ifndef SOUND_MIXER_READ
+#define SOUND_MIXER_READ MIXER_READ
+#endif
+#ifndef SOUND_MIXER_WRITE
+#define SOUND_MIXER_WRITE MIXER_WRITE
+#endif
+
+//for debug
+#define LOG_LEVEL_2
+#if defined(LOG_LEVEL_0)
+#define func_in()
+#define func_out()
+#elif defined(LOG_LEVEL_1)
+#define func_in() fprintf(stderr,"<< %s\n", __FUNCTION__)
+#define func_out() fprintf(stderr, ">> %s\n", __FUNCTION__)
+#elif defined(LOG_LEVEL_2)
+#include <dlog.h>
+#define LOG_TAG "MMFW_OPENAL"
+#define func_in() SLOG(LOG_VERBOSE, LOG_TAG, "<< %s\n", __FUNCTION__)
+#define func_out() SLOG(LOG_VERBOSE, LOG_TAG, ">> %s\n", __FUNCTION__)
+#endif
+
+static const ALCchar avsystem_Device[] = "avsystem";
+
+typedef struct {
+ avsys_audio_param_t param;
+ avsys_handle_t handle;
+ int data_size;
+ ALubyte *mix_data;
+ volatile int killNow;
+ ALboolean doCapture;
+ ALvoid *thread;
+ int asm_handle;
+ ASM_sound_events_t asm_event;
+} avsys_data;
+
+
+ASM_cb_result_t
+asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
+{
+ avsys_data *data = (avsys_data*) cb_data;
+ ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
+ if(!data)
+ {
+ AL_PRINT("asm_callback data is null\n");
+ return cb_res;
+ }
+
+ switch(command)
+ {
+ case ASM_COMMAND_STOP:
+ case ASM_COMMAND_PAUSE:
+ if(AVSYS_FAIL(avsys_audio_set_mute(data->handle, AVSYS_AUDIO_MUTE)))
+ {
+ AL_PRINT("set handle mute failed\n");
+ }
+ cb_res = ASM_CB_RES_PAUSE;
+ break;
+ case ASM_COMMAND_PLAY:
+ case ASM_COMMAND_RESUME:
+ if(AVSYS_FAIL(avsys_audio_set_mute(data->handle, AVSYS_AUDIO_UNMUTE)))
+ {
+ AL_PRINT("set handle unmute failed\n");
+ }
+ cb_res = ASM_CB_RES_PLAYING;
+ break;
+ }
+ return cb_res;
+}
+
+static ALuint AvsysProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ avsys_data *data;
+ ALint remaining = 0;
+ ALint wrote;
+ ALint lenByte, lenSample;
+
+ ALvoid* WritePtr = NULL;
+
+ func_in();
+ if (ptr == NULL)
+ {
+ AL_PRINT("__thread_input_parameter_is_null\n");
+ return 1;
+ }
+
+ data = (avsys_data*)pDevice->ExtraData;
+ if (data == NULL)
+ {
+ AL_PRINT("__thread_input_parameter_is_null\n");
+ return 1;
+ }
+ if (data->mix_data == NULL)
+ {
+ AL_PRINT("____mix_data is null\n");
+ return 1;
+ }
+
+ while(!data->killNow && pDevice->Connected)
+ {
+ lenByte = data->data_size;
+ lenSample = lenByte / FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+ WritePtr = data->mix_data;
+
+ aluMixData(pDevice, data->mix_data, lenSample);
+
+ while(lenByte > 0 && !data->killNow)
+ {
+ wrote = avsys_audio_write(data->handle, WritePtr, lenByte);
+ if(wrote < 0)
+ {
+ lenByte =0;
+ aluHandleDisconnect(pDevice);
+ }
+ lenByte -= wrote;
+ WritePtr += wrote;
+ }
+ }
+
+ func_out();
+ return 0;
+}
+
+static ALuint AvsysCaptureProc(ALvoid *ptr)
+{
+ (void)ptr;
+ return 0;
+}
+
+static ALCboolean avsystem_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ avsys_data *data = NULL;
+ int BufferSize =0;
+ int result = ALC_TRUE;
+
+ func_in();
+
+ if(deviceName)
+ {
+ if(strcmp(deviceName, avsystem_Device) != 0)
+ return ALC_FALSE;
+ device->szDeviceName = strdup(avsystem_Device);
+ }
+ else
+ device->szDeviceName = strdup(avsystem_Device);
+
+
+ data = (avsys_data*)calloc(1, sizeof(avsys_data));
+ if(data == NULL)
+ goto error;
+
+ data->param.mode = AVSYS_AUDIO_MODE_OUTPUT_LOW_LATENCY;
+ data->param.priority = AVSYS_AUDIO_PRIORITY_0;
+ data->param.channels = ChannelsFromDevFmt(device->FmtChans);;
+ data->param.samplerate = device->Frequency;
+ data->param.handle_route = 0;
+ data->param.vol_type = AVSYS_AUDIO_VOLUME_TYPE_MEDIA;
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ case DevFmtUByte:
+ data->param.format = AVSYS_AUDIO_FORMAT_8BIT;
+ break;
+ case DevFmtUShort:
+ device->FmtType = DevFmtShort;
+ /* fall-through */
+ case DevFmtShort:
+ data->param.format = AVSYS_AUDIO_FORMAT_16BIT;
+ break;
+#if defined(FORMAT_32)
+ case DevFmtFloat:
+ data->param.format = AVSYS_AUDIO_FORMAT_32BIT;
+ break;
+#endif
+ default :
+ AL_PRINT("Not supported format\n");
+ break;
+ }
+
+ if(AVSYS_STATE_SUCCESS !=
+ avsys_audio_open(&data->param, &data->handle, &BufferSize))
+ {
+ AL_PRINT("avsys_audio_open() failed\n");
+ goto error;
+ }
+ data->data_size = BufferSize;
+ device->ExtraData = data;
+
+ func_out();
+ return ALC_TRUE;
+
+error:
+ if(data != NULL)
+ {
+ if(data->handle)
+ {
+ avsys_audio_close(data->handle);
+ }
+ free(data);
+ data = NULL;
+ }
+
+ return ALC_FALSE;
+
+}
+
+static ALCboolean avsystem_reset_playback(ALCdevice *device)
+{
+ avsys_data *data = NULL;
+ avsys_audio_volume_t avsys_volume;
+ int loaded_volume = 9;
+ int sessionType = MM_SESSION_TYPE_SHARE;
+ ASM_sound_events_t asm_event = ASM_EVENT_NONE;
+ int errorcode = 0;
+ func_in();
+ if(device == NULL)
+ {
+ AL_PRINT("input parameter is null [%d][%s]\n", __LINE__,__func__);
+ return ALC_FALSE;
+ }
+ if(device->ExtraData == NULL)
+ {
+ AL_PRINT("input parameter is null [%d][%s]\n", __LINE__,__func__);
+ return ALC_FALSE;
+ }
+ data = (avsys_data*)device->ExtraData;
+
+ // read session type
+ if(_mm_session_util_read_type(-1, &sessionType) < 0)
+ {
+ AL_PRINT("Read Session Type failed. Set default \"Share\" type\n");
+ sessionType = MM_SESSION_TYPE_SHARE;
+ if(mm_session_init(sessionType) < 0)
+ {
+ AL_PRINT("mm_session_init() failed\n");
+ return ALC_FALSE;
+ }
+ }
+
+ // convert MM_SESSION_TYPE to ASM_EVENT_TYPE
+ if(sessionType != MM_SESSION_TYPE_CALL)
+ {
+ switch(sessionType)
+ {
+ case MM_SESSION_TYPE_SHARE:
+ asm_event = ASM_EVENT_SHARE_OPENAL;
+ break;
+ case MM_SESSION_TYPE_EXCLUSIVE:
+ asm_event = ASM_EVENT_EXCLUSIVE_OPENAL;
+ break;
+ case MM_SESSION_TYPE_NOTIFY:
+ asm_event = ASM_EVENT_NOTIFY;
+ break;
+ case MM_SESSION_TYPE_ALARM:
+ asm_event = ASM_EVENT_ALARM;
+ break;
+ default:
+ AL_PRINT("Unexpected %d\n", sessionType);
+ return ALC_FALSE;
+ }
+ }
+
+ data->asm_event = asm_event;
+
+
+ data->mix_data = calloc(1, data->data_size);
+ if(data->mix_data == NULL)
+ {
+ AL_PRINT("Memory Allocation failed\n");
+ return ALC_FALSE;
+ }
+ device->UpdateSize = data->data_size /FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ SetDefaultChannelOrder(device);
+
+ // register asm handle
+ if(!ASM_register_sound(-1, &data->asm_handle, asm_event, ASM_STATE_PLAYING, asm_callback, data, ASM_RESOURCE_NONE, &errorcode))
+ {
+ AL_PRINT("ASM_register_sound() failed 0x%x\n", errorcode);
+ return ALC_FALSE;
+ }
+
+ data->thread = StartThread(AvsysProc, device);
+ if(data->thread == NULL)
+ {
+ AL_PRINT("Could not create playback thread\n");
+ if(!ASM_unregister_sound(data->asm_handle, asm_event, &errorcode))
+ {
+ AL_PRINT("ASM_unregister_sound() failed 0x%x\n", errorcode);
+ return ALC_FALSE;
+ }
+ return ALC_FALSE;
+ }
+ func_out();
+ return ALC_TRUE;
+}
+
+static void avsystem_stop_playback(ALCdevice *device)
+{
+ int errorcode = 0;
+ avsys_data *data = (avsys_data*)device->ExtraData;
+ func_in();
+ if(data->thread)
+ {
+ data->killNow = 1;
+ StopThread(data->thread);
+ AL_PRINT("Thread Stopped\n");
+ data->thread = NULL;
+ }
+
+ free(data->mix_data);
+ data->mix_data = NULL;
+
+ if(data->asm_event != ASM_EVENT_CALL)
+ {
+ if(!ASM_unregister_sound(data->asm_handle, data->asm_event, &errorcode))
+ {
+ AL_PRINT("ASM_unregister failed in avsystem_stop_playback with 0x%x\n", errorcode);
+ }
+ }
+
+ func_out();
+}
+
+static void avsystem_close_playback(ALCdevice *device)
+{
+ avsys_data *data = (avsys_data*)device->ExtraData;
+
+ func_in();
+
+ avsys_audio_close(data->handle);
+
+ free(data);
+ device->ExtraData = NULL;
+
+ func_out();
+}
+
+static ALCboolean avsystem_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
+{
+ func_in();
+ (void)device;
+ (void)deviceName;
+ func_out();
+ return ALC_FALSE;
+}
+
+static void avsystem_close_capture(ALCdevice *device)
+{
+ func_in();
+ (void)device;
+ func_out();
+}
+
+static void avsystem_start_capture(ALCdevice *pDevice)
+{
+ func_in();
+ (void)pDevice;
+ func_out();
+}
+
+static void avsystem_stop_capture(ALCdevice *pDevice)
+{
+ func_in();
+ (void)pDevice;
+ func_out();
+}
+
+static void avsystem_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+ func_in();
+ (void)pDevice;
+ (void)pBuffer;
+ (void)lSamples;
+ func_out();
+}
+
+static ALCuint avsystem_available_samples(ALCdevice *pDevice)
+{
+ func_in();
+ (void)pDevice;
+ return 0;
+ func_out();
+}
+
+BackendFuncs avsys_funcs = {
+ avsystem_open_playback,
+ avsystem_close_playback,
+ avsystem_reset_playback,
+ avsystem_stop_playback,
+ avsystem_open_capture,
+ avsystem_close_capture,
+ avsystem_start_capture,
+ avsystem_stop_capture,
+ avsystem_capture_samples,
+ avsystem_available_samples,
+};
+
+void alc_avsystem_init(BackendFuncs *func_list)
+{
+ func_in();
+ *func_list = avsys_funcs;
+ func_out();
+}
+
+void alc_avsystem_deinit(void)
+{
+ func_in();
+ func_out();
+}
+
+void alc_avsystem_probe(int type)
+{
+ if(type == DEVICE_PROBE)
+ AppendDeviceList(avsystem_Device);
+ else if(type == ALL_DEVICE_PROBE)
+ AppendAllDeviceList(avsystem_Device);
+ else if(type == CAPTURE_DEVICE_PROBE)
+ AppendCaptureDeviceList(avsystem_Device);
+
+}
--- /dev/null
+/*-
+ * Copyright (c) 2005 Boris Mikhaylov
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "bs2b.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Single pole IIR filter.
+ * O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1]
+ */
+
+/* Lowpass filter */
+#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1))
+
+/* Highboost filter */
+#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1))
+
+/* Set up all data. */
+static void init(struct bs2b *bs2b)
+{
+ double Fc_lo, Fc_hi;
+ double G_lo, G_hi;
+ double x;
+
+ if ((bs2b->srate > 192000) || (bs2b->srate < 2000))
+ bs2b->srate = BS2B_DEFAULT_SRATE;
+
+ switch(bs2b->level)
+ {
+ case BS2B_LOW_CLEVEL: /* Low crossfeed level */
+ Fc_lo = 360.0;
+ Fc_hi = 501.0;
+ G_lo = 0.398107170553497;
+ G_hi = 0.205671765275719;
+ break;
+
+ case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */
+ Fc_lo = 500.0;
+ Fc_hi = 711.0;
+ G_lo = 0.459726988530872;
+ G_hi = 0.228208484414988;
+ break;
+
+ case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */
+ Fc_lo = 700.0;
+ Fc_hi = 1021.0;
+ G_lo = 0.530884444230988;
+ G_hi = 0.250105790667544;
+ break;
+
+ case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */
+ Fc_lo = 360.0;
+ Fc_hi = 494.0;
+ G_lo = 0.316227766016838;
+ G_hi = 0.168236228897329;
+ break;
+
+ case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */
+ Fc_lo = 500.0;
+ Fc_hi = 689.0;
+ G_lo = 0.354813389233575;
+ G_hi = 0.187169483835901;
+ break;
+
+ default: /* High easy crossfeed level */
+ bs2b->level = BS2B_HIGH_ECLEVEL;
+
+ Fc_lo = 700.0;
+ Fc_hi = 975.0;
+ G_lo = 0.398107170553497;
+ G_hi = 0.205671765275719;
+ break;
+ } /* switch */
+
+ /* $fc = $Fc / $s;
+ * $d = 1 / 2 / pi / $fc;
+ * $x = exp(-1 / $d);
+ */
+
+ x = exp(-2.0 * M_PI * Fc_lo / bs2b->srate);
+ bs2b->b1_lo = x;
+ bs2b->a0_lo = G_lo * (1.0 - x);
+
+ x = exp(-2.0 * M_PI * Fc_hi / bs2b->srate);
+ bs2b->b1_hi = x;
+ bs2b->a0_hi = 1.0 - G_hi * (1.0 - x);
+ bs2b->a1_hi = -x;
+
+ bs2b->gain = 1.0 / (1.0 - G_hi + G_lo);
+} /* init */
+
+/* Exported functions.
+ * See descriptions in "bs2b.h"
+ */
+
+void bs2b_set_level(struct bs2b *bs2b, int level)
+{
+ if(level == bs2b->level)
+ return;
+ bs2b->level = level;
+ init(bs2b);
+} /* bs2b_set_level */
+
+int bs2b_get_level(struct bs2b *bs2b)
+{
+ return bs2b->level;
+} /* bs2b_get_level */
+
+void bs2b_set_srate(struct bs2b *bs2b, int srate)
+{
+ if (srate == bs2b->srate)
+ return;
+ bs2b->srate = srate;
+ init(bs2b);
+} /* bs2b_set_srate */
+
+int bs2b_get_srate(struct bs2b *bs2b)
+{
+ return bs2b->srate;
+} /* bs2b_get_srate */
+
+void bs2b_clear(struct bs2b *bs2b)
+{
+ int loopv = sizeof(bs2b->last_sample);
+
+ while (loopv)
+ {
+ ((char *)&bs2b->last_sample)[--loopv] = 0;
+ }
+} /* bs2b_clear */
+
+int bs2b_is_clear(struct bs2b *bs2b)
+{
+ int loopv = sizeof(bs2b->last_sample);
+
+ while (loopv)
+ {
+ if (((char *)&bs2b->last_sample)[--loopv] != 0)
+ return 0;
+ }
+ return 1;
+} /* bs2b_is_clear */
+
+void bs2b_cross_feed(struct bs2b *bs2b, float *sample)
+{
+ /* Lowpass filter */
+ bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]);
+ bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]);
+
+ /* Highboost filter */
+ bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]);
+ bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]);
+ bs2b->last_sample.asis[0] = sample[0];
+ bs2b->last_sample.asis[1] = sample[1];
+
+ /* Crossfeed */
+ sample[0] = bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1];
+ sample[1] = bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0];
+
+ /* Bass boost cause allpass attenuation */
+ sample[0] *= bs2b->gain;
+ sample[1] *= bs2b->gain;
+
+ /* Clipping of overloaded samples */
+#if 0
+ if (sample[0] > 1.0)
+ sample[0] = 1.0;
+ if (sample[0] < -1.0)
+ sample[0] = -1.0;
+ if (sample[1] > 1.0)
+ sample[1] = 1.0;
+ if (sample[1] < -1.0)
+ sample[1] = -1.0;
+#endif
+} /* bs2b_cross_feed */
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#define _WIN32_WINNT 0x0500
+#define INITGUID
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+#include <dsound.h>
+#include <cguid.h>
+#include <mmreg.h>
+#ifndef _WAVEFORMATEXTENSIBLE_
+#include <ks.h>
+#include <ksmedia.h>
+#endif
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#ifndef DSSPEAKER_5POINT1
+#define DSSPEAKER_5POINT1 6
+#endif
+#ifndef DSSPEAKER_7POINT1
+#define DSSPEAKER_7POINT1 7
+#endif
+
+DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+
+static void *ds_handle;
+static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
+static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
+
+
+typedef struct {
+ // DirectSound Playback Device
+ LPDIRECTSOUND lpDS;
+ LPDIRECTSOUNDBUFFER DSpbuffer;
+ LPDIRECTSOUNDBUFFER DSsbuffer;
+
+ volatile int killNow;
+ ALvoid *thread;
+} DSoundData;
+
+
+typedef struct {
+ ALCchar *name;
+ GUID guid;
+} DevMap;
+
+static const ALCchar dsDevice[] = "DirectSound Default";
+static DevMap *DeviceList;
+static ALuint NumDevices;
+
+
+void *DSoundLoad(void)
+{
+ if(!ds_handle)
+ {
+#ifdef _WIN32
+ ds_handle = LoadLibraryA("dsound.dll");
+ if(ds_handle == NULL)
+ {
+ AL_PRINT("Failed to load dsound.dll\n");
+ return NULL;
+ }
+
+#define LOAD_FUNC(f) do { \
+ p##f = (void*)GetProcAddress((HMODULE)ds_handle, #f); \
+ if(p##f == NULL) \
+ { \
+ FreeLibrary(ds_handle); \
+ ds_handle = NULL; \
+ AL_PRINT("Could not load %s from dsound.dll\n", #f); \
+ return NULL; \
+ } \
+} while(0)
+#else
+ ds_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(f) p##f = f
+#endif
+
+LOAD_FUNC(DirectSoundCreate);
+LOAD_FUNC(DirectSoundEnumerateA);
+#undef LOAD_FUNC
+ }
+ return ds_handle;
+}
+
+
+static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
+{
+ char str[1024];
+ void *temp;
+ int count;
+ ALuint i;
+
+ (void)data;
+ (void)drvname;
+
+ if(NumDevices == 0)
+ {
+ temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
+ if(temp)
+ {
+ DeviceList = temp;
+ DeviceList[NumDevices].name = strdup(dsDevice);
+ DeviceList[NumDevices].guid = GUID_NULL;
+ NumDevices++;
+ }
+ }
+
+ if(!guid)
+ return TRUE;
+
+ count = 0;
+ do {
+ if(count == 0)
+ snprintf(str, sizeof(str), "%s via DirectSound", desc);
+ else
+ snprintf(str, sizeof(str), "%s #%d via DirectSound", desc, count+1);
+ count++;
+
+ for(i = 0;i < NumDevices;i++)
+ {
+ if(strcmp(str, DeviceList[i].name) == 0)
+ break;
+ }
+ } while(i != NumDevices);
+
+ temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
+ if(temp)
+ {
+ DeviceList = temp;
+ DeviceList[NumDevices].name = strdup(str);
+ DeviceList[NumDevices].guid = *guid;
+ NumDevices++;
+ }
+
+ return TRUE;
+}
+
+
+static ALuint DSoundProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ DSoundData *pData = (DSoundData*)pDevice->ExtraData;
+ DSBCAPS DSBCaps;
+ DWORD LastCursor = 0;
+ DWORD PlayCursor;
+ VOID *WritePtr1, *WritePtr2;
+ DWORD WriteCnt1, WriteCnt2;
+ BOOL Playing = FALSE;
+ DWORD FrameSize;
+ DWORD FragSize;
+ DWORD avail;
+ HRESULT err;
+
+ SetRTPriority();
+
+ memset(&DSBCaps, 0, sizeof(DSBCaps));
+ DSBCaps.dwSize = sizeof(DSBCaps);
+ err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
+ if(FAILED(err))
+ {
+ AL_PRINT("Failed to get buffer caps: 0x%lx\n", err);
+ aluHandleDisconnect(pDevice);
+ return 1;
+ }
+
+ FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+ FragSize = pDevice->UpdateSize * FrameSize;
+
+ IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
+ while(!pData->killNow)
+ {
+ // Get current play and write cursors
+ IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
+ avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
+
+ if(avail < FragSize)
+ {
+ if(!Playing)
+ {
+ err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
+ if(FAILED(err))
+ {
+ AL_PRINT("Failed to play buffer: 0x%lx\n", err);
+ aluHandleDisconnect(pDevice);
+ return 1;
+ }
+ Playing = TRUE;
+ }
+ Sleep(1);
+ continue;
+ }
+ avail -= avail%FragSize;
+
+ // Lock output buffer
+ WriteCnt1 = 0;
+ WriteCnt2 = 0;
+ err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
+
+ // If the buffer is lost, restore it and lock
+ if(err == DSERR_BUFFERLOST)
+ {
+ err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
+ if(SUCCEEDED(err))
+ {
+ Playing = FALSE;
+ LastCursor = 0;
+ err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
+ }
+ }
+
+ // Successfully locked the output buffer
+ if(SUCCEEDED(err))
+ {
+ // If we have an active context, mix data directly into output buffer otherwise fill with silence
+ aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize);
+ aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize);
+
+ // Unlock output buffer only when successfully locked
+ IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
+ }
+ else
+ {
+ AL_PRINT("Buffer lock error: %#lx\n", err);
+ aluHandleDisconnect(pDevice);
+ return 1;
+ }
+
+ // Update old write cursor location
+ LastCursor += WriteCnt1+WriteCnt2;
+ LastCursor %= DSBCaps.dwBufferBytes;
+ }
+
+ return 0;
+}
+
+static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
+{
+ DSoundData *pData = NULL;
+ LPGUID guid = NULL;
+ HRESULT hr;
+
+ if(!DSoundLoad())
+ return ALC_FALSE;
+
+ if(!deviceName)
+ deviceName = dsDevice;
+ else if(strcmp(deviceName, dsDevice) != 0)
+ {
+ ALuint i;
+
+ if(!DeviceList)
+ {
+ hr = pDirectSoundEnumerateA(DSoundEnumDevices, NULL);
+ if(FAILED(hr))
+ AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
+ }
+
+ for(i = 0;i < NumDevices;i++)
+ {
+ if(strcmp(deviceName, DeviceList[i].name) == 0)
+ {
+ if(i > 0)
+ guid = &DeviceList[i].guid;
+ break;
+ }
+ }
+ if(i == NumDevices)
+ return ALC_FALSE;
+ }
+
+ //Initialise requested device
+ pData = calloc(1, sizeof(DSoundData));
+ if(!pData)
+ {
+ alcSetError(device, ALC_OUT_OF_MEMORY);
+ return ALC_FALSE;
+ }
+
+ //DirectSound Init code
+ hr = pDirectSoundCreate(guid, &pData->lpDS, NULL);
+ if(SUCCEEDED(hr))
+ hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
+ if(FAILED(hr))
+ {
+ if(pData->lpDS)
+ IDirectSound_Release(pData->lpDS);
+ free(pData);
+ AL_PRINT("Device init failed: 0x%08lx\n", hr);
+ return ALC_FALSE;
+ }
+
+ device->szDeviceName = strdup(deviceName);
+ device->ExtraData = pData;
+ return ALC_TRUE;
+}
+
+static void DSoundClosePlayback(ALCdevice *device)
+{
+ DSoundData *pData = device->ExtraData;
+
+ IDirectSound_Release(pData->lpDS);
+ free(pData);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean DSoundResetPlayback(ALCdevice *device)
+{
+ DSoundData *pData = (DSoundData*)device->ExtraData;
+ DSBUFFERDESC DSBDescription;
+ WAVEFORMATEXTENSIBLE OutputType;
+ DWORD speakers;
+ HRESULT hr;
+
+ memset(&OutputType, 0, sizeof(OutputType));
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ device->FmtType = DevFmtUByte;
+ break;
+ case DevFmtUShort:
+ device->FmtType = DevFmtShort;
+ break;
+ case DevFmtUByte:
+ case DevFmtShort:
+ case DevFmtFloat:
+ break;
+ }
+
+ hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
+ if(SUCCEEDED(hr) && ConfigValueExists(NULL, "format"))
+ {
+ switch(device->FmtChans)
+ {
+ case DevFmtMono:
+ speakers = DSSPEAKER_COMBINED(DSSPEAKER_MONO, 0);
+ break;
+ case DevFmtStereo:
+ speakers = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, 0);
+ break;
+ case DevFmtQuad:
+ speakers = DSSPEAKER_COMBINED(DSSPEAKER_QUAD, 0);
+ break;
+ case DevFmtX51:
+ speakers = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, 0);
+ break;
+ case DevFmtX61:
+ /* ??? */;
+ break;
+ case DevFmtX71:
+ speakers = DSSPEAKER_COMBINED(DSSPEAKER_7POINT1, 0);
+ break;
+ }
+ }
+ if(SUCCEEDED(hr))
+ {
+ speakers = DSSPEAKER_CONFIG(speakers);
+ if(speakers == DSSPEAKER_MONO)
+ {
+ device->FmtChans = DevFmtMono;
+ OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
+ }
+ else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
+ {
+ device->FmtChans = DevFmtStereo;
+ OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+ SPEAKER_FRONT_RIGHT;
+ }
+ else if(speakers == DSSPEAKER_QUAD)
+ {
+ device->FmtChans = DevFmtQuad;
+ OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+ SPEAKER_FRONT_RIGHT |
+ SPEAKER_BACK_LEFT |
+ SPEAKER_BACK_RIGHT;
+ }
+ else if(speakers == DSSPEAKER_5POINT1)
+ {
+ device->FmtChans = DevFmtX51;
+ OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+ SPEAKER_FRONT_RIGHT |
+ SPEAKER_FRONT_CENTER |
+ SPEAKER_LOW_FREQUENCY |
+ SPEAKER_BACK_LEFT |
+ SPEAKER_BACK_RIGHT;
+ }
+ else if(speakers == DSSPEAKER_7POINT1)
+ {
+ device->FmtChans = DevFmtX71;
+ OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+ SPEAKER_FRONT_RIGHT |
+ SPEAKER_FRONT_CENTER |
+ SPEAKER_LOW_FREQUENCY |
+ SPEAKER_BACK_LEFT |
+ SPEAKER_BACK_RIGHT |
+ SPEAKER_SIDE_LEFT |
+ SPEAKER_SIDE_RIGHT;
+ }
+
+ OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
+ OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
+ OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
+ OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
+ OutputType.Format.nSamplesPerSec = device->Frequency;
+ OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
+ OutputType.Format.cbSize = 0;
+ }
+
+ if(OutputType.Format.nChannels > 2 || OutputType.Format.wBitsPerSample > 16)
+ {
+ OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
+ OutputType.Format.cbSize = 22;
+ if(OutputType.Format.wBitsPerSample == 32)
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ else
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }
+ else
+ {
+ if(SUCCEEDED(hr))
+ {
+ memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
+ DSBDescription.dwSize=sizeof(DSBUFFERDESC);
+ DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
+ hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
+ }
+ if(SUCCEEDED(hr))
+ hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
+ DSBDescription.dwSize=sizeof(DSBUFFERDESC);
+ DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
+ DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
+ OutputType.Format.nBlockAlign;
+ DSBDescription.lpwfxFormat=&OutputType.Format;
+ hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ SetDefaultWFXChannelOrder(device);
+ pData->thread = StartThread(DSoundProc, device);
+ if(!pData->thread)
+ hr = E_FAIL;
+ }
+
+ if(FAILED(hr))
+ {
+ if (pData->DSsbuffer)
+ IDirectSoundBuffer_Release(pData->DSsbuffer);
+ pData->DSsbuffer = NULL;
+ if (pData->DSpbuffer)
+ IDirectSoundBuffer_Release(pData->DSpbuffer);
+ pData->DSpbuffer = NULL;
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void DSoundStopPlayback(ALCdevice *device)
+{
+ DSoundData *pData = device->ExtraData;
+
+ if(!pData->thread)
+ return;
+
+ pData->killNow = 1;
+ StopThread(pData->thread);
+ pData->thread = NULL;
+
+ pData->killNow = 0;
+
+ IDirectSoundBuffer_Release(pData->DSsbuffer);
+ pData->DSsbuffer = NULL;
+ if (pData->DSpbuffer)
+ IDirectSoundBuffer_Release(pData->DSpbuffer);
+ pData->DSpbuffer = NULL;
+}
+
+
+static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ (void)pDevice;
+ (void)deviceName;
+ return ALC_FALSE;
+}
+
+static void DSoundCloseCapture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void DSoundStartCapture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void DSoundStopCapture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+ (void)pDevice;
+ (void)pBuffer;
+ (void)lSamples;
+}
+
+static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
+{
+ (void)pDevice;
+ return 0;
+}
+
+
+BackendFuncs DSoundFuncs = {
+ DSoundOpenPlayback,
+ DSoundClosePlayback,
+ DSoundResetPlayback,
+ DSoundStopPlayback,
+ DSoundOpenCapture,
+ DSoundCloseCapture,
+ DSoundStartCapture,
+ DSoundStopCapture,
+ DSoundCaptureSamples,
+ DSoundAvailableSamples
+};
+
+
+void alcDSoundInit(BackendFuncs *FuncList)
+{
+ *FuncList = DSoundFuncs;
+}
+
+void alcDSoundDeinit(void)
+{
+ ALuint i;
+
+ for(i = 0;i < NumDevices;++i)
+ free(DeviceList[i].name);
+ free(DeviceList);
+ DeviceList = NULL;
+ NumDevices = 0;
+
+ if(ds_handle)
+ {
+#ifdef _WIN32
+ FreeLibrary(ds_handle);
+#endif
+ ds_handle = NULL;
+ }
+}
+
+void alcDSoundProbe(int type)
+{
+ if(!DSoundLoad()) return;
+
+ if(type == DEVICE_PROBE)
+ AppendDeviceList(dsDevice);
+ else if(type == ALL_DEVICE_PROBE)
+ {
+ HRESULT hr;
+ ALuint i;
+
+ for(i = 0;i < NumDevices;++i)
+ free(DeviceList[i].name);
+ free(DeviceList);
+ DeviceList = NULL;
+ NumDevices = 0;
+
+ hr = pDirectSoundEnumerateA(DSoundEnumDevices, NULL);
+ if(FAILED(hr))
+ AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
+ else
+ {
+ for(i = 0;i < NumDevices;i++)
+ AppendAllDeviceList(DeviceList[i].name);
+ }
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alListener.h"
+#include "alAuxEffectSlot.h"
+#include "alu.h"
+#include "bs2b.h"
+
+
+static __inline ALdouble point32(const ALfloat *vals, ALint step, ALint frac)
+{ return vals[0]; (void)step; (void)frac; }
+static __inline ALdouble lerp32(const ALfloat *vals, ALint step, ALint frac)
+{ return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)); }
+static __inline ALdouble cubic32(const ALfloat *vals, ALint step, ALint frac)
+{ return cubic(vals[-step], vals[0], vals[step], vals[step+step],
+ frac * (1.0/FRACTIONONE)); }
+
+static __inline ALdouble point16(const ALshort *vals, ALint step, ALint frac)
+{ return vals[0] * (1.0/32767.0); (void)step; (void)frac; }
+static __inline ALdouble lerp16(const ALshort *vals, ALint step, ALint frac)
+{ return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)) * (1.0/32767.0); }
+static __inline ALdouble cubic16(const ALshort *vals, ALint step, ALint frac)
+{ return cubic(vals[-step], vals[0], vals[step], vals[step+step],
+ frac * (1.0/FRACTIONONE)) * (1.0/32767.0); }
+
+static __inline ALdouble point8(const ALubyte *vals, ALint step, ALint frac)
+{ return (vals[0]-128.0) * (1.0/127.0); (void)step; (void)frac; }
+static __inline ALdouble lerp8(const ALubyte *vals, ALint step, ALint frac)
+{ return (lerp(vals[0], vals[step],
+ frac * (1.0/FRACTIONONE))-128.0) * (1.0/127.0); }
+static __inline ALdouble cubic8(const ALubyte *vals, ALint step, ALint frac)
+{ return (cubic(vals[-step], vals[0], vals[step], vals[step+step],
+ frac * (1.0/FRACTIONONE))-128.0) * (1.0/127.0); }
+
+//#define MEASURE_OPENAL_MIXING_PERFORMANCE
+#ifdef MEASURE_OPENAL_MIXING_PERFORMANCE
+
+#include <sys/time.h>
+
+unsigned long int OpenALGetSysElapsedTime(void)
+{
+ static struct timeval init_time = { 0 , 0 };
+ static int bFirst = 0;
+ struct timeval current_time;
+
+ if ( bFirst == 0 )
+ {
+ bFirst = 1;
+ gettimeofday(&init_time, NULL);
+ }
+
+ gettimeofday(¤t_time, NULL);
+ return ((current_time.tv_sec * 1000000 + current_time.tv_usec) - (init_time.tv_sec * 1000000 + init_time.tv_usec));///1000;
+}
+
+
+#define OPENAL_PERFORMANCE_LOG(msg...) \
+do{\
+ printf("\n[%s %s %d %lu] ", __FILE__, __func__, __LINE__,OpenALGetSysElapsedTime());\
+ printf(msg);\
+}while(0)
+
+#define OPENAL_PERFORMANCE_LOG_CNT_START(count, msg...)\
+static unsigned int counter = count;\
+static unsigned int counter_at_start = count;\
+static unsigned long int time = 0;\
+static unsigned int fail_cases = 0;\
+unsigned long int time_start = 0;\
+unsigned long int time_stop = 0;\
+time_start = OpenALGetSysElapsedTime()
+
+
+#define OPENAL_PERFORMANCE_LOG_CNT_FAIL(msg...)\
+time_stop = OpenALGetSysElapsedTime();\
+counter--;\
+time += time_stop-time_start;\
+fail_cases++;\
+if (counter == 0)\
+{\
+ printf("\n[%s %d %lu] time = %lu count = %u fail=%u ", __func__, __LINE__,OpenALGetSysElapsedTime()/1000,time/1000, counter_at_start, fail_cases);\
+ printf(msg);\
+ counter = counter_at_start;\
+ time = 0;\
+ fail_cases = 0;\
+}
+
+#define OPENAL_PERFORMANCE_LOG_CNT_STOP(msg...)\
+time_stop = OpenALGetSysElapsedTime();\
+counter--;\
+time += time_stop-time_start;\
+if (counter == 0)\
+{\
+ /*printf("\n[%s %d %lu] time = %lu count = %u fail=%u ", __func__, __LINE__,OpenALGetSysElapsedTime()/1000,time/1000, counter_at_start, fail_cases);*/\
+ printf("\n[%d %lu] time = %lu count = %u fail=%u ", __LINE__,OpenALGetSysElapsedTime()/1000,time/1000, counter_at_start, fail_cases);\
+ printf(msg);\
+ counter = counter_at_start;\
+ time = 0;\
+ fail_cases = 0;\
+}
+#else
+#define OPENAL_PERFORMANCE_LOG(msg...)
+#define OPENAL_PERFORMANCE_LOG_CNT_START(count, msg...)
+#define OPENAL_PERFORMANCE_LOG_CNT_FAIL(msg...)
+#define OPENAL_PERFORMANCE_LOG_CNT_STOP(msg...)
+#endif
+
+//#define CODE_REARRANGE_APPROACH
+#if defined(ARM_ARCH)
+//#define NEON_ASSEMBLY_APPROACH
+//#define TEST_NEON
+#elif defined(I386_ARCH)
+#endif
+
+#if (defined(CODE_REARRANGE_APPROACH) && defined(NEON_ASSEMBLY_APPROACH))
+#error "YOU CANNOT DEFINE BOTH FLAGS CODE_REARRANGE_APPROACH and NEON_ASSEMBLY_APPROACH. ENABLE ONE OR NONE"
+#endif
+
+#if defined NEON_ASSEMBLY_APPROACH
+#define DECL_TEMPLATE(T, sampler) \
+static void Mix_##T##_1_##sampler(ALsource *Source, ALCdevice *Device, \
+ const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
+ ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
+{ \
+ OPENAL_PERFORMANCE_LOG_CNT_START(100);\
+ static ALint cumm_BufferSize = 0;\
+ static ALint cumm_SamplesToDo = 0;\
+ cumm_SamplesToDo+=SamplesToDo;\
+ cumm_BufferSize+=BufferSize;\
+ \
+ ALfloat (*DryBuffer)[MAXCHANNELS]; \
+ ALfloat *ClickRemoval, *PendingClicks; \
+ ALuint pos, frac; \
+ ALfloat DrySend[MAXCHANNELS]; \
+ FILTER *DryFilter; \
+ ALuint BufferIdx; \
+ ALuint increment; \
+ ALuint out, c; \
+ ALfloat value; \
+ ALfloat* DryBufferIn; \
+ \
+ increment = Source->Params.Step; \
+ \
+ DryBuffer = Device->DryBuffer; \
+ ClickRemoval = Device->ClickRemoval; \
+ PendingClicks = Device->PendingClicks; \
+ DryFilter = &Source->Params.iirFilter; \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ DrySend[c] = Source->Params.DryGains[0][c]; \
+ \
+ pos = 0; \
+ frac = *DataPosFrac; \
+ \
+ if(OutPos == 0) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter4PC(DryFilter, 0, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ ClickRemoval[c] -= value*DrySend[c]; \
+ } \
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
+ { \
+ DryBufferIn=DryBuffer[OutPos];\
+ /* First order interpolator */ \
+ value = sampler(data+pos, 1, frac); \
+ \
+ /* Direct path final mix buffer and panning */ \
+ value = lpFilter4P(DryFilter, 0, value); \
+ /* for(c = 0;c < MAXCHANNELS;c++) */ \
+ /* DryBuffer[OutPos][c] += value*DrySend[c]; */ \
+ __asm__ volatile (\
+ "mov r0,#-32 \n\t"\
+ "vld1.32 {d0,d1,d2,d3}, [%0]! \n\t"\
+ "vld1.32 {d8,d9,d10,d11}, [%2]! \n\t"\
+ "vld1.32 d4,[%0] \n\t"\
+ "vld1.32 d5,[%2],r0 \n\t"\
+ "vdup.f32 q6, %1 \n\t"\
+ "vmla.f32 q0, q4, q6 \n\t"\
+ "vmla.f32 q1, q5, q6 \n\t"\
+ "vmla.f32 s8, s10, s24 \n\t"\
+ "vst1.32 {d4}, [%0],r0 \n\t"\
+ "vst1.32 {d0,d1,d2,d3}, [%0] \n\t"\
+ ::"r"(DryBufferIn),"r"(value), "r"(DrySend):"r0", "q0", "q1", "q2", "q3", "q4", "q5", "q6");\
+ \
+ frac += increment; \
+ pos += frac>>FRACTIONBITS; \
+ frac &= FRACTIONMASK; \
+ OutPos++; \
+ } \
+ if(OutPos == SamplesToDo) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter4PC(DryFilter, 0, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ PendingClicks[c] += value*DrySend[c]; \
+ } \
+ \
+ for(out = 0;out < Device->NumAuxSends;out++) \
+ { \
+ ALfloat WetSend; \
+ ALfloat *WetBuffer; \
+ ALfloat *WetClickRemoval; \
+ ALfloat *WetPendingClicks; \
+ FILTER *WetFilter; \
+ \
+ if(!Source->Send[out].Slot || \
+ Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
+ continue; \
+ \
+ WetBuffer = Source->Send[out].Slot->WetBuffer; \
+ WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
+ WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
+ WetFilter = &Source->Params.Send[out].iirFilter; \
+ WetSend = Source->Params.Send[out].WetGain; \
+ \
+ pos = 0; \
+ frac = *DataPosFrac; \
+ OutPos -= BufferSize; \
+ \
+ if(OutPos == 0) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter2PC(WetFilter, 0, value); \
+ WetClickRemoval[0] -= value*WetSend; \
+ } \
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
+ { \
+ /* First order interpolator */ \
+ value = sampler(data+pos, 1, frac); \
+ \
+ /* Room path final mix buffer and panning */ \
+ value = lpFilter2P(WetFilter, 0, value); \
+ WetBuffer[OutPos] += value*WetSend; \
+ \
+ frac += increment; \
+ pos += frac>>FRACTIONBITS; \
+ frac &= FRACTIONMASK; \
+ OutPos++; \
+ } \
+ if(OutPos == SamplesToDo) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter2PC(WetFilter, 0, value); \
+ WetPendingClicks[0] += value*WetSend; \
+ } \
+ } \
+ *DataPosInt += pos; \
+ *DataPosFrac = frac; \
+ OPENAL_PERFORMANCE_LOG_CNT_STOP("Neon Chan=1 T_SamplesToDo=%d", cumm_SamplesToDo);\
+}
+#else
+#define DECL_TEMPLATE(T, sampler) \
+static void Mix_##T##_1_##sampler(ALsource *Source, ALCdevice *Device, \
+ const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
+ ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
+{ \
+ OPENAL_PERFORMANCE_LOG_CNT_START(100);\
+ static ALint cumm_BufferSize = 0;\
+ static ALint cumm_SamplesToDo = 0;\
+ cumm_SamplesToDo+=SamplesToDo;\
+ cumm_BufferSize+=BufferSize;\
+ \
+ ALfloat (*DryBuffer)[MAXCHANNELS]; \
+ ALfloat *ClickRemoval, *PendingClicks; \
+ ALuint pos, frac; \
+ ALfloat DrySend[MAXCHANNELS]; \
+ FILTER *DryFilter; \
+ ALuint BufferIdx; \
+ ALuint increment; \
+ ALuint out, c; \
+ ALfloat value; \
+ \
+ increment = Source->Params.Step; \
+ \
+ DryBuffer = Device->DryBuffer; \
+ ClickRemoval = Device->ClickRemoval; \
+ PendingClicks = Device->PendingClicks; \
+ DryFilter = &Source->Params.iirFilter; \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ DrySend[c] = Source->Params.DryGains[0][c]; \
+ \
+ pos = 0; \
+ frac = *DataPosFrac; \
+ \
+ if(OutPos == 0) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter4PC(DryFilter, 0, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ ClickRemoval[c] -= value*DrySend[c]; \
+ } \
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
+ { \
+ /* First order interpolator */ \
+ value = sampler(data+pos, 1, frac); \
+ \
+ /* Direct path final mix buffer and panning */ \
+ value = lpFilter4P(DryFilter, 0, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ DryBuffer[OutPos][c] += value*DrySend[c]; \
+ \
+ frac += increment; \
+ pos += frac>>FRACTIONBITS; \
+ frac &= FRACTIONMASK; \
+ OutPos++; \
+ } \
+ if(OutPos == SamplesToDo) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter4PC(DryFilter, 0, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ PendingClicks[c] += value*DrySend[c]; \
+ } \
+ \
+ for(out = 0;out < Device->NumAuxSends;out++) \
+ { \
+ ALfloat WetSend; \
+ ALfloat *WetBuffer; \
+ ALfloat *WetClickRemoval; \
+ ALfloat *WetPendingClicks; \
+ FILTER *WetFilter; \
+ \
+ if(!Source->Send[out].Slot || \
+ Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
+ continue; \
+ \
+ WetBuffer = Source->Send[out].Slot->WetBuffer; \
+ WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
+ WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
+ WetFilter = &Source->Params.Send[out].iirFilter; \
+ WetSend = Source->Params.Send[out].WetGain; \
+ \
+ pos = 0; \
+ frac = *DataPosFrac; \
+ OutPos -= BufferSize; \
+ \
+ if(OutPos == 0) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter2PC(WetFilter, 0, value); \
+ WetClickRemoval[0] -= value*WetSend; \
+ } \
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
+ { \
+ /* First order interpolator */ \
+ value = sampler(data+pos, 1, frac); \
+ \
+ /* Room path final mix buffer and panning */ \
+ value = lpFilter2P(WetFilter, 0, value); \
+ WetBuffer[OutPos] += value*WetSend; \
+ \
+ frac += increment; \
+ pos += frac>>FRACTIONBITS; \
+ frac &= FRACTIONMASK; \
+ OutPos++; \
+ } \
+ if(OutPos == SamplesToDo) \
+ { \
+ value = sampler(data+pos, 1, frac); \
+ \
+ value = lpFilter2PC(WetFilter, 0, value); \
+ WetPendingClicks[0] += value*WetSend; \
+ } \
+ } \
+ *DataPosInt += pos; \
+ *DataPosFrac = frac; \
+ OPENAL_PERFORMANCE_LOG_CNT_STOP("Orig Chan=1 T_SamplesToDo=%d", cumm_SamplesToDo);\
+}
+#endif
+
+DECL_TEMPLATE(ALfloat, point32)
+DECL_TEMPLATE(ALfloat, lerp32)
+DECL_TEMPLATE(ALfloat, cubic32)
+
+DECL_TEMPLATE(ALshort, point16)
+DECL_TEMPLATE(ALshort, lerp16)
+DECL_TEMPLATE(ALshort, cubic16)
+
+DECL_TEMPLATE(ALubyte, point8)
+DECL_TEMPLATE(ALubyte, lerp8)
+DECL_TEMPLATE(ALubyte, cubic8)
+
+#undef DECL_TEMPLATE
+
+
+
+#define DECL_TEMPLATE(T, chnct, sampler) \
+static void Mix_##T##_##chnct##_##sampler(ALsource *Source, ALCdevice *Device,\
+ const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
+ ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
+{ \
+ OPENAL_PERFORMANCE_LOG_CNT_START(100);\
+ static ALint cumm_BufferSize = 0;\
+ static ALint cumm_SamplesToDo = 0;\
+ cumm_SamplesToDo+=SamplesToDo;\
+ cumm_BufferSize+=BufferSize;\
+ \
+ const ALuint Channels = chnct; \
+ const ALfloat scaler = 1.0f/chnct; \
+ ALfloat (*DryBuffer)[MAXCHANNELS]; \
+ ALfloat *ClickRemoval, *PendingClicks; \
+ ALuint pos, frac; \
+ ALfloat DrySend[chnct][MAXCHANNELS]; \
+ FILTER *DryFilter; \
+ ALuint BufferIdx; \
+ ALuint increment; \
+ ALuint i, out, c; \
+ ALfloat value; \
+ \
+ increment = Source->Params.Step; \
+ \
+ DryBuffer = Device->DryBuffer; \
+ ClickRemoval = Device->ClickRemoval; \
+ PendingClicks = Device->PendingClicks; \
+ DryFilter = &Source->Params.iirFilter; \
+ for(i = 0;i < Channels;i++) \
+ { \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ DrySend[i][c] = Source->Params.DryGains[i][c]; \
+ } \
+ \
+ pos = 0; \
+ frac = *DataPosFrac; \
+ \
+ if(OutPos == 0) \
+ { \
+ for(i = 0;i < Channels;i++) \
+ { \
+ value = sampler(data + pos*Channels + i, Channels, frac); \
+ \
+ value = lpFilter2PC(DryFilter, i*2, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ ClickRemoval[c] -= value*DrySend[i][c]; \
+ } \
+ } \
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
+ { \
+ for(i = 0;i < Channels;i++) \
+ { \
+ value = sampler(data + pos*Channels + i, Channels, frac); \
+ \
+ value = lpFilter2P(DryFilter, i*2, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ DryBuffer[OutPos][c] += value*DrySend[i][c]; \
+ } \
+ \
+ frac += increment; \
+ pos += frac>>FRACTIONBITS; \
+ frac &= FRACTIONMASK; \
+ OutPos++; \
+ } \
+ if(OutPos == SamplesToDo) \
+ { \
+ for(i = 0;i < Channels;i++) \
+ { \
+ value = sampler(data + pos*Channels + i, Channels, frac); \
+ \
+ value = lpFilter2PC(DryFilter, i*2, value); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ PendingClicks[c] += value*DrySend[i][c]; \
+ } \
+ } \
+ \
+ for(out = 0;out < Device->NumAuxSends;out++) \
+ { \
+ ALfloat WetSend; \
+ ALfloat *WetBuffer; \
+ ALfloat *WetClickRemoval; \
+ ALfloat *WetPendingClicks; \
+ FILTER *WetFilter; \
+ \
+ if(!Source->Send[out].Slot || \
+ Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
+ continue; \
+ \
+ WetBuffer = Source->Send[out].Slot->WetBuffer; \
+ WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
+ WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
+ WetFilter = &Source->Params.Send[out].iirFilter; \
+ WetSend = Source->Params.Send[out].WetGain; \
+ \
+ pos = 0; \
+ frac = *DataPosFrac; \
+ OutPos -= BufferSize; \
+ \
+ if(OutPos == 0) \
+ { \
+ for(i = 0;i < Channels;i++) \
+ { \
+ value = sampler(data + pos*Channels + i, Channels, frac); \
+ \
+ value = lpFilter1PC(WetFilter, i, value); \
+ WetClickRemoval[0] -= value*WetSend * scaler; \
+ } \
+ } \
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
+ { \
+ for(i = 0;i < Channels;i++) \
+ { \
+ value = sampler(data + pos*Channels + i, Channels, frac); \
+ \
+ value = lpFilter1P(WetFilter, i, value); \
+ WetBuffer[OutPos] += value*WetSend * scaler; \
+ } \
+ \
+ frac += increment; \
+ pos += frac>>FRACTIONBITS; \
+ frac &= FRACTIONMASK; \
+ OutPos++; \
+ } \
+ if(OutPos == SamplesToDo) \
+ { \
+ for(i = 0;i < Channels;i++) \
+ { \
+ value = sampler(data + pos*Channels + i, Channels, frac); \
+ \
+ value = lpFilter1PC(WetFilter, i, value); \
+ WetPendingClicks[0] += value*WetSend * scaler; \
+ } \
+ } \
+ } \
+ *DataPosInt += pos; \
+ *DataPosFrac = frac; \
+ OPENAL_PERFORMANCE_LOG_CNT_STOP("Orig T_SamplesToDo=%d ", cumm_SamplesToDo);\
+}
+
+DECL_TEMPLATE(ALfloat, 2, point32)
+DECL_TEMPLATE(ALfloat, 2, lerp32)
+DECL_TEMPLATE(ALfloat, 2, cubic32)
+
+
+#if defined (NEON_ASSEMBLY_APPROACH)
+static void Mix_ALshort_2_point16(ALsource *Source, ALCdevice *Device,
+ const ALshort *data, ALuint *DataPosInt, ALuint *DataPosFrac,
+ ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+{
+ OPENAL_PERFORMANCE_LOG_CNT_START(100);
+ static ALint cumm_BufferSize = 0;
+ static ALint cumm_SamplesToDo = 0;
+ cumm_SamplesToDo+=SamplesToDo;
+ cumm_BufferSize+=BufferSize;
+#define chnct 2
+#define sampler point16
+
+ const ALuint Channels = chnct;
+ const ALfloat scaler = 1.0f/chnct;
+ ALfloat (*DryBuffer)[MAXCHANNELS];
+ ALfloat *ClickRemoval, *PendingClicks;
+ ALuint pos, frac;
+ ALfloat DrySend[chnct][MAXCHANNELS];
+ FILTER *DryFilter;
+ ALuint BufferIdx;
+ ALuint increment;
+ ALuint i, out, c;
+ ALfloat value;
+ ALfloat dryValue0;
+ ALfloat dryValue1;
+ ALfloat* DryBufferIn;
+ ALfloat* DrySendIn0;
+ ALfloat* DrySendIn1;
+ increment = Source->Params.Step;
+ DrySendIn0=DrySend[0];
+ DrySendIn1=DrySend[1];
+
+ DryBuffer = Device->DryBuffer;
+ ClickRemoval = Device->ClickRemoval;
+ PendingClicks = Device->PendingClicks;
+ DryFilter = &Source->Params.iirFilter;
+// DrySendIn0=DrySend[0];
+// DrySendIn1=DrySend[1];
+
+ for(i = 0;i < Channels;i++)
+ {
+ for(c = 0;c < MAXCHANNELS;c++)
+ DrySend[i][c] = Source->Params.DryGains[i][c];
+ }
+
+ pos = 0;
+ frac = *DataPosFrac;
+
+ if(OutPos == 0)
+ {
+ // for(i = 0;i < Channels;i++)
+ //{
+ dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);
+ dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);
+
+ dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);
+ dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);
+ for(c = 0;c < MAXCHANNELS;c++)
+ {
+ ClickRemoval[c] -= dryValue0*DrySend[0][c];
+ ClickRemoval[c] -= dryValue1*DrySend[1][c];
+ }
+ // }
+ }
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)
+ {
+ //for(i = 0;i < Channels;i++)
+ // {
+ DryBufferIn=DryBuffer[OutPos];
+ dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);
+ dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);
+
+ dryValue0 = lpFilter2P(DryFilter, 0*2, dryValue0);
+ dryValue1 = lpFilter2P(DryFilter, 1*2, dryValue1);
+
+#if defined(TEST_NEON)
+ ALfloat TestDryBufferIn[MAXCHANNELS];
+ memcpy(TestDryBufferIn, DryBufferIn,MAXCHANNELS*sizeof(ALfloat) );
+ for(i = 0;i < MAXCHANNELS;i++)
+ {
+ TestDryBufferIn[i] += dryValue0*DrySend[0][i];
+ TestDryBufferIn[i] += dryValue1*DrySend[1][i];
+ }
+#endif
+ __asm__ volatile (
+ "mov r0,#-32 \n\t"
+ "vld1.32 {d0,d1,d2,d3}, [%0]! \n\t"
+ "vld1.32 {d12,d13,d14,d15}, [%3]! \n\t"
+ "vld1.32 {d16,d17,d18,d19}, [%4]! \n\t"
+ "vld1.32 d4,[%0] \n\t"
+ "vld1.32 d5,[%3],r0 \n\t"
+ "vld1.32 d6,[%4],r0 \n\t"
+ "vdup.f32 q4, %1 \n\t"
+ "vdup.f32 q5, %2 \n\t"
+ "vmla.f32 q0, q4, q6 \n\t"
+ "vmla.f32 q0, q5, q8 \n\t"
+ "vmla.f32 q1, q4, q7 \n\t"
+ "vmla.f32 q1, q5, q9 \n\t"
+ "vmla.f32 s8, s16, s10 \n\t"
+ "vmla.f32 s8, s20, s12 \n\t"
+ "vst1.32 {d4}, [%0],r0 \n\t"
+ "vst1.32 {d0,d1,d2,d3}, [%0] \n\t"
+ ::"r"(DryBufferIn),"r"(dryValue0), "r"(dryValue1), "r"(DrySendIn0), "r"(DrySendIn1):"r0", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9");
+
+#if defined(TEST_NEON)
+ for(i = 0;i < (MAXCHANNELS-1);i++)
+ {
+ if (DryBufferIn[i] !=TestDryBufferIn[i])
+ printf("\n%d not same %f %f %f %f %f %f", i,DryBufferIn[i],TestDryBufferIn[i], dryValue0,DrySend[0][i],dryValue1,DrySend[1][i]);
+ }
+#endif
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ OutPos++;
+ }
+ if(OutPos == SamplesToDo)
+ {
+ //for(i = 0;i < Channels;i++)
+ //{
+ dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);
+ dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);
+
+ dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);
+ dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);
+ for(c = 0;c < MAXCHANNELS;c++)
+ {
+ PendingClicks[c] += dryValue0*DrySend[0][c];
+ PendingClicks[c] += dryValue1*DrySend[1][c];
+ }
+ // }
+ }
+
+ for(out = 0;out < Device->NumAuxSends;out++)
+ {
+ ALfloat WetSend;
+ ALfloat *WetBuffer;
+ ALfloat *WetClickRemoval;
+ ALfloat *WetPendingClicks;
+ FILTER *WetFilter;
+
+ if(!Source->Send[out].Slot ||
+ Source->Send[out].Slot->effect.type == AL_EFFECT_NULL)
+ {
+ /*
+ printf("\nslot=%d type=%d"\
+ ,Source->Send[out].Slot \
+ ,Source->Send[out].Slot ? Source->Send[out].Slot->effect.type:0);
+ */
+ continue;
+ }
+
+ /*OPENAL_PERFORMANCE_LOG_CNT_START(100);*/
+ WetBuffer = Source->Send[out].Slot->WetBuffer;
+ WetClickRemoval = Source->Send[out].Slot->ClickRemoval;
+ WetPendingClicks = Source->Send[out].Slot->PendingClicks;
+ WetFilter = &Source->Params.Send[out].iirFilter;
+ WetSend = Source->Params.Send[out].WetGain;
+
+ pos = 0;
+ frac = *DataPosFrac;
+ OutPos -= BufferSize;
+
+ if(OutPos == 0)
+ {
+ for(i = 0;i < Channels;i++)
+ {
+ value = sampler(data + pos*Channels + i, Channels, frac);
+
+ value = lpFilter1PC(WetFilter, i, value);
+ WetClickRemoval[0] -= value*WetSend * scaler;
+ }
+ }
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)
+ {
+ for(i = 0;i < Channels;i++)
+ {
+ value = sampler(data + pos*Channels + i, Channels, frac);
+
+ value = lpFilter1P(WetFilter, i, value);
+ WetBuffer[OutPos] += value*WetSend * scaler;
+ }
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ OutPos++;
+ }
+ if(OutPos == SamplesToDo)
+ {
+ for(i = 0;i < Channels;i++)
+ {
+ value = sampler(data + pos*Channels + i, Channels, frac);
+
+ value = lpFilter1PC(WetFilter, i, value);
+ WetPendingClicks[0] += value*WetSend * scaler;
+ }
+ }
+/*OPENAL_PERFORMANCE_LOG_CNT_STOP("WetBuffer is calculated");*/
+ }
+ *DataPosInt += pos;
+ *DataPosFrac = frac;
+ #undef chnct
+ #undef sampler
+ OPENAL_PERFORMANCE_LOG_CNT_STOP("App1+Neon T_SamplesToDo=%d ", cumm_SamplesToDo);
+}
+
+#elif defined (CODE_REARRANGE_APPROACH)
+/*static*/ void Mix_ALshort_2_point16(ALsource *Source, ALCdevice *Device,
+ const ALshort *data, ALuint *DataPosInt, ALuint *DataPosFrac,
+ ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
+{
+ OPENAL_PERFORMANCE_LOG_CNT_START(100);
+ static ALint cumm_BufferSize = 0;
+ static ALint cumm_SamplesToDo = 0;
+ cumm_SamplesToDo+=SamplesToDo;
+ cumm_BufferSize+=BufferSize;
+#define chnct 2
+#define sampler point16
+
+ const ALuint Channels = chnct;
+ const ALfloat scaler = 1.0f/chnct;
+ ALfloat (*DryBuffer)[MAXCHANNELS];
+ ALfloat *ClickRemoval, *PendingClicks;
+ ALuint pos, frac;
+ ALfloat DrySend[chnct][MAXCHANNELS];
+ FILTER *DryFilter;
+ ALuint BufferIdx;
+ ALuint increment;
+ ALuint i, out, c;
+ ALfloat value;
+ ALfloat dryValue0;
+ ALfloat dryValue1;
+ ALfloat wetValue0;
+ ALfloat wetValue1;
+
+ increment = Source->Params.Step;
+
+ DryBuffer = Device->DryBuffer;
+ ClickRemoval = Device->ClickRemoval;
+ PendingClicks = Device->PendingClicks;
+ DryFilter = &Source->Params.iirFilter;
+ for(i = 0;i < Channels;i++)
+ {
+ for(c = 0;c < MAXCHANNELS;c++)
+ DrySend[i][c] = Source->Params.DryGains[i][c];
+ }
+
+ pos = 0;
+ frac = *DataPosFrac;
+
+ if(OutPos == 0)
+ {
+ // for(i = 0;i < Channels;i++)
+ //{
+ dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);
+ dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);
+
+ dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);
+ dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);
+ for(c = 0;c < MAXCHANNELS;c++)
+ {
+ ClickRemoval[c] -= dryValue0*DrySend[0][c];
+ ClickRemoval[c] -= dryValue1*DrySend[1][c];
+ }
+ // }
+ }
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)
+ {
+ //for(i = 0;i < Channels;i++)
+ // {
+ dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);
+ dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);
+
+ dryValue0 = lpFilter2P(DryFilter, 0*2, dryValue0);
+ dryValue1 = lpFilter2P(DryFilter, 1*2, dryValue1);
+ for(c = 0;c < MAXCHANNELS;c++)
+ {
+ DryBuffer[OutPos][c] += dryValue0*DrySend[0][c];
+ DryBuffer[OutPos][c] += dryValue1*DrySend[1][c];
+ }
+ // }
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ OutPos++;
+ }
+ if(OutPos == SamplesToDo)
+ {
+ //for(i = 0;i < Channels;i++)
+ //{
+ dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);
+ dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);
+
+ dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);
+ dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);
+ for(c = 0;c < MAXCHANNELS;c++)
+ {
+ PendingClicks[c] += dryValue0*DrySend[0][c];
+ PendingClicks[c] += dryValue1*DrySend[1][c];
+ }
+ // }
+ }
+
+ for(out = 0;out < Device->NumAuxSends;out++)
+ {
+ ALfloat WetSend;
+ ALfloat *WetBuffer;
+ ALfloat *WetClickRemoval;
+ ALfloat *WetPendingClicks;
+ FILTER *WetFilter;
+
+ if(!Source->Send[out].Slot ||
+ Source->Send[out].Slot->effect.type == AL_EFFECT_NULL)
+ continue;
+
+ /*OPENAL_PERFORMANCE_LOG_CNT_START(100);*/
+ WetBuffer = Source->Send[out].Slot->WetBuffer;
+ WetClickRemoval = Source->Send[out].Slot->ClickRemoval;
+ WetPendingClicks = Source->Send[out].Slot->PendingClicks;
+ WetFilter = &Source->Params.Send[out].iirFilter;
+ WetSend = Source->Params.Send[out].WetGain;
+
+ pos = 0;
+ frac = *DataPosFrac;
+ OutPos -= BufferSize;
+
+ if(OutPos == 0)
+ {
+ for(i = 0;i < Channels;i++)
+ {
+ value = sampler(data + pos*Channels + i, Channels, frac);
+
+ value = lpFilter1PC(WetFilter, i, value);
+ WetClickRemoval[0] -= value*WetSend * scaler;
+ }
+ }
+ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)
+ {
+ for(i = 0;i < Channels;i++)
+ {
+ value = sampler(data + pos*Channels + i, Channels, frac);
+
+ value = lpFilter1P(WetFilter, i, value);
+ WetBuffer[OutPos] += value*WetSend * scaler;
+ }
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ OutPos++;
+ }
+ if(OutPos == SamplesToDo)
+ {
+ for(i = 0;i < Channels;i++)
+ {
+ value = sampler(data + pos*Channels + i, Channels, frac);
+
+ value = lpFilter1PC(WetFilter, i, value);
+ WetPendingClicks[0] += value*WetSend * scaler;
+ }
+ }
+/*OPENAL_PERFORMANCE_LOG_CNT_STOP("WetBuffer is calculated");*/
+ }
+ *DataPosInt += pos;
+ *DataPosFrac = frac;
+ #undef chnct
+ #undef sampler
+ OPENAL_PERFORMANCE_LOG_CNT_STOP("App1 T_SamplesToDo=%d T_BufferSize=%u NumAuxSends=%u", cumm_SamplesToDo, cumm_BufferSize,Device->NumAuxSends);
+}
+
+#else
+DECL_TEMPLATE(ALshort, 2, point16)
+#endif
+DECL_TEMPLATE(ALshort, 2, lerp16)
+DECL_TEMPLATE(ALshort, 2, cubic16)
+
+DECL_TEMPLATE(ALubyte, 2, point8)
+DECL_TEMPLATE(ALubyte, 2, lerp8)
+DECL_TEMPLATE(ALubyte, 2, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 4, point32)
+DECL_TEMPLATE(ALfloat, 4, lerp32)
+DECL_TEMPLATE(ALfloat, 4, cubic32)
+
+DECL_TEMPLATE(ALshort, 4, point16)
+DECL_TEMPLATE(ALshort, 4, lerp16)
+DECL_TEMPLATE(ALshort, 4, cubic16)
+
+DECL_TEMPLATE(ALubyte, 4, point8)
+DECL_TEMPLATE(ALubyte, 4, lerp8)
+DECL_TEMPLATE(ALubyte, 4, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 6, point32)
+DECL_TEMPLATE(ALfloat, 6, lerp32)
+DECL_TEMPLATE(ALfloat, 6, cubic32)
+
+DECL_TEMPLATE(ALshort, 6, point16)
+DECL_TEMPLATE(ALshort, 6, lerp16)
+DECL_TEMPLATE(ALshort, 6, cubic16)
+
+DECL_TEMPLATE(ALubyte, 6, point8)
+DECL_TEMPLATE(ALubyte, 6, lerp8)
+DECL_TEMPLATE(ALubyte, 6, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 7, point32)
+DECL_TEMPLATE(ALfloat, 7, lerp32)
+DECL_TEMPLATE(ALfloat, 7, cubic32)
+
+DECL_TEMPLATE(ALshort, 7, point16)
+DECL_TEMPLATE(ALshort, 7, lerp16)
+DECL_TEMPLATE(ALshort, 7, cubic16)
+
+DECL_TEMPLATE(ALubyte, 7, point8)
+DECL_TEMPLATE(ALubyte, 7, lerp8)
+DECL_TEMPLATE(ALubyte, 7, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 8, point32)
+DECL_TEMPLATE(ALfloat, 8, lerp32)
+DECL_TEMPLATE(ALfloat, 8, cubic32)
+
+DECL_TEMPLATE(ALshort, 8, point16)
+DECL_TEMPLATE(ALshort, 8, lerp16)
+DECL_TEMPLATE(ALshort, 8, cubic16)
+
+DECL_TEMPLATE(ALubyte, 8, point8)
+DECL_TEMPLATE(ALubyte, 8, lerp8)
+DECL_TEMPLATE(ALubyte, 8, cubic8)
+
+#undef DECL_TEMPLATE
+
+
+#define DECL_TEMPLATE(T, sampler) \
+static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
+ enum FmtChannels FmtChannels, \
+ const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
+ ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
+{ \
+ switch(FmtChannels) \
+ { \
+ case FmtMono: \
+ Mix_##T##_1_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ case FmtStereo: \
+ case FmtRear: \
+ Mix_##T##_2_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ case FmtQuad: \
+ Mix_##T##_4_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ case FmtX51: \
+ Mix_##T##_6_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ case FmtX61: \
+ Mix_##T##_7_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ case FmtX71: \
+ Mix_##T##_8_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ } \
+}
+
+DECL_TEMPLATE(ALfloat, point32)
+DECL_TEMPLATE(ALfloat, lerp32)
+DECL_TEMPLATE(ALfloat, cubic32)
+
+DECL_TEMPLATE(ALshort, point16)
+DECL_TEMPLATE(ALshort, lerp16)
+DECL_TEMPLATE(ALshort, cubic16)
+
+DECL_TEMPLATE(ALubyte, point8)
+DECL_TEMPLATE(ALubyte, lerp8)
+DECL_TEMPLATE(ALubyte, cubic8)
+
+#undef DECL_TEMPLATE
+
+
+#define DECL_TEMPLATE(sampler) \
+static void Mix_##sampler(ALsource *Source, ALCdevice *Device, \
+ enum FmtChannels FmtChannels, enum FmtType FmtType, \
+ const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
+ ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
+{ \
+ switch(FmtType) \
+ { \
+ case FmtUByte: \
+ Mix_ALubyte_##sampler##8(Source, Device, FmtChannels, \
+ Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ \
+ case FmtShort: \
+ Mix_ALshort_##sampler##16(Source, Device, FmtChannels, \
+ Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ \
+ case FmtFloat: \
+ Mix_ALfloat_##sampler##32(Source, Device, FmtChannels, \
+ Data, DataPosInt, DataPosFrac, \
+ OutPos, SamplesToDo, BufferSize); \
+ break; \
+ } \
+}
+
+DECL_TEMPLATE(point)
+DECL_TEMPLATE(lerp)
+DECL_TEMPLATE(cubic)
+
+#undef DECL_TEMPLATE
+
+
+ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
+{
+ ALbufferlistitem *BufferListItem;
+ ALuint DataPosInt, DataPosFrac;
+ enum FmtChannels FmtChannels;
+ enum FmtType FmtType;
+ ALuint BuffersPlayed;
+ ALboolean Looping;
+ ALuint increment;
+ resampler_t Resampler;
+ ALenum State;
+ ALuint OutPos;
+ ALuint FrameSize;
+ ALint64 DataSize64;
+ ALuint i;
+
+ /* Get source info */
+ State = Source->state;
+ BuffersPlayed = Source->BuffersPlayed;
+ DataPosInt = Source->position;
+ DataPosFrac = Source->position_fraction;
+ Looping = Source->bLooping;
+ increment = Source->Params.Step;
+ Resampler = (increment == FRACTIONONE) ? POINT_RESAMPLER :
+ Source->Resampler;
+
+ /* Get buffer info */
+ FrameSize = 0;
+ FmtChannels = FmtMono;
+ FmtType = FmtUByte;
+ BufferListItem = Source->queue;
+ for(i = 0;i < Source->BuffersInQueue;i++)
+ {
+ const ALbuffer *ALBuffer;
+ if((ALBuffer=BufferListItem->buffer) != NULL)
+ {
+ FmtChannels = ALBuffer->FmtChannels;
+ FmtType = ALBuffer->FmtType;
+ FrameSize = FrameSizeFromFmt(FmtChannels, FmtType);
+ break;
+ }
+ BufferListItem = BufferListItem->next;
+ }
+
+ /* Get current buffer queue item */
+ BufferListItem = Source->queue;
+ for(i = 0;i < BuffersPlayed;i++)
+ BufferListItem = BufferListItem->next;
+
+ OutPos = 0;
+ do {
+ const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
+ const ALuint BufferPadding = ResamplerPadding[Resampler];
+ ALubyte StackData[STACK_DATA_SIZE];
+ ALubyte *SrcData = StackData;
+ ALuint SrcDataSize = 0;
+ ALuint BufferSize;
+
+ /* Figure out how many buffer bytes will be needed */
+ DataSize64 = SamplesToDo-OutPos+1;
+ DataSize64 *= increment;
+ DataSize64 += DataPosFrac+FRACTIONMASK;
+ DataSize64 >>= FRACTIONBITS;
+ DataSize64 += BufferPadding+BufferPrePadding;
+ DataSize64 *= FrameSize;
+
+ BufferSize = min(DataSize64, STACK_DATA_SIZE);
+ BufferSize -= BufferSize%FrameSize;
+
+ if(Source->lSourceType == AL_STATIC)
+ {
+ const ALbuffer *ALBuffer = Source->Buffer;
+ const ALubyte *Data = ALBuffer->data;
+ ALuint DataSize;
+ ALuint pos;
+
+ /* If current pos is beyond the loop range, do not loop */
+ if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
+ {
+ Looping = AL_FALSE;
+
+ if(DataPosInt >= BufferPrePadding)
+ pos = (DataPosInt-BufferPrePadding)*FrameSize;
+ else
+ {
+ DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
+ DataSize = min(BufferSize, DataSize);
+
+ memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
+ SrcDataSize += DataSize;
+ BufferSize -= DataSize;
+
+ pos = 0;
+ }
+
+ /* Copy what's left to play in the source buffer, and clear the
+ * rest of the temp buffer */
+ DataSize = ALBuffer->size - pos;
+ DataSize = min(BufferSize, DataSize);
+
+ memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
+ SrcDataSize += DataSize;
+ BufferSize -= DataSize;
+
+ memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
+ SrcDataSize += BufferSize;
+ BufferSize -= BufferSize;
+ }
+ else
+ {
+ ALuint LoopStart = ALBuffer->LoopStart;
+ ALuint LoopEnd = ALBuffer->LoopEnd;
+
+ if(DataPosInt >= LoopStart)
+ {
+ pos = DataPosInt-LoopStart;
+ while(pos < BufferPrePadding)
+ pos += LoopEnd-LoopStart;
+ pos -= BufferPrePadding;
+ pos += LoopStart;
+ pos *= FrameSize;
+ }
+ else if(DataPosInt >= BufferPrePadding)
+ pos = (DataPosInt-BufferPrePadding)*FrameSize;
+ else
+ {
+ DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
+ DataSize = min(BufferSize, DataSize);
+
+ memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
+ SrcDataSize += DataSize;
+ BufferSize -= DataSize;
+
+ pos = 0;
+ }
+
+ /* Copy what's left of this loop iteration, then copy repeats
+ * of the loop section */
+ DataSize = LoopEnd*FrameSize - pos;
+ DataSize = min(BufferSize, DataSize);
+
+ memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
+ SrcDataSize += DataSize;
+ BufferSize -= DataSize;
+
+ DataSize = (LoopEnd-LoopStart) * FrameSize;
+ while(BufferSize > 0)
+ {
+ DataSize = min(BufferSize, DataSize);
+
+ memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
+ SrcDataSize += DataSize;
+ BufferSize -= DataSize;
+ }
+ }
+ }
+ else
+ {
+ /* Crawl the buffer queue to fill in the temp buffer */
+ ALbufferlistitem *BufferListIter = BufferListItem;
+ ALuint pos;
+
+ if(DataPosInt >= BufferPrePadding)
+ pos = (DataPosInt-BufferPrePadding)*FrameSize;
+ else
+ {
+ pos = (BufferPrePadding-DataPosInt)*FrameSize;
+ while(pos > 0)
+ {
+ if(!BufferListIter->prev && !Looping)
+ {
+ ALuint DataSize = min(BufferSize, pos);
+
+ memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
+ SrcDataSize += DataSize;
+ BufferSize -= DataSize;
+
+ pos = 0;
+ break;
+ }
+
+ if(BufferListIter->prev)
+ BufferListIter = BufferListIter->prev;
+ else
+ {
+ while(BufferListIter->next)
+ BufferListIter = BufferListIter->next;
+ }
+
+ if(BufferListIter->buffer)
+ {
+ if((ALuint)BufferListIter->buffer->size > pos)
+ {
+ pos = BufferListIter->buffer->size - pos;
+ break;
+ }
+ pos -= BufferListIter->buffer->size;
+ }
+ }
+ }
+
+ while(BufferListIter && BufferSize > 0)
+ {
+ const ALbuffer *ALBuffer;
+ if((ALBuffer=BufferListIter->buffer) != NULL)
+ {
+ const ALubyte *Data = ALBuffer->data;
+ ALuint DataSize = ALBuffer->size;
+
+ /* Skip the data already played */
+ if(DataSize <= pos)
+ pos -= DataSize;
+ else
+ {
+ Data += pos;
+ DataSize -= pos;
+ pos -= pos;
+
+ DataSize = min(BufferSize, DataSize);
+ memcpy(&SrcData[SrcDataSize], Data, DataSize);
+ SrcDataSize += DataSize;
+ BufferSize -= DataSize;
+ }
+ }
+ BufferListIter = BufferListIter->next;
+ if(!BufferListIter && Looping)
+ BufferListIter = Source->queue;
+ else if(!BufferListIter)
+ {
+ memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
+ SrcDataSize += BufferSize;
+ BufferSize -= BufferSize;
+ }
+ }
+ }
+
+ /* Figure out how many samples we can mix. */
+ DataSize64 = SrcDataSize / FrameSize;
+ DataSize64 -= BufferPadding+BufferPrePadding;
+ DataSize64 <<= FRACTIONBITS;
+ DataSize64 -= increment;
+ DataSize64 -= DataPosFrac;
+
+ BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
+ BufferSize = min(BufferSize, (SamplesToDo-OutPos));
+
+ SrcData += BufferPrePadding*FrameSize;
+ switch(Resampler)
+ {
+ case POINT_RESAMPLER:
+ Mix_point(Source, Device, FmtChannels, FmtType,
+ SrcData, &DataPosInt, &DataPosFrac,
+ OutPos, SamplesToDo, BufferSize);
+ break;
+ case LINEAR_RESAMPLER:
+ Mix_lerp(Source, Device, FmtChannels, FmtType,
+ SrcData, &DataPosInt, &DataPosFrac,
+ OutPos, SamplesToDo, BufferSize);
+ break;
+ case CUBIC_RESAMPLER:
+ Mix_cubic(Source, Device, FmtChannels, FmtType,
+ SrcData, &DataPosInt, &DataPosFrac,
+ OutPos, SamplesToDo, BufferSize);
+ break;
+ case RESAMPLER_MIN:
+ case RESAMPLER_MAX:
+ break;
+ }
+ OutPos += BufferSize;
+
+ /* Handle looping sources */
+ while(1)
+ {
+ const ALbuffer *ALBuffer;
+ ALuint DataSize = 0;
+ ALuint LoopStart = 0;
+ ALuint LoopEnd = 0;
+
+ if((ALBuffer=BufferListItem->buffer) != NULL)
+ {
+ DataSize = ALBuffer->size / FrameSize;
+ LoopStart = ALBuffer->LoopStart;
+ LoopEnd = ALBuffer->LoopEnd;
+ if(LoopEnd > DataPosInt)
+ break;
+ }
+
+ if(Looping && Source->lSourceType == AL_STATIC)
+ {
+ BufferListItem = Source->queue;
+ DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
+ break;
+ }
+
+ if(DataSize > DataPosInt)
+ break;
+
+ if(BufferListItem->next)
+ {
+ BufferListItem = BufferListItem->next;
+ BuffersPlayed++;
+ }
+ else if(Looping)
+ {
+ BufferListItem = Source->queue;
+ BuffersPlayed = 0;
+ }
+ else
+ {
+ State = AL_STOPPED;
+ BufferListItem = Source->queue;
+ BuffersPlayed = Source->BuffersInQueue;
+ DataPosInt = 0;
+ DataPosFrac = 0;
+ break;
+ }
+
+ DataPosInt -= DataSize;
+ }
+ } while(State == AL_PLAYING && OutPos < SamplesToDo);
+
+ /* Update source info */
+ Source->state = State;
+ Source->BuffersPlayed = BuffersPlayed;
+ Source->position = DataPosInt;
+ Source->position_fraction = DataPosFrac;
+ Source->Buffer = BufferListItem->buffer;
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2010 by Chris Robinson
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+
+typedef struct {
+ ALvoid *buffer;
+ ALuint size;
+
+ volatile int killNow;
+ ALvoid *thread;
+} null_data;
+
+
+static const ALCchar nullDevice[] = "No Output";
+
+static ALuint NullProc(ALvoid *ptr)
+{
+ ALCdevice *Device = (ALCdevice*)ptr;
+ null_data *data = (null_data*)Device->ExtraData;
+ ALuint now, start;
+ ALuint64 avail, done;
+ const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 /
+ Device->Frequency / 2;
+
+ done = 0;
+ start = timeGetTime();
+ while(!data->killNow && Device->Connected)
+ {
+ now = timeGetTime();
+
+ avail = (ALuint64)(now-start) * Device->Frequency / 1000;
+ if(avail < done)
+ {
+ /* Timer wrapped. Add the remainder of the cycle to the available
+ * count and reset the number of samples done */
+ avail += (ALuint64)0xFFFFFFFFu*Device->Frequency/1000 - done;
+ done = 0;
+ }
+ if(avail-done < Device->UpdateSize)
+ {
+ Sleep(restTime);
+ continue;
+ }
+
+ while(avail-done >= Device->UpdateSize)
+ {
+ aluMixData(Device, data->buffer, Device->UpdateSize);
+ done += Device->UpdateSize;
+ }
+ }
+
+ return 0;
+}
+
+static ALCboolean null_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ null_data *data;
+
+ if(!deviceName)
+ deviceName = nullDevice;
+ else if(strcmp(deviceName, nullDevice) != 0)
+ return ALC_FALSE;
+
+ data = (null_data*)calloc(1, sizeof(*data));
+
+ device->szDeviceName = strdup(deviceName);
+ device->ExtraData = data;
+ return ALC_TRUE;
+}
+
+static void null_close_playback(ALCdevice *device)
+{
+ null_data *data = (null_data*)device->ExtraData;
+
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean null_reset_playback(ALCdevice *device)
+{
+ null_data *data = (null_data*)device->ExtraData;
+
+ data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans,
+ device->FmtType);
+ data->buffer = malloc(data->size);
+ if(!data->buffer)
+ {
+ AL_PRINT("buffer malloc failed\n");
+ return ALC_FALSE;
+ }
+ SetDefaultWFXChannelOrder(device);
+
+ data->thread = StartThread(NullProc, device);
+ if(data->thread == NULL)
+ {
+ free(data->buffer);
+ data->buffer = NULL;
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void null_stop_playback(ALCdevice *device)
+{
+ null_data *data = (null_data*)device->ExtraData;
+
+ if(!data->thread)
+ return;
+
+ data->killNow = 1;
+ StopThread(data->thread);
+ data->thread = NULL;
+
+ data->killNow = 0;
+
+ free(data->buffer);
+ data->buffer = NULL;
+}
+
+
+static ALCboolean null_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+ (void)device;
+ (void)deviceName;
+ return ALC_FALSE;
+}
+
+
+BackendFuncs null_funcs = {
+ null_open_playback,
+ null_close_playback,
+ null_reset_playback,
+ null_stop_playback,
+ null_open_capture,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void alc_null_init(BackendFuncs *func_list)
+{
+ *func_list = null_funcs;
+}
+
+void alc_null_deinit(void)
+{
+}
+
+void alc_null_probe(int type)
+{
+ if(type == DEVICE_PROBE)
+ AppendDeviceList(nullDevice);
+ else if(type == ALL_DEVICE_PROBE)
+ AppendAllDeviceList(nullDevice);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <sys/soundcard.h>
+
+/*
+ * The OSS documentation talks about SOUND_MIXER_READ, but the header
+ * only contains MIXER_READ. Play safe. Same for WRITE.
+ */
+#ifndef SOUND_MIXER_READ
+#define SOUND_MIXER_READ MIXER_READ
+#endif
+#ifndef SOUND_MIXER_WRITE
+#define SOUND_MIXER_WRITE MIXER_WRITE
+#endif
+
+static const ALCchar oss_device[] = "OSS Default";
+
+typedef struct {
+ int fd;
+ volatile int killNow;
+ ALvoid *thread;
+
+ ALubyte *mix_data;
+ int data_size;
+
+ RingBuffer *ring;
+ int doCapture;
+} oss_data;
+
+
+static int log2i(ALCuint x)
+{
+ int y = 0;
+ while (x > 1)
+ {
+ x >>= 1;
+ y++;
+ }
+ return y;
+}
+
+
+static ALuint OSSProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ oss_data *data = (oss_data*)pDevice->ExtraData;
+ ALint frameSize;
+ ssize_t wrote;
+
+ SetRTPriority();
+
+ frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+ while(!data->killNow && pDevice->Connected)
+ {
+ ALint len = data->data_size;
+ ALubyte *WritePtr = data->mix_data;
+
+ aluMixData(pDevice, WritePtr, len/frameSize);
+ while(len > 0 && !data->killNow)
+ {
+ wrote = write(data->fd, WritePtr, len);
+ if(wrote < 0)
+ {
+ if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
+ {
+ AL_PRINT("write failed: %s\n", strerror(errno));
+ aluHandleDisconnect(pDevice);
+ break;
+ }
+
+ Sleep(1);
+ continue;
+ }
+
+ len -= wrote;
+ WritePtr += wrote;
+ }
+ }
+
+ return 0;
+}
+
+static ALuint OSSCaptureProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ oss_data *data = (oss_data*)pDevice->ExtraData;
+ int frameSize;
+ int amt;
+
+ SetRTPriority();
+
+ frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+ while(!data->killNow)
+ {
+ amt = read(data->fd, data->mix_data, data->data_size);
+ if(amt < 0)
+ {
+ AL_PRINT("read failed: %s\n", strerror(errno));
+ aluHandleDisconnect(pDevice);
+ break;
+ }
+ if(amt == 0)
+ {
+ Sleep(1);
+ continue;
+ }
+ if(data->doCapture)
+ WriteRingBuffer(data->ring, data->mix_data, amt/frameSize);
+ }
+
+ return 0;
+}
+
+static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ char driver[64];
+ oss_data *data;
+
+ strncpy(driver, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver)-1);
+ driver[sizeof(driver)-1] = 0;
+ if(!deviceName)
+ deviceName = oss_device;
+ else if(strcmp(deviceName, oss_device) != 0)
+ return ALC_FALSE;
+
+ data = (oss_data*)calloc(1, sizeof(oss_data));
+ data->killNow = 0;
+
+ data->fd = open(driver, O_WRONLY);
+ if(data->fd == -1)
+ {
+ free(data);
+ AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
+ return ALC_FALSE;
+ }
+
+ device->szDeviceName = strdup(deviceName);
+ device->ExtraData = data;
+ return ALC_TRUE;
+}
+
+static void oss_close_playback(ALCdevice *device)
+{
+ oss_data *data = (oss_data*)device->ExtraData;
+
+ close(data->fd);
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean oss_reset_playback(ALCdevice *device)
+{
+ oss_data *data = (oss_data*)device->ExtraData;
+ int numFragmentsLogSize;
+ int log2FragmentSize;
+ unsigned int periods;
+ audio_buf_info info;
+ ALuint frameSize;
+ int numChannels;
+ int ossFormat;
+ int ossSpeed;
+ char *err;
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ ossFormat = AFMT_S8;
+ break;
+ case DevFmtUByte:
+ ossFormat = AFMT_U8;
+ break;
+ case DevFmtUShort:
+ case DevFmtFloat:
+ device->FmtType = DevFmtShort;
+ /* fall-through */
+ case DevFmtShort:
+ ossFormat = AFMT_S16_NE;
+ break;
+ }
+
+ periods = device->NumUpdates;
+ numChannels = ChannelsFromDevFmt(device->FmtChans);
+ frameSize = numChannels * BytesFromDevFmt(device->FmtType);
+
+ ossSpeed = device->Frequency;
+ log2FragmentSize = log2i(device->UpdateSize * frameSize);
+
+ /* according to the OSS spec, 16 bytes are the minimum */
+ if (log2FragmentSize < 4)
+ log2FragmentSize = 4;
+ /* Subtract one period since the temp mixing buffer counts as one. Still
+ * need at least two on the card, though. */
+ if(periods > 2) periods--;
+ numFragmentsLogSize = (periods << 16) | log2FragmentSize;
+
+#define CHECKERR(func) if((func) < 0) { \
+ err = #func; \
+ goto err; \
+}
+ /* Don't fail if SETFRAGMENT fails. We can handle just about anything
+ * that's reported back via GETOSPACE */
+ ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info));
+ if(0)
+ {
+ err:
+ AL_PRINT("%s failed: %s\n", err, strerror(errno));
+ return ALC_FALSE;
+ }
+#undef CHECKERR
+
+ if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
+ {
+ AL_PRINT("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), numChannels);
+ return ALC_FALSE;
+ }
+
+ if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
+ (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
+ (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
+ {
+ AL_PRINT("Could not set %#x format type, got OSS format %#x\n", device->FmtType, ossFormat);
+ return ALC_FALSE;
+ }
+
+ device->Frequency = ossSpeed;
+ device->UpdateSize = info.fragsize / frameSize;
+ device->NumUpdates = info.fragments + 1;
+
+ data->data_size = device->UpdateSize * frameSize;
+ data->mix_data = calloc(1, data->data_size);
+
+ SetDefaultChannelOrder(device);
+
+ data->thread = StartThread(OSSProc, device);
+ if(data->thread == NULL)
+ {
+ free(data->mix_data);
+ data->mix_data = NULL;
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void oss_stop_playback(ALCdevice *device)
+{
+ oss_data *data = (oss_data*)device->ExtraData;
+
+ if(!data->thread)
+ return;
+
+ data->killNow = 1;
+ StopThread(data->thread);
+ data->thread = NULL;
+
+ data->killNow = 0;
+ if(ioctl(data->fd, SNDCTL_DSP_RESET) != 0)
+ AL_PRINT("Error resetting device: %s\n", strerror(errno));
+
+ free(data->mix_data);
+ data->mix_data = NULL;
+}
+
+
+static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+ int numFragmentsLogSize;
+ int log2FragmentSize;
+ unsigned int periods;
+ audio_buf_info info;
+ ALuint frameSize;
+ int numChannels;
+ char driver[64];
+ oss_data *data;
+ int ossFormat;
+ int ossSpeed;
+ char *err;
+
+ strncpy(driver, GetConfigValue("oss", "capture", "/dev/dsp"), sizeof(driver)-1);
+ driver[sizeof(driver)-1] = 0;
+ if(!deviceName)
+ deviceName = oss_device;
+ else if(strcmp(deviceName, oss_device) != 0)
+ return ALC_FALSE;
+
+ data = (oss_data*)calloc(1, sizeof(oss_data));
+ data->killNow = 0;
+
+ data->fd = open(driver, O_RDONLY);
+ if(data->fd == -1)
+ {
+ free(data);
+ AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
+ return ALC_FALSE;
+ }
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ ossFormat = AFMT_S8;
+ break;
+ case DevFmtUByte:
+ ossFormat = AFMT_U8;
+ break;
+ case DevFmtShort:
+ ossFormat = AFMT_S16_NE;
+ break;
+ case DevFmtUShort:
+ case DevFmtFloat:
+ free(data);
+ AL_PRINT("Format type %#x capture not supported on OSS\n", device->FmtType);
+ return ALC_FALSE;
+ }
+
+ periods = 4;
+ numChannels = ChannelsFromDevFmt(device->FmtChans);
+ frameSize = numChannels * BytesFromDevFmt(device->FmtType);
+ ossSpeed = device->Frequency;
+ log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
+ frameSize / periods);
+
+ /* according to the OSS spec, 16 bytes are the minimum */
+ if (log2FragmentSize < 4)
+ log2FragmentSize = 4;
+ numFragmentsLogSize = (periods << 16) | log2FragmentSize;
+
+#define CHECKERR(func) if((func) < 0) { \
+ err = #func; \
+ goto err; \
+}
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
+ CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info));
+ if(0)
+ {
+ err:
+ AL_PRINT("%s failed: %s\n", err, strerror(errno));
+ close(data->fd);
+ free(data);
+ return ALC_FALSE;
+ }
+#undef CHECKERR
+
+ if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
+ {
+ AL_PRINT("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), numChannels);
+ close(data->fd);
+ free(data);
+ return ALC_FALSE;
+ }
+
+ if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
+ (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
+ (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
+ {
+ AL_PRINT("Could not set %#x format type, got OSS format %#x\n", device->FmtType, ossFormat);
+ close(data->fd);
+ free(data);
+ return ALC_FALSE;
+ }
+
+ data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
+ if(!data->ring)
+ {
+ AL_PRINT("ring buffer create failed\n");
+ close(data->fd);
+ free(data);
+ return ALC_FALSE;
+ }
+
+ data->data_size = info.fragsize;
+ data->mix_data = calloc(1, data->data_size);
+
+ device->ExtraData = data;
+ data->thread = StartThread(OSSCaptureProc, device);
+ if(data->thread == NULL)
+ {
+ device->ExtraData = NULL;
+ free(data->mix_data);
+ free(data);
+ return ALC_FALSE;
+ }
+
+ device->szDeviceName = strdup(deviceName);
+ return ALC_TRUE;
+}
+
+static void oss_close_capture(ALCdevice *device)
+{
+ oss_data *data = (oss_data*)device->ExtraData;
+ data->killNow = 1;
+ StopThread(data->thread);
+
+ close(data->fd);
+
+ DestroyRingBuffer(data->ring);
+
+ free(data->mix_data);
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static void oss_start_capture(ALCdevice *pDevice)
+{
+ oss_data *data = (oss_data*)pDevice->ExtraData;
+ data->doCapture = 1;
+}
+
+static void oss_stop_capture(ALCdevice *pDevice)
+{
+ oss_data *data = (oss_data*)pDevice->ExtraData;
+ data->doCapture = 0;
+}
+
+static void oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+ oss_data *data = (oss_data*)pDevice->ExtraData;
+ if(lSamples <= (ALCuint)RingBufferSize(data->ring))
+ ReadRingBuffer(data->ring, pBuffer, lSamples);
+ else
+ alcSetError(pDevice, ALC_INVALID_VALUE);
+}
+
+static ALCuint oss_available_samples(ALCdevice *pDevice)
+{
+ oss_data *data = (oss_data*)pDevice->ExtraData;
+ return RingBufferSize(data->ring);
+}
+
+
+BackendFuncs oss_funcs = {
+ oss_open_playback,
+ oss_close_playback,
+ oss_reset_playback,
+ oss_stop_playback,
+ oss_open_capture,
+ oss_close_capture,
+ oss_start_capture,
+ oss_stop_capture,
+ oss_capture_samples,
+ oss_available_samples
+};
+
+void alc_oss_init(BackendFuncs *func_list)
+{
+ *func_list = oss_funcs;
+}
+
+void alc_oss_deinit(void)
+{
+}
+
+void alc_oss_probe(int type)
+{
+ if(type == DEVICE_PROBE)
+ {
+#ifdef HAVE_STAT
+ struct stat buf;
+ if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0)
+#endif
+ AppendDeviceList(oss_device);
+ }
+ else if(type == ALL_DEVICE_PROBE)
+ {
+#ifdef HAVE_STAT
+ struct stat buf;
+ if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0)
+#endif
+ AppendAllDeviceList(oss_device);
+ }
+ else if(type == CAPTURE_DEVICE_PROBE)
+ {
+#ifdef HAVE_STAT
+ struct stat buf;
+ if(stat(GetConfigValue("oss", "capture", "/dev/dsp"), &buf) == 0)
+#endif
+ AppendCaptureDeviceList(oss_device);
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2010 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alu.h"
+
+static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MAXCHANNELS],
+ Channel Speaker2Chan[MAXCHANNELS], ALint chans)
+{
+ char layout_str[256];
+ char *confkey, *next;
+ char *sep, *end;
+ Channel val;
+ int i;
+
+ if(!ConfigValueExists(NULL, name))
+ name = "layout";
+
+ strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str));
+ layout_str[sizeof(layout_str)-1] = 0;
+
+ if(!layout_str[0])
+ return;
+
+ next = confkey = layout_str;
+ while(next && *next)
+ {
+ confkey = next;
+ next = strchr(confkey, ',');
+ if(next)
+ {
+ *next = 0;
+ do {
+ next++;
+ } while(isspace(*next) || *next == ',');
+ }
+
+ sep = strchr(confkey, '=');
+ if(!sep || confkey == sep)
+ continue;
+
+ end = sep - 1;
+ while(isspace(*end) && end != confkey)
+ end--;
+ *(++end) = 0;
+
+ if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
+ val = FRONT_LEFT;
+ else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
+ val = FRONT_RIGHT;
+ else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
+ val = FRONT_CENTER;
+ else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
+ val = BACK_LEFT;
+ else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
+ val = BACK_RIGHT;
+ else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
+ val = BACK_CENTER;
+ else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
+ val = SIDE_LEFT;
+ else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
+ val = SIDE_RIGHT;
+ else
+ {
+ AL_PRINT("Unknown speaker for %s: \"%s\"\n", name, confkey);
+ continue;
+ }
+
+ *(sep++) = 0;
+ while(isspace(*sep))
+ sep++;
+
+ for(i = 0;i < chans;i++)
+ {
+ if(Speaker2Chan[i] == val)
+ {
+ long angle = strtol(sep, NULL, 10);
+ if(angle >= -180 && angle <= 180)
+ SpeakerAngle[i] = angle * M_PI/180.0f;
+ else
+ AL_PRINT("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
+ break;
+ }
+ }
+ }
+
+ for(i = 0;i < chans;i++)
+ {
+ int min = i;
+ int i2;
+
+ for(i2 = i+1;i2 < chans;i2++)
+ {
+ if(SpeakerAngle[i2] < SpeakerAngle[min])
+ min = i2;
+ }
+
+ if(min != i)
+ {
+ ALfloat tmpf;
+ Channel tmpc;
+
+ tmpf = SpeakerAngle[i];
+ SpeakerAngle[i] = SpeakerAngle[min];
+ SpeakerAngle[min] = tmpf;
+
+ tmpc = Speaker2Chan[i];
+ Speaker2Chan[i] = Speaker2Chan[min];
+ Speaker2Chan[min] = tmpc;
+ }
+ }
+}
+
+static ALfloat aluLUTpos2Angle(ALint pos)
+{
+ if(pos < QUADRANT_NUM)
+ return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
+ if(pos < 2 * QUADRANT_NUM)
+ return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
+ if(pos < 3 * QUADRANT_NUM)
+ return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
+ return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
+}
+
+ALint aluCart2LUTpos(ALfloat re, ALfloat im)
+{
+ ALint pos = 0;
+ ALfloat denom = aluFabs(re) + aluFabs(im);
+ if(denom > 0.0f)
+ pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
+
+ if(re < 0.0)
+ pos = 2 * QUADRANT_NUM - pos;
+ if(im < 0.0)
+ pos = LUT_NUM - pos;
+ return pos%LUT_NUM;
+}
+
+ALvoid aluInitPanning(ALCdevice *Device)
+{
+ ALfloat SpeakerAngle[MAXCHANNELS];
+ ALfloat (*Matrix)[MAXCHANNELS];
+ Channel *Speaker2Chan;
+ ALfloat Alpha, Theta;
+ ALfloat *PanningLUT;
+ ALint pos, offset;
+ ALuint s, s2;
+
+ for(s = 0;s < MAXCHANNELS;s++)
+ {
+ for(s2 = 0;s2 < MAXCHANNELS;s2++)
+ Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
+ }
+
+ Speaker2Chan = Device->Speaker2Chan;
+ Matrix = Device->ChannelMatrix;
+ switch(Device->FmtChans)
+ {
+ case DevFmtMono:
+ Matrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5);
+ Matrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
+ Matrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5);
+ Matrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
+ Matrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5);
+ Matrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
+ Matrix[BACK_CENTER][FRONT_CENTER] = 1.0f;
+ Device->NumChan = 1;
+ Speaker2Chan[0] = FRONT_CENTER;
+ SpeakerAngle[0] = 0.0f * M_PI/180.0f;
+ break;
+
+ case DevFmtStereo:
+ Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
+ Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
+ Matrix[SIDE_LEFT][FRONT_LEFT] = 1.0f;
+ Matrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f;
+ Matrix[BACK_LEFT][FRONT_LEFT] = 1.0f;
+ Matrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f;
+ Matrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5);
+ Matrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
+ Device->NumChan = 2;
+ Speaker2Chan[0] = FRONT_LEFT;
+ Speaker2Chan[1] = FRONT_RIGHT;
+ SpeakerAngle[0] = -90.0f * M_PI/180.0f;
+ SpeakerAngle[1] = 90.0f * M_PI/180.0f;
+ SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtQuad:
+ Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
+ Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
+ Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
+ Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
+ Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
+ Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
+ Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
+ Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
+ Device->NumChan = 4;
+ Speaker2Chan[0] = BACK_LEFT;
+ Speaker2Chan[1] = FRONT_LEFT;
+ Speaker2Chan[2] = FRONT_RIGHT;
+ Speaker2Chan[3] = BACK_RIGHT;
+ SpeakerAngle[0] = -135.0f * M_PI/180.0f;
+ SpeakerAngle[1] = -45.0f * M_PI/180.0f;
+ SpeakerAngle[2] = 45.0f * M_PI/180.0f;
+ SpeakerAngle[3] = 135.0f * M_PI/180.0f;
+ SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtX51:
+ Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
+ Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
+ Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
+ Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
+ Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
+ Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
+ Device->NumChan = 5;
+ Speaker2Chan[0] = BACK_LEFT;
+ Speaker2Chan[1] = FRONT_LEFT;
+ Speaker2Chan[2] = FRONT_CENTER;
+ Speaker2Chan[3] = FRONT_RIGHT;
+ Speaker2Chan[4] = BACK_RIGHT;
+ SpeakerAngle[0] = -110.0f * M_PI/180.0f;
+ SpeakerAngle[1] = -30.0f * M_PI/180.0f;
+ SpeakerAngle[2] = 0.0f * M_PI/180.0f;
+ SpeakerAngle[3] = 30.0f * M_PI/180.0f;
+ SpeakerAngle[4] = 110.0f * M_PI/180.0f;
+ SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtX61:
+ Matrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5);
+ Matrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5);
+ Matrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
+ Matrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5);
+ Device->NumChan = 6;
+ Speaker2Chan[0] = SIDE_LEFT;
+ Speaker2Chan[1] = FRONT_LEFT;
+ Speaker2Chan[2] = FRONT_CENTER;
+ Speaker2Chan[3] = FRONT_RIGHT;
+ Speaker2Chan[4] = SIDE_RIGHT;
+ Speaker2Chan[5] = BACK_CENTER;
+ SpeakerAngle[0] = -90.0f * M_PI/180.0f;
+ SpeakerAngle[1] = -30.0f * M_PI/180.0f;
+ SpeakerAngle[2] = 0.0f * M_PI/180.0f;
+ SpeakerAngle[3] = 30.0f * M_PI/180.0f;
+ SpeakerAngle[4] = 90.0f * M_PI/180.0f;
+ SpeakerAngle[5] = 180.0f * M_PI/180.0f;
+ SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtX71:
+ Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
+ Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
+ Device->NumChan = 7;
+ Speaker2Chan[0] = BACK_LEFT;
+ Speaker2Chan[1] = SIDE_LEFT;
+ Speaker2Chan[2] = FRONT_LEFT;
+ Speaker2Chan[3] = FRONT_CENTER;
+ Speaker2Chan[4] = FRONT_RIGHT;
+ Speaker2Chan[5] = SIDE_RIGHT;
+ Speaker2Chan[6] = BACK_RIGHT;
+ SpeakerAngle[0] = -150.0f * M_PI/180.0f;
+ SpeakerAngle[1] = -90.0f * M_PI/180.0f;
+ SpeakerAngle[2] = -30.0f * M_PI/180.0f;
+ SpeakerAngle[3] = 0.0f * M_PI/180.0f;
+ SpeakerAngle[4] = 30.0f * M_PI/180.0f;
+ SpeakerAngle[5] = 90.0f * M_PI/180.0f;
+ SpeakerAngle[6] = 150.0f * M_PI/180.0f;
+ SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+ }
+
+ if(GetConfigValueBool(NULL, "scalemix", 0))
+ {
+ ALfloat maxout = 1.0f;
+ for(s = 0;s < MAXCHANNELS;s++)
+ {
+ ALfloat out = 0.0f;
+ for(s2 = 0;s2 < MAXCHANNELS;s2++)
+ out += Device->ChannelMatrix[s2][s];
+ maxout = __max(maxout, out);
+ }
+
+ maxout = 1.0f/maxout;
+ for(s = 0;s < MAXCHANNELS;s++)
+ {
+ for(s2 = 0;s2 < MAXCHANNELS;s2++)
+ Device->ChannelMatrix[s2][s] *= maxout;
+ }
+ }
+
+ PanningLUT = Device->PanningLUT;
+ for(pos = 0; pos < LUT_NUM; pos++)
+ {
+ /* clear all values */
+ offset = MAXCHANNELS * pos;
+ for(s = 0; s < MAXCHANNELS; s++)
+ PanningLUT[offset+s] = 0.0f;
+
+ if(Device->NumChan == 1)
+ {
+ PanningLUT[offset + Speaker2Chan[0]] = 1.0f;
+ continue;
+ }
+
+ /* source angle */
+ Theta = aluLUTpos2Angle(pos);
+
+ /* set panning values */
+ for(s = 0; s < Device->NumChan - 1; s++)
+ {
+ if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
+ {
+ /* source between speaker s and speaker s+1 */
+ Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
+ (SpeakerAngle[s+1]-SpeakerAngle[s]);
+ PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
+ PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
+ break;
+ }
+ }
+ if(s == Device->NumChan - 1)
+ {
+ /* source between last and first speaker */
+ if(Theta < SpeakerAngle[0])
+ Theta += 2.0f * M_PI;
+ Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
+ (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
+ PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
+ PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);
+ }
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <portaudio.h>
+
+static void *pa_handle;
+#define MAKE_FUNC(x) static typeof(x) * p##x
+MAKE_FUNC(Pa_Initialize);
+MAKE_FUNC(Pa_Terminate);
+MAKE_FUNC(Pa_GetErrorText);
+MAKE_FUNC(Pa_StartStream);
+MAKE_FUNC(Pa_StopStream);
+MAKE_FUNC(Pa_OpenStream);
+MAKE_FUNC(Pa_CloseStream);
+MAKE_FUNC(Pa_GetDefaultOutputDevice);
+MAKE_FUNC(Pa_GetStreamInfo);
+#undef MAKE_FUNC
+
+
+static const ALCchar pa_device[] = "PortAudio Default";
+
+
+void *pa_load(void)
+{
+ if(!pa_handle)
+ {
+ PaError err;
+
+#ifdef _WIN32
+ pa_handle = LoadLibrary("portaudio.dll");
+#define LOAD_FUNC(x) do { \
+ p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
+ if(!(p##x)) { \
+ AL_PRINT("Could not load %s from portaudio.dll\n", #x); \
+ FreeLibrary(pa_handle); \
+ pa_handle = NULL; \
+ return NULL; \
+ } \
+} while(0)
+
+#elif defined(HAVE_DLFCN_H)
+
+ const char *str;
+#if defined(__APPLE__) && defined(__MACH__)
+# define PALIB "libportaudio.2.dylib"
+#else
+# define PALIB "libportaudio.so.2"
+#endif
+ pa_handle = dlopen(PALIB, RTLD_NOW);
+ dlerror();
+
+#define LOAD_FUNC(f) do { \
+ p##f = (typeof(f)*)dlsym(pa_handle, #f); \
+ if((str=dlerror()) != NULL) \
+ { \
+ dlclose(pa_handle); \
+ pa_handle = NULL; \
+ AL_PRINT("Could not load %s from "PALIB": %s\n", #f, str); \
+ return NULL; \
+ } \
+} while(0)
+
+#else
+ pa_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(f) p##f = f
+#endif
+
+ if(!pa_handle)
+ return NULL;
+
+LOAD_FUNC(Pa_Initialize);
+LOAD_FUNC(Pa_Terminate);
+LOAD_FUNC(Pa_GetErrorText);
+LOAD_FUNC(Pa_StartStream);
+LOAD_FUNC(Pa_StopStream);
+LOAD_FUNC(Pa_OpenStream);
+LOAD_FUNC(Pa_CloseStream);
+LOAD_FUNC(Pa_GetDefaultOutputDevice);
+LOAD_FUNC(Pa_GetStreamInfo);
+
+#undef LOAD_FUNC
+
+ if((err=pPa_Initialize()) != paNoError)
+ {
+ AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err));
+#ifdef _WIN32
+ FreeLibrary(pa_handle);
+#elif defined(HAVE_DLFCN_H)
+ dlclose(pa_handle);
+#endif
+ pa_handle = NULL;
+ return NULL;
+ }
+ }
+ return pa_handle;
+}
+
+
+typedef struct {
+ PaStream *stream;
+ ALuint update_size;
+
+ RingBuffer *ring;
+} pa_data;
+
+
+static int pa_callback(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData)
+{
+ ALCdevice *device = (ALCdevice*)userData;
+
+ (void)inputBuffer;
+ (void)timeInfo;
+ (void)statusFlags;
+
+ aluMixData(device, outputBuffer, framesPerBuffer);
+ return 0;
+}
+
+static int pa_capture_cb(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData)
+{
+ ALCdevice *device = (ALCdevice*)userData;
+ pa_data *data = (pa_data*)device->ExtraData;
+
+ (void)outputBuffer;
+ (void)timeInfo;
+ (void)statusFlags;
+
+ WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer);
+ return 0;
+}
+
+
+static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ const PaStreamInfo *streamInfo;
+ PaStreamParameters outParams;
+ pa_data *data;
+ PaError err;
+
+ if(!deviceName)
+ deviceName = pa_device;
+ else if(strcmp(deviceName, pa_device) != 0)
+ return ALC_FALSE;
+
+ if(!pa_load())
+ return ALC_FALSE;
+
+ data = (pa_data*)calloc(1, sizeof(pa_data));
+ data->update_size = device->UpdateSize;
+
+ device->ExtraData = data;
+
+ outParams.device = GetConfigValueInt("port", "device", -1);
+ if(outParams.device < 0)
+ outParams.device = pPa_GetDefaultOutputDevice();
+ outParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
+ (float)device->Frequency;
+ outParams.hostApiSpecificStreamInfo = NULL;
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ outParams.sampleFormat = paInt8;
+ break;
+ case DevFmtUByte:
+ outParams.sampleFormat = paUInt8;
+ break;
+ case DevFmtUShort:
+ device->FmtType = DevFmtShort;
+ /* fall-through */
+ case DevFmtShort:
+ outParams.sampleFormat = paInt16;
+ break;
+ case DevFmtFloat:
+ outParams.sampleFormat = paFloat32;
+ break;
+ }
+ outParams.channelCount = ChannelsFromDevFmt(device->FmtChans);
+
+ SetDefaultChannelOrder(device);
+
+ err = pPa_OpenStream(&data->stream, NULL, &outParams, device->Frequency,
+ device->UpdateSize, paNoFlag, pa_callback, device);
+ if(err != paNoError)
+ {
+ AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err));
+ device->ExtraData = NULL;
+ free(data);
+ return ALC_FALSE;
+ }
+ streamInfo = pPa_GetStreamInfo(data->stream);
+
+ device->szDeviceName = strdup(deviceName);
+ device->Frequency = streamInfo->sampleRate;
+
+ return ALC_TRUE;
+}
+
+static void pa_close_playback(ALCdevice *device)
+{
+ pa_data *data = (pa_data*)device->ExtraData;
+ PaError err;
+
+ err = pPa_CloseStream(data->stream);
+ if(err != paNoError)
+ AL_PRINT("Error closing stream: %s\n", pPa_GetErrorText(err));
+
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean pa_reset_playback(ALCdevice *device)
+{
+ pa_data *data = (pa_data*)device->ExtraData;
+ const PaStreamInfo *streamInfo;
+ PaError err;
+
+ streamInfo = pPa_GetStreamInfo(data->stream);
+ device->Frequency = streamInfo->sampleRate;
+ device->UpdateSize = data->update_size;
+
+ err = pPa_StartStream(data->stream);
+ if(err != paNoError)
+ {
+ AL_PRINT("Pa_StartStream() returned an error: %s\n", pPa_GetErrorText(err));
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void pa_stop_playback(ALCdevice *device)
+{
+ pa_data *data = (pa_data*)device->ExtraData;
+ PaError err;
+
+ err = pPa_StopStream(data->stream);
+ if(err != paNoError)
+ AL_PRINT("Error stopping stream: %s\n", pPa_GetErrorText(err));
+}
+
+
+static ALCboolean pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+ PaStreamParameters inParams;
+ ALuint frame_size;
+ pa_data *data;
+ PaError err;
+
+ if(!deviceName)
+ deviceName = pa_device;
+ else if(strcmp(deviceName, pa_device) != 0)
+ return ALC_FALSE;
+
+ if(!pa_load())
+ return ALC_FALSE;
+
+ data = (pa_data*)calloc(1, sizeof(pa_data));
+ if(data == NULL)
+ {
+ alcSetError(device, ALC_OUT_OF_MEMORY);
+ return ALC_FALSE;
+ }
+
+ frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates);
+ if(data->ring == NULL)
+ {
+ alcSetError(device, ALC_OUT_OF_MEMORY);
+ goto error;
+ }
+
+ inParams.device = GetConfigValueInt("port", "capture", -1);
+ if(inParams.device < 0)
+ inParams.device = pPa_GetDefaultOutputDevice();
+ inParams.suggestedLatency = 0.0f;
+ inParams.hostApiSpecificStreamInfo = NULL;
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ inParams.sampleFormat = paInt8;
+ break;
+ case DevFmtUByte:
+ inParams.sampleFormat = paUInt8;
+ break;
+ case DevFmtShort:
+ inParams.sampleFormat = paInt16;
+ break;
+ case DevFmtFloat:
+ inParams.sampleFormat = paFloat32;
+ break;
+ case DevFmtUShort:
+ AL_PRINT("Unsigned short not supported\n");
+ goto error;
+ }
+ inParams.channelCount = ChannelsFromDevFmt(device->FmtChans);
+
+ err = pPa_OpenStream(&data->stream, &inParams, NULL, device->Frequency,
+ paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device);
+ if(err != paNoError)
+ {
+ AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err));
+ goto error;
+ }
+
+ device->szDeviceName = strdup(deviceName);
+
+ device->ExtraData = data;
+ return ALC_TRUE;
+
+error:
+ DestroyRingBuffer(data->ring);
+ free(data);
+ return ALC_FALSE;
+}
+
+static void pa_close_capture(ALCdevice *device)
+{
+ pa_data *data = (pa_data*)device->ExtraData;
+ PaError err;
+
+ err = pPa_CloseStream(data->stream);
+ if(err != paNoError)
+ AL_PRINT("Error closing stream: %s\n", pPa_GetErrorText(err));
+
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static void pa_start_capture(ALCdevice *device)
+{
+ pa_data *data = device->ExtraData;
+ PaError err;
+
+ err = pPa_StartStream(data->stream);
+ if(err != paNoError)
+ AL_PRINT("Error starting stream: %s\n", pPa_GetErrorText(err));
+}
+
+static void pa_stop_capture(ALCdevice *device)
+{
+ pa_data *data = (pa_data*)device->ExtraData;
+ PaError err;
+
+ err = pPa_StopStream(data->stream);
+ if(err != paNoError)
+ AL_PRINT("Error stopping stream: %s\n", pPa_GetErrorText(err));
+}
+
+static void pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+{
+ pa_data *data = device->ExtraData;
+ if(samples <= (ALCuint)RingBufferSize(data->ring))
+ ReadRingBuffer(data->ring, buffer, samples);
+ else
+ alcSetError(device, ALC_INVALID_VALUE);
+}
+
+static ALCuint pa_available_samples(ALCdevice *device)
+{
+ pa_data *data = device->ExtraData;
+ return RingBufferSize(data->ring);
+}
+
+
+static const BackendFuncs pa_funcs = {
+ pa_open_playback,
+ pa_close_playback,
+ pa_reset_playback,
+ pa_stop_playback,
+ pa_open_capture,
+ pa_close_capture,
+ pa_start_capture,
+ pa_stop_capture,
+ pa_capture_samples,
+ pa_available_samples
+};
+
+void alc_pa_init(BackendFuncs *func_list)
+{
+ *func_list = pa_funcs;
+}
+
+void alc_pa_deinit(void)
+{
+ if(pa_handle)
+ {
+ pPa_Terminate();
+#ifdef _WIN32
+ FreeLibrary(pa_handle);
+#elif defined(HAVE_DLFCN_H)
+ dlclose(pa_handle);
+#endif
+ pa_handle = NULL;
+ }
+}
+
+void alc_pa_probe(int type)
+{
+ if(!pa_load()) return;
+
+ if(type == DEVICE_PROBE)
+ AppendDeviceList(pa_device);
+ else if(type == ALL_DEVICE_PROBE)
+ AppendAllDeviceList(pa_device);
+ else if(type == CAPTURE_DEVICE_PROBE)
+ AppendCaptureDeviceList(pa_device);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Konstantinos Natsakis <konstantinos.natsakis@gmail.com>
+ * Copyright (C) 2010 by Chris Robinson <chris.kcat@gmail.com>
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include "alMain.h"
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <pulse/pulseaudio.h>
+
+#if PA_API_VERSION == 11
+#define PA_STREAM_ADJUST_LATENCY 0x2000U
+#define PA_STREAM_EARLY_REQUESTS 0x4000U
+static __inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
+{
+ return (x == PA_STREAM_CREATING || x == PA_STREAM_READY);
+}
+static __inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
+{
+ return (x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING ||
+ x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY);
+}
+#define PA_STREAM_IS_GOOD PA_STREAM_IS_GOOD
+#define PA_CONTEXT_IS_GOOD PA_CONTEXT_IS_GOOD
+#elif PA_API_VERSION != 12
+#error Invalid PulseAudio API version
+#endif
+
+#ifndef PA_CHECK_VERSION
+#define PA_CHECK_VERSION(major,minor,micro) \
+ ((PA_MAJOR > (major)) || \
+ (PA_MAJOR == (major) && PA_MINOR > (minor)) || \
+ (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
+#endif
+
+static void *pa_handle;
+#define MAKE_FUNC(x) static typeof(x) * p##x
+MAKE_FUNC(pa_context_unref);
+MAKE_FUNC(pa_sample_spec_valid);
+MAKE_FUNC(pa_stream_drop);
+MAKE_FUNC(pa_strerror);
+MAKE_FUNC(pa_context_get_state);
+MAKE_FUNC(pa_stream_get_state);
+MAKE_FUNC(pa_threaded_mainloop_signal);
+MAKE_FUNC(pa_stream_peek);
+MAKE_FUNC(pa_threaded_mainloop_wait);
+MAKE_FUNC(pa_threaded_mainloop_unlock);
+MAKE_FUNC(pa_threaded_mainloop_in_thread);
+MAKE_FUNC(pa_context_new);
+MAKE_FUNC(pa_threaded_mainloop_stop);
+MAKE_FUNC(pa_context_disconnect);
+MAKE_FUNC(pa_threaded_mainloop_start);
+MAKE_FUNC(pa_threaded_mainloop_get_api);
+MAKE_FUNC(pa_context_set_state_callback);
+MAKE_FUNC(pa_stream_write);
+MAKE_FUNC(pa_xfree);
+MAKE_FUNC(pa_stream_connect_record);
+MAKE_FUNC(pa_stream_connect_playback);
+MAKE_FUNC(pa_stream_readable_size);
+MAKE_FUNC(pa_stream_writable_size);
+MAKE_FUNC(pa_stream_cork);
+MAKE_FUNC(pa_stream_is_suspended);
+MAKE_FUNC(pa_stream_get_device_name);
+MAKE_FUNC(pa_path_get_filename);
+MAKE_FUNC(pa_get_binary_name);
+MAKE_FUNC(pa_threaded_mainloop_free);
+MAKE_FUNC(pa_context_errno);
+MAKE_FUNC(pa_xmalloc);
+MAKE_FUNC(pa_stream_unref);
+MAKE_FUNC(pa_threaded_mainloop_accept);
+MAKE_FUNC(pa_stream_set_write_callback);
+MAKE_FUNC(pa_threaded_mainloop_new);
+MAKE_FUNC(pa_context_connect);
+MAKE_FUNC(pa_stream_set_buffer_attr);
+MAKE_FUNC(pa_stream_get_buffer_attr);
+MAKE_FUNC(pa_stream_get_sample_spec);
+MAKE_FUNC(pa_stream_get_time);
+MAKE_FUNC(pa_stream_set_read_callback);
+MAKE_FUNC(pa_stream_set_state_callback);
+MAKE_FUNC(pa_stream_set_moved_callback);
+MAKE_FUNC(pa_stream_set_underflow_callback);
+MAKE_FUNC(pa_stream_new);
+MAKE_FUNC(pa_stream_disconnect);
+MAKE_FUNC(pa_threaded_mainloop_lock);
+MAKE_FUNC(pa_channel_map_init_auto);
+MAKE_FUNC(pa_channel_map_parse);
+MAKE_FUNC(pa_channel_map_snprint);
+MAKE_FUNC(pa_channel_map_equal);
+MAKE_FUNC(pa_context_get_server_info);
+MAKE_FUNC(pa_context_get_sink_info_by_name);
+MAKE_FUNC(pa_context_get_sink_info_list);
+MAKE_FUNC(pa_context_get_source_info_list);
+MAKE_FUNC(pa_operation_get_state);
+MAKE_FUNC(pa_operation_unref);
+#if PA_CHECK_VERSION(0,9,15)
+MAKE_FUNC(pa_channel_map_superset);
+MAKE_FUNC(pa_stream_set_buffer_attr_callback);
+#endif
+#if PA_CHECK_VERSION(0,9,16)
+MAKE_FUNC(pa_stream_begin_write);
+#endif
+#undef MAKE_FUNC
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+typedef struct {
+ char *device_name;
+
+ ALCuint samples;
+ ALCuint frame_size;
+
+ RingBuffer *ring;
+
+ pa_buffer_attr attr;
+ pa_sample_spec spec;
+
+ pa_threaded_mainloop *loop;
+
+ ALvoid *thread;
+ volatile ALboolean killNow;
+
+ pa_stream *stream;
+ pa_context *context;
+} pulse_data;
+
+typedef struct {
+ char *name;
+ char *device_name;
+} DevMap;
+
+
+static const ALCchar pulse_device[] = "PulseAudio Default";
+static DevMap *allDevNameMap;
+static ALuint numDevNames;
+static DevMap *allCaptureDevNameMap;
+static ALuint numCaptureDevNames;
+static pa_context_flags_t pulse_ctx_flags;
+
+
+void *pulse_load(void) //{{{
+{
+ if(!pa_handle)
+ {
+#ifdef _WIN32
+ pa_handle = LoadLibrary("libpulse-0.dll");
+#define LOAD_FUNC(x) do { \
+ p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
+ if(!(p##x)) { \
+ AL_PRINT("Could not load %s from libpulse-0.dll\n", #x); \
+ FreeLibrary(pa_handle); \
+ pa_handle = NULL; \
+ return NULL; \
+ } \
+} while(0)
+#define LOAD_OPTIONAL_FUNC(x) do { \
+ p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
+} while(0)
+
+#elif defined (HAVE_DLFCN_H)
+
+ const char *err;
+#if defined(__APPLE__) && defined(__MACH__)
+ pa_handle = dlopen("libpulse.0.dylib", RTLD_NOW);
+#else
+ pa_handle = dlopen("libpulse.so.0", RTLD_NOW);
+#endif
+ dlerror();
+
+#define LOAD_FUNC(x) do { \
+ p##x = dlsym(pa_handle, #x); \
+ if((err=dlerror()) != NULL) { \
+ AL_PRINT("Could not load %s from libpulse: %s\n", #x, err); \
+ dlclose(pa_handle); \
+ pa_handle = NULL; \
+ return NULL; \
+ } \
+} while(0)
+#define LOAD_OPTIONAL_FUNC(x) do { \
+ p##x = dlsym(pa_handle, #x); \
+ if((err=dlerror()) != NULL) { \
+ p##x = NULL; \
+ } \
+} while(0)
+
+#else
+
+ pa_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(x) p##x = (x)
+#define LOAD_OPTIONAL_FUNC(x) p##x = (x)
+
+#endif
+ if(!pa_handle)
+ return NULL;
+
+LOAD_FUNC(pa_context_unref);
+LOAD_FUNC(pa_sample_spec_valid);
+LOAD_FUNC(pa_stream_drop);
+LOAD_FUNC(pa_strerror);
+LOAD_FUNC(pa_context_get_state);
+LOAD_FUNC(pa_stream_get_state);
+LOAD_FUNC(pa_threaded_mainloop_signal);
+LOAD_FUNC(pa_stream_peek);
+LOAD_FUNC(pa_threaded_mainloop_wait);
+LOAD_FUNC(pa_threaded_mainloop_unlock);
+LOAD_FUNC(pa_threaded_mainloop_in_thread);
+LOAD_FUNC(pa_context_new);
+LOAD_FUNC(pa_threaded_mainloop_stop);
+LOAD_FUNC(pa_context_disconnect);
+LOAD_FUNC(pa_threaded_mainloop_start);
+LOAD_FUNC(pa_threaded_mainloop_get_api);
+LOAD_FUNC(pa_context_set_state_callback);
+LOAD_FUNC(pa_stream_write);
+LOAD_FUNC(pa_xfree);
+LOAD_FUNC(pa_stream_connect_record);
+LOAD_FUNC(pa_stream_connect_playback);
+LOAD_FUNC(pa_stream_readable_size);
+LOAD_FUNC(pa_stream_writable_size);
+LOAD_FUNC(pa_stream_cork);
+LOAD_FUNC(pa_stream_is_suspended);
+LOAD_FUNC(pa_stream_get_device_name);
+LOAD_FUNC(pa_path_get_filename);
+LOAD_FUNC(pa_get_binary_name);
+LOAD_FUNC(pa_threaded_mainloop_free);
+LOAD_FUNC(pa_context_errno);
+LOAD_FUNC(pa_xmalloc);
+LOAD_FUNC(pa_stream_unref);
+LOAD_FUNC(pa_threaded_mainloop_accept);
+LOAD_FUNC(pa_stream_set_write_callback);
+LOAD_FUNC(pa_threaded_mainloop_new);
+LOAD_FUNC(pa_context_connect);
+LOAD_FUNC(pa_stream_set_buffer_attr);
+LOAD_FUNC(pa_stream_get_buffer_attr);
+LOAD_FUNC(pa_stream_get_sample_spec);
+LOAD_FUNC(pa_stream_get_time);
+LOAD_FUNC(pa_stream_set_read_callback);
+LOAD_FUNC(pa_stream_set_state_callback);
+LOAD_FUNC(pa_stream_set_moved_callback);
+LOAD_FUNC(pa_stream_set_underflow_callback);
+LOAD_FUNC(pa_stream_new);
+LOAD_FUNC(pa_stream_disconnect);
+LOAD_FUNC(pa_threaded_mainloop_lock);
+LOAD_FUNC(pa_channel_map_init_auto);
+LOAD_FUNC(pa_channel_map_parse);
+LOAD_FUNC(pa_channel_map_snprint);
+LOAD_FUNC(pa_channel_map_equal);
+LOAD_FUNC(pa_context_get_server_info);
+LOAD_FUNC(pa_context_get_sink_info_by_name);
+LOAD_FUNC(pa_context_get_sink_info_list);
+LOAD_FUNC(pa_context_get_source_info_list);
+LOAD_FUNC(pa_operation_get_state);
+LOAD_FUNC(pa_operation_unref);
+#if PA_CHECK_VERSION(0,9,15)
+LOAD_OPTIONAL_FUNC(pa_channel_map_superset);
+LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback);
+#endif
+#if PA_CHECK_VERSION(0,9,16)
+LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
+#endif
+
+#undef LOAD_OPTIONAL_FUNC
+#undef LOAD_FUNC
+ }
+ return pa_handle;
+} //}}}
+
+// PulseAudio Event Callbacks //{{{
+static void context_state_callback(pa_context *context, void *pdata) //{{{
+{
+ pa_threaded_mainloop *loop = pdata;
+ pa_context_state_t state;
+
+ state = ppa_context_get_state(context);
+ if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state))
+ ppa_threaded_mainloop_signal(loop, 0);
+}//}}}
+
+static void stream_state_callback(pa_stream *stream, void *pdata) //{{{
+{
+ pa_threaded_mainloop *loop = pdata;
+ pa_stream_state_t state;
+
+ state = ppa_stream_get_state(stream);
+ if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state))
+ ppa_threaded_mainloop_signal(loop, 0);
+}//}}}
+
+static void stream_signal_callback(pa_stream *stream, void *pdata) //{{{
+{
+ ALCdevice *Device = pdata;
+ pulse_data *data = Device->ExtraData;
+ (void)stream;
+
+ ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void stream_buffer_attr_callback(pa_stream *stream, void *pdata) //{{{
+{
+ ALCdevice *Device = pdata;
+ pulse_data *data = Device->ExtraData;
+
+ SuspendContext(NULL);
+
+ data->attr = *(ppa_stream_get_buffer_attr(stream));
+ Device->UpdateSize = data->attr.minreq / data->frame_size;
+ Device->NumUpdates = (data->attr.tlength/data->frame_size) / Device->UpdateSize;
+ if(Device->NumUpdates <= 1)
+ {
+ Device->NumUpdates = 1;
+ AL_PRINT("PulseAudio returned minreq > tlength/2; expect break up\n");
+ }
+
+ ProcessContext(NULL);
+}//}}}
+
+static void stream_device_callback(pa_stream *stream, void *pdata) //{{{
+{
+ ALCdevice *Device = pdata;
+ pulse_data *data = Device->ExtraData;
+
+ free(data->device_name);
+ data->device_name = strdup(ppa_stream_get_device_name(stream));
+}//}}}
+
+static void context_state_callback2(pa_context *context, void *pdata) //{{{
+{
+ ALCdevice *Device = pdata;
+ pulse_data *data = Device->ExtraData;
+
+ if(ppa_context_get_state(context) == PA_CONTEXT_FAILED)
+ {
+ AL_PRINT("Received context failure!\n");
+ aluHandleDisconnect(Device);
+ }
+ ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void stream_state_callback2(pa_stream *stream, void *pdata) //{{{
+{
+ ALCdevice *Device = pdata;
+ pulse_data *data = Device->ExtraData;
+
+ if(ppa_stream_get_state(stream) == PA_STREAM_FAILED)
+ {
+ AL_PRINT("Received stream failure!\n");
+ aluHandleDisconnect(Device);
+ }
+ ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void stream_success_callback(pa_stream *stream, int success, void *pdata) //{{{
+{
+ ALCdevice *Device = pdata;
+ pulse_data *data = Device->ExtraData;
+ (void)stream;
+ (void)success;
+
+ ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
+{
+ ALCdevice *device = pdata;
+ pulse_data *data = device->ExtraData;
+ char chanmap_str[256] = "";
+ const struct {
+ const char *str;
+ enum DevFmtChannels chans;
+ } chanmaps[] = {
+ { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
+ DevFmtX71 },
+ { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
+ DevFmtX61 },
+ { "front-left,front-right,front-center,lfe,rear-left,rear-right",
+ DevFmtX51 },
+ { "front-left,front-right,rear-left,rear-right", DevFmtQuad },
+ { "front-left,front-right", DevFmtStereo },
+ { "mono", DevFmtMono },
+ { NULL, 0 }
+ };
+ int i;
+ (void)context;
+
+ if(eol)
+ {
+ ppa_threaded_mainloop_signal(data->loop, 0);
+ return;
+ }
+
+ for(i = 0;chanmaps[i].str;i++)
+ {
+ pa_channel_map map;
+ if(!ppa_channel_map_parse(&map, chanmaps[i].str))
+ continue;
+
+ if(ppa_channel_map_equal(&info->channel_map, &map)
+#if PA_CHECK_VERSION(0,9,15)
+ || (ppa_channel_map_superset &&
+ ppa_channel_map_superset(&info->channel_map, &map))
+#endif
+ )
+ {
+ device->FmtChans = chanmaps[i].chans;
+ return;
+ }
+ }
+
+ ppa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
+ AL_PRINT("Failed to find format for channel map:\n %s\n", chanmap_str);
+}//}}}
+
+static void sink_device_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
+{
+ pa_threaded_mainloop *loop = pdata;
+ char str[1024];
+ void *temp;
+ int count;
+ ALuint i;
+
+ (void)context;
+
+ if(eol)
+ {
+ ppa_threaded_mainloop_signal(loop, 0);
+ return;
+ }
+
+ count = 0;
+ do {
+ if(count == 0)
+ snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
+ else
+ snprintf(str, sizeof(str), "%s #%d via PulseAudio", info->description, count+1);
+ count++;
+
+ for(i = 0;i < numDevNames;i++)
+ {
+ if(strcmp(str, allDevNameMap[i].name) == 0)
+ break;
+ }
+ } while(i != numDevNames);
+
+ temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap));
+ if(temp)
+ {
+ allDevNameMap = temp;
+ allDevNameMap[numDevNames].name = strdup(str);
+ allDevNameMap[numDevNames].device_name = strdup(info->name);
+ numDevNames++;
+ }
+}//}}}
+
+static void source_device_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata) //{{{
+{
+ pa_threaded_mainloop *loop = pdata;
+ char str[1024];
+ void *temp;
+ int count;
+ ALuint i;
+
+ (void)context;
+
+ if(eol)
+ {
+ ppa_threaded_mainloop_signal(loop, 0);
+ return;
+ }
+
+ count = 0;
+ do {
+ if(count == 0)
+ snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
+ else
+ snprintf(str, sizeof(str), "%s #%d via PulseAudio", info->description, count+1);
+ count++;
+
+ for(i = 0;i < numCaptureDevNames;i++)
+ {
+ if(strcmp(str, allCaptureDevNameMap[i].name) == 0)
+ break;
+ }
+ } while(i != numCaptureDevNames);
+
+ temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
+ if(temp)
+ {
+ allCaptureDevNameMap = temp;
+ allCaptureDevNameMap[numCaptureDevNames].name = strdup(str);
+ allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
+ numCaptureDevNames++;
+ }
+}//}}}
+//}}}
+
+// PulseAudio I/O Callbacks //{{{
+static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
+{
+ ALCdevice *Device = pdata;
+ pulse_data *data = Device->ExtraData;
+ (void)stream;
+ (void)len;
+
+ ppa_threaded_mainloop_signal(data->loop, 0);
+} //}}}
+//}}}
+
+static ALuint PulseProc(ALvoid *param)
+{
+ ALCdevice *Device = param;
+ pulse_data *data = Device->ExtraData;
+ ssize_t len;
+
+ SetRTPriority();
+
+ ppa_threaded_mainloop_lock(data->loop);
+ do {
+ len = (Device->Connected ? ppa_stream_writable_size(data->stream) : 0);
+ len -= len%(Device->UpdateSize*data->frame_size);
+ if(len == 0)
+ {
+ ppa_threaded_mainloop_wait(data->loop);
+ continue;
+ }
+
+ while(len > 0)
+ {
+ size_t newlen = len;
+ void *buf;
+ pa_free_cb_t free_func = NULL;
+
+#if PA_CHECK_VERSION(0,9,16)
+ if(!ppa_stream_begin_write ||
+ ppa_stream_begin_write(data->stream, &buf, &newlen) < 0)
+#endif
+ {
+ buf = ppa_xmalloc(newlen);
+ free_func = ppa_xfree;
+ }
+ ppa_threaded_mainloop_unlock(data->loop);
+
+ aluMixData(Device, buf, newlen/data->frame_size);
+
+ ppa_threaded_mainloop_lock(data->loop);
+ ppa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
+ len -= newlen;
+ }
+ } while(Device->Connected && !data->killNow);
+ ppa_threaded_mainloop_unlock(data->loop);
+
+ return 0;
+}
+
+static pa_context *connect_context(pa_threaded_mainloop *loop)
+{
+ const char *name = "OpenAL Soft";
+ char path_name[PATH_MAX];
+ pa_context_state_t state;
+ pa_context *context;
+ int err;
+
+ if(ppa_get_binary_name(path_name, sizeof(path_name)))
+ name = ppa_path_get_filename(path_name);
+
+ context = ppa_context_new(ppa_threaded_mainloop_get_api(loop), name);
+ if(!context)
+ {
+ AL_PRINT("pa_context_new() failed\n");
+ return NULL;
+ }
+
+ ppa_context_set_state_callback(context, context_state_callback, loop);
+
+ if((err=ppa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0)
+ {
+ while((state=ppa_context_get_state(context)) != PA_CONTEXT_READY)
+ {
+ if(!PA_CONTEXT_IS_GOOD(state))
+ {
+ err = ppa_context_errno(context);
+ if(err > 0) err = -err;
+ break;
+ }
+
+ ppa_threaded_mainloop_wait(loop);
+ }
+ }
+ ppa_context_set_state_callback(context, NULL, NULL);
+
+ if(err < 0)
+ {
+ AL_PRINT("Context did not connect: %s\n", ppa_strerror(err));
+ ppa_context_unref(context);
+ return NULL;
+ }
+
+ return context;
+}
+
+static pa_stream *connect_playback_stream(ALCdevice *device,
+ pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
+ pa_channel_map *chanmap)
+{
+ pulse_data *data = device->ExtraData;
+ pa_stream_state_t state;
+ pa_stream *stream;
+
+ stream = ppa_stream_new(data->context, "Playback Stream", spec, chanmap);
+ if(!stream)
+ {
+ AL_PRINT("pa_stream_new() failed: %s\n",
+ ppa_strerror(ppa_context_errno(data->context)));
+ return NULL;
+ }
+
+ ppa_stream_set_state_callback(stream, stream_state_callback, data->loop);
+
+ if(ppa_stream_connect_playback(stream, data->device_name, attr, flags, NULL, NULL) < 0)
+ {
+ AL_PRINT("Stream did not connect: %s\n",
+ ppa_strerror(ppa_context_errno(data->context)));
+ ppa_stream_unref(stream);
+ return NULL;
+ }
+
+ while((state=ppa_stream_get_state(stream)) != PA_STREAM_READY)
+ {
+ if(!PA_STREAM_IS_GOOD(state))
+ {
+ AL_PRINT("Stream did not get ready: %s\n",
+ ppa_strerror(ppa_context_errno(data->context)));
+ ppa_stream_unref(stream);
+ return NULL;
+ }
+
+ ppa_threaded_mainloop_wait(data->loop);
+ }
+ ppa_stream_set_state_callback(stream, NULL, NULL);
+
+ return stream;
+}
+
+static void probe_devices(ALboolean capture)
+{
+ pa_threaded_mainloop *loop;
+
+ if(capture == AL_FALSE)
+ allDevNameMap = malloc(sizeof(DevMap) * 1);
+ else
+ allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
+
+ if((loop=ppa_threaded_mainloop_new()) &&
+ ppa_threaded_mainloop_start(loop) >= 0)
+ {
+ pa_context *context;
+
+ ppa_threaded_mainloop_lock(loop);
+ context = connect_context(loop);
+ if(context)
+ {
+ pa_operation *o;
+
+ if(capture == AL_FALSE)
+ {
+ allDevNameMap[0].name = strdup(pulse_device);
+ allDevNameMap[0].device_name = NULL;
+ numDevNames = 1;
+
+ o = ppa_context_get_sink_info_list(context, sink_device_callback, loop);
+ }
+ else
+ {
+ allCaptureDevNameMap[0].name = strdup(pulse_device);
+ allCaptureDevNameMap[0].device_name = NULL;
+ numCaptureDevNames = 1;
+
+ o = ppa_context_get_source_info_list(context, source_device_callback, loop);
+ }
+ while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+ ppa_threaded_mainloop_wait(loop);
+ ppa_operation_unref(o);
+
+ ppa_context_disconnect(context);
+ ppa_context_unref(context);
+ }
+ ppa_threaded_mainloop_unlock(loop);
+ ppa_threaded_mainloop_stop(loop);
+ }
+ if(loop)
+ ppa_threaded_mainloop_free(loop);
+}
+
+
+static ALCboolean pulse_open(ALCdevice *device, const ALCchar *device_name) //{{{
+{
+ pulse_data *data = ppa_xmalloc(sizeof(pulse_data));
+ memset(data, 0, sizeof(*data));
+
+ if(!(data->loop = ppa_threaded_mainloop_new()))
+ {
+ AL_PRINT("pa_threaded_mainloop_new() failed!\n");
+ goto out;
+ }
+ if(ppa_threaded_mainloop_start(data->loop) < 0)
+ {
+ AL_PRINT("pa_threaded_mainloop_start() failed\n");
+ goto out;
+ }
+
+ ppa_threaded_mainloop_lock(data->loop);
+ device->ExtraData = data;
+
+ data->context = connect_context(data->loop);
+ if(!data->context)
+ {
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto out;
+ }
+ ppa_context_set_state_callback(data->context, context_state_callback2, device);
+
+ device->szDeviceName = strdup(device_name);
+
+ ppa_threaded_mainloop_unlock(data->loop);
+ return ALC_TRUE;
+
+out:
+ if(data->loop)
+ {
+ ppa_threaded_mainloop_stop(data->loop);
+ ppa_threaded_mainloop_free(data->loop);
+ }
+
+ device->ExtraData = NULL;
+ ppa_xfree(data);
+ return ALC_FALSE;
+} //}}}
+
+static void pulse_close(ALCdevice *device) //{{{
+{
+ pulse_data *data = device->ExtraData;
+
+ ppa_threaded_mainloop_lock(data->loop);
+
+ if(data->stream)
+ {
+ ppa_stream_disconnect(data->stream);
+ ppa_stream_unref(data->stream);
+ }
+
+ ppa_context_disconnect(data->context);
+ ppa_context_unref(data->context);
+
+ ppa_threaded_mainloop_unlock(data->loop);
+
+ ppa_threaded_mainloop_stop(data->loop);
+ ppa_threaded_mainloop_free(data->loop);
+
+ DestroyRingBuffer(data->ring);
+ free(data->device_name);
+
+ device->ExtraData = NULL;
+ ppa_xfree(data);
+} //}}}
+//}}}
+
+// OpenAL {{{
+static ALCboolean pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{
+{
+ char *pulse_name = NULL;
+ pa_sample_spec spec;
+ pulse_data *data;
+
+ if(!pulse_load())
+ return ALC_FALSE;
+
+ if(!allDevNameMap)
+ probe_devices(AL_FALSE);
+
+ if(!device_name && numDevNames > 0)
+ device_name = allDevNameMap[0].name;
+ else
+ {
+ ALuint i;
+
+ for(i = 0;i < numDevNames;i++)
+ {
+ if(strcmp(device_name, allDevNameMap[i].name) == 0)
+ {
+ pulse_name = allDevNameMap[i].device_name;
+ break;
+ }
+ }
+ if(i == numDevNames)
+ return ALC_FALSE;
+ }
+
+ if(pulse_open(device, device_name) == ALC_FALSE)
+ return ALC_FALSE;
+
+ data = device->ExtraData;
+
+ ppa_threaded_mainloop_lock(data->loop);
+
+ spec.format = PA_SAMPLE_S16NE;
+ spec.rate = 44100;
+ spec.channels = 2;
+
+ data->device_name = pulse_name;
+ pa_stream *stream = connect_playback_stream(device, 0, NULL, &spec, NULL);
+ if(!stream)
+ {
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ if(ppa_stream_is_suspended(stream))
+ {
+ AL_PRINT("Device is suspended\n");
+ ppa_stream_disconnect(stream);
+ ppa_stream_unref(stream);
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+ data->device_name = strdup(ppa_stream_get_device_name(stream));
+
+ ppa_stream_disconnect(stream);
+ ppa_stream_unref(stream);
+
+ ppa_threaded_mainloop_unlock(data->loop);
+
+ return ALC_TRUE;
+
+fail:
+ pulse_close(device);
+ return ALC_FALSE;
+} //}}}
+
+static void pulse_close_playback(ALCdevice *device) //{{{
+{
+ pulse_close(device);
+} //}}}
+
+static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
+{
+ pulse_data *data = device->ExtraData;
+ pa_stream_flags_t flags = 0;
+ pa_channel_map chanmap;
+
+ ppa_threaded_mainloop_lock(data->loop);
+
+ if(!ConfigValueExists(NULL, "format"))
+ {
+ pa_operation *o;
+ o = ppa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device);
+ while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+ ppa_threaded_mainloop_wait(data->loop);
+ ppa_operation_unref(o);
+ }
+ if(!ConfigValueExists(NULL, "frequency"))
+ flags |= PA_STREAM_FIX_RATE;
+
+ data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ data->attr.prebuf = -1;
+ data->attr.fragsize = -1;
+ data->attr.minreq = device->UpdateSize * data->frame_size;
+ data->attr.tlength = data->attr.minreq * device->NumUpdates;
+ if(data->attr.tlength < data->attr.minreq*2)
+ data->attr.tlength = data->attr.minreq*2;
+ data->attr.maxlength = data->attr.tlength;
+ flags |= PA_STREAM_EARLY_REQUESTS;
+ flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ device->FmtType = DevFmtUByte;
+ /* fall-through */
+ case DevFmtUByte:
+ data->spec.format = PA_SAMPLE_U8;
+ break;
+ case DevFmtUShort:
+ device->FmtType = DevFmtShort;
+ /* fall-through */
+ case DevFmtShort:
+ data->spec.format = PA_SAMPLE_S16NE;
+ break;
+ case DevFmtFloat:
+ data->spec.format = PA_SAMPLE_FLOAT32NE;
+ break;
+ }
+ data->spec.rate = device->Frequency;
+ data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
+
+ if(ppa_sample_spec_valid(&data->spec) == 0)
+ {
+ AL_PRINT("Invalid sample format\n");
+ ppa_threaded_mainloop_unlock(data->loop);
+ return ALC_FALSE;
+ }
+
+ if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
+ {
+ AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
+ ppa_threaded_mainloop_unlock(data->loop);
+ return ALC_FALSE;
+ }
+ SetDefaultWFXChannelOrder(device);
+
+ data->stream = connect_playback_stream(device, flags, &data->attr, &data->spec, &chanmap);
+ if(!data->stream)
+ {
+ ppa_threaded_mainloop_unlock(data->loop);
+ return ALC_FALSE;
+ }
+
+ ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
+
+ data->spec = *(ppa_stream_get_sample_spec(data->stream));
+ if(device->Frequency != data->spec.rate)
+ {
+ pa_operation *o;
+
+ /* Server updated our playback rate, so modify the buffer attribs
+ * accordingly. */
+ data->attr.minreq = (ALuint64)(data->attr.minreq/data->frame_size) *
+ data->spec.rate / device->Frequency * data->frame_size;
+ data->attr.tlength = data->attr.minreq * device->NumUpdates;
+ data->attr.maxlength = data->attr.tlength;
+
+ o = ppa_stream_set_buffer_attr(data->stream, &data->attr,
+ stream_success_callback, device);
+ while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+ ppa_threaded_mainloop_wait(data->loop);
+ ppa_operation_unref(o);
+
+ device->Frequency = data->spec.rate;
+ }
+
+ stream_buffer_attr_callback(data->stream, device);
+#if PA_CHECK_VERSION(0,9,15)
+ if(ppa_stream_set_buffer_attr_callback)
+ ppa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);
+#endif
+ ppa_stream_set_moved_callback(data->stream, stream_device_callback, device);
+ ppa_stream_set_write_callback(data->stream, stream_write_callback, device);
+ ppa_stream_set_underflow_callback(data->stream, stream_signal_callback, device);
+
+ data->thread = StartThread(PulseProc, device);
+ if(!data->thread)
+ {
+#if PA_CHECK_VERSION(0,9,15)
+ if(ppa_stream_set_buffer_attr_callback)
+ ppa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
+#endif
+ ppa_stream_set_moved_callback(data->stream, NULL, NULL);
+ ppa_stream_set_write_callback(data->stream, NULL, NULL);
+ ppa_stream_set_underflow_callback(data->stream, NULL, NULL);
+ ppa_stream_disconnect(data->stream);
+ ppa_stream_unref(data->stream);
+ data->stream = NULL;
+
+ ppa_threaded_mainloop_unlock(data->loop);
+ return ALC_FALSE;
+ }
+
+ ppa_threaded_mainloop_unlock(data->loop);
+ return ALC_TRUE;
+} //}}}
+
+static void pulse_stop_playback(ALCdevice *device) //{{{
+{
+ pulse_data *data = device->ExtraData;
+
+ if(!data->stream)
+ return;
+
+ data->killNow = AL_TRUE;
+ if(data->thread)
+ {
+ ppa_threaded_mainloop_signal(data->loop, 0);
+ StopThread(data->thread);
+ data->thread = NULL;
+ }
+ data->killNow = AL_FALSE;
+
+ ppa_threaded_mainloop_lock(data->loop);
+
+#if PA_CHECK_VERSION(0,9,15)
+ if(ppa_stream_set_buffer_attr_callback)
+ ppa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
+#endif
+ ppa_stream_set_moved_callback(data->stream, NULL, NULL);
+ ppa_stream_set_write_callback(data->stream, NULL, NULL);
+ ppa_stream_set_underflow_callback(data->stream, NULL, NULL);
+ ppa_stream_disconnect(data->stream);
+ ppa_stream_unref(data->stream);
+ data->stream = NULL;
+
+ ppa_threaded_mainloop_unlock(data->loop);
+} //}}}
+
+
+static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{
+{
+ char *pulse_name = NULL;
+ pulse_data *data;
+ pa_stream_flags_t flags = 0;
+ pa_stream_state_t state;
+ pa_channel_map chanmap;
+
+ if(!pulse_load())
+ return ALC_FALSE;
+
+ if(!allCaptureDevNameMap)
+ probe_devices(AL_TRUE);
+
+ if(!device_name && numCaptureDevNames > 0)
+ device_name = allCaptureDevNameMap[0].name;
+ else
+ {
+ ALuint i;
+
+ for(i = 0;i < numCaptureDevNames;i++)
+ {
+ if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
+ {
+ pulse_name = allCaptureDevNameMap[i].device_name;
+ break;
+ }
+ }
+ if(i == numCaptureDevNames)
+ return ALC_FALSE;
+ }
+
+ if(pulse_open(device, device_name) == ALC_FALSE)
+ return ALC_FALSE;
+
+ data = device->ExtraData;
+ ppa_threaded_mainloop_lock(data->loop);
+
+ data->samples = device->UpdateSize * device->NumUpdates;
+ data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ if(data->samples < 100 * device->Frequency / 1000)
+ data->samples = 100 * device->Frequency / 1000;
+
+ if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples)))
+ {
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ data->attr.minreq = -1;
+ data->attr.prebuf = -1;
+ data->attr.maxlength = data->samples * data->frame_size;
+ data->attr.tlength = -1;
+ data->attr.fragsize = min(data->samples, 50 * device->Frequency / 1000) *
+ data->frame_size;
+
+ data->spec.rate = device->Frequency;
+ data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
+
+ switch(device->FmtType)
+ {
+ case DevFmtUByte:
+ data->spec.format = PA_SAMPLE_U8;
+ break;
+ case DevFmtShort:
+ data->spec.format = PA_SAMPLE_S16NE;
+ break;
+ case DevFmtFloat:
+ data->spec.format = PA_SAMPLE_FLOAT32NE;
+ break;
+ case DevFmtByte:
+ case DevFmtUShort:
+ AL_PRINT("Capture format type %#x capture not supported on PulseAudio\n", device->FmtType);
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ if(ppa_sample_spec_valid(&data->spec) == 0)
+ {
+ AL_PRINT("Invalid sample format\n");
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
+ {
+ AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ data->stream = ppa_stream_new(data->context, "Capture Stream", &data->spec, &chanmap);
+ if(!data->stream)
+ {
+ AL_PRINT("pa_stream_new() failed: %s\n",
+ ppa_strerror(ppa_context_errno(data->context)));
+
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ ppa_stream_set_state_callback(data->stream, stream_state_callback, data->loop);
+
+ flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
+ if(ppa_stream_connect_record(data->stream, pulse_name, &data->attr, flags) < 0)
+ {
+ AL_PRINT("Stream did not connect: %s\n",
+ ppa_strerror(ppa_context_errno(data->context)));
+
+ ppa_stream_unref(data->stream);
+ data->stream = NULL;
+
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
+ {
+ if(!PA_STREAM_IS_GOOD(state))
+ {
+ AL_PRINT("Stream did not get ready: %s\n",
+ ppa_strerror(ppa_context_errno(data->context)));
+
+ ppa_stream_unref(data->stream);
+ data->stream = NULL;
+
+ ppa_threaded_mainloop_unlock(data->loop);
+ goto fail;
+ }
+
+ ppa_threaded_mainloop_wait(data->loop);
+ }
+ ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
+
+ ppa_threaded_mainloop_unlock(data->loop);
+ return ALC_TRUE;
+
+fail:
+ pulse_close(device);
+ return ALC_FALSE;
+} //}}}
+
+static void pulse_close_capture(ALCdevice *device) //{{{
+{
+ pulse_close(device);
+} //}}}
+
+static void pulse_start_capture(ALCdevice *device) //{{{
+{
+ pulse_data *data = device->ExtraData;
+ pa_operation *o;
+
+ ppa_threaded_mainloop_lock(data->loop);
+ o = ppa_stream_cork(data->stream, 0, stream_success_callback, device);
+ while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+ ppa_threaded_mainloop_wait(data->loop);
+ ppa_operation_unref(o);
+ ppa_threaded_mainloop_unlock(data->loop);
+} //}}}
+
+static void pulse_stop_capture(ALCdevice *device) //{{{
+{
+ pulse_data *data = device->ExtraData;
+ pa_operation *o;
+
+ ppa_threaded_mainloop_lock(data->loop);
+ o = ppa_stream_cork(data->stream, 1, stream_success_callback, device);
+ while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+ ppa_threaded_mainloop_wait(data->loop);
+ ppa_operation_unref(o);
+ ppa_threaded_mainloop_unlock(data->loop);
+} //}}}
+
+static ALCuint pulse_available_samples(ALCdevice *device) //{{{
+{
+ pulse_data *data = device->ExtraData;
+ size_t samples;
+
+ ppa_threaded_mainloop_lock(data->loop);
+ /* Capture is done in fragment-sized chunks, so we loop until we get all
+ * that's available */
+ samples = (device->Connected ? ppa_stream_readable_size(data->stream) : 0);
+ while(samples > 0)
+ {
+ const void *buf;
+ size_t length;
+
+ if(ppa_stream_peek(data->stream, &buf, &length) < 0)
+ {
+ AL_PRINT("pa_stream_peek() failed: %s\n",
+ ppa_strerror(ppa_context_errno(data->context)));
+ break;
+ }
+
+ WriteRingBuffer(data->ring, buf, length/data->frame_size);
+ samples -= length;
+
+ ppa_stream_drop(data->stream);
+ }
+ ppa_threaded_mainloop_unlock(data->loop);
+
+ return RingBufferSize(data->ring);
+} //}}}
+
+static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{
+{
+ pulse_data *data = device->ExtraData;
+
+ if(pulse_available_samples(device) >= samples)
+ ReadRingBuffer(data->ring, buffer, samples);
+ else
+ alcSetError(device, ALC_INVALID_VALUE);
+} //}}}
+
+
+BackendFuncs pulse_funcs = { //{{{
+ pulse_open_playback,
+ pulse_close_playback,
+ pulse_reset_playback,
+ pulse_stop_playback,
+ pulse_open_capture,
+ pulse_close_capture,
+ pulse_start_capture,
+ pulse_stop_capture,
+ pulse_capture_samples,
+ pulse_available_samples
+}; //}}}
+
+void alc_pulse_init(BackendFuncs *func_list) //{{{
+{
+ *func_list = pulse_funcs;
+
+ pulse_ctx_flags = 0;
+ if(!GetConfigValueBool("pulse", "spawn-server", 0))
+ pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
+} //}}}
+
+void alc_pulse_deinit(void) //{{{
+{
+ ALuint i;
+
+ for(i = 0;i < numDevNames;++i)
+ {
+ free(allDevNameMap[i].name);
+ free(allDevNameMap[i].device_name);
+ }
+ free(allDevNameMap);
+ allDevNameMap = NULL;
+ numDevNames = 0;
+
+ for(i = 0;i < numCaptureDevNames;++i)
+ {
+ free(allCaptureDevNameMap[i].name);
+ free(allCaptureDevNameMap[i].device_name);
+ }
+ free(allCaptureDevNameMap);
+ allCaptureDevNameMap = NULL;
+ numCaptureDevNames = 0;
+
+ if(pa_handle)
+ {
+#ifdef _WIN32
+ FreeLibrary(pa_handle);
+#elif defined (HAVE_DLFCN_H)
+ dlclose(pa_handle);
+#endif
+ pa_handle = NULL;
+ }
+} //}}}
+
+void alc_pulse_probe(int type) //{{{
+{
+ if(!pulse_load()) return;
+
+ if(type == DEVICE_PROBE)
+ {
+ pa_threaded_mainloop *loop;
+
+ if((loop=ppa_threaded_mainloop_new()) &&
+ ppa_threaded_mainloop_start(loop) >= 0)
+ {
+ pa_context *context;
+
+ ppa_threaded_mainloop_lock(loop);
+ context = connect_context(loop);
+ if(context)
+ {
+ AppendDeviceList(pulse_device);
+
+ ppa_context_disconnect(context);
+ ppa_context_unref(context);
+ }
+ ppa_threaded_mainloop_unlock(loop);
+ ppa_threaded_mainloop_stop(loop);
+ }
+ if(loop)
+ ppa_threaded_mainloop_free(loop);
+ }
+ else if(type == ALL_DEVICE_PROBE)
+ {
+ ALuint i;
+
+ for(i = 0;i < numDevNames;++i)
+ {
+ free(allDevNameMap[i].name);
+ free(allDevNameMap[i].device_name);
+ }
+ free(allDevNameMap);
+ allDevNameMap = NULL;
+ numDevNames = 0;
+
+ probe_devices(AL_FALSE);
+
+ for(i = 0;i < numDevNames;i++)
+ AppendAllDeviceList(allDevNameMap[i].name);
+ }
+ else if(type == CAPTURE_DEVICE_PROBE)
+ {
+ ALuint i;
+
+ for(i = 0;i < numCaptureDevNames;++i)
+ {
+ free(allCaptureDevNameMap[i].name);
+ free(allCaptureDevNameMap[i].device_name);
+ }
+ free(allCaptureDevNameMap);
+ allCaptureDevNameMap = NULL;
+ numCaptureDevNames = 0;
+
+ probe_devices(AL_TRUE);
+
+ for(i = 0;i < numCaptureDevNames;i++)
+ AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
+ }
+} //}}}
+//}}}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <sys/audioio.h>
+
+
+static const ALCchar solaris_device[] = "Solaris Default";
+
+typedef struct {
+ int fd;
+ volatile int killNow;
+ ALvoid *thread;
+
+ ALubyte *mix_data;
+ int data_size;
+} solaris_data;
+
+
+static ALuint SolarisProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ solaris_data *data = (solaris_data*)pDevice->ExtraData;
+ ALint frameSize;
+ int wrote;
+
+ SetRTPriority();
+
+ frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+ while(!data->killNow && pDevice->Connected)
+ {
+ ALint len = data->data_size;
+ ALubyte *WritePtr = data->mix_data;
+
+ aluMixData(pDevice, WritePtr, len/frameSize);
+ while(len > 0 && !data->killNow)
+ {
+ wrote = write(data->fd, WritePtr, len);
+ if(wrote < 0)
+ {
+ if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
+ {
+ AL_PRINT("write failed: %s\n", strerror(errno));
+ aluHandleDisconnect(pDevice);
+ break;
+ }
+
+ Sleep(1);
+ continue;
+ }
+
+ len -= wrote;
+ WritePtr += wrote;
+ }
+ }
+
+ return 0;
+}
+
+
+static ALCboolean solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ char driver[64];
+ solaris_data *data;
+
+ strncpy(driver, GetConfigValue("solaris", "device", "/dev/audio"), sizeof(driver)-1);
+ driver[sizeof(driver)-1] = 0;
+
+ if(!deviceName)
+ deviceName = solaris_device;
+ else if(strcmp(deviceName, solaris_device) != 0)
+ return ALC_FALSE;
+
+ data = (solaris_data*)calloc(1, sizeof(solaris_data));
+ data->killNow = 0;
+
+ data->fd = open(driver, O_WRONLY);
+ if(data->fd == -1)
+ {
+ free(data);
+ AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
+ return ALC_FALSE;
+ }
+
+ device->szDeviceName = strdup(deviceName);
+ device->ExtraData = data;
+ return ALC_TRUE;
+}
+
+static void solaris_close_playback(ALCdevice *device)
+{
+ solaris_data *data = (solaris_data*)device->ExtraData;
+
+ close(data->fd);
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean solaris_reset_playback(ALCdevice *device)
+{
+ solaris_data *data = (solaris_data*)device->ExtraData;
+ audio_info_t info;
+ ALuint frameSize;
+ int numChannels;
+
+ AUDIO_INITINFO(&info);
+
+ info.play.sample_rate = device->Frequency;
+
+ if(device->FmtChans != DevFmtMono)
+ device->FmtChans = DevFmtStereo;
+ numChannels = ChannelsFromDevFmt(device->FmtChans);
+ info.play.channels = numChannels;
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ info.play.precision = 8;
+ info.play.encoding = AUDIO_ENCODING_LINEAR;
+ break;
+ case DevFmtUByte:
+ info.play.precision = 8;
+ info.play.encoding = AUDIO_ENCODING_LINEAR8;
+ break;
+ case DevFmtUShort:
+ case DevFmtFloat:
+ device->FmtType = DevFmtShort;
+ /* fall-through */
+ case DevFmtShort:
+ info.play.precision = 16;
+ info.play.encoding = AUDIO_ENCODING_LINEAR;
+ break;
+ }
+
+ frameSize = numChannels * BytesFromDevFmt(device->FmtType);
+ info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;
+
+ if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
+ {
+ AL_PRINT("ioctl failed: %s\n", strerror(errno));
+ return ALC_FALSE;
+ }
+
+ if(ChannelsFromDevFmt(device->FmtChans) != info.play.channels)
+ {
+ AL_PRINT("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), info.play.channels);
+ return ALC_FALSE;
+ }
+
+ if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR &&
+ device->FmtType == DevFmtByte) ||
+ (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 &&
+ device->FmtType == DevFmtUByte) ||
+ (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR &&
+ device->FmtType == DevFmtShort)))
+ {
+ AL_PRINT("Could not set %#x sample type, got %d (%#x)\n",
+ device->FmtType, info.play.precision, info.play.encoding);
+ return ALC_FALSE;
+ }
+
+ device->Frequency = info.play.sample_rate;
+ device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1;
+
+ data->data_size = device->UpdateSize * frameSize;
+ data->mix_data = calloc(1, data->data_size);
+
+ SetDefaultChannelOrder(device);
+
+ data->thread = StartThread(SolarisProc, device);
+ if(data->thread == NULL)
+ {
+ free(data->mix_data);
+ data->mix_data = NULL;
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void solaris_stop_playback(ALCdevice *device)
+{
+ solaris_data *data = (solaris_data*)device->ExtraData;
+
+ if(!data->thread)
+ return;
+
+ data->killNow = 1;
+ StopThread(data->thread);
+ data->thread = NULL;
+
+ data->killNow = 0;
+ if(ioctl(data->fd, AUDIO_DRAIN) < 0)
+ AL_PRINT("Error draining device: %s\n", strerror(errno));
+
+ free(data->mix_data);
+ data->mix_data = NULL;
+}
+
+
+static ALCboolean solaris_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+ (void)device;
+ (void)deviceName;
+ return ALC_FALSE;
+}
+
+static void solaris_close_capture(ALCdevice *device)
+{
+ (void)device;
+}
+
+static void solaris_start_capture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void solaris_stop_capture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void solaris_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+ (void)pDevice;
+ (void)pBuffer;
+ (void)lSamples;
+}
+
+static ALCuint solaris_available_samples(ALCdevice *pDevice)
+{
+ (void)pDevice;
+ return 0;
+}
+
+
+BackendFuncs solaris_funcs = {
+ solaris_open_playback,
+ solaris_close_playback,
+ solaris_reset_playback,
+ solaris_stop_playback,
+ solaris_open_capture,
+ solaris_close_capture,
+ solaris_start_capture,
+ solaris_stop_capture,
+ solaris_capture_samples,
+ solaris_available_samples
+};
+
+void alc_solaris_init(BackendFuncs *func_list)
+{
+ *func_list = solaris_funcs;
+}
+
+void alc_solaris_deinit(void)
+{
+}
+
+void alc_solaris_probe(int type)
+{
+#ifdef HAVE_STAT
+ struct stat buf;
+ if(stat(GetConfigValue("solaris", "device", "/dev/audio"), &buf) != 0)
+ return;
+#endif
+
+ if(type == DEVICE_PROBE)
+ AppendDeviceList(solaris_device);
+ else if(type == ALL_DEVICE_PROBE)
+ AppendAllDeviceList(solaris_device);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+
+typedef struct {
+ FILE *f;
+ long DataStart;
+
+ ALvoid *buffer;
+ ALuint size;
+
+ volatile int killNow;
+ ALvoid *thread;
+} wave_data;
+
+
+static const ALCchar waveDevice[] = "Wave File Writer";
+
+static const ALubyte SUBTYPE_PCM[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
+ 0x00, 0x38, 0x9b, 0x71
+};
+static const ALubyte SUBTYPE_FLOAT[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
+ 0x00, 0x38, 0x9b, 0x71
+};
+
+static const ALuint channel_masks[] = {
+ 0, /* invalid */
+ 0x4, /* Mono */
+ 0x1 | 0x2, /* Stereo */
+ 0, /* 3 channel */
+ 0x1 | 0x2 | 0x10 | 0x20, /* Quad */
+ 0, /* 5 channel */
+ 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */
+ 0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */
+ 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */
+};
+
+
+static void fwrite16le(ALushort val, FILE *f)
+{
+ fputc(val&0xff, f);
+ fputc((val>>8)&0xff, f);
+}
+
+static void fwrite32le(ALuint val, FILE *f)
+{
+ fputc(val&0xff, f);
+ fputc((val>>8)&0xff, f);
+ fputc((val>>16)&0xff, f);
+ fputc((val>>24)&0xff, f);
+}
+
+
+static ALuint WaveProc(ALvoid *ptr)
+{
+ ALCdevice *pDevice = (ALCdevice*)ptr;
+ wave_data *data = (wave_data*)pDevice->ExtraData;
+ ALuint frameSize;
+ ALuint now, start;
+ ALuint64 avail, done;
+ size_t fs;
+ union {
+ short s;
+ char b[sizeof(short)];
+ } uSB;
+ const ALuint restTime = (ALuint64)pDevice->UpdateSize * 1000 /
+ pDevice->Frequency / 2;
+
+ uSB.s = 1;
+ frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+ done = 0;
+ start = timeGetTime();
+ while(!data->killNow && pDevice->Connected)
+ {
+ now = timeGetTime();
+
+ avail = (ALuint64)(now-start) * pDevice->Frequency / 1000;
+ if(avail < done)
+ {
+ /* Timer wrapped. Add the remainder of the cycle to the available
+ * count and reset the number of samples done */
+ avail += (ALuint64)0xFFFFFFFFu*pDevice->Frequency/1000 - done;
+ done = 0;
+ }
+ if(avail-done < pDevice->UpdateSize)
+ {
+ Sleep(restTime);
+ continue;
+ }
+
+ while(avail-done >= pDevice->UpdateSize)
+ {
+ aluMixData(pDevice, data->buffer, pDevice->UpdateSize);
+ done += pDevice->UpdateSize;
+
+ if(uSB.b[0] != 1)
+ {
+ ALuint bytesize = BytesFromDevFmt(pDevice->FmtType);
+ ALubyte *bytes = data->buffer;
+ ALuint i;
+
+ if(bytesize == 1)
+ {
+ for(i = 0;i < data->size;i++)
+ fputc(bytes[i], data->f);
+ }
+ else if(bytesize == 2)
+ {
+ for(i = 0;i < data->size;i++)
+ fputc(bytes[i^1], data->f);
+ }
+ else if(bytesize == 4)
+ {
+ for(i = 0;i < data->size;i++)
+ fputc(bytes[i^3], data->f);
+ }
+ }
+ else
+ fs = fwrite(data->buffer, frameSize, pDevice->UpdateSize,
+ data->f);
+ if(ferror(data->f))
+ {
+ AL_PRINT("Error writing to file\n");
+ aluHandleDisconnect(pDevice);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ wave_data *data;
+ const char *fname;
+
+ fname = GetConfigValue("wave", "file", "");
+ if(!fname[0])
+ return ALC_FALSE;
+
+ if(!deviceName)
+ deviceName = waveDevice;
+ else if(strcmp(deviceName, waveDevice) != 0)
+ return ALC_FALSE;
+
+ data = (wave_data*)calloc(1, sizeof(wave_data));
+
+ data->f = fopen(fname, "wb");
+ if(!data->f)
+ {
+ free(data);
+ AL_PRINT("Could not open file '%s': %s\n", fname, strerror(errno));
+ return ALC_FALSE;
+ }
+
+ device->szDeviceName = strdup(deviceName);
+ device->ExtraData = data;
+ return ALC_TRUE;
+}
+
+static void wave_close_playback(ALCdevice *device)
+{
+ wave_data *data = (wave_data*)device->ExtraData;
+
+ fclose(data->f);
+ free(data);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean wave_reset_playback(ALCdevice *device)
+{
+ wave_data *data = (wave_data*)device->ExtraData;
+ ALuint channels=0, bits=0;
+ size_t val;
+
+ fseek(data->f, 0, SEEK_SET);
+ clearerr(data->f);
+
+ switch(device->FmtType)
+ {
+ case DevFmtByte:
+ device->FmtType = DevFmtUByte;
+ break;
+ case DevFmtUShort:
+ device->FmtType = DevFmtShort;
+ break;
+ case DevFmtUByte:
+ case DevFmtShort:
+ case DevFmtFloat:
+ break;
+ }
+ bits = BytesFromDevFmt(device->FmtType) * 8;
+ channels = ChannelsFromDevFmt(device->FmtChans);
+
+ fprintf(data->f, "RIFF");
+ fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close
+
+ fprintf(data->f, "WAVE");
+
+ fprintf(data->f, "fmt ");
+ fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE
+
+ // 16-bit val, format type id (extensible: 0xFFFE)
+ fwrite16le(0xFFFE, data->f);
+ // 16-bit val, channel count
+ fwrite16le(channels, data->f);
+ // 32-bit val, frequency
+ fwrite32le(device->Frequency, data->f);
+ // 32-bit val, bytes per second
+ fwrite32le(device->Frequency * channels * bits / 8, data->f);
+ // 16-bit val, frame size
+ fwrite16le(channels * bits / 8, data->f);
+ // 16-bit val, bits per sample
+ fwrite16le(bits, data->f);
+ // 16-bit val, extra byte count
+ fwrite16le(22, data->f);
+ // 16-bit val, valid bits per sample
+ fwrite16le(bits, data->f);
+ // 32-bit val, channel mask
+ fwrite32le(channel_masks[channels], data->f);
+ // 16 byte GUID, sub-type format
+ val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);
+
+ fprintf(data->f, "data");
+ fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close
+
+ if(ferror(data->f))
+ {
+ AL_PRINT("Error writing header: %s\n", strerror(errno));
+ return ALC_FALSE;
+ }
+
+ data->DataStart = ftell(data->f);
+
+ data->size = device->UpdateSize * channels * bits / 8;
+ data->buffer = malloc(data->size);
+ if(!data->buffer)
+ {
+ AL_PRINT("buffer malloc failed\n");
+ return ALC_FALSE;
+ }
+
+ SetDefaultWFXChannelOrder(device);
+
+ data->thread = StartThread(WaveProc, device);
+ if(data->thread == NULL)
+ {
+ free(data->buffer);
+ data->buffer = NULL;
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void wave_stop_playback(ALCdevice *device)
+{
+ wave_data *data = (wave_data*)device->ExtraData;
+ ALuint dataLen;
+ long size;
+
+ if(!data->thread)
+ return;
+
+ data->killNow = 1;
+ StopThread(data->thread);
+ data->thread = NULL;
+
+ data->killNow = 0;
+
+ free(data->buffer);
+ data->buffer = NULL;
+
+ size = ftell(data->f);
+ if(size > 0)
+ {
+ dataLen = size - data->DataStart;
+ if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0)
+ fwrite32le(dataLen, data->f); // 'data' header len
+ if(fseek(data->f, 4, SEEK_SET) == 0)
+ fwrite32le(size-8, data->f); // 'WAVE' header len
+ }
+}
+
+
+static ALCboolean wave_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ (void)pDevice;
+ (void)deviceName;
+ return ALC_FALSE;
+}
+
+
+BackendFuncs wave_funcs = {
+ wave_open_playback,
+ wave_close_playback,
+ wave_reset_playback,
+ wave_stop_playback,
+ wave_open_capture,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void alc_wave_init(BackendFuncs *func_list)
+{
+ *func_list = wave_funcs;
+}
+
+void alc_wave_deinit(void)
+{
+}
+
+void alc_wave_probe(int type)
+{
+ if(!ConfigValueExists("wave", "file"))
+ return;
+
+ if(type == DEVICE_PROBE)
+ AppendDeviceList(waveDevice);
+ else if(type == ALL_DEVICE_PROBE)
+ AppendAllDeviceList(waveDevice);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#define _WIN32_WINNT 0x0500
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+
+typedef struct {
+ // MMSYSTEM Device
+ volatile ALboolean bWaveShutdown;
+ HANDLE hWaveHdrEvent;
+ HANDLE hWaveThreadEvent;
+ HANDLE hWaveThread;
+ DWORD ulWaveThreadID;
+ LONG lWaveBuffersCommitted;
+ WAVEHDR WaveBuffer[4];
+
+ union {
+ HWAVEIN In;
+ HWAVEOUT Out;
+ } hWaveHandle;
+
+ ALsizei Frequency;
+
+ RingBuffer *pRing;
+} WinMMData;
+
+
+static const ALCchar woDefault[] = "WaveOut Default";
+
+static ALCchar **PlaybackDeviceList;
+static ALuint NumPlaybackDevices;
+static ALCchar **CaptureDeviceList;
+static ALuint NumCaptureDevices;
+
+
+static void ProbePlaybackDevices(void)
+{
+ ALuint i;
+
+ for(i = 0;i < NumPlaybackDevices;i++)
+ free(PlaybackDeviceList[i]);
+
+ NumPlaybackDevices = waveOutGetNumDevs();
+ PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices);
+ for(i = 0;i < NumPlaybackDevices;i++)
+ {
+ WAVEOUTCAPS WaveCaps;
+
+ PlaybackDeviceList[i] = NULL;
+ if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
+ {
+ char name[1024];
+ ALuint count, j;
+
+ count = 0;
+ do {
+ if(count == 0)
+ snprintf(name, sizeof(name), "%s via WaveOut", WaveCaps.szPname);
+ else
+ snprintf(name, sizeof(name), "%s #%d via WaveOut", WaveCaps.szPname, count+1);
+ count++;
+
+ for(j = 0;j < i;j++)
+ {
+ if(strcmp(name, PlaybackDeviceList[j]) == 0)
+ break;
+ }
+ } while(j != i);
+
+ PlaybackDeviceList[i] = strdup(name);
+ }
+ }
+}
+
+static void ProbeCaptureDevices(void)
+{
+ ALuint i;
+
+ for(i = 0;i < NumCaptureDevices;i++)
+ free(CaptureDeviceList[i]);
+
+ NumCaptureDevices = waveInGetNumDevs();
+ CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
+ for(i = 0;i < NumCaptureDevices;i++)
+ {
+ WAVEINCAPS WaveInCaps;
+
+ CaptureDeviceList[i] = NULL;
+ if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
+ {
+ char name[1024];
+ ALuint count, j;
+
+ count = 0;
+ do {
+ if(count == 0)
+ snprintf(name, sizeof(name), "%s via WaveIn", WaveInCaps.szPname);
+ else
+ snprintf(name, sizeof(name), "%s #%d via WaveIn", WaveInCaps.szPname, count+1);
+ count++;
+
+ for(j = 0;j < i;j++)
+ {
+ if(strcmp(name, CaptureDeviceList[j]) == 0)
+ break;
+ }
+ } while(j != i);
+
+ CaptureDeviceList[i] = strdup(name);
+ }
+ }
+}
+
+
+/*
+ WaveOutProc
+
+ Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
+ returns to the application (for more data)
+*/
+static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
+{
+ ALCdevice *pDevice = (ALCdevice*)dwInstance;
+ WinMMData *pData = pDevice->ExtraData;
+
+ (void)hDevice;
+ (void)dwParam2;
+
+ if(uMsg != WOM_DONE)
+ return;
+
+ // Decrement number of buffers in use
+ InterlockedDecrement(&pData->lWaveBuffersCommitted);
+
+ if(pData->bWaveShutdown == AL_FALSE)
+ {
+ // Notify Wave Processor Thread that a Wave Header has returned
+ PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
+ }
+ else
+ {
+ if(pData->lWaveBuffersCommitted == 0)
+ {
+ // Signal Wave Buffers Returned event
+ if(pData->hWaveHdrEvent)
+ SetEvent(pData->hWaveHdrEvent);
+
+ // Post 'Quit' Message to WaveOut Processor Thread
+ PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
+ }
+ }
+}
+
+/*
+ PlaybackThreadProc
+
+ Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
+ audio data.
+*/
+static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
+{
+ ALCdevice *pDevice = (ALCdevice*)lpParameter;
+ WinMMData *pData = pDevice->ExtraData;
+ LPWAVEHDR pWaveHdr;
+ ALuint FrameSize;
+ MSG msg;
+
+ FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+ while(GetMessage(&msg, NULL, 0, 0))
+ {
+ if(msg.message != WOM_DONE || pData->bWaveShutdown)
+ continue;
+
+ pWaveHdr = ((LPWAVEHDR)msg.lParam);
+
+ aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);
+
+ // Send buffer back to play more data
+ waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR));
+ InterlockedIncrement(&pData->lWaveBuffersCommitted);
+ }
+
+ // Signal Wave Thread completed event
+ if(pData->hWaveThreadEvent)
+ SetEvent(pData->hWaveThreadEvent);
+
+ ExitThread(0);
+
+ return 0;
+}
+
+/*
+ WaveInProc
+
+ Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
+ returns to the application (with more data)
+*/
+static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
+{
+ ALCdevice *pDevice = (ALCdevice*)dwInstance;
+ WinMMData *pData = pDevice->ExtraData;
+
+ (void)hDevice;
+ (void)dwParam2;
+
+ if(uMsg != WIM_DATA)
+ return;
+
+ // Decrement number of buffers in use
+ InterlockedDecrement(&pData->lWaveBuffersCommitted);
+
+ if(pData->bWaveShutdown == AL_FALSE)
+ {
+ // Notify Wave Processor Thread that a Wave Header has returned
+ PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
+ }
+ else
+ {
+ if(pData->lWaveBuffersCommitted == 0)
+ {
+ // Signal Wave Buffers Returned event
+ if(pData->hWaveHdrEvent)
+ SetEvent(pData->hWaveHdrEvent);
+
+ // Post 'Quit' Message to WaveIn Processor Thread
+ PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0);
+ }
+ }
+}
+
+/*
+ CaptureThreadProc
+
+ Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
+ audio data.
+*/
+static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
+{
+ ALCdevice *pDevice = (ALCdevice*)lpParameter;
+ WinMMData *pData = pDevice->ExtraData;
+ LPWAVEHDR pWaveHdr;
+ ALuint FrameSize;
+ MSG msg;
+
+ FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+ while(GetMessage(&msg, NULL, 0, 0))
+ {
+ if(msg.message != WIM_DATA || pData->bWaveShutdown)
+ continue;
+
+ pWaveHdr = ((LPWAVEHDR)msg.lParam);
+
+ WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,
+ pWaveHdr->dwBytesRecorded/FrameSize);
+
+ // Send buffer back to capture more data
+ waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR));
+ InterlockedIncrement(&pData->lWaveBuffersCommitted);
+ }
+
+ // Signal Wave Thread completed event
+ if(pData->hWaveThreadEvent)
+ SetEvent(pData->hWaveThreadEvent);
+
+ ExitThread(0);
+
+ return 0;
+}
+
+
+static ALCboolean WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ WAVEFORMATEX wfexFormat;
+ WinMMData *pData = NULL;
+ UINT lDeviceID = 0;
+ MMRESULT res;
+ ALuint i = 0;
+
+ // Find the Device ID matching the deviceName if valid
+ if(!deviceName || strcmp(deviceName, woDefault) == 0)
+ lDeviceID = WAVE_MAPPER;
+ else
+ {
+ if(!PlaybackDeviceList)
+ ProbePlaybackDevices();
+
+ for(i = 0;i < NumPlaybackDevices;i++)
+ {
+ if(PlaybackDeviceList[i] &&
+ strcmp(deviceName, PlaybackDeviceList[i]) == 0)
+ {
+ lDeviceID = i;
+ break;
+ }
+ }
+ if(i == NumPlaybackDevices)
+ return ALC_FALSE;
+ }
+
+ pData = calloc(1, sizeof(*pData));
+ if(!pData)
+ {
+ alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+ return ALC_FALSE;
+ }
+ pDevice->ExtraData = pData;
+
+ if(pDevice->FmtChans != DevFmtMono)
+ pDevice->FmtChans = DevFmtStereo;
+ switch(pDevice->FmtType)
+ {
+ case DevFmtByte:
+ pDevice->FmtType = DevFmtUByte;
+ break;
+ case DevFmtUShort:
+ case DevFmtFloat:
+ pDevice->FmtType = DevFmtShort;
+ break;
+ case DevFmtUByte:
+ case DevFmtShort:
+ break;
+ }
+
+ memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
+ wfexFormat.wFormatTag = WAVE_FORMAT_PCM;
+ wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
+ wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
+ wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
+ wfexFormat.nChannels / 8;
+ wfexFormat.nSamplesPerSec = pDevice->Frequency;
+ wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
+ wfexFormat.nBlockAlign;
+ wfexFormat.cbSize = 0;
+
+ if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
+ {
+ AL_PRINT("waveInOpen failed: %u\n", res);
+ goto failure;
+ }
+
+ pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutAllHeadersReturned");
+ pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutThreadDestroyed");
+ if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL)
+ {
+ AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
+ goto failure;
+ }
+
+ pData->Frequency = pDevice->Frequency;
+
+ pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
+ PlaybackDeviceList[lDeviceID]);
+ return ALC_TRUE;
+
+failure:
+ if(pData->hWaveThreadEvent)
+ CloseHandle(pData->hWaveThreadEvent);
+ if(pData->hWaveHdrEvent)
+ CloseHandle(pData->hWaveHdrEvent);
+
+ if(pData->hWaveHandle.Out)
+ waveOutClose(pData->hWaveHandle.Out);
+
+ free(pData);
+ pDevice->ExtraData = NULL;
+ return ALC_FALSE;
+}
+
+static void WinMMClosePlayback(ALCdevice *device)
+{
+ WinMMData *pData = (WinMMData*)device->ExtraData;
+
+ // Close the Wave device
+ CloseHandle(pData->hWaveThreadEvent);
+ pData->hWaveThreadEvent = 0;
+
+ CloseHandle(pData->hWaveHdrEvent);
+ pData->hWaveHdrEvent = 0;
+
+ waveInClose(pData->hWaveHandle.In);
+ pData->hWaveHandle.In = 0;
+
+ free(pData);
+ device->ExtraData = NULL;
+}
+
+static ALCboolean WinMMResetPlayback(ALCdevice *device)
+{
+ WinMMData *pData = (WinMMData*)device->ExtraData;
+ ALbyte *BufferData;
+ ALint lBufferSize;
+ ALuint i;
+
+ pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
+ if(pData->hWaveThread == NULL)
+ return ALC_FALSE;
+
+ device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
+ pData->Frequency / device->Frequency);
+ device->Frequency = pData->Frequency;
+
+ pData->lWaveBuffersCommitted = 0;
+
+ // Create 4 Buffers
+ lBufferSize = device->UpdateSize*device->NumUpdates / 4;
+ lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+
+ BufferData = calloc(4, lBufferSize);
+ for(i = 0;i < 4;i++)
+ {
+ memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
+ pData->WaveBuffer[i].dwBufferLength = lBufferSize;
+ pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
+ (pData->WaveBuffer[i-1].lpData +
+ pData->WaveBuffer[i-1].dwBufferLength));
+ waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+ waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+ InterlockedIncrement(&pData->lWaveBuffersCommitted);
+ }
+
+ return ALC_TRUE;
+}
+
+static void WinMMStopPlayback(ALCdevice *device)
+{
+ WinMMData *pData = (WinMMData*)device->ExtraData;
+ int i;
+
+ if(pData->hWaveThread == NULL)
+ return;
+
+ // Set flag to stop processing headers
+ pData->bWaveShutdown = AL_TRUE;
+
+ // Wait for signal that all Wave Buffers have returned
+ WaitForSingleObjectEx(pData->hWaveHdrEvent, 5000, FALSE);
+
+ // Wait for signal that Wave Thread has been destroyed
+ WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
+
+ CloseHandle(pData->hWaveThread);
+ pData->hWaveThread = 0;
+
+ pData->bWaveShutdown = AL_FALSE;
+
+ // Release the wave buffers
+ for(i = 0;i < 4;i++)
+ {
+ waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+ if(i == 0)
+ free(pData->WaveBuffer[i].lpData);
+ pData->WaveBuffer[i].lpData = NULL;
+ }
+}
+
+
+static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ WAVEFORMATEX wfexCaptureFormat;
+ DWORD ulCapturedDataSize;
+ WinMMData *pData = NULL;
+ UINT lDeviceID = 0;
+ ALbyte *BufferData;
+ ALint lBufferSize;
+ MMRESULT res;
+ ALuint i;
+
+ if(!CaptureDeviceList)
+ ProbeCaptureDevices();
+
+ // Find the Device ID matching the deviceName if valid
+ if(deviceName)
+ {
+ for(i = 0;i < NumCaptureDevices;i++)
+ {
+ if(CaptureDeviceList[i] &&
+ strcmp(deviceName, CaptureDeviceList[i]) == 0)
+ {
+ lDeviceID = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for(i = 0;i < NumCaptureDevices;i++)
+ {
+ if(CaptureDeviceList[i])
+ {
+ lDeviceID = i;
+ break;
+ }
+ }
+ }
+ if(i == NumCaptureDevices)
+ return ALC_FALSE;
+
+ pData = calloc(1, sizeof(*pData));
+ if(!pData)
+ {
+ alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+ return ALC_FALSE;
+ }
+ pDevice->ExtraData = pData;
+
+ if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) ||
+ (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort))
+ {
+ alcSetError(pDevice, ALC_INVALID_ENUM);
+ goto failure;
+ }
+
+ memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
+ wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM;
+ wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
+ wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
+ wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
+ wfexCaptureFormat.nChannels / 8;
+ wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
+ wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
+ wfexCaptureFormat.nBlockAlign;
+ wfexCaptureFormat.cbSize = 0;
+
+ if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
+ {
+ AL_PRINT("waveInOpen failed: %u\n", res);
+ goto failure;
+ }
+
+ pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInAllHeadersReturned");
+ pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInThreadDestroyed");
+ if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL)
+ {
+ AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
+ goto failure;
+ }
+
+ pData->Frequency = pDevice->Frequency;
+
+ // Allocate circular memory buffer for the captured audio
+ ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
+
+ // Make sure circular buffer is at least 100ms in size
+ if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10))
+ ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10;
+
+ pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize);
+ if(!pData->pRing)
+ goto failure;
+
+ pData->lWaveBuffersCommitted = 0;
+
+ // Create 4 Buffers of 50ms each
+ lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20;
+ lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign);
+
+ BufferData = calloc(4, lBufferSize);
+ if(!BufferData)
+ goto failure;
+
+ for(i = 0;i < 4;i++)
+ {
+ memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
+ pData->WaveBuffer[i].dwBufferLength = lBufferSize;
+ pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
+ (pData->WaveBuffer[i-1].lpData +
+ pData->WaveBuffer[i-1].dwBufferLength));
+ pData->WaveBuffer[i].dwFlags = 0;
+ pData->WaveBuffer[i].dwLoops = 0;
+ waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+ waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+ InterlockedIncrement(&pData->lWaveBuffersCommitted);
+ }
+
+ pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
+ if (pData->hWaveThread == NULL)
+ goto failure;
+
+ pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
+ return ALC_TRUE;
+
+failure:
+ if(pData->hWaveThread)
+ CloseHandle(pData->hWaveThread);
+
+ for(i = 0;i < 4;i++)
+ {
+ if(pData->WaveBuffer[i].lpData)
+ {
+ waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+ if(i == 0)
+ free(pData->WaveBuffer[i].lpData);
+ }
+ }
+
+ if(pData->pRing)
+ DestroyRingBuffer(pData->pRing);
+
+ if(pData->hWaveThreadEvent)
+ CloseHandle(pData->hWaveThreadEvent);
+ if(pData->hWaveHdrEvent)
+ CloseHandle(pData->hWaveHdrEvent);
+
+ if(pData->hWaveHandle.In)
+ waveInClose(pData->hWaveHandle.In);
+
+ free(pData);
+ pDevice->ExtraData = NULL;
+ return ALC_FALSE;
+}
+
+static void WinMMCloseCapture(ALCdevice *pDevice)
+{
+ WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+ int i;
+
+ // Call waveOutReset to shutdown wave device
+ pData->bWaveShutdown = AL_TRUE;
+ waveInReset(pData->hWaveHandle.In);
+
+ // Wait for signal that all Wave Buffers have returned
+ WaitForSingleObjectEx(pData->hWaveHdrEvent, 5000, FALSE);
+
+ // Wait for signal that Wave Thread has been destroyed
+ WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
+
+ CloseHandle(pData->hWaveThread);
+ pData->hWaveThread = 0;
+
+ // Release the wave buffers
+ for(i = 0;i < 4;i++)
+ {
+ waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+ if(i == 0)
+ free(pData->WaveBuffer[i].lpData);
+ pData->WaveBuffer[i].lpData = NULL;
+ }
+
+ DestroyRingBuffer(pData->pRing);
+ pData->pRing = NULL;
+
+ // Close the Wave device
+ CloseHandle(pData->hWaveThreadEvent);
+ pData->hWaveThreadEvent = 0;
+
+ CloseHandle(pData->hWaveHdrEvent);
+ pData->hWaveHdrEvent = 0;
+
+ waveInClose(pData->hWaveHandle.In);
+ pData->hWaveHandle.In = 0;
+
+ free(pData);
+ pDevice->ExtraData = NULL;
+}
+
+static void WinMMStartCapture(ALCdevice *pDevice)
+{
+ WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+ waveInStart(pData->hWaveHandle.In);
+}
+
+static void WinMMStopCapture(ALCdevice *pDevice)
+{
+ WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+ waveInStop(pData->hWaveHandle.In);
+}
+
+static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
+{
+ WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+ return RingBufferSize(pData->pRing);
+}
+
+static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+ WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+
+ if(WinMMAvailableSamples(pDevice) >= lSamples)
+ ReadRingBuffer(pData->pRing, pBuffer, lSamples);
+ else
+ alcSetError(pDevice, ALC_INVALID_VALUE);
+}
+
+
+static BackendFuncs WinMMFuncs = {
+ WinMMOpenPlayback,
+ WinMMClosePlayback,
+ WinMMResetPlayback,
+ WinMMStopPlayback,
+ WinMMOpenCapture,
+ WinMMCloseCapture,
+ WinMMStartCapture,
+ WinMMStopCapture,
+ WinMMCaptureSamples,
+ WinMMAvailableSamples
+};
+
+void alcWinMMInit(BackendFuncs *FuncList)
+{
+ *FuncList = WinMMFuncs;
+}
+
+void alcWinMMDeinit()
+{
+ ALuint lLoop;
+
+ for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
+ free(PlaybackDeviceList[lLoop]);
+ free(PlaybackDeviceList);
+ PlaybackDeviceList = NULL;
+
+ NumPlaybackDevices = 0;
+
+
+ for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
+ free(CaptureDeviceList[lLoop]);
+ free(CaptureDeviceList);
+ CaptureDeviceList = NULL;
+
+ NumCaptureDevices = 0;
+}
+
+void alcWinMMProbe(int type)
+{
+ ALuint i;
+
+ if(type == DEVICE_PROBE)
+ {
+ ProbePlaybackDevices();
+ if(NumPlaybackDevices > 0)
+ AppendDeviceList(woDefault);
+ }
+ else if(type == ALL_DEVICE_PROBE)
+ {
+ ProbePlaybackDevices();
+ if(NumPlaybackDevices > 0)
+ AppendAllDeviceList(woDefault);
+ for(i = 0;i < NumPlaybackDevices;i++)
+ {
+ if(PlaybackDeviceList[i])
+ AppendAllDeviceList(PlaybackDeviceList[i]);
+ }
+ }
+ else if(type == CAPTURE_DEVICE_PROBE)
+ {
+ ProbeCaptureDevices();
+ for(i = 0;i < NumCaptureDevices;i++)
+ {
+ if(CaptureDeviceList[i])
+ AppendCaptureDeviceList(CaptureDeviceList[i]);
+ }
+ }
+}
--- /dev/null
+# CMake build file list for OpenAL
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+
+IF(COMMAND CMAKE_POLICY)
+ CMAKE_POLICY(SET CMP0003 NEW)
+ENDIF(COMMAND CMAKE_POLICY)
+
+SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckSharedLibraryExists)
+INCLUDE(CheckIncludeFile)
+INCLUDE(CheckIncludeFiles)
+INCLUDE(CheckSymbolExists)
+INCLUDE(CheckCCompilerFlag)
+INCLUDE(CheckCSourceCompiles)
+INCLUDE(CheckTypeSize)
+
+
+PROJECT(OpenAL C)
+
+
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
+
+
+OPTION(ALSA "Check for ALSA backend" ON)
+OPTION(OSS "Check for OSS backend" ON)
+OPTION(SOLARIS "Check for Solaris backend" ON)
+OPTION(DSOUND "Check for DirectSound backend" ON)
+OPTION(WINMM "Check for Windows Multimedia backend" ON)
+OPTION(PORTAUDIO "Check for PortAudio backend" ON)
+OPTION(PULSEAUDIO "Check for PulseAudio backend" ON)
+OPTION(WAVE "Enable Wave Writer backend" ON)
+OPTION(AVSYSTEM "Check for Avsystem backend" ON)
+
+OPTION(DLOPEN "Check for the dlopen API for loading optional libs" ON)
+
+OPTION(WERROR "Treat compile warnings as errors" OFF)
+
+OPTION(UTILS "Build and install utility programs" ON)
+
+OPTION(ALSOFT_CONFIG "Install alsoft.conf configuration file" ON)
+
+
+IF(WIN32)
+ SET(LIBNAME OpenAL32)
+ ADD_DEFINITIONS("-D_WIN32")
+ELSE()
+ SET(LIBNAME openal)
+ENDIF()
+
+IF(NOT LIBTYPE)
+ SET(LIBTYPE SHARED)
+ENDIF()
+
+SET(LIB_MAJOR_VERSION "1")
+SET(LIB_MINOR_VERSION "13")
+SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}")
+
+
+CHECK_TYPE_SIZE("long" SIZEOF_LONG)
+CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
+CHECK_TYPE_SIZE("unsigned int" SIZEOF_UINT)
+CHECK_TYPE_SIZE("void*" SIZEOF_VOIDP)
+
+
+# Add definitions, compiler switches, etc.
+INCLUDE_DIRECTORIES(OpenAL32/Include include "${OpenAL_BINARY_DIR}")
+
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+ "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
+ FORCE)
+ENDIF()
+IF(NOT CMAKE_DEBUG_POSTFIX)
+ SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING
+ "Library postfix for debug builds. Normally left blank."
+ FORCE)
+ENDIF()
+
+IF(MSVC)
+ # ???
+ SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEBUG")
+ SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DNDEBUG")
+ SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
+ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
+ ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
+ ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
+
+ IF(NOT DXSDK_DIR)
+ STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}")
+ ELSE()
+ STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "${DXSDK_DIR}")
+ ENDIF()
+ IF(DXSDK_DIR)
+ MESSAGE(STATUS "Using DirectX SDK directory: ${DXSDK_DIR}")
+ SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} "${DXSDK_DIR}/Include")
+ INCLUDE_DIRECTORIES("${DXSDK_DIR}/Include")
+ LINK_DIRECTORIES("${DXSDK_DIR}/Lib")
+ ENDIF()
+
+ OPTION(FORCE_STATIC_VCRT "Force /MT for static VC runtimes" OFF)
+ IF(FORCE_STATIC_VCRT)
+ FOREACH(flag_var
+ CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+ CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
+ IF(${flag_var} MATCHES "/MD")
+ STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ ENDIF()
+ ENDFOREACH(flag_var)
+ ENDIF()
+ELSE()
+ ADD_DEFINITIONS(-Winline -Wall)
+ CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA)
+ IF(HAVE_W_EXTRA)
+ ADD_DEFINITIONS(-Wextra)
+ ENDIF()
+
+ IF(WERROR)
+ ADD_DEFINITIONS(-Werror)
+ ENDIF()
+
+ SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O2 -D_DEBUG" CACHE STRING
+ "Flags used by the compiler during Release with Debug Info builds."
+ FORCE)
+ SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" CACHE STRING
+ "Flags used by the compiler during release minsize builds."
+ FORCE)
+ SET(CMAKE_C_FLAGS_RELEASE "-O2 -fomit-frame-pointer -DNDEBUG" CACHE STRING
+ "Flags used by the compiler during release builds"
+ FORCE)
+ SET(CMAKE_C_FLAGS_DEBUG "-g3 -D_DEBUG" CACHE STRING
+ "Flags used by the compiler during debug builds."
+ FORCE)
+
+ CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
+ int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
+
+ # Set visibility options if available
+ IF(NOT WIN32)
+ CHECK_C_COMPILER_FLAG(-fvisibility=internal HAVE_VISIBILITY_SWITCH)
+ IF(HAVE_VISIBILITY_SWITCH)
+ CHECK_C_SOURCE_COMPILES("int foo() __attribute__((visibility(\"default\")));
+ int main() {return 0;}" HAVE_GCC_VISIBILITY)
+ IF(HAVE_GCC_VISIBILITY)
+ ADD_DEFINITIONS(-fvisibility=internal -DHAVE_GCC_VISIBILITY)
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(printf, 1, 2)));
+ int main() {return 0;}" HAVE_GCC_FORMAT)
+
+CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H)
+CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H)
+
+CHECK_LIBRARY_EXISTS(m powf "" HAVE_POWF)
+CHECK_LIBRARY_EXISTS(m sqrtf "" HAVE_SQRTF)
+CHECK_LIBRARY_EXISTS(m acosf "" HAVE_ACOSF)
+CHECK_LIBRARY_EXISTS(m atanf "" HAVE_ATANF)
+CHECK_LIBRARY_EXISTS(m fabsf "" HAVE_FABSF)
+IF(HAVE_FENV_H)
+ CHECK_LIBRARY_EXISTS(m fesetround "" HAVE_FESETROUND)
+ENDIF()
+IF(HAVE_SQRTF OR HAVE_ACOSF OR HAVE_ATANF OR HAVE_FABSF OR HAVE_FESETROUND)
+ SET(EXTRA_LIBS m ${EXTRA_LIBS})
+ENDIF()
+CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
+CHECK_FUNCTION_EXISTS(_controlfp HAVE__CONTROLFP)
+
+CHECK_FUNCTION_EXISTS(stat HAVE_STAT)
+CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP)
+IF(NOT HAVE_STRCASECMP)
+ CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP)
+ IF(NOT HAVE__STRICMP)
+ MESSAGE(FATAL_ERROR "No case-insensitive compare function found, please report!")
+ ENDIF()
+
+ ADD_DEFINITIONS(-Dstrcasecmp=_stricmp)
+ENDIF()
+
+CHECK_FUNCTION_EXISTS(strncasecmp HAVE_STRNCASECMP)
+IF(NOT HAVE_STRNCASECMP)
+ CHECK_FUNCTION_EXISTS(_strnicmp HAVE__STRNICMP)
+ IF(NOT HAVE__STRNICMP)
+ MESSAGE(FATAL_ERROR "No case-insensitive size-limitted compare function found, please report!")
+ ENDIF()
+
+ ADD_DEFINITIONS(-Dstrncasecmp=_strnicmp)
+ENDIF()
+
+CHECK_FUNCTION_EXISTS(snprintf HAVE_SNPRINTF)
+IF(NOT HAVE_SNPRINTF)
+ CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF)
+ IF(NOT HAVE__SNPRINTF)
+ MESSAGE(FATAL_ERROR "No snprintf function found, please report!")
+ ENDIF()
+
+ ADD_DEFINITIONS(-Dsnprintf=_snprintf)
+ENDIF()
+
+CHECK_FUNCTION_EXISTS(vsnprintf HAVE_VSNPRINTF)
+IF(NOT HAVE_VSNPRINTF)
+ CHECK_FUNCTION_EXISTS(_vsnprintf HAVE__VSNPRINTF)
+ IF(NOT HAVE__VSNPRINTF)
+ MESSAGE(FATAL_ERROR "No vsnprintf function found, please report!")
+ ENDIF()
+
+ ADD_DEFINITIONS(-Dvsnprintf=_vsnprintf)
+ENDIF()
+
+CHECK_SYMBOL_EXISTS(isnan math.h HAVE_ISNAN)
+IF(NOT HAVE_ISNAN)
+ CHECK_FUNCTION_EXISTS(_isnan HAVE__ISNAN)
+ IF(NOT HAVE__ISNAN)
+ MESSAGE(FATAL_ERROR "No isnan function found, please report!")
+ ENDIF()
+
+ ADD_DEFINITIONS(-Disnan=_isnan)
+ENDIF()
+
+
+# Check for the dlopen API (for dynamicly loading backend libs)
+IF(DLOPEN)
+ CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H)
+ IF(HAVE_DLFCN_H)
+ CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL)
+ IF(HAVE_LIBDL)
+ SET(EXTRA_LIBS dl ${EXTRA_LIBS})
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+# Check if we have Windows headers
+CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0500)
+IF(NOT HAVE_WINDOWS_H)
+ CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY)
+ IF(NOT HAVE_GETTIMEOFDAY)
+ MESSAGE(FATAL_ERROR "No timing function found!")
+ ENDIF()
+
+ CHECK_FUNCTION_EXISTS(nanosleep HAVE_NANOSLEEP)
+ IF(NOT HAVE_NANOSLEEP)
+ MESSAGE(FATAL_ERROR "No sleep function found!")
+ ENDIF()
+
+ CHECK_C_COMPILER_FLAG(-pthread HAVE_PTHREAD)
+ IF(HAVE_PTHREAD)
+ ADD_DEFINITIONS(-pthread)
+ SET(EXTRA_LIBS ${EXTRA_LIBS} -pthread)
+ ENDIF()
+
+ # We need pthreads outside of Windows
+ CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
+ IF(NOT HAVE_PTHREAD_H)
+ MESSAGE(FATAL_ERROR "PThreads is required for non-Windows builds!")
+ ENDIF()
+ # Some systems need pthread_np.h to get recursive mutexes
+ CHECK_INCLUDE_FILES("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H)
+
+ # _GNU_SOURCE is needed on some systems for extra attributes, and
+ # _REENTRANT is needed for libc thread-safety
+ ADD_DEFINITIONS(-D_GNU_SOURCE=1)
+ CHECK_LIBRARY_EXISTS(pthread pthread_create "" HAVE_LIBPTHREAD)
+ IF(HAVE_LIBPTHREAD)
+ SET(EXTRA_LIBS pthread ${EXTRA_LIBS})
+ ENDIF()
+
+ CHECK_LIBRARY_EXISTS(pthread pthread_setschedparam "" HAVE_PTHREAD_SETSCHEDPARAM)
+
+ CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT)
+ IF(HAVE_LIBRT)
+ SET(EXTRA_LIBS rt ${EXTRA_LIBS})
+ ENDIF()
+ENDIF()
+
+# Check for a 64-bit type
+CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
+IF(NOT HAVE_STDINT_H)
+ IF(HAVE_WINDOWS_H)
+ CHECK_C_SOURCE_COMPILES("\#define _WIN32_WINNT 0x0500
+ \#include <windows.h>
+ __int64 foo;
+ int main() {return 0;}" HAVE___INT64)
+ ENDIF()
+ IF(NOT HAVE___INT64)
+ IF(NOT SIZEOF_LONG MATCHES "8")
+ IF(NOT SIZEOF_LONG_LONG MATCHES "8")
+ MESSAGE(FATAL_ERROR "No 64-bit types found, please report!")
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+IF(WIN32)
+ # Windows needs winmm for timeGetTime, even if the backend is disabled
+ CHECK_SHARED_LIBRARY_EXISTS(winmm timeGetTime 0 "" HAVE_LIBWINMM)
+ IF(HAVE_LIBWINMM)
+ SET(EXTRA_LIBS winmm ${EXTRA_LIBS})
+ SET(PKG_CONFIG_LIBS ${PKG_CONFIG_LIBS} -lwinmm)
+ ENDIF()
+ENDIF()
+
+
+SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
+ OpenAL32/alBuffer.c
+ OpenAL32/alDatabuffer.c
+ OpenAL32/alEffect.c
+ OpenAL32/alError.c
+ OpenAL32/alExtension.c
+ OpenAL32/alFilter.c
+ OpenAL32/alListener.c
+ OpenAL32/alSource.c
+ OpenAL32/alState.c
+ OpenAL32/alThunk.c
+)
+SET(ALC_OBJS Alc/ALc.c
+ Alc/ALu.c
+ Alc/alcConfig.c
+ Alc/alcEcho.c
+ Alc/alcModulator.c
+ Alc/alcReverb.c
+ Alc/alcRing.c
+ Alc/alcThread.c
+ Alc/bs2b.c
+ Alc/mixer.c
+ Alc/panning.c
+ Alc/null.c
+)
+
+SET(BACKENDS "")
+SET(HAVE_ALSA 0)
+SET(HAVE_OSS 0)
+SET(HAVE_SOLARIS 0)
+SET(HAVE_DSOUND 0)
+SET(HAVE_WINMM 0)
+SET(HAVE_PORTAUDIO 0)
+SET(HAVE_PULSEAUDIO 0)
+SET(HAVE_WAVE 0)
+SET(HAVE_AVSYSTEM 0)
+
+# Check ALSA backend
+IF(ALSA)
+ CHECK_INCLUDE_FILE(alsa/asoundlib.h HAVE_ALSA_ASOUNDLIB_H)
+ IF(HAVE_ALSA_ASOUNDLIB_H)
+ CHECK_SHARED_LIBRARY_EXISTS(asound snd_pcm_open 4 "" HAVE_LIBASOUND)
+ IF(HAVE_LIBASOUND OR HAVE_DLFCN_H OR WIN32)
+ SET(HAVE_ALSA 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/alsa.c)
+ IF(HAVE_DLFCN_H OR WIN32)
+ SET(BACKENDS "${BACKENDS} ALSA,")
+ ELSE()
+ SET(BACKENDS "${BACKENDS} ALSA \(linked\),")
+ SET(EXTRA_LIBS asound ${EXTRA_LIBS})
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+# Check OSS backend
+IF(OSS)
+ CHECK_INCLUDE_FILE(sys/soundcard.h HAVE_SYS_SOUNDCARD_H)
+ IF(HAVE_SYS_SOUNDCARD_H)
+ SET(HAVE_OSS 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/oss.c)
+ SET(BACKENDS "${BACKENDS} OSS,")
+ ENDIF()
+ENDIF()
+
+# Check Solaris backend
+IF(SOLARIS)
+ CHECK_INCLUDE_FILE(sys/audioio.h HAVE_SYS_AUDIOIO_H)
+ IF(HAVE_SYS_AUDIOIO_H)
+ SET(HAVE_SOLARIS 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/solaris.c)
+ SET(BACKENDS "${BACKENDS} Solaris,")
+ ENDIF()
+ENDIF()
+
+# Check DSound/MMSystem backend
+IF(DSOUND)
+ CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
+ IF(HAVE_DSOUND_H)
+ CHECK_SHARED_LIBRARY_EXISTS(dsound DirectSoundCreate 3 "" HAVE_LIBDSOUND)
+ IF(HAVE_LIBDSOUND OR HAVE_DLFCN_H OR WIN32)
+ SET(HAVE_DSOUND 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c)
+
+ IF(HAVE_DLFCN_H OR WIN32)
+ SET(BACKENDS "${BACKENDS} DirectSound,")
+ ELSE()
+ SET(BACKENDS "${BACKENDS} DirectSound \(linked\),")
+ SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+IF(HAVE_WINDOWS_H)
+ IF(WINMM)
+ CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0500)
+ IF(HAVE_MMSYSTEM_H AND HAVE_LIBWINMM)
+ SET(HAVE_WINMM 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/winmm.c)
+ SET(BACKENDS "${BACKENDS} WinMM,")
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+# Check PortAudio backend
+IF(PORTAUDIO)
+ CHECK_INCLUDE_FILE(portaudio.h HAVE_PORTAUDIO_H)
+ IF(HAVE_PORTAUDIO_H)
+ CHECK_SHARED_LIBRARY_EXISTS(portaudio Pa_Initialize 0 "" HAVE_LIBPORTAUDIO)
+ IF(HAVE_LIBPORTAUDIO OR HAVE_DLFCN_H OR WIN32)
+ SET(HAVE_PORTAUDIO 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/portaudio.c)
+ IF(HAVE_DLFCN_H OR WIN32)
+ SET(BACKENDS "${BACKENDS} PortAudio,")
+ ELSE()
+ SET(BACKENDS "${BACKENDS} PortAudio \(linked\),")
+ SET(EXTRA_LIBS portaudio ${EXTRA_LIBS})
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+# Check PortAudio backend
+IF(PULSEAUDIO)
+ CHECK_INCLUDE_FILE(pulse/pulseaudio.h HAVE_PULSE_PULSEAUDIO_H)
+ IF(HAVE_PULSE_PULSEAUDIO_H)
+ CHECK_SHARED_LIBRARY_EXISTS(pulse pa_context_new 2 "" HAVE_LIBPULSE)
+ IF(HAVE_LIBPULSE OR HAVE_DLFCN_H OR WIN32)
+ SET(HAVE_PULSEAUDIO 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/pulseaudio.c)
+ IF(HAVE_DLFCN_H OR WIN32)
+ SET(BACKENDS "${BACKENDS} PulseAudio,")
+ ELSE()
+ SET(BACKENDS "${BACKENDS} PulseAudio \(linked\),")
+ SET(EXTRA_LIBS pulse ${EXTRA_LIBS})
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+# Optionally enable the Wave Writer backend
+IF(WAVE)
+ SET(HAVE_WAVE 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/wave.c)
+ SET(BACKENDS "${BACKENDS} WaveFile,")
+ENDIF()
+
+# Check AVSYSTEM backend
+IF(AVSYSTEM)
+ CHECK_INCLUDE_FILE(avsystem/avsys-audio.h HAVE_AVSYSTEM_H)
+ IF(HAVE_AVSYSTEM_H)
+ SET(HAVE_AVSYSTEM 1)
+ INCLUDE(FindPkgConfig)
+ pkg_check_modules(REQ_PKGS REQUIRED avsysaudio mm-session audio-session-mgr)
+ FOREACH(flag ${REQ_PKGS_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ ENDFOREACH(flag)
+ FOREACH(flag ${REQ_PKGS_LDFLAGS})
+ SET(EXTRA_LIBS "${EXTRA_LIBS} ${flag}")
+ ENDFOREACH(flag)
+ SET(EXTRA_LIBS avsysaudio mmfsession audio-session-mgr vconf ${EXTRA_LIBS})
+ SET(ALC_OBJS ${ALC_OBJS} Alc/avsystem.c)
+ SET(BACKENDS "${BACKENDS} AVSYSTEM,")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+ ENDIF()
+ENDIF()
+
+# This is always available
+SET(BACKENDS "${BACKENDS} Null")
+
+IF(LIBTYPE STREQUAL "STATIC")
+ ADD_DEFINITIONS(-DAL_LIBTYPE_STATIC)
+ SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC ${PKG_CONFIG_CFLAGS})
+ENDIF()
+
+# Needed for openal.pc.in
+SET(prefix ${CMAKE_INSTALL_PREFIX})
+SET(exec_prefix "\${prefix}")
+SET(libdir "\${exec_prefix}/lib${LIB_SUFFIX}")
+SET(bindir "\${exec_prefix}/bin")
+SET(includedir "\${prefix}/include")
+SET(PACKAGE_VERSION "${LIB_VERSION}")
+
+# End configuration
+CONFIGURE_FILE(
+ "${OpenAL_SOURCE_DIR}/config.h.in"
+ "${OpenAL_BINARY_DIR}/config.h")
+CONFIGURE_FILE(
+ "${OpenAL_SOURCE_DIR}/openal.pc.in"
+ "${OpenAL_BINARY_DIR}/openal.pc"
+ @ONLY)
+
+# Build a library
+ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
+SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES DEFINE_SYMBOL AL_BUILD_LIBRARY
+ COMPILE_FLAGS -DAL_ALEXT_PROTOTYPES
+ VERSION ${LIB_VERSION}.0
+ SOVERSION ${LIB_MAJOR_VERSION})
+IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
+ SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
+ENDIF()
+
+TARGET_LINK_LIBRARIES(${LIBNAME} ${EXTRA_LIBS})
+
+# Add an install target here
+INSTALL(TARGETS ${LIBNAME}
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+)
+INSTALL(FILES include/AL/al.h
+ include/AL/alc.h
+ include/AL/alext.h
+ include/AL/efx.h
+ include/AL/efx-creative.h
+ DESTINATION include/AL
+)
+INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
+ DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
+
+
+MESSAGE(STATUS "")
+MESSAGE(STATUS "Building OpenAL with support for the following backends:")
+MESSAGE(STATUS " ${BACKENDS}")
+MESSAGE(STATUS "")
+
+IF(WIN32)
+ IF(NOT HAVE_DSOUND)
+ MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output")
+ MESSAGE(STATUS " This is probably NOT what you want!")
+ MESSAGE(STATUS "")
+ ENDIF()
+ENDIF()
+
+# Install alsoft.conf configuration file
+IF(ALSOFT_CONFIG)
+ INSTALL(FILES alsoftrc.sample
+ DESTINATION /etc/openal
+ RENAME alsoft.conf
+ )
+ MESSAGE(STATUS "Installing sample alsoft.conf")
+ MESSAGE(STATUS "")
+ENDIF()
+
+IF(UTILS)
+ ADD_EXECUTABLE(openal-info utils/openal-info.c)
+ TARGET_LINK_LIBRARIES(openal-info ${LIBNAME})
+ INSTALL(TARGETS openal-info
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+ )
+ MESSAGE(STATUS "Building utility programs")
+ MESSAGE(STATUS "")
+ENDIF()
--- /dev/null
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
--- /dev/null
+#ifndef _AL_AUXEFFECTSLOT_H_
+#define _AL_AUXEFFECTSLOT_H_
+
+#include "AL/al.h"
+#include "alEffect.h"
+#include "alFilter.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ALeffectState ALeffectState;
+
+typedef struct ALeffectslot
+{
+ ALeffect effect;
+
+ ALfloat Gain;
+ ALboolean AuxSendAuto;
+
+ ALeffectState *EffectState;
+
+ ALfloat WetBuffer[BUFFERSIZE];
+
+ ALfloat ClickRemoval[1];
+ ALfloat PendingClicks[1];
+
+ ALuint refcount;
+
+ // Index to itself
+ ALuint effectslot;
+
+ struct ALeffectslot *next;
+} ALeffectslot;
+
+
+ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
+
+
+struct ALeffectState {
+ ALvoid (*Destroy)(ALeffectState *State);
+ ALboolean (*DeviceUpdate)(ALeffectState *State, ALCdevice *Device);
+ ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect);
+ ALvoid (*Process)(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS]);
+};
+
+ALeffectState *NoneCreate(void);
+ALeffectState *EAXVerbCreate(void);
+ALeffectState *VerbCreate(void);
+ALeffectState *EchoCreate(void);
+ALeffectState *ModulatorCreate(void);
+
+#define ALEffect_Destroy(a) ((a)->Destroy((a)))
+#define ALEffect_DeviceUpdate(a,b) ((a)->DeviceUpdate((a),(b)))
+#define ALEffect_Update(a,b,c) ((a)->Update((a),(b),(c)))
+#define ALEffect_Process(a,b,c,d,e) ((a)->Process((a),(b),(c),(d),(e)))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_BUFFER_H_
+#define _AL_BUFFER_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Input formats (some are currently theoretical) */
+enum UserFmtType {
+ UserFmtByte, /* AL_BYTE */
+ UserFmtUByte, /* AL_UNSIGNED_BYTE */
+ UserFmtShort, /* AL_SHORT */
+ UserFmtUShort, /* AL_UNSIGNED_SHORT */
+ UserFmtInt, /* AL_INT */
+ UserFmtUInt, /* AL_UNSIGNED_INT */
+ UserFmtFloat, /* AL_FLOAT */
+ UserFmtDouble, /* AL_DOUBLE */
+ UserFmtMulaw, /* AL_MULAW */
+ UserFmtIMA4, /* AL_IMA4 */
+};
+enum UserFmtChannels {
+ UserFmtMono, /* AL_MONO */
+ UserFmtStereo, /* AL_STEREO */
+ UserFmtRear, /* AL_REAR */
+ UserFmtQuad, /* AL_QUAD */
+ UserFmtX51, /* AL_5POINT1 (WFX order) */
+ UserFmtX61, /* AL_6POINT1 (WFX order) */
+ UserFmtX71, /* AL_7POINT1 (WFX order) */
+};
+
+ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
+ enum UserFmtType *type);
+ALuint BytesFromUserFmt(enum UserFmtType type);
+ALuint ChannelsFromUserFmt(enum UserFmtChannels chans);
+static __inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans,
+ enum UserFmtType type)
+{
+ return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
+}
+
+
+/* Storable formats */
+enum FmtType {
+ FmtUByte = UserFmtUByte,
+ FmtShort = UserFmtShort,
+ FmtFloat = UserFmtFloat,
+};
+enum FmtChannels {
+ FmtMono = UserFmtMono,
+ FmtStereo = UserFmtStereo,
+ FmtRear = UserFmtRear,
+ FmtQuad = UserFmtQuad,
+ FmtX51 = UserFmtX51,
+ FmtX61 = UserFmtX61,
+ FmtX71 = UserFmtX71,
+};
+
+ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type);
+ALuint BytesFromFmt(enum FmtType type);
+ALuint ChannelsFromFmt(enum FmtChannels chans);
+static __inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
+{
+ return ChannelsFromFmt(chans) * BytesFromFmt(type);
+}
+
+
+typedef struct ALbuffer
+{
+ ALvoid *data;
+ ALsizei size;
+
+ ALsizei Frequency;
+ enum FmtChannels FmtChannels;
+ enum FmtType FmtType;
+
+ enum UserFmtChannels OriginalChannels;
+ enum UserFmtType OriginalType;
+ ALsizei OriginalSize;
+ ALsizei OriginalAlign;
+
+ ALsizei LoopStart;
+ ALsizei LoopEnd;
+
+ ALuint refcount; // Number of sources using this buffer (deletion can only occur when this is 0)
+
+ // Index to itself
+ ALuint buffer;
+} ALbuffer;
+
+ALvoid ReleaseALBuffers(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_DATABUFFER_H_
+#define _AL_DATABUFFER_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UNMAPPED 0
+#define MAPPED 1
+
+typedef struct ALdatabuffer
+{
+ ALubyte *data;
+ ALintptrEXT size;
+
+ ALenum state;
+ ALenum usage;
+
+ /* Index to self */
+ ALuint databuffer;
+
+ struct ALdatabuffer *next;
+} ALdatabuffer;
+
+ALvoid ReleaseALDatabuffers(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+// NOTE: The effect structure is getting too large, it may be a good idea to
+// start using a union or another form of unified storage.
+#ifndef _AL_EFFECT_H_
+#define _AL_EFFECT_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ EAXREVERB = 0,
+ REVERB,
+ ECHO,
+ MODULATOR,
+
+ MAX_EFFECTS
+};
+extern ALboolean DisabledEffects[MAX_EFFECTS];
+
+typedef struct ALeffect
+{
+ // Effect type (AL_EFFECT_NULL, ...)
+ ALenum type;
+
+ struct {
+ // Shared Reverb Properties
+ ALfloat Density;
+ ALfloat Diffusion;
+ ALfloat Gain;
+ ALfloat GainHF;
+ ALfloat DecayTime;
+ ALfloat DecayHFRatio;
+ ALfloat ReflectionsGain;
+ ALfloat ReflectionsDelay;
+ ALfloat LateReverbGain;
+ ALfloat LateReverbDelay;
+ ALfloat AirAbsorptionGainHF;
+ ALfloat RoomRolloffFactor;
+ ALboolean DecayHFLimit;
+
+ // Additional EAX Reverb Properties
+ ALfloat GainLF;
+ ALfloat DecayLFRatio;
+ ALfloat ReflectionsPan[3];
+ ALfloat LateReverbPan[3];
+ ALfloat EchoTime;
+ ALfloat EchoDepth;
+ ALfloat ModulationTime;
+ ALfloat ModulationDepth;
+ ALfloat HFReference;
+ ALfloat LFReference;
+ } Reverb;
+
+ struct {
+ ALfloat Delay;
+ ALfloat LRDelay;
+
+ ALfloat Damping;
+ ALfloat Feedback;
+
+ ALfloat Spread;
+ } Echo;
+
+ struct {
+ ALfloat Frequency;
+ ALfloat HighPassCutoff;
+ ALint Waveform;
+ } Modulator;
+
+ // Index to itself
+ ALuint effect;
+} ALeffect;
+
+
+ALvoid ReleaseALEffects(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_ERROR_H_
+#define _AL_ERROR_H_
+
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_FILTER_H_
+#define _AL_FILTER_H_
+
+#include "AL/al.h"
+#include "alu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ ALfloat coeff;
+#ifndef _MSC_VER
+ ALfloat history[0];
+#else
+ ALfloat history[1];
+#endif
+} FILTER;
+
+static __inline ALfloat lpFilter4P(FILTER *iir, ALuint offset, ALfloat input)
+{
+ ALfloat *history = &iir->history[offset];
+ ALfloat a = iir->coeff;
+ ALfloat output = input;
+
+ output = output + (history[0]-output)*a;
+ history[0] = output;
+ output = output + (history[1]-output)*a;
+ history[1] = output;
+ output = output + (history[2]-output)*a;
+ history[2] = output;
+ output = output + (history[3]-output)*a;
+ history[3] = output;
+
+ return output;
+}
+
+static __inline ALfloat lpFilter2P(FILTER *iir, ALuint offset, ALfloat input)
+{
+ ALfloat *history = &iir->history[offset];
+ ALfloat a = iir->coeff;
+ ALfloat output = input;
+
+ output = output + (history[0]-output)*a;
+ history[0] = output;
+ output = output + (history[1]-output)*a;
+ history[1] = output;
+
+ return output;
+}
+
+static __inline ALfloat lpFilter1P(FILTER *iir, ALuint offset, ALfloat input)
+{
+ ALfloat *history = &iir->history[offset];
+ ALfloat a = iir->coeff;
+ ALfloat output = input;
+
+ output = output + (history[0]-output)*a;
+ history[0] = output;
+
+ return output;
+}
+
+static __inline ALfloat lpFilter4PC(const FILTER *iir, ALuint offset, ALfloat input)
+{
+ const ALfloat *history = &iir->history[offset];
+ ALfloat a = iir->coeff;
+ ALfloat output = input;
+
+ output = output + (history[0]-output)*a;
+ output = output + (history[1]-output)*a;
+ output = output + (history[2]-output)*a;
+ output = output + (history[3]-output)*a;
+
+ return output;
+}
+
+static __inline ALfloat lpFilter2PC(const FILTER *iir, ALuint offset, ALfloat input)
+{
+ const ALfloat *history = &iir->history[offset];
+ ALfloat a = iir->coeff;
+ ALfloat output = input;
+
+ output = output + (history[0]-output)*a;
+ output = output + (history[1]-output)*a;
+
+ return output;
+}
+
+static __inline ALfloat lpFilter1PC(FILTER *iir, ALuint offset, ALfloat input)
+{
+ const ALfloat *history = &iir->history[offset];
+ ALfloat a = iir->coeff;
+ ALfloat output = input;
+
+ output = output + (history[0]-output)*a;
+
+ return output;
+}
+
+/* Calculates the low-pass filter coefficient given the pre-scaled gain and
+ * cos(w) value. Note that g should be pre-scaled (sqr(gain) for one-pole,
+ * sqrt(gain) for four-pole, etc) */
+static __inline ALfloat lpCoeffCalc(ALfloat g, ALfloat cw)
+{
+ ALfloat a = 0.0f;
+
+ /* Be careful with gains < 0.01, as that causes the coefficient
+ * head towards 1, which will flatten the signal */
+ g = __max(g, 0.01f);
+ if(g < 0.9999f) /* 1-epsilon */
+ a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) /
+ (1 - g);
+
+ return a;
+}
+
+
+typedef struct ALfilter
+{
+ // Filter type (AL_FILTER_NULL, ...)
+ ALenum type;
+
+ ALfloat Gain;
+ ALfloat GainHF;
+
+ // Index to itself
+ ALuint filter;
+} ALfilter;
+
+
+ALvoid ReleaseALFilters(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_LISTENER_H_
+#define _AL_LISTENER_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ALlistener_struct
+{
+ ALfloat Position[3];
+ ALfloat Velocity[3];
+ ALfloat Forward[3];
+ ALfloat Up[3];
+ ALfloat Gain;
+ ALfloat MetersPerUnit;
+} ALlistener;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef AL_MAIN_H
+#define AL_MAIN_H
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef HAVE_FENV_H
+#include <fenv.h>
+#endif
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#ifndef AL_EXT_sample_buffer_object
+#define AL_EXT_sample_buffer_object 1
+typedef ptrdiff_t ALintptrEXT;
+typedef ptrdiff_t ALsizeiptrEXT;
+#define AL_SAMPLE_SOURCE_EXT 0x1040
+#define AL_SAMPLE_SINK_EXT 0x1041
+#define AL_READ_ONLY_EXT 0x1042
+#define AL_WRITE_ONLY_EXT 0x1043
+#define AL_READ_WRITE_EXT 0x1044
+#define AL_STREAM_WRITE_EXT 0x1045
+#define AL_STREAM_READ_EXT 0x1046
+#define AL_STREAM_COPY_EXT 0x1047
+#define AL_STATIC_WRITE_EXT 0x1048
+#define AL_STATIC_READ_EXT 0x1049
+#define AL_STATIC_COPY_EXT 0x104A
+#define AL_DYNAMIC_WRITE_EXT 0x104B
+#define AL_DYNAMIC_READ_EXT 0x104C
+#define AL_DYNAMIC_COPY_EXT 0x104D
+typedef ALvoid (AL_APIENTRY*PFNALGENDATABUFFERSEXTPROC)(ALsizei n,ALuint *puiBuffers);
+typedef ALvoid (AL_APIENTRY*PFNALDELETEDATABUFFERSEXTPROC)(ALsizei n, const ALuint *puiBuffers);
+typedef ALboolean (AL_APIENTRY*PFNALISDATABUFFEREXTPROC)(ALuint uiBuffer);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERDATAEXTPROC)(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat flValue);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, const ALfloat* flValues);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint lValue);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, const ALint* plValues);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat *pflValue);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, ALfloat* pflValues);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint *plValue);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, ALint* plValues);
+typedef ALvoid (AL_APIENTRY*PFNALSELECTDATABUFFEREXTPROC)(ALenum target, ALuint uiBuffer);
+typedef ALvoid* (AL_APIENTRY*PFNALMAPDATABUFFEREXTPROC)(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access);
+typedef ALvoid (AL_APIENTRY*PFNALUNMAPDATABUFFEREXTPROC)(ALuint uiBuffer);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers);
+AL_API ALvoid AL_APIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *puiBuffers);
+AL_API ALboolean AL_APIENTRY alIsDatabufferEXT(ALuint uiBuffer);
+AL_API ALvoid AL_APIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage);
+AL_API ALvoid AL_APIENTRY alDatabufferSubDataEXT(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *data);
+AL_API ALvoid AL_APIENTRY alGetDatabufferSubDataEXT(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *data);
+AL_API ALvoid AL_APIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues);
+AL_API ALvoid AL_APIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue);
+AL_API ALvoid AL_APIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues);
+AL_API ALvoid AL_APIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues);
+AL_API ALvoid AL_APIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue);
+AL_API ALvoid AL_APIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues);
+AL_API ALvoid AL_APIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer);
+AL_API ALvoid* AL_APIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access);
+AL_API ALvoid AL_APIENTRY alUnmapDatabufferEXT(ALuint uiBuffer);
+#endif
+#endif
+
+
+#if defined(HAVE_STDINT_H)
+#include <stdint.h>
+typedef int64_t ALint64;
+typedef uint64_t ALuint64;
+#elif defined(HAVE___INT64)
+typedef __int64 ALint64;
+typedef unsigned __int64 ALuint64;
+#elif (SIZEOF_LONG == 8)
+typedef long ALint64;
+typedef unsigned long ALuint64;
+#elif (SIZEOF_LONG_LONG == 8)
+typedef long long ALint64;
+typedef unsigned long long ALuint64;
+#endif
+
+#ifdef HAVE_GCC_FORMAT
+#define PRINTF_STYLE(x, y) __attribute__((format(printf, (x), (y))))
+#else
+#define PRINTF_STYLE(x, y)
+#endif
+
+#ifdef _WIN32
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <windows.h>
+
+typedef DWORD tls_type;
+#define tls_create(x) (*(x) = TlsAlloc())
+#define tls_delete(x) TlsFree((x))
+#define tls_get(x) TlsGetValue((x))
+#define tls_set(x, a) TlsSetValue((x), (a))
+
+#else
+
+#include <unistd.h>
+#include <assert.h>
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#define IsBadWritePtr(a,b) ((a) == NULL && (b) != 0)
+
+typedef pthread_key_t tls_type;
+#define tls_create(x) pthread_key_create((x), NULL)
+#define tls_delete(x) pthread_key_delete((x))
+#define tls_get(x) pthread_getspecific((x))
+#define tls_set(x, a) pthread_setspecific((x), (a))
+
+typedef pthread_mutex_t CRITICAL_SECTION;
+static __inline void EnterCriticalSection(CRITICAL_SECTION *cs)
+{
+ int ret;
+ ret = pthread_mutex_lock(cs);
+ assert(ret == 0);
+}
+static __inline void LeaveCriticalSection(CRITICAL_SECTION *cs)
+{
+ int ret;
+ ret = pthread_mutex_unlock(cs);
+ assert(ret == 0);
+}
+static __inline void InitializeCriticalSection(CRITICAL_SECTION *cs)
+{
+ pthread_mutexattr_t attrib;
+ int ret;
+
+ ret = pthread_mutexattr_init(&attrib);
+ assert(ret == 0);
+
+ ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE);
+#ifdef HAVE_PTHREAD_NP_H
+ if(ret != 0)
+ ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE);
+#endif
+ assert(ret == 0);
+ ret = pthread_mutex_init(cs, &attrib);
+ assert(ret == 0);
+
+ pthread_mutexattr_destroy(&attrib);
+}
+
+static __inline void DeleteCriticalSection(CRITICAL_SECTION *cs)
+{
+ int ret;
+ ret = pthread_mutex_destroy(cs);
+ assert(ret == 0);
+}
+
+/* NOTE: This wrapper isn't quite accurate as it returns an ALuint, as opposed
+ * to the expected DWORD. Both are defined as unsigned 32-bit types, however.
+ * Additionally, Win32 is supposed to measure the time since Windows started,
+ * as opposed to the actual time. */
+static __inline ALuint timeGetTime(void)
+{
+#if _POSIX_TIMERS > 0
+ struct timespec ts;
+ int ret = -1;
+
+#if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
+#if _POSIX_MONOTONIC_CLOCK == 0
+ static int hasmono = 0;
+ if(hasmono > 0 || (hasmono == 0 &&
+ (hasmono=sysconf(_SC_MONOTONIC_CLOCK)) > 0))
+#endif
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
+ if(ret != 0)
+ ret = clock_gettime(CLOCK_REALTIME, &ts);
+ assert(ret == 0);
+
+ return ts.tv_nsec/1000000 + ts.tv_sec*1000;
+#else
+ struct timeval tv;
+ int ret;
+
+ ret = gettimeofday(&tv, NULL);
+ assert(ret == 0);
+
+ return tv.tv_usec/1000 + tv.tv_sec*1000;
+#endif
+}
+
+static __inline void Sleep(ALuint t)
+{
+ struct timespec tv, rem;
+ tv.tv_nsec = (t*1000000)%1000000000;
+ tv.tv_sec = t/1000;
+
+ while(nanosleep(&tv, &rem) == -1 && errno == EINTR)
+ tv = rem;
+}
+#define min(x,y) (((x)<(y))?(x):(y))
+#define max(x,y) (((x)>(y))?(x):(y))
+#endif
+
+#include "alListener.h"
+#include "alu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SWMIXER_OUTPUT_RATE 44100
+
+#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
+#define AIRABSORBGAINDBHF (-0.05f)
+
+#define LOWPASSFREQCUTOFF (5000)
+
+#define DEFAULT_HEAD_DAMPEN (0.25f)
+
+
+// Find the next power-of-2 for non-power-of-2 numbers.
+static __inline ALuint NextPowerOf2(ALuint value)
+{
+ ALuint powerOf2 = 1;
+
+ if(value)
+ {
+ value--;
+ while(value)
+ {
+ value >>= 1;
+ powerOf2 <<= 1;
+ }
+ }
+ return powerOf2;
+}
+
+
+typedef struct {
+ ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*);
+ void (*ClosePlayback)(ALCdevice*);
+ ALCboolean (*ResetPlayback)(ALCdevice*);
+ void (*StopPlayback)(ALCdevice*);
+
+ ALCboolean (*OpenCapture)(ALCdevice*, const ALCchar*);
+ void (*CloseCapture)(ALCdevice*);
+ void (*StartCapture)(ALCdevice*);
+ void (*StopCapture)(ALCdevice*);
+ void (*CaptureSamples)(ALCdevice*, void*, ALCuint);
+ ALCuint (*AvailableSamples)(ALCdevice*);
+} BackendFuncs;
+
+enum {
+ DEVICE_PROBE,
+ ALL_DEVICE_PROBE,
+ CAPTURE_DEVICE_PROBE
+};
+
+void alc_alsa_init(BackendFuncs *func_list);
+void alc_alsa_deinit(void);
+void alc_alsa_probe(int type);
+void alc_oss_init(BackendFuncs *func_list);
+void alc_oss_deinit(void);
+void alc_oss_probe(int type);
+void alc_solaris_init(BackendFuncs *func_list);
+void alc_solaris_deinit(void);
+void alc_solaris_probe(int type);
+void alcDSoundInit(BackendFuncs *func_list);
+void alcDSoundDeinit(void);
+void alcDSoundProbe(int type);
+void alcWinMMInit(BackendFuncs *FuncList);
+void alcWinMMDeinit(void);
+void alcWinMMProbe(int type);
+void alc_pa_init(BackendFuncs *func_list);
+void alc_pa_deinit(void);
+void alc_pa_probe(int type);
+void alc_wave_init(BackendFuncs *func_list);
+void alc_wave_deinit(void);
+void alc_wave_probe(int type);
+void alc_pulse_init(BackendFuncs *func_list);
+void alc_pulse_deinit(void);
+void alc_pulse_probe(int type);
+void alc_null_init(BackendFuncs *func_list);
+void alc_null_deinit(void);
+void alc_null_probe(int type);
+
+/*- * avsystem porting- */
+void alc_avsystem_init(BackendFuncs *func_list);
+void alc_avsystem_deinit(void);
+void alc_avsystem_probe(int type);
+
+
+typedef struct UIntMap {
+ struct {
+ ALuint key;
+ ALvoid *value;
+ } *array;
+ ALsizei size;
+ ALsizei maxsize;
+} UIntMap;
+
+void InitUIntMap(UIntMap *map);
+void ResetUIntMap(UIntMap *map);
+ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
+void RemoveUIntMapKey(UIntMap *map, ALuint key);
+ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
+
+/* Device formats */
+enum DevFmtType {
+ DevFmtByte, /* AL_BYTE */
+ DevFmtUByte, /* AL_UNSIGNED_BYTE */
+ DevFmtShort, /* AL_SHORT */
+ DevFmtUShort, /* AL_UNSIGNED_SHORT */
+ DevFmtFloat, /* AL_FLOAT */
+};
+enum DevFmtChannels {
+ DevFmtMono, /* AL_MONO */
+ DevFmtStereo, /* AL_STEREO */
+ DevFmtQuad, /* AL_QUAD */
+ DevFmtX51, /* AL_5POINT1 */
+ DevFmtX61, /* AL_6POINT1 */
+ DevFmtX71, /* AL_7POINT1 */
+};
+
+ALuint BytesFromDevFmt(enum DevFmtType type);
+ALuint ChannelsFromDevFmt(enum DevFmtChannels chans);
+static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans,
+ enum DevFmtType type)
+{
+ return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type);
+}
+
+
+struct ALCdevice_struct
+{
+ ALCboolean Connected;
+ ALboolean IsCaptureDevice;
+
+ ALuint Frequency;
+ ALuint UpdateSize;
+ ALuint NumUpdates;
+ enum DevFmtChannels FmtChans;
+ enum DevFmtType FmtType;
+
+ ALCchar *szDeviceName;
+
+ ALCenum LastError;
+
+ // Maximum number of sources that can be created
+ ALuint MaxNoOfSources;
+ // Maximum number of slots that can be created
+ ALuint AuxiliaryEffectSlotMax;
+
+ ALCuint NumMonoSources;
+ ALCuint NumStereoSources;
+ ALuint NumAuxSends;
+
+ // Map of Buffers for this device
+ UIntMap BufferMap;
+
+ // Map of Effects for this device
+ UIntMap EffectMap;
+
+ // Map of Filters for this device
+ UIntMap FilterMap;
+
+ // Map of Databuffers for this device
+ UIntMap DatabufferMap;
+
+ // Stereo-to-binaural filter
+ struct bs2b *Bs2b;
+ ALCint Bs2bLevel;
+
+ // Simulated dampening from head occlusion
+ ALfloat HeadDampen;
+
+ // Duplicate stereo sources on the side/rear channels
+ ALboolean DuplicateStereo;
+
+ // Dry path buffer mix
+ ALfloat DryBuffer[BUFFERSIZE][MAXCHANNELS];
+
+ ALuint DevChannels[MAXCHANNELS];
+
+ ALfloat ChannelMatrix[MAXCHANNELS][MAXCHANNELS];
+
+ Channel Speaker2Chan[MAXCHANNELS];
+ ALfloat PanningLUT[MAXCHANNELS * LUT_NUM];
+ ALuint NumChan;
+
+ ALfloat ClickRemoval[MAXCHANNELS];
+ ALfloat PendingClicks[MAXCHANNELS];
+
+ // Contexts created on this device
+ ALCcontext **Contexts;
+ ALuint NumContexts;
+
+ BackendFuncs *Funcs;
+ void *ExtraData; // For the backend's use
+
+ ALCdevice *next;
+};
+
+#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b)))
+#define ALCdevice_ClosePlayback(a) ((a)->Funcs->ClosePlayback((a)))
+#define ALCdevice_ResetPlayback(a) ((a)->Funcs->ResetPlayback((a)))
+#define ALCdevice_StopPlayback(a) ((a)->Funcs->StopPlayback((a)))
+#define ALCdevice_OpenCapture(a,b) ((a)->Funcs->OpenCapture((a), (b)))
+#define ALCdevice_CloseCapture(a) ((a)->Funcs->CloseCapture((a)))
+#define ALCdevice_StartCapture(a) ((a)->Funcs->StartCapture((a)))
+#define ALCdevice_StopCapture(a) ((a)->Funcs->StopCapture((a)))
+#define ALCdevice_CaptureSamples(a,b,c) ((a)->Funcs->CaptureSamples((a), (b), (c)))
+#define ALCdevice_AvailableSamples(a) ((a)->Funcs->AvailableSamples((a)))
+
+struct ALCcontext_struct
+{
+ ALlistener Listener;
+
+ UIntMap SourceMap;
+ UIntMap EffectSlotMap;
+
+ struct ALdatabuffer *SampleSource;
+ struct ALdatabuffer *SampleSink;
+
+ ALenum LastError;
+
+ ALboolean Suspended;
+
+ ALenum DistanceModel;
+ ALboolean SourceDistanceModel;
+
+ ALfloat DopplerFactor;
+ ALfloat DopplerVelocity;
+ ALfloat flSpeedOfSound;
+
+ struct ALsource **ActiveSources;
+ ALsizei ActiveSourceCount;
+ ALsizei MaxActiveSources;
+
+ ALCdevice *Device;
+ const ALCchar *ExtensionList;
+
+ ALCcontext *next;
+};
+
+void AppendDeviceList(const ALCchar *name);
+void AppendAllDeviceList(const ALCchar *name);
+void AppendCaptureDeviceList(const ALCchar *name);
+
+ALCvoid alcSetError(ALCdevice *device, ALenum errorCode);
+
+ALCvoid SuspendContext(ALCcontext *context);
+ALCvoid ProcessContext(ALCcontext *context);
+
+ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr);
+ALuint StopThread(ALvoid *thread);
+
+ALCcontext *GetContextSuspended(void);
+
+typedef struct RingBuffer RingBuffer;
+RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length);
+void DestroyRingBuffer(RingBuffer *ring);
+ALsizei RingBufferSize(RingBuffer *ring);
+void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len);
+void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len);
+
+void ReadALConfig(void);
+void FreeALConfig(void);
+int ConfigValueExists(const char *blockName, const char *keyName);
+const char *GetConfigValue(const char *blockName, const char *keyName, const char *def);
+int GetConfigValueInt(const char *blockName, const char *keyName, int def);
+float GetConfigValueFloat(const char *blockName, const char *keyName, float def);
+int GetConfigValueBool(const char *blockName, const char *keyName, int def);
+
+void SetRTPriority(void);
+
+void SetDefaultChannelOrder(ALCdevice *device);
+void SetDefaultWFXChannelOrder(ALCdevice *device);
+
+void al_print(const char *fname, unsigned int line, const char *fmt, ...)
+ PRINTF_STYLE(3,4);
+#define AL_PRINT(...) al_print(__FILE__, __LINE__, __VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_SOURCE_H_
+#define _AL_SOURCE_H_
+
+#define MAX_SENDS 4
+
+#include "alFilter.h"
+#include "alu.h"
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ POINT_RESAMPLER = 0,
+ LINEAR_RESAMPLER,
+ CUBIC_RESAMPLER,
+
+ RESAMPLER_MAX,
+ RESAMPLER_MIN = -1,
+ RESAMPLER_DEFAULT = LINEAR_RESAMPLER
+} resampler_t;
+extern resampler_t DefaultResampler;
+
+extern const ALsizei ResamplerPadding[RESAMPLER_MAX];
+extern const ALsizei ResamplerPrePadding[RESAMPLER_MAX];
+
+
+typedef struct ALbufferlistitem
+{
+ struct ALbuffer *buffer;
+ struct ALbufferlistitem *next;
+ struct ALbufferlistitem *prev;
+} ALbufferlistitem;
+
+typedef struct ALsource
+{
+ ALfloat flPitch;
+ ALfloat flGain;
+ ALfloat flOuterGain;
+ ALfloat flMinGain;
+ ALfloat flMaxGain;
+ ALfloat flInnerAngle;
+ ALfloat flOuterAngle;
+ ALfloat flRefDistance;
+ ALfloat flMaxDistance;
+ ALfloat flRollOffFactor;
+ ALfloat vPosition[3];
+ ALfloat vVelocity[3];
+ ALfloat vOrientation[3];
+ ALboolean bHeadRelative;
+ ALboolean bLooping;
+ ALenum DistanceModel;
+
+ resampler_t Resampler;
+
+ ALenum state;
+ ALuint position;
+ ALuint position_fraction;
+
+ struct ALbuffer *Buffer;
+
+ ALbufferlistitem *queue; // Linked list of buffers in queue
+ ALuint BuffersInQueue; // Number of buffers in queue
+ ALuint BuffersPlayed; // Number of buffers played on this loop
+
+ ALfilter DirectFilter;
+
+ struct {
+ struct ALeffectslot *Slot;
+ ALfilter WetFilter;
+ } Send[MAX_SENDS];
+
+ ALboolean DryGainHFAuto;
+ ALboolean WetGainAuto;
+ ALboolean WetGainHFAuto;
+ ALfloat OuterGainHF;
+
+ ALfloat AirAbsorptionFactor;
+ ALfloat RoomRolloffFactor;
+ ALfloat DopplerFactor;
+
+ ALint lOffset;
+ ALint lOffsetType;
+
+ // Source Type (Static, Streaming, or Undetermined)
+ ALint lSourceType;
+
+ // Current target parameters used for mixing
+ ALboolean NeedsUpdate;
+ struct {
+ ALint Step;
+
+ /* A mixing matrix. First subscript is the channel number of the input
+ * data (regardless of channel configuration) and the second is the
+ * channel target (eg. FRONT_LEFT) */
+ ALfloat DryGains[MAXCHANNELS][MAXCHANNELS];
+ FILTER iirFilter;
+ ALfloat history[MAXCHANNELS*2];
+
+ struct {
+ ALfloat WetGain;
+ FILTER iirFilter;
+ ALfloat history[MAXCHANNELS];
+ } Send[MAX_SENDS];
+ } Params;
+
+ ALvoid (*Update)(struct ALsource *self, const ALCcontext *context);
+
+ // Index to itself
+ ALuint source;
+} ALsource;
+#define ALsource_Update(s,a) ((s)->Update(s,a))
+
+ALvoid ReleaseALSources(ALCcontext *Context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_STATE_H_
+#define _AL_STATE_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+#ifndef _AL_THUNK_H_
+#define _AL_THUNK_H_
+
+#include "config.h"
+
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void alThunkInit(void);
+void alThunkExit(void);
+ALuint alThunkAddEntry(ALvoid *ptr);
+void alThunkRemoveEntry(ALuint index);
+ALvoid *alThunkLookupEntry(ALuint index);
+
+#if (SIZEOF_VOIDP > SIZEOF_UINT)
+
+#define ALTHUNK_INIT() alThunkInit()
+#define ALTHUNK_EXIT() alThunkExit()
+#define ALTHUNK_ADDENTRY(p) alThunkAddEntry(p)
+#define ALTHUNK_REMOVEENTRY(i) alThunkRemoveEntry(i)
+#define ALTHUNK_LOOKUPENTRY(i) alThunkLookupEntry(i)
+
+#else
+
+#define ALTHUNK_INIT()
+#define ALTHUNK_EXIT()
+#define ALTHUNK_ADDENTRY(p) ((ALuint)p)
+#define ALTHUNK_REMOVEENTRY(i) ((ALvoid)i)
+#define ALTHUNK_LOOKUPENTRY(i) ((ALvoid*)(i))
+
+#endif // (SIZEOF_VOIDP > SIZEOF_INT)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_AL_THUNK_H_
+
--- /dev/null
+#ifndef _ALU_H_
+#define _ALU_H_
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include <limits.h>
+#include <math.h>
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 /* pi */
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#endif
+
+#ifdef HAVE_POWF
+#define aluPow(x,y) ((ALfloat)powf((float)(x),(float)(y)))
+#else
+#define aluPow(x,y) ((ALfloat)pow((double)(x),(double)(y)))
+#endif
+
+#ifdef HAVE_SQRTF
+#define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
+#else
+#define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
+#endif
+
+#ifdef HAVE_ACOSF
+#define aluAcos(x) ((ALfloat)acosf((float)(x)))
+#else
+#define aluAcos(x) ((ALfloat)acos((double)(x)))
+#endif
+
+#ifdef HAVE_ATANF
+#define aluAtan(x) ((ALfloat)atanf((float)(x)))
+#else
+#define aluAtan(x) ((ALfloat)atan((double)(x)))
+#endif
+
+#ifdef HAVE_FABSF
+#define aluFabs(x) ((ALfloat)fabsf((float)(x)))
+#else
+#define aluFabs(x) ((ALfloat)fabs((double)(x)))
+#endif
+
+// fixes for mingw32.
+#if defined(max) && !defined(__max)
+#define __max max
+#endif
+#if defined(min) && !defined(__min)
+#define __min min
+#endif
+
+#define QUADRANT_NUM 128
+#define LUT_NUM (4 * QUADRANT_NUM)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ FRONT_LEFT = 0,
+ FRONT_RIGHT,
+ FRONT_CENTER,
+ LFE,
+ BACK_LEFT,
+ BACK_RIGHT,
+ BACK_CENTER,
+ SIDE_LEFT,
+ SIDE_RIGHT,
+
+ MAXCHANNELS
+} Channel;
+
+#define BUFFERSIZE 4096
+
+#define FRACTIONBITS (14)
+#define FRACTIONONE (1<<FRACTIONBITS)
+#define FRACTIONMASK (FRACTIONONE-1)
+
+/* Size for temporary stack storage of buffer data. Larger values need more
+ * stack, while smaller values may need more iterations. The value needs to be
+ * a sensible size, however, as it constrains the max stepping value used for
+ * mixing.
+ * The mixer requires being able to do two samplings per mixing loop. A 16KB
+ * buffer can hold 512 sample frames for a 7.1 float buffer. With the cubic
+ * resampler (which requires 3 padding sample frames), this limits the maximum
+ * step to about 508. This means that buffer_freq*source_pitch cannot exceed
+ * device_freq*508 for an 8-channel 32-bit buffer. */
+#ifndef STACK_DATA_SIZE
+#define STACK_DATA_SIZE 16384
+#endif
+
+
+static __inline ALdouble lerp(ALdouble val1, ALdouble val2, ALdouble mu)
+{
+ return val1 + (val2-val1)*mu;
+}
+static __inline ALdouble cubic(ALdouble val0, ALdouble val1, ALdouble val2, ALdouble val3, ALdouble mu)
+{
+ ALdouble mu2 = mu*mu;
+ ALdouble a0 = -0.5*val0 + 1.5*val1 + -1.5*val2 + 0.5*val3;
+ ALdouble a1 = val0 + -2.5*val1 + 2.0*val2 + -0.5*val3;
+ ALdouble a2 = -0.5*val0 + 0.5*val2;
+ ALdouble a3 = val1;
+
+ return a0*mu*mu2 + a1*mu2 + a2*mu + a3;
+}
+
+struct ALsource;
+
+ALvoid aluInitPanning(ALCdevice *Device);
+ALint aluCart2LUTpos(ALfloat re, ALfloat im);
+
+ALvoid CalcSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
+ALvoid CalcNonAttnSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
+
+ALvoid MixSource(struct ALsource *Source, ALCdevice *Device, ALuint SamplesToDo);
+
+ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
+ALvoid aluHandleDisconnect(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+/*-
+ * Copyright (c) 2005 Boris Mikhaylov
+ *
+ * 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.
+ */
+
+#ifndef BS2B_H
+#define BS2B_H
+
+/* Number of crossfeed levels */
+#define BS2B_CLEVELS 3
+
+/* Normal crossfeed levels */
+#define BS2B_HIGH_CLEVEL 3
+#define BS2B_MIDDLE_CLEVEL 2
+#define BS2B_LOW_CLEVEL 1
+
+/* Easy crossfeed levels */
+#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS
+#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS
+#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS
+
+/* Default crossfeed levels */
+#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL
+/* Default sample rate (Hz) */
+#define BS2B_DEFAULT_SRATE 44100
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct bs2b {
+ int level; /* Crossfeed level */
+ int srate; /* Sample rate (Hz) */
+
+ /* Lowpass IIR filter coefficients */
+ double a0_lo;
+ double b1_lo;
+
+ /* Highboost IIR filter coefficients */
+ double a0_hi;
+ double a1_hi;
+ double b1_hi;
+
+ /* Global gain against overloading */
+ double gain;
+
+ /* Buffer of last filtered sample.
+ * [0] - first channel, [1] - second channel
+ */
+ struct t_last_sample {
+ double asis[2];
+ double lo[2];
+ double hi[2];
+ } last_sample;
+};
+
+/* Clear buffers and set new coefficients with new crossfeed level value.
+ * level - crossfeed level of *LEVEL values.
+ */
+void bs2b_set_level(struct bs2b *bs2b, int level);
+
+/* Return current crossfeed level value */
+int bs2b_get_level(struct bs2b *bs2b);
+
+/* Clear buffers and set new coefficients with new sample rate value.
+ * srate - sample rate by Hz.
+ */
+void bs2b_set_srate(struct bs2b *bs2b, int srate);
+
+/* Return current sample rate value */
+int bs2b_get_srate(struct bs2b *bs2b);
+
+/* Clear buffer */
+void bs2b_clear(struct bs2b *bs2b);
+
+/* Return 1 if buffer is clear */
+int bs2b_is_clear(struct bs2b *bs2b);
+
+/* Crossfeeds one stereo sample that are pointed by sample.
+ * [0] - first channel, [1] - second channel.
+ * Returns crossfided samle by sample pointer.
+ */
+
+/* sample poits to floats */
+void bs2b_cross_feed(struct bs2b *bs2b, float *sample);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* BS2B_H */
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+#include "alThunk.h"
+#include "alError.h"
+#include "alSource.h"
+
+
+static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
+
+#define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
+#define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if(n < 0 || IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
+ alSetError(Context, AL_INVALID_VALUE);
+ else if((ALuint)n > Device->AuxiliaryEffectSlotMax - Context->EffectSlotMap.size)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ ALenum err;
+ ALsizei i, j;
+
+ i = 0;
+ while(i < n)
+ {
+ ALeffectslot *slot = calloc(1, sizeof(ALeffectslot));
+ if(!slot || !(slot->EffectState=NoneCreate()))
+ {
+ free(slot);
+ // We must have run out or memory
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ alDeleteAuxiliaryEffectSlots(i, effectslots);
+ break;
+ }
+
+ slot->effectslot = (ALuint)ALTHUNK_ADDENTRY(slot);
+ err = InsertUIntMapEntry(&Context->EffectSlotMap,
+ slot->effectslot, slot);
+ if(err != AL_NO_ERROR)
+ {
+ ALTHUNK_REMOVEENTRY(slot->effectslot);
+ ALEffect_Destroy(slot->EffectState);
+ free(slot);
+
+ alSetError(Context, err);
+ alDeleteAuxiliaryEffectSlots(i, effectslots);
+ break;
+ }
+
+ effectslots[i++] = slot->effectslot;
+
+ slot->Gain = 1.0;
+ slot->AuxSendAuto = AL_TRUE;
+ for(j = 0;j < BUFFERSIZE;j++)
+ slot->WetBuffer[j] = 0.0f;
+ for(j = 0;j < 1;j++)
+ {
+ slot->ClickRemoval[j] = 0.0f;
+ slot->PendingClicks[j] = 0.0f;
+ }
+ slot->refcount = 0;
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
+{
+ ALCcontext *Context;
+ ALeffectslot *EffectSlot;
+ ALboolean SlotsValid = AL_FALSE;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ SlotsValid = AL_TRUE;
+ // Check that all effectslots are valid
+ for(i = 0;i < n;i++)
+ {
+ if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ SlotsValid = AL_FALSE;
+ break;
+ }
+ else if(EffectSlot->refcount > 0)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ SlotsValid = AL_FALSE;
+ break;
+ }
+ }
+ }
+
+ if(SlotsValid)
+ {
+ // All effectslots are valid
+ for(i = 0;i < n;i++)
+ {
+ // Recheck that the effectslot is valid, because there could be duplicated names
+ if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL)
+ continue;
+
+ ALEffect_Destroy(EffectSlot->EffectState);
+
+ RemoveUIntMapKey(&Context->EffectSlotMap, EffectSlot->effectslot);
+ ALTHUNK_REMOVEENTRY(EffectSlot->effectslot);
+
+ memset(EffectSlot, 0, sizeof(ALeffectslot));
+ free(EffectSlot);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
+{
+ ALCcontext *Context;
+ ALboolean result;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ result = (LookupEffectSlot(Context->EffectSlotMap, effectslot) ?
+ AL_TRUE : AL_FALSE);
+
+ ProcessContext(Context);
+
+ return result;
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
+{
+ ALCdevice *Device;
+ ALCcontext *Context;
+ ALboolean updateSources = AL_FALSE;
+ ALeffectslot *EffectSlot;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_EFFECT: {
+ ALeffect *effect = NULL;
+
+ if(iValue == 0 ||
+ (effect=LookupEffect(Device->EffectMap, iValue)) != NULL)
+ {
+ InitializeEffect(Context, EffectSlot, effect);
+ updateSources = AL_TRUE;
+ }
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ } break;
+
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ if(iValue == AL_TRUE || iValue == AL_FALSE)
+ {
+ EffectSlot->AuxSendAuto = iValue;
+ updateSources = AL_TRUE;
+ }
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ // Force updating the sources that use this slot, since it affects the
+ // sending parameters
+ if(updateSources)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ ALsource *source = Context->SourceMap.array[pos].value;
+ ALuint i;
+ for(i = 0;i < Device->NumAuxSends;i++)
+ {
+ if(!source->Send[i].Slot ||
+ source->Send[i].Slot->effectslot != effectslot)
+ continue;
+ source->NeedsUpdate = AL_TRUE;
+ break;
+ }
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_EFFECT:
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
+{
+ ALCcontext *Context;
+ ALeffectslot *EffectSlot;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_GAIN:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ EffectSlot->Gain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_GAIN:
+ alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
+{
+ ALCcontext *Context;
+ ALeffectslot *EffectSlot;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_EFFECT:
+ *piValue = EffectSlot->effect.effect;
+ break;
+
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ *piValue = EffectSlot->AuxSendAuto;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_EFFECT:
+ case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+ alGetAuxiliaryEffectSloti(effectslot, param, piValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
+{
+ ALCcontext *Context;
+ ALeffectslot *EffectSlot;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_GAIN:
+ *pflValue = EffectSlot->Gain;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_GAIN:
+ alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+
+static ALvoid NoneDestroy(ALeffectState *State)
+{ free(State); }
+static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
+{
+ return AL_TRUE;
+ (void)State;
+ (void)Device;
+}
+static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect)
+{
+ (void)State;
+ (void)Context;
+ (void)Effect;
+}
+static ALvoid NoneProcess(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+ (void)State;
+ (void)Slot;
+ (void)SamplesToDo;
+ (void)SamplesIn;
+ (void)SamplesOut;
+}
+ALeffectState *NoneCreate(void)
+{
+ ALeffectState *state;
+
+ state = calloc(1, sizeof(*state));
+ if(!state)
+ return NULL;
+
+ state->Destroy = NoneDestroy;
+ state->DeviceUpdate = NoneDeviceUpdate;
+ state->Update = NoneUpdate;
+ state->Process = NoneProcess;
+
+ return state;
+}
+
+static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
+{
+ if(EffectSlot->effect.type != (effect?effect->type:AL_EFFECT_NULL))
+ {
+ ALeffectState *NewState = NULL;
+ if(!effect || effect->type == AL_EFFECT_NULL)
+ NewState = NoneCreate();
+ else if(effect->type == AL_EFFECT_EAXREVERB)
+ NewState = EAXVerbCreate();
+ else if(effect->type == AL_EFFECT_REVERB)
+ NewState = VerbCreate();
+ else if(effect->type == AL_EFFECT_ECHO)
+ NewState = EchoCreate();
+ else if(effect->type == AL_EFFECT_RING_MODULATOR)
+ NewState = ModulatorCreate();
+ /* No new state? An error occured.. */
+ if(NewState == NULL ||
+ ALEffect_DeviceUpdate(NewState, Context->Device) == AL_FALSE)
+ {
+ if(NewState)
+ ALEffect_Destroy(NewState);
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ return;
+ }
+ if(EffectSlot->EffectState)
+ ALEffect_Destroy(EffectSlot->EffectState);
+ EffectSlot->EffectState = NewState;
+ }
+ if(!effect)
+ memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
+ else
+ memcpy(&EffectSlot->effect, effect, sizeof(*effect));
+ ALEffect_Update(EffectSlot->EffectState, Context, effect);
+}
+
+
+ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
+{
+ ALsizei pos;
+ for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
+ {
+ ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
+ Context->EffectSlotMap.array[pos].value = NULL;
+
+ // Release effectslot structure
+ ALEffect_Destroy(temp->EffectState);
+
+ ALTHUNK_REMOVEENTRY(temp->effectslot);
+ memset(temp, 0, sizeof(ALeffectslot));
+ free(temp);
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alError.h"
+#include "alBuffer.h"
+#include "alDatabuffer.h"
+#include "alThunk.h"
+
+
+static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei size, enum UserFmtChannels chans, enum UserFmtType type, const ALvoid *data);
+static void ConvertData(ALvoid *dst, enum FmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei len);
+static void ConvertDataIMA4(ALvoid *dst, enum FmtType dstType, const ALvoid *src, ALint chans, ALsizei len);
+
+#define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
+
+
+/*
+ * Global Variables
+ */
+
+/* IMA ADPCM Stepsize table */
+static const long IMAStep_size[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19,
+ 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
+ 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157,
+ 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
+ 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
+ 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660,
+ 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,
+ 11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794,
+ 32767
+};
+
+/* IMA4 ADPCM Codeword decode table */
+static const long IMA4Codeword[16] = {
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ -1,-3,-5,-7,-9,-11,-13,-15,
+};
+
+/* IMA4 ADPCM Step index adjust decode table */
+static const long IMA4Index_adjust[16] = {
+ -1,-1,-1,-1, 2, 4, 6, 8,
+ -1,-1,-1,-1, 2, 4, 6, 8
+};
+
+/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
+ * signed 16-bit sample */
+static const ALshort muLawDecompressionTable[256] = {
+ -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
+ -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
+ -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
+ -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
+ -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+ -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+ -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+ -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+ -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+ -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
+ -876, -844, -812, -780, -748, -716, -684, -652,
+ -620, -588, -556, -524, -492, -460, -428, -396,
+ -372, -356, -340, -324, -308, -292, -276, -260,
+ -244, -228, -212, -196, -180, -164, -148, -132,
+ -120, -112, -104, -96, -88, -80, -72, -64,
+ -56, -48, -40, -32, -24, -16, -8, 0,
+ 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+ 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+ 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+ 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
+ 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
+ 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
+ 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
+ 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
+ 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
+ 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
+ 876, 844, 812, 780, 748, 716, 684, 652,
+ 620, 588, 556, 524, 492, 460, 428, 396,
+ 372, 356, 340, 324, 308, 292, 276, 260,
+ 244, 228, 212, 196, 180, 164, 148, 132,
+ 120, 112, 104, 96, 88, 80, 72, 64,
+ 56, 48, 40, 32, 24, 16, 8, 0
+};
+
+/* Values used when encoding a muLaw sample */
+static const int muLawBias = 0x84;
+static const int muLawClip = 32635;
+static const char muLawCompressTable[256] =
+{
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+/*
+ * alGenBuffers(ALsizei n, ALuint *buffers)
+ *
+ * Generates n AL Buffers, and stores the Buffers Names in the array pointed
+ * to by buffers
+ */
+AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
+{
+ ALCcontext *Context;
+ ALsizei i=0;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ /* Check that we are actually generating some Buffers */
+ if(n < 0 || IsBadWritePtr((void*)buffers, n * sizeof(ALuint)))
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ ALCdevice *device = Context->Device;
+ ALenum err;
+
+ // Create all the new Buffers
+ while(i < n)
+ {
+ ALbuffer *buffer = calloc(1, sizeof(ALbuffer));
+ if(!buffer)
+ {
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ alDeleteBuffers(i, buffers);
+ break;
+ }
+
+ buffer->buffer = (ALuint)ALTHUNK_ADDENTRY(buffer);
+ err = InsertUIntMapEntry(&device->BufferMap, buffer->buffer, buffer);
+ if(err != AL_NO_ERROR)
+ {
+ ALTHUNK_REMOVEENTRY(buffer->buffer);
+ memset(buffer, 0, sizeof(ALbuffer));
+ free(buffer);
+
+ alSetError(Context, err);
+ alDeleteBuffers(i, buffers);
+ break;
+ }
+ buffers[i++] = buffer->buffer;
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+/*
+ * alDeleteBuffers(ALsizei n, ALuint *buffers)
+ *
+ * Deletes the n AL Buffers pointed to by buffers
+ */
+AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
+{
+ ALCcontext *Context;
+ ALCdevice *device;
+ ALboolean Failed;
+ ALbuffer *ALBuf;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Failed = AL_TRUE;
+ device = Context->Device;
+ /* Check we are actually Deleting some Buffers */
+ if(n < 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ Failed = AL_FALSE;
+
+ /* Check that all the buffers are valid and can actually be deleted */
+ for(i = 0;i < n;i++)
+ {
+ if(!buffers[i])
+ continue;
+
+ /* Check for valid Buffer ID */
+ if((ALBuf=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ Failed = AL_TRUE;
+ break;
+ }
+ else if(ALBuf->refcount != 0)
+ {
+ /* Buffer still in use, cannot be deleted */
+ alSetError(Context, AL_INVALID_OPERATION);
+ Failed = AL_TRUE;
+ break;
+ }
+ }
+ }
+
+ /* If all the Buffers were valid (and have Reference Counts of 0), then we
+ * can delete them */
+ if(!Failed)
+ {
+ for(i = 0;i < n;i++)
+ {
+ if((ALBuf=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
+ continue;
+
+ /* Release the memory used to store audio data */
+ free(ALBuf->data);
+
+ /* Release buffer structure */
+ RemoveUIntMapKey(&device->BufferMap, ALBuf->buffer);
+ ALTHUNK_REMOVEENTRY(ALBuf->buffer);
+
+ memset(ALBuf, 0, sizeof(ALbuffer));
+ free(ALBuf);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+/*
+ * alIsBuffer(ALuint buffer)
+ *
+ * Checks if buffer is a valid Buffer Name
+ */
+AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
+{
+ ALCcontext *Context;
+ ALboolean result;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ result = ((!buffer || LookupBuffer(Context->Device->BufferMap, buffer)) ?
+ AL_TRUE : AL_FALSE);
+
+ ProcessContext(Context);
+
+ return result;
+}
+
+/*
+ * alBufferData(ALuint buffer, ALenum format, const ALvoid *data,
+ * ALsizei size, ALsizei freq)
+ *
+ * Fill buffer with audio data
+ */
+AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *data,ALsizei size,ALsizei freq)
+{
+ enum UserFmtChannels SrcChannels;
+ enum UserFmtType SrcType;
+ ALCcontext *Context;
+ ALCdevice *device;
+ ALbuffer *ALBuf;
+ ALenum err;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(Context->SampleSource)
+ {
+ ALintptrEXT offset;
+
+ if(Context->SampleSource->state == MAPPED)
+ {
+ alSetError(Context, AL_INVALID_OPERATION);
+ ProcessContext(Context);
+ return;
+ }
+
+ offset = (const ALubyte*)data - (ALubyte*)NULL;
+ data = Context->SampleSource->data + offset;
+ }
+
+ device = Context->Device;
+ if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+ alSetError(Context, AL_INVALID_NAME);
+ else if(ALBuf->refcount != 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else if(size < 0 || freq < 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE)
+ alSetError(Context, AL_INVALID_ENUM);
+ else switch(SrcType)
+ {
+ case UserFmtByte:
+ case UserFmtUByte:
+ case UserFmtShort:
+ case UserFmtUShort:
+ case UserFmtInt:
+ case UserFmtUInt:
+ case UserFmtFloat:
+ err = LoadData(ALBuf, freq, format, size, SrcChannels, SrcType, data);
+ if(err != AL_NO_ERROR)
+ alSetError(Context, err);
+ break;
+
+ case UserFmtDouble: {
+ ALenum NewFormat = AL_FORMAT_MONO_FLOAT32;
+ switch(SrcChannels)
+ {
+ case UserFmtMono: NewFormat = AL_FORMAT_MONO_FLOAT32; break;
+ case UserFmtStereo: NewFormat = AL_FORMAT_STEREO_FLOAT32; break;
+ case UserFmtRear: NewFormat = AL_FORMAT_REAR32; break;
+ case UserFmtQuad: NewFormat = AL_FORMAT_QUAD32; break;
+ case UserFmtX51: NewFormat = AL_FORMAT_51CHN32; break;
+ case UserFmtX61: NewFormat = AL_FORMAT_61CHN32; break;
+ case UserFmtX71: NewFormat = AL_FORMAT_71CHN32; break;
+ }
+ err = LoadData(ALBuf, freq, NewFormat, size, SrcChannels, SrcType, data);
+ if(err != AL_NO_ERROR)
+ alSetError(Context, err);
+ } break;
+
+ case UserFmtMulaw:
+ case UserFmtIMA4: {
+ ALenum NewFormat = AL_FORMAT_MONO16;
+ switch(SrcChannels)
+ {
+ case UserFmtMono: NewFormat = AL_FORMAT_MONO16; break;
+ case UserFmtStereo: NewFormat = AL_FORMAT_STEREO16; break;
+ case UserFmtRear: NewFormat = AL_FORMAT_REAR16; break;
+ case UserFmtQuad: NewFormat = AL_FORMAT_QUAD16; break;
+ case UserFmtX51: NewFormat = AL_FORMAT_51CHN16; break;
+ case UserFmtX61: NewFormat = AL_FORMAT_61CHN16; break;
+ case UserFmtX71: NewFormat = AL_FORMAT_71CHN16; break;
+ }
+ err = LoadData(ALBuf, freq, NewFormat, size, SrcChannels, SrcType, data);
+ if(err != AL_NO_ERROR)
+ alSetError(Context, err);
+ } break;
+ }
+
+ ProcessContext(Context);
+}
+
+/*
+ * alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data,
+ * ALsizei offset, ALsizei length)
+ *
+ * Update buffer's audio data
+ */
+AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length)
+{
+ enum UserFmtChannels SrcChannels;
+ enum UserFmtType SrcType;
+ ALCcontext *Context;
+ ALCdevice *device;
+ ALbuffer *ALBuf;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(Context->SampleSource)
+ {
+ ALintptrEXT offset;
+
+ if(Context->SampleSource->state == MAPPED)
+ {
+ alSetError(Context, AL_INVALID_OPERATION);
+ ProcessContext(Context);
+ return;
+ }
+
+ offset = (const ALubyte*)data - (ALubyte*)NULL;
+ data = Context->SampleSource->data + offset;
+ }
+
+ device = Context->Device;
+ if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+ alSetError(Context, AL_INVALID_NAME);
+ else if(length < 0 || offset < 0 || (length > 0 && data == NULL))
+ alSetError(Context, AL_INVALID_VALUE);
+ else if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE ||
+ SrcChannels != ALBuf->OriginalChannels ||
+ SrcType != ALBuf->OriginalType)
+ alSetError(Context, AL_INVALID_ENUM);
+ else if(offset > ALBuf->OriginalSize ||
+ length > ALBuf->OriginalSize-offset ||
+ (offset%ALBuf->OriginalAlign) != 0 ||
+ (length%ALBuf->OriginalAlign) != 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ if(SrcType == UserFmtIMA4)
+ {
+ ALuint Channels = ChannelsFromFmt(ALBuf->FmtChannels);
+ ALuint Bytes = BytesFromFmt(ALBuf->FmtType);
+
+ /* offset -> byte offset, length -> block count */
+ offset /= 36;
+ offset *= 65;
+ offset *= Bytes;
+ length /= ALBuf->OriginalAlign;
+
+ ConvertDataIMA4(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
+ data, Channels, length);
+ }
+ else
+ {
+ ALuint OldBytes = BytesFromUserFmt(SrcType);
+ ALuint Bytes = BytesFromFmt(ALBuf->FmtType);
+
+ offset /= OldBytes;
+ offset *= Bytes;
+ length /= OldBytes;
+
+ ConvertData(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
+ data, SrcType, length);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+
+AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ (void)flValue;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ (void)flValue1;
+ (void)flValue2;
+ (void)flValue3;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum eParam, const ALfloat* flValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!flValues)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum eParam, ALint lValue)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ (void)lValue;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBuffer3i( ALuint buffer, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ (void)lValue1;
+ (void)lValue2;
+ (void)lValue3;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum eParam, const ALint* plValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+ ALbuffer *ALBuf;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!plValues)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ case AL_LOOP_POINTS_SOFT:
+ if(ALBuf->refcount > 0)
+ alSetError(pContext, AL_INVALID_OPERATION);
+ else if(plValues[0] < 0 || plValues[1] < 0 ||
+ plValues[0] >= plValues[1] || ALBuf->size == 0)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else
+ {
+ ALint maxlen = ALBuf->size /
+ FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType);
+ if(plValues[0] > maxlen || plValues[1] > maxlen)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else
+ {
+ ALBuf->LoopStart = plValues[0];
+ ALBuf->LoopEnd = plValues[1];
+ }
+ }
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum eParam, ALfloat *pflValue)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!pflValue)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!pflValue1 || !pflValue2 || !pflValue3)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum eParam, ALfloat* pflValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!pflValues)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plValue)
+{
+ ALCcontext *pContext;
+ ALbuffer *pBuffer;
+ ALCdevice *device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!plValue)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if((pBuffer=LookupBuffer(device->BufferMap, buffer)) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ case AL_FREQUENCY:
+ *plValue = pBuffer->Frequency;
+ break;
+
+ case AL_BITS:
+ *plValue = BytesFromFmt(pBuffer->FmtType) * 8;
+ break;
+
+ case AL_CHANNELS:
+ *plValue = ChannelsFromFmt(pBuffer->FmtChannels);
+ break;
+
+ case AL_SIZE:
+ *plValue = pBuffer->size;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!plValue1 || !plValue2 || !plValue3)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum eParam, ALint* plValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *device;
+ ALbuffer *ALBuf;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ device = pContext->Device;
+ if(!plValues)
+ alSetError(pContext, AL_INVALID_VALUE);
+ else if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+ alSetError(pContext, AL_INVALID_NAME);
+ else
+ {
+ switch(eParam)
+ {
+ case AL_FREQUENCY:
+ case AL_BITS:
+ case AL_CHANNELS:
+ case AL_SIZE:
+ alGetBufferi(buffer, eParam, plValues);
+ break;
+
+ case AL_LOOP_POINTS_SOFT:
+ plValues[0] = ALBuf->LoopStart;
+ plValues[1] = ALBuf->LoopEnd;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+typedef ALubyte ALmulaw;
+
+static __inline ALshort DecodeMuLaw(ALmulaw val)
+{ return muLawDecompressionTable[val]; }
+
+static ALmulaw EncodeMuLaw(ALshort val)
+{
+ ALint mant, exp, sign;
+
+ sign = (val>>8) & 0x80;
+ if(sign)
+ {
+ /* -32768 doesn't properly negate on a short; it results in itself.
+ * So clamp to -32767 */
+ val = max(val, -32767);
+ val = -val;
+ }
+
+ val = min(val, muLawClip);
+ val += muLawBias;
+
+ exp = muLawCompressTable[(val>>7) & 0xff];
+ mant = (val >> (exp+3)) & 0x0f;
+
+ return ~(sign | (exp<<4) | mant);
+}
+
+static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans)
+{
+ ALint sample[MAXCHANNELS], index[MAXCHANNELS];
+ ALuint code[MAXCHANNELS];
+ ALsizei j,k,c;
+
+ for(c = 0;c < numchans;c++)
+ {
+ sample[c] = *(src++);
+ sample[c] |= *(src++) << 8;
+ sample[c] = (sample[c]^0x8000) - 32768;
+ index[c] = *(src++);
+ index[c] |= *(src++) << 8;
+ index[c] = (index[c]^0x8000) - 32768;
+
+ index[c] = max(0, index[c]);
+ index[c] = min(index[c], 88);
+
+ dst[c] = sample[c];
+ }
+
+ j = 1;
+ while(j < 65)
+ {
+ for(c = 0;c < numchans;c++)
+ {
+ code[c] = *(src++);
+ code[c] |= *(src++) << 8;
+ code[c] |= *(src++) << 16;
+ code[c] |= *(src++) << 24;
+ }
+
+ for(k = 0;k < 8;k++,j++)
+ {
+ for(c = 0;c < numchans;c++)
+ {
+ int nibble = code[c]&0xf;
+ code[c] >>= 4;
+
+ sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8;
+ sample[c] = max(-32768, sample[c]);
+ sample[c] = min(sample[c], 32767);
+
+ index[c] += IMA4Index_adjust[nibble];
+ index[c] = max(0, index[c]);
+ index[c] = min(index[c], 88);
+
+ dst[j*numchans + c] = sample[c];
+ }
+ }
+ }
+}
+
+static void EncodeIMA4Block(ALubyte *dst, const ALshort *src, ALint *sample, ALint *index, ALint numchans)
+{
+ ALsizei j,k,c;
+
+ for(c = 0;c < numchans;c++)
+ {
+ int diff = src[c] - sample[c];
+ int step = IMAStep_size[index[c]];
+ int nibble;
+
+ nibble = 0;
+ if(diff < 0)
+ {
+ nibble = 0x8;
+ diff = -diff;
+ }
+
+ diff = min(step*2, diff);
+ nibble |= (diff*8/step - 1) / 2;
+
+ sample[c] += IMA4Codeword[nibble] * step / 8;
+ sample[c] = max(-32768, sample[c]);
+ sample[c] = min(sample[c], 32767);
+
+ index[c] += IMA4Index_adjust[nibble];
+ index[c] = max(0, index[c]);
+ index[c] = min(index[c], 88);
+
+ *(dst++) = sample[c] & 0xff;
+ *(dst++) = (sample[c]>>8) & 0xff;
+ *(dst++) = index[c] & 0xff;
+ *(dst++) = (index[c]>>8) & 0xff;
+ }
+
+ j = 1;
+ while(j < 65)
+ {
+ for(c = 0;c < numchans;c++)
+ {
+ for(k = 0;k < 8;k++)
+ {
+ int diff = src[(j+k)*numchans + c] - sample[c];
+ int step = IMAStep_size[index[c]];
+ int nibble;
+
+ nibble = 0;
+ if(diff < 0)
+ {
+ nibble = 0x8;
+ diff = -diff;
+ }
+
+ diff = min(step*2, diff);
+ nibble |= (diff*8/step - 1) / 2;
+
+ sample[c] += IMA4Codeword[nibble] * step / 8;
+ sample[c] = max(-32768, sample[c]);
+ sample[c] = min(sample[c], 32767);
+
+ index[c] += IMA4Index_adjust[nibble];
+ index[c] = max(0, index[c]);
+ index[c] = min(index[c], 88);
+
+ if(!(k&1)) *dst = nibble;
+ else *(dst++) |= nibble<<4;
+ }
+ }
+ j += 8;
+ }
+}
+
+
+static __inline ALbyte Conv_ALbyte_ALbyte(ALbyte val)
+{ return val; }
+static __inline ALbyte Conv_ALbyte_ALubyte(ALubyte val)
+{ return val-128; }
+static __inline ALbyte Conv_ALbyte_ALshort(ALshort val)
+{ return val>>8; }
+static __inline ALbyte Conv_ALbyte_ALushort(ALushort val)
+{ return (val>>8)-128; }
+static __inline ALbyte Conv_ALbyte_ALint(ALint val)
+{ return val>>24; }
+static __inline ALbyte Conv_ALbyte_ALuint(ALuint val)
+{ return (val>>24)-128; }
+static __inline ALbyte Conv_ALbyte_ALfloat(ALfloat val)
+{
+ if(val > 1.0f) return 127;
+ if(val < -1.0f) return -128;
+ return (ALint)(val * 127.0f);
+}
+static __inline ALbyte Conv_ALbyte_ALdouble(ALdouble val)
+{
+ if(val > 1.0) return 127;
+ if(val < -1.0) return -128;
+ return (ALint)(val * 127.0);
+}
+static __inline ALbyte Conv_ALbyte_ALmulaw(ALmulaw val)
+{ return Conv_ALbyte_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALubyte Conv_ALubyte_ALbyte(ALbyte val)
+{ return val+128; }
+static __inline ALubyte Conv_ALubyte_ALubyte(ALubyte val)
+{ return val; }
+static __inline ALubyte Conv_ALubyte_ALshort(ALshort val)
+{ return (val>>8)+128; }
+static __inline ALubyte Conv_ALubyte_ALushort(ALushort val)
+{ return val>>8; }
+static __inline ALubyte Conv_ALubyte_ALint(ALint val)
+{ return (val>>24)+128; }
+static __inline ALubyte Conv_ALubyte_ALuint(ALuint val)
+{ return val>>24; }
+static __inline ALubyte Conv_ALubyte_ALfloat(ALfloat val)
+{
+ if(val > 1.0f) return 255;
+ if(val < -1.0f) return 0;
+ return (ALint)(val * 127.0f) + 128;
+}
+static __inline ALubyte Conv_ALubyte_ALdouble(ALdouble val)
+{
+ if(val > 1.0) return 255;
+ if(val < -1.0) return 0;
+ return (ALint)(val * 127.0) + 128;
+}
+static __inline ALubyte Conv_ALubyte_ALmulaw(ALmulaw val)
+{ return Conv_ALubyte_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALshort Conv_ALshort_ALbyte(ALbyte val)
+{ return val<<8; }
+static __inline ALshort Conv_ALshort_ALubyte(ALubyte val)
+{ return (val-128)<<8; }
+static __inline ALshort Conv_ALshort_ALshort(ALshort val)
+{ return val; }
+static __inline ALshort Conv_ALshort_ALushort(ALushort val)
+{ return val-32768; }
+static __inline ALshort Conv_ALshort_ALint(ALint val)
+{ return val>>16; }
+static __inline ALshort Conv_ALshort_ALuint(ALuint val)
+{ return (val>>16)-32768; }
+static __inline ALshort Conv_ALshort_ALfloat(ALfloat val)
+{
+ if(val > 1.0f) return 32767;
+ if(val < -1.0f) return -32768;
+ return (ALint)(val * 32767.0f);
+}
+static __inline ALshort Conv_ALshort_ALdouble(ALdouble val)
+{
+ if(val > 1.0) return 32767;
+ if(val < -1.0) return -32768;
+ return (ALint)(val * 32767.0);
+}
+static __inline ALshort Conv_ALshort_ALmulaw(ALmulaw val)
+{ return Conv_ALshort_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALushort Conv_ALushort_ALbyte(ALbyte val)
+{ return (val+128)<<8; }
+static __inline ALushort Conv_ALushort_ALubyte(ALubyte val)
+{ return val<<8; }
+static __inline ALushort Conv_ALushort_ALshort(ALshort val)
+{ return val+32768; }
+static __inline ALushort Conv_ALushort_ALushort(ALushort val)
+{ return val; }
+static __inline ALushort Conv_ALushort_ALint(ALint val)
+{ return (val>>16)+32768; }
+static __inline ALushort Conv_ALushort_ALuint(ALuint val)
+{ return val>>16; }
+static __inline ALushort Conv_ALushort_ALfloat(ALfloat val)
+{
+ if(val > 1.0f) return 65535;
+ if(val < -1.0f) return 0;
+ return (ALint)(val * 32767.0f) + 32768;
+}
+static __inline ALushort Conv_ALushort_ALdouble(ALdouble val)
+{
+ if(val > 1.0) return 65535;
+ if(val < -1.0) return 0;
+ return (ALint)(val * 32767.0) + 32768;
+}
+static __inline ALushort Conv_ALushort_ALmulaw(ALmulaw val)
+{ return Conv_ALushort_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALint Conv_ALint_ALbyte(ALbyte val)
+{ return val<<24; }
+static __inline ALint Conv_ALint_ALubyte(ALubyte val)
+{ return (val-128)<<24; }
+static __inline ALint Conv_ALint_ALshort(ALshort val)
+{ return val<<16; }
+static __inline ALint Conv_ALint_ALushort(ALushort val)
+{ return (val-32768)<<16; }
+static __inline ALint Conv_ALint_ALint(ALint val)
+{ return val; }
+static __inline ALint Conv_ALint_ALuint(ALuint val)
+{ return val-2147483648u; }
+static __inline ALint Conv_ALint_ALfloat(ALfloat val)
+{
+ if(val > 1.0f) return 2147483647;
+ if(val < -1.0f) return -2147483647-1;
+ return (ALint)(val * 2147483647.0);
+}
+static __inline ALint Conv_ALint_ALdouble(ALdouble val)
+{
+ if(val > 1.0) return 2147483647;
+ if(val < -1.0) return -2147483647-1;
+ return (ALint)(val * 2147483647.0);
+}
+static __inline ALint Conv_ALint_ALmulaw(ALmulaw val)
+{ return Conv_ALint_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALuint Conv_ALuint_ALbyte(ALbyte val)
+{ return (val+128)<<24; }
+static __inline ALuint Conv_ALuint_ALubyte(ALubyte val)
+{ return val<<24; }
+static __inline ALuint Conv_ALuint_ALshort(ALshort val)
+{ return (val+32768)<<16; }
+static __inline ALuint Conv_ALuint_ALushort(ALushort val)
+{ return val<<16; }
+static __inline ALuint Conv_ALuint_ALint(ALint val)
+{ return val+2147483648u; }
+static __inline ALuint Conv_ALuint_ALuint(ALuint val)
+{ return val; }
+static __inline ALuint Conv_ALuint_ALfloat(ALfloat val)
+{
+ if(val > 1.0f) return 4294967295u;
+ if(val < -1.0f) return 0;
+ return (ALint)(val * 2147483647.0) + 2147483648u;
+}
+static __inline ALuint Conv_ALuint_ALdouble(ALdouble val)
+{
+ if(val > 1.0) return 4294967295u;
+ if(val < -1.0) return 0;
+ return (ALint)(val * 2147483647.0) + 2147483648u;
+}
+static __inline ALuint Conv_ALuint_ALmulaw(ALmulaw val)
+{ return Conv_ALuint_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALfloat Conv_ALfloat_ALbyte(ALbyte val)
+{ return val * (1.0f/127.0f); }
+static __inline ALfloat Conv_ALfloat_ALubyte(ALubyte val)
+{ return (val-128) * (1.0f/127.0f); }
+static __inline ALfloat Conv_ALfloat_ALshort(ALshort val)
+{ return val * (1.0f/32767.0f); }
+static __inline ALfloat Conv_ALfloat_ALushort(ALushort val)
+{ return (val-32768) * (1.0f/32767.0f); }
+static __inline ALfloat Conv_ALfloat_ALint(ALint val)
+{ return val * (1.0/2147483647.0); }
+static __inline ALfloat Conv_ALfloat_ALuint(ALuint val)
+{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); }
+static __inline ALfloat Conv_ALfloat_ALfloat(ALfloat val)
+{ return val; }
+static __inline ALfloat Conv_ALfloat_ALdouble(ALdouble val)
+{ return val; }
+static __inline ALfloat Conv_ALfloat_ALmulaw(ALmulaw val)
+{ return Conv_ALfloat_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALdouble Conv_ALdouble_ALbyte(ALbyte val)
+{ return val * (1.0/127.0); }
+static __inline ALdouble Conv_ALdouble_ALubyte(ALubyte val)
+{ return (val-128) * (1.0/127.0); }
+static __inline ALdouble Conv_ALdouble_ALshort(ALshort val)
+{ return val * (1.0/32767.0); }
+static __inline ALdouble Conv_ALdouble_ALushort(ALushort val)
+{ return (val-32768) * (1.0/32767.0); }
+static __inline ALdouble Conv_ALdouble_ALint(ALint val)
+{ return val * (1.0/2147483647.0); }
+static __inline ALdouble Conv_ALdouble_ALuint(ALuint val)
+{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); }
+static __inline ALdouble Conv_ALdouble_ALfloat(ALfloat val)
+{ return val; }
+static __inline ALdouble Conv_ALdouble_ALdouble(ALdouble val)
+{ return val; }
+static __inline ALdouble Conv_ALdouble_ALmulaw(ALmulaw val)
+{ return Conv_ALdouble_ALshort(DecodeMuLaw(val)); }
+
+#define DECL_TEMPLATE(T) \
+static __inline ALmulaw Conv_ALmulaw_##T(T val) \
+{ return EncodeMuLaw(Conv_ALshort_##T(val)); }
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+static __inline ALmulaw Conv_ALmulaw_ALmulaw(ALmulaw val)
+{ return val; }
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T1, T2) \
+static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALuint len) \
+{ \
+ ALuint i; \
+ for(i = 0;i < len;i++) \
+ *(dst++) = Conv_##T1##_##T2(*(src++)); \
+}
+
+DECL_TEMPLATE(ALbyte, ALbyte)
+DECL_TEMPLATE(ALbyte, ALubyte)
+DECL_TEMPLATE(ALbyte, ALshort)
+DECL_TEMPLATE(ALbyte, ALushort)
+DECL_TEMPLATE(ALbyte, ALint)
+DECL_TEMPLATE(ALbyte, ALuint)
+DECL_TEMPLATE(ALbyte, ALfloat)
+DECL_TEMPLATE(ALbyte, ALdouble)
+DECL_TEMPLATE(ALbyte, ALmulaw)
+
+DECL_TEMPLATE(ALubyte, ALbyte)
+DECL_TEMPLATE(ALubyte, ALubyte)
+DECL_TEMPLATE(ALubyte, ALshort)
+DECL_TEMPLATE(ALubyte, ALushort)
+DECL_TEMPLATE(ALubyte, ALint)
+DECL_TEMPLATE(ALubyte, ALuint)
+DECL_TEMPLATE(ALubyte, ALfloat)
+DECL_TEMPLATE(ALubyte, ALdouble)
+DECL_TEMPLATE(ALubyte, ALmulaw)
+
+DECL_TEMPLATE(ALshort, ALbyte)
+DECL_TEMPLATE(ALshort, ALubyte)
+DECL_TEMPLATE(ALshort, ALshort)
+DECL_TEMPLATE(ALshort, ALushort)
+DECL_TEMPLATE(ALshort, ALint)
+DECL_TEMPLATE(ALshort, ALuint)
+DECL_TEMPLATE(ALshort, ALfloat)
+DECL_TEMPLATE(ALshort, ALdouble)
+DECL_TEMPLATE(ALshort, ALmulaw)
+
+DECL_TEMPLATE(ALushort, ALbyte)
+DECL_TEMPLATE(ALushort, ALubyte)
+DECL_TEMPLATE(ALushort, ALshort)
+DECL_TEMPLATE(ALushort, ALushort)
+DECL_TEMPLATE(ALushort, ALint)
+DECL_TEMPLATE(ALushort, ALuint)
+DECL_TEMPLATE(ALushort, ALfloat)
+DECL_TEMPLATE(ALushort, ALdouble)
+DECL_TEMPLATE(ALushort, ALmulaw)
+
+DECL_TEMPLATE(ALint, ALbyte)
+DECL_TEMPLATE(ALint, ALubyte)
+DECL_TEMPLATE(ALint, ALshort)
+DECL_TEMPLATE(ALint, ALushort)
+DECL_TEMPLATE(ALint, ALint)
+DECL_TEMPLATE(ALint, ALuint)
+DECL_TEMPLATE(ALint, ALfloat)
+DECL_TEMPLATE(ALint, ALdouble)
+DECL_TEMPLATE(ALint, ALmulaw)
+
+DECL_TEMPLATE(ALuint, ALbyte)
+DECL_TEMPLATE(ALuint, ALubyte)
+DECL_TEMPLATE(ALuint, ALshort)
+DECL_TEMPLATE(ALuint, ALushort)
+DECL_TEMPLATE(ALuint, ALint)
+DECL_TEMPLATE(ALuint, ALuint)
+DECL_TEMPLATE(ALuint, ALfloat)
+DECL_TEMPLATE(ALuint, ALdouble)
+DECL_TEMPLATE(ALuint, ALmulaw)
+
+DECL_TEMPLATE(ALfloat, ALbyte)
+DECL_TEMPLATE(ALfloat, ALubyte)
+DECL_TEMPLATE(ALfloat, ALshort)
+DECL_TEMPLATE(ALfloat, ALushort)
+DECL_TEMPLATE(ALfloat, ALint)
+DECL_TEMPLATE(ALfloat, ALuint)
+DECL_TEMPLATE(ALfloat, ALfloat)
+DECL_TEMPLATE(ALfloat, ALdouble)
+DECL_TEMPLATE(ALfloat, ALmulaw)
+
+DECL_TEMPLATE(ALdouble, ALbyte)
+DECL_TEMPLATE(ALdouble, ALubyte)
+DECL_TEMPLATE(ALdouble, ALshort)
+DECL_TEMPLATE(ALdouble, ALushort)
+DECL_TEMPLATE(ALdouble, ALint)
+DECL_TEMPLATE(ALdouble, ALuint)
+DECL_TEMPLATE(ALdouble, ALfloat)
+DECL_TEMPLATE(ALdouble, ALdouble)
+DECL_TEMPLATE(ALdouble, ALmulaw)
+
+DECL_TEMPLATE(ALmulaw, ALbyte)
+DECL_TEMPLATE(ALmulaw, ALubyte)
+DECL_TEMPLATE(ALmulaw, ALshort)
+DECL_TEMPLATE(ALmulaw, ALushort)
+DECL_TEMPLATE(ALmulaw, ALint)
+DECL_TEMPLATE(ALmulaw, ALuint)
+DECL_TEMPLATE(ALmulaw, ALfloat)
+DECL_TEMPLATE(ALmulaw, ALdouble)
+DECL_TEMPLATE(ALmulaw, ALmulaw)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T) \
+static void Convert_##T##_IMA4(T *dst, const ALubyte *src, ALuint numchans, \
+ ALuint numblocks) \
+{ \
+ ALuint i, j; \
+ ALshort tmp[65*MAXCHANNELS]; /* Max samples an IMA4 frame can be */ \
+ for(i = 0;i < numblocks;i++) \
+ { \
+ DecodeIMA4Block(tmp, src, numchans); \
+ src += 36*numchans; \
+ for(j = 0;j < 65*numchans;j++) \
+ *(dst++) = Conv_##T##_ALshort(tmp[j]); \
+ } \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+DECL_TEMPLATE(ALmulaw)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T) \
+static void Convert_IMA4_##T(ALubyte *dst, const T *src, ALuint numchans, \
+ ALuint numblocks) \
+{ \
+ ALuint i, j; \
+ ALshort tmp[65*MAXCHANNELS]; /* Max samples an IMA4 frame can be */ \
+ ALint sample[MAXCHANNELS] = {0,0,0,0,0,0,0,0}; \
+ ALint index[MAXCHANNELS] = {0,0,0,0,0,0,0,0}; \
+ for(i = 0;i < numblocks;i++) \
+ { \
+ for(j = 0;j < 65*numchans;j++) \
+ tmp[j] = Conv_ALshort_##T(*(src++)); \
+ EncodeIMA4Block(dst, tmp, sample, index, numchans); \
+ dst += 36*numchans; \
+ } \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+DECL_TEMPLATE(ALmulaw)
+
+#undef DECL_TEMPLATE
+
+static void Convert_IMA4_IMA4(ALubyte *dst, const ALubyte *src, ALuint numchans,
+ ALuint numblocks)
+{
+ memcpy(dst, src, numblocks*36*numchans);
+}
+
+#define DECL_TEMPLATE(T) \
+static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \
+ ALsizei len) \
+{ \
+ switch(srcType) \
+ { \
+ case UserFmtByte: \
+ Convert_##T##_ALbyte(dst, src, len); \
+ break; \
+ case UserFmtUByte: \
+ Convert_##T##_ALubyte(dst, src, len); \
+ break; \
+ case UserFmtShort: \
+ Convert_##T##_ALshort(dst, src, len); \
+ break; \
+ case UserFmtUShort: \
+ Convert_##T##_ALushort(dst, src, len); \
+ break; \
+ case UserFmtInt: \
+ Convert_##T##_ALint(dst, src, len); \
+ break; \
+ case UserFmtUInt: \
+ Convert_##T##_ALuint(dst, src, len); \
+ break; \
+ case UserFmtFloat: \
+ Convert_##T##_ALfloat(dst, src, len); \
+ break; \
+ case UserFmtDouble: \
+ Convert_##T##_ALdouble(dst, src, len); \
+ break; \
+ case UserFmtMulaw: \
+ Convert_##T##_ALmulaw(dst, src, len); \
+ break; \
+ case UserFmtIMA4: \
+ break; /* not handled here */ \
+ } \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+DECL_TEMPLATE(ALmulaw)
+
+#undef DECL_TEMPLATE
+
+static void Convert_IMA4(ALubyte *dst, const ALvoid *src, enum UserFmtType srcType,
+ ALint chans, ALsizei len)
+{
+ switch(srcType)
+ {
+ case UserFmtByte:
+ Convert_IMA4_ALbyte(dst, src, chans, len);
+ break;
+ case UserFmtUByte:
+ Convert_IMA4_ALubyte(dst, src, chans, len);
+ break;
+ case UserFmtShort:
+ Convert_IMA4_ALshort(dst, src, chans, len);
+ break;
+ case UserFmtUShort:
+ Convert_IMA4_ALushort(dst, src, chans, len);
+ break;
+ case UserFmtInt:
+ Convert_IMA4_ALint(dst, src, chans, len);
+ break;
+ case UserFmtUInt:
+ Convert_IMA4_ALuint(dst, src, chans, len);
+ break;
+ case UserFmtFloat:
+ Convert_IMA4_ALfloat(dst, src, chans, len);
+ break;
+ case UserFmtDouble:
+ Convert_IMA4_ALdouble(dst, src, chans, len);
+ break;
+ case UserFmtMulaw:
+ Convert_IMA4_ALmulaw(dst, src, chans, len);
+ break;
+ case UserFmtIMA4:
+ Convert_IMA4_IMA4(dst, src, chans, len);
+ break;
+ }
+}
+
+
+static void ConvertData(ALvoid *dst, enum FmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei len)
+{
+ switch(dstType)
+ {
+ (void)Convert_ALbyte;
+ case FmtUByte:
+ Convert_ALubyte(dst, src, srcType, len);
+ break;
+ case FmtShort:
+ Convert_ALshort(dst, src, srcType, len);
+ break;
+ (void)Convert_ALushort;
+ (void)Convert_ALint;
+ (void)Convert_ALuint;
+ case FmtFloat:
+ Convert_ALfloat(dst, src, srcType, len);
+ break;
+ (void)Convert_ALdouble;
+ (void)Convert_ALmulaw;
+ (void)Convert_IMA4;
+ }
+}
+
+static void ConvertDataIMA4(ALvoid *dst, enum FmtType dstType, const ALvoid *src, ALint chans, ALsizei len)
+{
+ switch(dstType)
+ {
+ (void)Convert_ALbyte_IMA4;
+ case FmtUByte:
+ Convert_ALubyte_IMA4(dst, src, chans, len);
+ break;
+ case FmtShort:
+ Convert_ALshort_IMA4(dst, src, chans, len);
+ break;
+ (void)Convert_ALushort_IMA4;
+ (void)Convert_ALint_IMA4;
+ (void)Convert_ALuint_IMA4;
+ case FmtFloat:
+ Convert_ALfloat_IMA4(dst, src, chans, len);
+ break;
+ (void)Convert_ALdouble_IMA4;
+ (void)Convert_ALmulaw_IMA4;
+ }
+}
+
+
+/*
+ * LoadData
+ *
+ * Loads the specified data into the buffer, using the specified formats.
+ * Currently, the new format must have the same channel configuration as the
+ * original format.
+ */
+static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data)
+{
+ ALuint NewChannels, NewBytes;
+ enum FmtChannels DstChannels;
+ enum FmtType DstType;
+ ALuint64 newsize;
+ ALvoid *temp;
+
+ DecomposeFormat(NewFormat, &DstChannels, &DstType);
+ NewChannels = ChannelsFromFmt(DstChannels);
+ NewBytes = BytesFromFmt(DstType);
+
+ assert(SrcChannels == DstChannels);
+
+ if(SrcType == UserFmtIMA4)
+ {
+ ALuint OrigChannels = ChannelsFromUserFmt(SrcChannels);
+
+ /* Here is where things vary:
+ * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
+ * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
+ */
+ if((size%(36*OrigChannels)) != 0)
+ return AL_INVALID_VALUE;
+
+ newsize = size / 36;
+ newsize *= 65;
+ newsize *= NewBytes;
+ if(newsize > INT_MAX)
+ return AL_OUT_OF_MEMORY;
+
+ temp = realloc(ALBuf->data, newsize);
+ if(!temp && newsize) return AL_OUT_OF_MEMORY;
+ ALBuf->data = temp;
+ ALBuf->size = newsize;
+
+ if(data != NULL)
+ ConvertDataIMA4(ALBuf->data, DstType, data, OrigChannels,
+ newsize/(65*NewChannels*NewBytes));
+
+ ALBuf->OriginalChannels = SrcChannels;
+ ALBuf->OriginalType = SrcType;
+ ALBuf->OriginalSize = size;
+ ALBuf->OriginalAlign = 36 * OrigChannels;
+ }
+ else
+ {
+ ALuint OrigBytes = BytesFromUserFmt(SrcType);
+ ALuint OrigChannels = ChannelsFromUserFmt(SrcChannels);
+
+ if((size%(OrigBytes*OrigChannels)) != 0)
+ return AL_INVALID_VALUE;
+
+ newsize = size / OrigBytes;
+ newsize *= NewBytes;
+ if(newsize > INT_MAX)
+ return AL_OUT_OF_MEMORY;
+
+ temp = realloc(ALBuf->data, newsize);
+ if(!temp && newsize) return AL_OUT_OF_MEMORY;
+ ALBuf->data = temp;
+ ALBuf->size = newsize;
+
+ if(data != NULL)
+ ConvertData(ALBuf->data, DstType, data, SrcType, newsize/NewBytes);
+
+ ALBuf->OriginalChannels = SrcChannels;
+ ALBuf->OriginalType = SrcType;
+ ALBuf->OriginalSize = size;
+ ALBuf->OriginalAlign = OrigBytes * OrigChannels;
+ }
+
+ ALBuf->Frequency = freq;
+ ALBuf->FmtChannels = DstChannels;
+ ALBuf->FmtType = DstType;
+
+ ALBuf->LoopStart = 0;
+ ALBuf->LoopEnd = newsize / NewChannels / NewBytes;
+
+ return AL_NO_ERROR;
+}
+
+
+ALuint BytesFromUserFmt(enum UserFmtType type)
+{
+ switch(type)
+ {
+ case UserFmtByte: return sizeof(ALbyte);
+ case UserFmtUByte: return sizeof(ALubyte);
+ case UserFmtShort: return sizeof(ALshort);
+ case UserFmtUShort: return sizeof(ALushort);
+ case UserFmtInt: return sizeof(ALint);
+ case UserFmtUInt: return sizeof(ALuint);
+ case UserFmtFloat: return sizeof(ALfloat);
+ case UserFmtDouble: return sizeof(ALdouble);
+ case UserFmtMulaw: return sizeof(ALubyte);
+ case UserFmtIMA4: break; /* not handled here */
+ }
+ return 0;
+}
+ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
+{
+ switch(chans)
+ {
+ case UserFmtMono: return 1;
+ case UserFmtStereo: return 2;
+ case UserFmtRear: return 2;
+ case UserFmtQuad: return 4;
+ case UserFmtX51: return 6;
+ case UserFmtX61: return 7;
+ case UserFmtX71: return 8;
+ }
+ return 0;
+}
+ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
+ enum UserFmtType *type)
+{
+ switch(format)
+ {
+ case AL_FORMAT_MONO8:
+ *chans = UserFmtMono;
+ *type = UserFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_MONO16:
+ *chans = UserFmtMono;
+ *type = UserFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_MONO_FLOAT32:
+ *chans = UserFmtMono;
+ *type = UserFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_MONO_DOUBLE_EXT:
+ *chans = UserFmtMono;
+ *type = UserFmtDouble;
+ return AL_TRUE;
+ case AL_FORMAT_MONO_IMA4:
+ *chans = UserFmtMono;
+ *type = UserFmtIMA4;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO8:
+ *chans = UserFmtStereo;
+ *type = UserFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO16:
+ *chans = UserFmtStereo;
+ *type = UserFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO_FLOAT32:
+ *chans = UserFmtStereo;
+ *type = UserFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO_DOUBLE_EXT:
+ *chans = UserFmtStereo;
+ *type = UserFmtDouble;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO_IMA4:
+ *chans = UserFmtStereo;
+ *type = UserFmtIMA4;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD8_LOKI:
+ case AL_FORMAT_QUAD8:
+ *chans = UserFmtQuad;
+ *type = UserFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD16_LOKI:
+ case AL_FORMAT_QUAD16:
+ *chans = UserFmtQuad;
+ *type = UserFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD32:
+ *chans = UserFmtQuad;
+ *type = UserFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_REAR8:
+ *chans = UserFmtRear;
+ *type = UserFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_REAR16:
+ *chans = UserFmtRear;
+ *type = UserFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_REAR32:
+ *chans = UserFmtRear;
+ *type = UserFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN8:
+ *chans = UserFmtX51;
+ *type = UserFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN16:
+ *chans = UserFmtX51;
+ *type = UserFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN32:
+ *chans = UserFmtX51;
+ *type = UserFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN8:
+ *chans = UserFmtX61;
+ *type = UserFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN16:
+ *chans = UserFmtX61;
+ *type = UserFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN32:
+ *chans = UserFmtX61;
+ *type = UserFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN8:
+ *chans = UserFmtX71;
+ *type = UserFmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN16:
+ *chans = UserFmtX71;
+ *type = UserFmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN32:
+ *chans = UserFmtX71;
+ *type = UserFmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_MONO_MULAW:
+ *chans = UserFmtMono;
+ *type = UserFmtMulaw;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO_MULAW:
+ *chans = UserFmtStereo;
+ *type = UserFmtMulaw;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD_MULAW:
+ *chans = UserFmtQuad;
+ *type = UserFmtMulaw;
+ return AL_TRUE;
+ case AL_FORMAT_REAR_MULAW:
+ *chans = UserFmtRear;
+ *type = UserFmtMulaw;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN_MULAW:
+ *chans = UserFmtX51;
+ *type = UserFmtMulaw;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN_MULAW:
+ *chans = UserFmtX61;
+ *type = UserFmtMulaw;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN_MULAW:
+ *chans = UserFmtX71;
+ *type = UserFmtMulaw;
+ return AL_TRUE;
+ }
+ return AL_FALSE;
+}
+
+ALuint BytesFromFmt(enum FmtType type)
+{
+ switch(type)
+ {
+ case FmtUByte: return sizeof(ALubyte);
+ case FmtShort: return sizeof(ALshort);
+ case FmtFloat: return sizeof(ALfloat);
+ }
+ return 0;
+}
+ALuint ChannelsFromFmt(enum FmtChannels chans)
+{
+ switch(chans)
+ {
+ case FmtMono: return 1;
+ case FmtStereo: return 2;
+ case FmtRear: return 2;
+ case FmtQuad: return 4;
+ case FmtX51: return 6;
+ case FmtX61: return 7;
+ case FmtX71: return 8;
+ }
+ return 0;
+}
+ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
+{
+ switch(format)
+ {
+ case AL_FORMAT_MONO8:
+ *chans = FmtMono;
+ *type = FmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_MONO16:
+ *chans = FmtMono;
+ *type = FmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_MONO_FLOAT32:
+ *chans = FmtMono;
+ *type = FmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO8:
+ *chans = FmtStereo;
+ *type = FmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO16:
+ *chans = FmtStereo;
+ *type = FmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_STEREO_FLOAT32:
+ *chans = FmtStereo;
+ *type = FmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD8_LOKI:
+ case AL_FORMAT_QUAD8:
+ *chans = FmtQuad;
+ *type = FmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD16_LOKI:
+ case AL_FORMAT_QUAD16:
+ *chans = FmtQuad;
+ *type = FmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_QUAD32:
+ *chans = FmtQuad;
+ *type = FmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_REAR8:
+ *chans = FmtRear;
+ *type = FmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_REAR16:
+ *chans = FmtRear;
+ *type = FmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_REAR32:
+ *chans = FmtRear;
+ *type = FmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN8:
+ *chans = FmtX51;
+ *type = FmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN16:
+ *chans = FmtX51;
+ *type = FmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_51CHN32:
+ *chans = FmtX51;
+ *type = FmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN8:
+ *chans = FmtX61;
+ *type = FmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN16:
+ *chans = FmtX61;
+ *type = FmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_61CHN32:
+ *chans = FmtX61;
+ *type = FmtFloat;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN8:
+ *chans = FmtX71;
+ *type = FmtUByte;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN16:
+ *chans = FmtX71;
+ *type = FmtShort;
+ return AL_TRUE;
+ case AL_FORMAT_71CHN32:
+ *chans = FmtX71;
+ *type = FmtFloat;
+ return AL_TRUE;
+ }
+ return AL_FALSE;
+}
+
+
+/*
+ * ReleaseALBuffers()
+ *
+ * INTERNAL: Called to destroy any buffers that still exist on the device
+ */
+ALvoid ReleaseALBuffers(ALCdevice *device)
+{
+ ALsizei i;
+ for(i = 0;i < device->BufferMap.size;i++)
+ {
+ ALbuffer *temp = device->BufferMap.array[i].value;
+ device->BufferMap.array[i].value = NULL;
+
+ free(temp->data);
+
+ ALTHUNK_REMOVEENTRY(temp->buffer);
+ memset(temp, 0, sizeof(ALbuffer));
+ free(temp);
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+#include "alError.h"
+#include "alDatabuffer.h"
+#include "alThunk.h"
+
+
+#define LookupDatabuffer(m, k) ((ALdatabuffer*)LookupUIntMapKey(&(m), (k)))
+
+/*
+* alGenDatabuffersEXT(ALsizei n, ALuint *puiBuffers)
+*
+* Generates n AL Databuffers, and stores the Databuffers Names in the array pointed to by puiBuffers
+*/
+AL_API ALvoid AL_APIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers)
+{
+ ALCcontext *Context;
+ ALsizei i=0;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ /* Check that we are actually generation some Databuffers */
+ if(n < 0 || IsBadWritePtr((void*)puiBuffers, n * sizeof(ALuint)))
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ ALCdevice *device = Context->Device;
+ ALenum err;
+
+ /* Create all the new Databuffers */
+ while(i < n)
+ {
+ ALdatabuffer *buffer = calloc(1, sizeof(ALdatabuffer));
+ if(!buffer)
+ {
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ alDeleteDatabuffersEXT(i, puiBuffers);
+ break;
+ }
+
+ buffer->databuffer = ALTHUNK_ADDENTRY(buffer);
+ err = InsertUIntMapEntry(&device->DatabufferMap,
+ buffer->databuffer, buffer);
+ if(err != AL_NO_ERROR)
+ {
+ ALTHUNK_REMOVEENTRY(buffer->databuffer);
+ memset(buffer, 0, sizeof(ALdatabuffer));
+ free(buffer);
+
+ alSetError(Context, err);
+ alDeleteDatabuffersEXT(i, puiBuffers);
+ break;
+ }
+ puiBuffers[i++] = buffer->databuffer;
+
+ buffer->state = UNMAPPED;
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+/*
+* alDatabeleteBuffersEXT(ALsizei n, ALuint *puiBuffers)
+*
+* Deletes the n AL Databuffers pointed to by puiBuffers
+*/
+AL_API ALvoid AL_APIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *buffers)
+{
+ ALCcontext *Context;
+ ALCdevice *device;
+ ALdatabuffer *ALBuf;
+ ALboolean Failed;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ /* Check we are actually Deleting some Databuffers */
+ Failed = AL_TRUE;
+ device = Context->Device;
+ if(n < 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ Failed = AL_FALSE;
+ /* Check that all the databuffers are valid and can actually be
+ * deleted */
+ for(i = 0;i < n;i++)
+ {
+ if(!buffers[i])
+ continue;
+
+ /* Check for valid Buffer ID */
+ if((ALBuf=LookupDatabuffer(device->DatabufferMap, buffers[i])) == NULL)
+ {
+ /* Invalid Databuffer */
+ alSetError(Context, AL_INVALID_NAME);
+ Failed = AL_TRUE;
+ break;
+ }
+ else if(ALBuf->state != UNMAPPED)
+ {
+ /* Databuffer still in use, cannot be deleted */
+ alSetError(Context, AL_INVALID_OPERATION);
+ Failed = AL_TRUE;
+ break;
+ }
+ }
+ }
+
+ /* If all the Databuffers were valid (and unmapped), then we can delete them */
+ if(!Failed)
+ {
+ for(i = 0;i < n;i++)
+ {
+ if((ALBuf=LookupDatabuffer(device->DatabufferMap, buffers[i])) == NULL)
+ continue;
+
+ if(ALBuf == Context->SampleSource)
+ Context->SampleSource = NULL;
+ if(ALBuf == Context->SampleSink)
+ Context->SampleSink = NULL;
+
+ // Release the memory used to store audio data
+ free(ALBuf->data);
+
+ // Release buffer structure
+ RemoveUIntMapKey(&device->DatabufferMap, ALBuf->databuffer);
+ ALTHUNK_REMOVEENTRY(ALBuf->databuffer);
+
+ memset(ALBuf, 0, sizeof(ALdatabuffer));
+ free(ALBuf);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+/*
+* alIsDatabufferEXT(ALuint uiBuffer)
+*
+* Checks if ulBuffer is a valid Databuffer Name
+*/
+AL_API ALboolean AL_APIENTRY alIsDatabufferEXT(ALuint buffer)
+{
+ ALCcontext *Context;
+ ALboolean result;
+ ALCdevice *device;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ device = Context->Device;
+ result = ((!buffer || LookupDatabuffer(device->DatabufferMap, buffer)) ?
+ AL_TRUE : AL_FALSE);
+
+ ProcessContext(Context);
+
+ return result;
+}
+
+/*
+* alDatabufferDataEXT(ALuint buffer,ALvoid *data,ALsizei size,ALenum usage)
+*
+* Fill databuffer with data
+*/
+AL_API ALvoid AL_APIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage)
+{
+ ALCcontext *Context;
+ ALdatabuffer *ALBuf;
+ ALCdevice *Device;
+ ALvoid *temp;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALBuf=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL)
+ {
+ if(ALBuf->state == UNMAPPED)
+ {
+ if(usage == AL_STREAM_WRITE_EXT || usage == AL_STREAM_READ_EXT ||
+ usage == AL_STREAM_COPY_EXT || usage == AL_STATIC_WRITE_EXT ||
+ usage == AL_STATIC_READ_EXT || usage == AL_STATIC_COPY_EXT ||
+ usage == AL_DYNAMIC_WRITE_EXT || usage == AL_DYNAMIC_READ_EXT ||
+ usage == AL_DYNAMIC_COPY_EXT)
+ {
+ if(size >= 0)
+ {
+ /* (Re)allocate data */
+ temp = realloc(ALBuf->data, size);
+ if(temp)
+ {
+ ALBuf->data = temp;
+ ALBuf->size = size;
+ ALBuf->usage = usage;
+ if(data)
+ memcpy(ALBuf->data, data, size);
+ }
+ else
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ }
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_OPERATION);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *data)
+{
+ ALCcontext *pContext;
+ ALdatabuffer *pBuffer;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+ {
+ if(start >= 0 && length >= 0 && start+length <= pBuffer->size)
+ {
+ if(pBuffer->state == UNMAPPED)
+ memcpy(pBuffer->data+start, data, length);
+ else
+ alSetError(pContext, AL_INVALID_OPERATION);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *data)
+{
+ ALCcontext *pContext;
+ ALdatabuffer *pBuffer;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+ {
+ if(start >= 0 && length >= 0 && start+length <= pBuffer->size)
+ {
+ if(pBuffer->state == UNMAPPED)
+ memcpy(data, pBuffer->data+start, length);
+ else
+ alSetError(pContext, AL_INVALID_OPERATION);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue)
+{
+ ALCcontext *pContext;
+ ALCdevice *Device;
+
+ (void)flValue;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *Device;
+
+ (void)flValues;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue)
+{
+ ALCcontext *pContext;
+ ALCdevice *Device;
+
+ (void)lValue;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *Device;
+
+ (void)plValues;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue)
+{
+ ALCcontext *pContext;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValue)
+ {
+ Device = pContext->Device;
+ if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValues)
+ {
+ Device = pContext->Device;
+ if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue)
+{
+ ALCcontext *pContext;
+ ALdatabuffer *pBuffer;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValue)
+ {
+ Device = pContext->Device;
+ if((pBuffer=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_SIZE:
+ *plValue = (ALint)pBuffer->size;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues)
+{
+ ALCcontext *pContext;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValues)
+ {
+ Device = pContext->Device;
+ if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+ {
+ switch (eParam)
+ {
+ case AL_SIZE:
+ alGetDatabufferiEXT(buffer, eParam, plValues);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer)
+{
+ ALCcontext *pContext;
+ ALdatabuffer *pBuffer = NULL;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if(uiBuffer == 0 ||
+ (pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+ {
+ if(target == AL_SAMPLE_SOURCE_EXT)
+ pContext->SampleSource = pBuffer;
+ else if(target == AL_SAMPLE_SINK_EXT)
+ pContext->SampleSink = pBuffer;
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid* AL_APIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access)
+{
+ ALCcontext *pContext;
+ ALdatabuffer *pBuffer;
+ ALvoid *ret = NULL;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return NULL;
+
+ Device = pContext->Device;
+ if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+ {
+ if(start >= 0 && length >= 0 && start+length <= pBuffer->size)
+ {
+ if(access == AL_READ_ONLY_EXT || access == AL_WRITE_ONLY_EXT ||
+ access == AL_READ_WRITE_EXT)
+ {
+ if(pBuffer->state == UNMAPPED)
+ {
+ ret = pBuffer->data + start;
+ pBuffer->state = MAPPED;
+ }
+ else
+ alSetError(pContext, AL_INVALID_OPERATION);
+ }
+ else
+ alSetError(pContext, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+
+ return ret;
+}
+
+AL_API ALvoid AL_APIENTRY alUnmapDatabufferEXT(ALuint uiBuffer)
+{
+ ALCcontext *pContext;
+ ALdatabuffer *pBuffer;
+ ALCdevice *Device;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ Device = pContext->Device;
+ if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+ {
+ if(pBuffer->state == MAPPED)
+ pBuffer->state = UNMAPPED;
+ else
+ alSetError(pContext, AL_INVALID_OPERATION);
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+/*
+* ReleaseALDatabuffers()
+*
+* INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist
+*/
+ALvoid ReleaseALDatabuffers(ALCdevice *device)
+{
+ ALsizei i;
+ for(i = 0;i < device->DatabufferMap.size;i++)
+ {
+ ALdatabuffer *temp = device->DatabufferMap.array[i].value;
+ device->DatabufferMap.array[i].value = NULL;
+
+ // Release buffer data
+ free(temp->data);
+
+ // Release Buffer structure
+ ALTHUNK_REMOVEENTRY(temp->databuffer);
+ memset(temp, 0, sizeof(ALdatabuffer));
+ free(temp);
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alEffect.h"
+#include "alThunk.h"
+#include "alError.h"
+
+
+ALboolean DisabledEffects[MAX_EFFECTS];
+
+
+static void InitEffectParams(ALeffect *effect, ALenum type);
+
+#define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
+{
+ ALCcontext *Context;
+ ALsizei i=0;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0 || IsBadWritePtr((void*)effects, n * sizeof(ALuint)))
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ ALCdevice *device = Context->Device;
+ ALenum err;
+
+ while(i < n)
+ {
+ ALeffect *effect = calloc(1, sizeof(ALeffect));
+ if(!effect)
+ {
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ alDeleteEffects(i, effects);
+ break;
+ }
+
+ effect->effect = ALTHUNK_ADDENTRY(effect);
+ err = InsertUIntMapEntry(&device->EffectMap, effect->effect, effect);
+ if(err != AL_NO_ERROR)
+ {
+ ALTHUNK_REMOVEENTRY(effect->effect);
+ memset(effect, 0, sizeof(ALeffect));
+ free(effect);
+
+ alSetError(Context, err);
+ alDeleteEffects(i, effects);
+ break;
+ }
+
+ effects[i++] = effect->effect;
+ InitEffectParams(effect, AL_EFFECT_NULL);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects)
+{
+ ALCcontext *Context;
+ ALCdevice *device;
+ ALeffect *ALEffect;
+ ALboolean Failed;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Failed = AL_TRUE;
+ device = Context->Device;
+ if(n < 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ Failed = AL_FALSE;
+ // Check that all effects are valid
+ for(i = 0;i < n;i++)
+ {
+ if(!effects[i])
+ continue;
+
+ if(LookupEffect(device->EffectMap, effects[i]) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ Failed = AL_TRUE;
+ break;
+ }
+ }
+ }
+
+ if(!Failed)
+ {
+ // All effects are valid
+ for(i = 0;i < n;i++)
+ {
+ // Recheck that the effect is valid, because there could be duplicated names
+ if((ALEffect=LookupEffect(device->EffectMap, effects[i])) == NULL)
+ continue;
+
+ RemoveUIntMapKey(&device->EffectMap, ALEffect->effect);
+ ALTHUNK_REMOVEENTRY(ALEffect->effect);
+
+ memset(ALEffect, 0, sizeof(ALeffect));
+ free(ALEffect);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
+{
+ ALCcontext *Context;
+ ALboolean result;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ result = ((!effect || LookupEffect(Context->Device->EffectMap, effect)) ?
+ AL_TRUE : AL_FALSE);
+
+ ProcessContext(Context);
+
+ return result;
+}
+
+AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(param == AL_EFFECT_TYPE)
+ {
+ ALboolean isOk = (iValue == AL_EFFECT_NULL ||
+ (iValue == AL_EFFECT_EAXREVERB && !DisabledEffects[EAXREVERB]) ||
+ (iValue == AL_EFFECT_REVERB && !DisabledEffects[REVERB]) ||
+ (iValue == AL_EFFECT_ECHO && !DisabledEffects[ECHO]) ||
+ (iValue == AL_EFFECT_RING_MODULATOR && !DisabledEffects[MODULATOR]));
+
+ if(isOk)
+ InitEffectParams(ALEffect, iValue);
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ }
+ else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DECAY_HFLIMIT:
+ if(iValue >= AL_EAXREVERB_MIN_DECAY_HFLIMIT &&
+ iValue <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)
+ ALEffect->Reverb.DecayHFLimit = iValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DECAY_HFLIMIT:
+ if(iValue >= AL_REVERB_MIN_DECAY_HFLIMIT &&
+ iValue <= AL_REVERB_MAX_DECAY_HFLIMIT)
+ ALEffect->Reverb.DecayHFLimit = iValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ alEffectf(effect, param, (ALfloat)iValue);
+ break;
+
+ case AL_RING_MODULATOR_WAVEFORM:
+ if(iValue >= AL_RING_MODULATOR_MIN_WAVEFORM &&
+ iValue <= AL_RING_MODULATOR_MAX_WAVEFORM)
+ ALEffect->Modulator.Waveform = iValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(param == AL_EFFECT_TYPE)
+ {
+ alEffecti(effect, param, piValues[0]);
+ }
+ else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DECAY_HFLIMIT:
+ alEffecti(effect, param, piValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DECAY_HFLIMIT:
+ alEffecti(effect, param, piValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ case AL_RING_MODULATOR_WAVEFORM:
+ alEffecti(effect, param, piValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DENSITY:
+ if(flValue >= AL_EAXREVERB_MIN_DENSITY &&
+ flValue <= AL_EAXREVERB_MAX_DENSITY)
+ ALEffect->Reverb.Density = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DIFFUSION:
+ if(flValue >= AL_EAXREVERB_MIN_DIFFUSION &&
+ flValue <= AL_EAXREVERB_MAX_DIFFUSION)
+ ALEffect->Reverb.Diffusion = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_GAIN:
+ if(flValue >= AL_EAXREVERB_MIN_GAIN &&
+ flValue <= AL_EAXREVERB_MAX_GAIN)
+ ALEffect->Reverb.Gain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_GAINHF:
+ if(flValue >= AL_EAXREVERB_MIN_GAINHF &&
+ flValue <= AL_EAXREVERB_MAX_GAIN)
+ ALEffect->Reverb.GainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_GAINLF:
+ if(flValue >= AL_EAXREVERB_MIN_GAINLF &&
+ flValue <= AL_EAXREVERB_MAX_GAINLF)
+ ALEffect->Reverb.GainLF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DECAY_TIME:
+ if(flValue >= AL_EAXREVERB_MIN_DECAY_TIME &&
+ flValue <= AL_EAXREVERB_MAX_DECAY_TIME)
+ ALEffect->Reverb.DecayTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ if(flValue >= AL_EAXREVERB_MIN_DECAY_HFRATIO &&
+ flValue <= AL_EAXREVERB_MAX_DECAY_HFRATIO)
+ ALEffect->Reverb.DecayHFRatio = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ if(flValue >= AL_EAXREVERB_MIN_DECAY_LFRATIO &&
+ flValue <= AL_EAXREVERB_MAX_DECAY_LFRATIO)
+ ALEffect->Reverb.DecayLFRatio = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ if(flValue >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN &&
+ flValue <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)
+ ALEffect->Reverb.ReflectionsGain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ if(flValue >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY &&
+ flValue <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)
+ ALEffect->Reverb.ReflectionsDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ if(flValue >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN &&
+ flValue <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)
+ ALEffect->Reverb.LateReverbGain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
+ if(flValue >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY &&
+ flValue <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)
+ ALEffect->Reverb.LateReverbDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+ if(flValue >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF &&
+ flValue <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)
+ ALEffect->Reverb.AirAbsorptionGainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_ECHO_TIME:
+ if(flValue >= AL_EAXREVERB_MIN_ECHO_TIME &&
+ flValue <= AL_EAXREVERB_MAX_ECHO_TIME)
+ ALEffect->Reverb.EchoTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_ECHO_DEPTH:
+ if(flValue >= AL_EAXREVERB_MIN_ECHO_DEPTH &&
+ flValue <= AL_EAXREVERB_MAX_ECHO_DEPTH)
+ ALEffect->Reverb.EchoDepth = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_MODULATION_TIME:
+ if(flValue >= AL_EAXREVERB_MIN_MODULATION_TIME &&
+ flValue <= AL_EAXREVERB_MAX_MODULATION_TIME)
+ ALEffect->Reverb.ModulationTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ if(flValue >= AL_EAXREVERB_MIN_MODULATION_DEPTH &&
+ flValue <= AL_EAXREVERB_MAX_MODULATION_DEPTH)
+ ALEffect->Reverb.ModulationDepth = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_HFREFERENCE:
+ if(flValue >= AL_EAXREVERB_MIN_HFREFERENCE &&
+ flValue <= AL_EAXREVERB_MAX_HFREFERENCE)
+ ALEffect->Reverb.HFReference = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_LFREFERENCE:
+ if(flValue >= AL_EAXREVERB_MIN_LFREFERENCE &&
+ flValue <= AL_EAXREVERB_MAX_LFREFERENCE)
+ ALEffect->Reverb.LFReference = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ if(flValue >= 0.0f && flValue <= 10.0f)
+ ALEffect->Reverb.RoomRolloffFactor = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DENSITY:
+ if(flValue >= AL_REVERB_MIN_DENSITY &&
+ flValue <= AL_REVERB_MAX_DENSITY)
+ ALEffect->Reverb.Density = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_DIFFUSION:
+ if(flValue >= AL_REVERB_MIN_DIFFUSION &&
+ flValue <= AL_REVERB_MAX_DIFFUSION)
+ ALEffect->Reverb.Diffusion = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_GAIN:
+ if(flValue >= AL_REVERB_MIN_GAIN &&
+ flValue <= AL_REVERB_MAX_GAIN)
+ ALEffect->Reverb.Gain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_GAINHF:
+ if(flValue >= AL_REVERB_MIN_GAINHF &&
+ flValue <= AL_REVERB_MAX_GAINHF)
+ ALEffect->Reverb.GainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_DECAY_TIME:
+ if(flValue >= AL_REVERB_MIN_DECAY_TIME &&
+ flValue <= AL_REVERB_MAX_DECAY_TIME)
+ ALEffect->Reverb.DecayTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_DECAY_HFRATIO:
+ if(flValue >= AL_REVERB_MIN_DECAY_HFRATIO &&
+ flValue <= AL_REVERB_MAX_DECAY_HFRATIO)
+ ALEffect->Reverb.DecayHFRatio = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_REFLECTIONS_GAIN:
+ if(flValue >= AL_REVERB_MIN_REFLECTIONS_GAIN &&
+ flValue <= AL_REVERB_MAX_REFLECTIONS_GAIN)
+ ALEffect->Reverb.ReflectionsGain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_REFLECTIONS_DELAY:
+ if(flValue >= AL_REVERB_MIN_REFLECTIONS_DELAY &&
+ flValue <= AL_REVERB_MAX_REFLECTIONS_DELAY)
+ ALEffect->Reverb.ReflectionsDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_LATE_REVERB_GAIN:
+ if(flValue >= AL_REVERB_MIN_LATE_REVERB_GAIN &&
+ flValue <= AL_REVERB_MAX_LATE_REVERB_GAIN)
+ ALEffect->Reverb.LateReverbGain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_LATE_REVERB_DELAY:
+ if(flValue >= AL_REVERB_MIN_LATE_REVERB_DELAY &&
+ flValue <= AL_REVERB_MAX_LATE_REVERB_DELAY)
+ ALEffect->Reverb.LateReverbDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
+ if(flValue >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF &&
+ flValue <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)
+ ALEffect->Reverb.AirAbsorptionGainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+ if(flValue >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR &&
+ flValue <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)
+ ALEffect->Reverb.RoomRolloffFactor = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ case AL_ECHO_DELAY:
+ if(flValue >= AL_ECHO_MIN_DELAY && flValue <= AL_ECHO_MAX_DELAY)
+ ALEffect->Echo.Delay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_LRDELAY:
+ if(flValue >= AL_ECHO_MIN_LRDELAY && flValue <= AL_ECHO_MAX_LRDELAY)
+ ALEffect->Echo.LRDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_DAMPING:
+ if(flValue >= AL_ECHO_MIN_DAMPING && flValue <= AL_ECHO_MAX_DAMPING)
+ ALEffect->Echo.Damping = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_FEEDBACK:
+ if(flValue >= AL_ECHO_MIN_FEEDBACK && flValue <= AL_ECHO_MAX_FEEDBACK)
+ ALEffect->Echo.Feedback = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_SPREAD:
+ if(flValue >= AL_ECHO_MIN_SPREAD && flValue <= AL_ECHO_MAX_SPREAD)
+ ALEffect->Echo.Spread = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ if(flValue >= AL_RING_MODULATOR_MIN_FREQUENCY &&
+ flValue <= AL_RING_MODULATOR_MAX_FREQUENCY)
+ ALEffect->Modulator.Frequency = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ if(flValue >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF &&
+ flValue <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)
+ ALEffect->Modulator.HighPassCutoff = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DENSITY:
+ case AL_EAXREVERB_DIFFUSION:
+ case AL_EAXREVERB_GAIN:
+ case AL_EAXREVERB_GAINHF:
+ case AL_EAXREVERB_GAINLF:
+ case AL_EAXREVERB_DECAY_TIME:
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+ case AL_EAXREVERB_ECHO_TIME:
+ case AL_EAXREVERB_ECHO_DEPTH:
+ case AL_EAXREVERB_MODULATION_TIME:
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ case AL_EAXREVERB_HFREFERENCE:
+ case AL_EAXREVERB_LFREFERENCE:
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ alEffectf(effect, param, pflValues[0]);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_PAN:
+ if(!isnan(pflValues[0]) && !isnan(pflValues[1]) && !isnan(pflValues[2]))
+ {
+ ALEffect->Reverb.ReflectionsPan[0] = pflValues[0];
+ ALEffect->Reverb.ReflectionsPan[1] = pflValues[1];
+ ALEffect->Reverb.ReflectionsPan[2] = pflValues[2];
+ }
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+ case AL_EAXREVERB_LATE_REVERB_PAN:
+ if(!isnan(pflValues[0]) && !isnan(pflValues[1]) && !isnan(pflValues[2]))
+ {
+ ALEffect->Reverb.LateReverbPan[0] = pflValues[0];
+ ALEffect->Reverb.LateReverbPan[1] = pflValues[1];
+ ALEffect->Reverb.LateReverbPan[2] = pflValues[2];
+ }
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DENSITY:
+ case AL_REVERB_DIFFUSION:
+ case AL_REVERB_GAIN:
+ case AL_REVERB_GAINHF:
+ case AL_REVERB_DECAY_TIME:
+ case AL_REVERB_DECAY_HFRATIO:
+ case AL_REVERB_REFLECTIONS_GAIN:
+ case AL_REVERB_REFLECTIONS_DELAY:
+ case AL_REVERB_LATE_REVERB_GAIN:
+ case AL_REVERB_LATE_REVERB_DELAY:
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+ alEffectf(effect, param, pflValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ case AL_ECHO_DELAY:
+ case AL_ECHO_LRDELAY:
+ case AL_ECHO_DAMPING:
+ case AL_ECHO_FEEDBACK:
+ case AL_ECHO_SPREAD:
+ alEffectf(effect, param, pflValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ alEffectf(effect, param, pflValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(param == AL_EFFECT_TYPE)
+ {
+ *piValue = ALEffect->type;
+ }
+ else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DECAY_HFLIMIT:
+ *piValue = ALEffect->Reverb.DecayHFLimit;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DECAY_HFLIMIT:
+ *piValue = ALEffect->Reverb.DecayHFLimit;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ *piValue = (ALint)ALEffect->Modulator.Frequency;
+ break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ *piValue = (ALint)ALEffect->Modulator.HighPassCutoff;
+ break;
+ case AL_RING_MODULATOR_WAVEFORM:
+ *piValue = ALEffect->Modulator.Waveform;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(param == AL_EFFECT_TYPE)
+ {
+ alGetEffecti(effect, param, piValues);
+ }
+ else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DECAY_HFLIMIT:
+ alGetEffecti(effect, param, piValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DECAY_HFLIMIT:
+ alGetEffecti(effect, param, piValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ case AL_RING_MODULATOR_WAVEFORM:
+ alGetEffecti(effect, param, piValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DENSITY:
+ *pflValue = ALEffect->Reverb.Density;
+ break;
+
+ case AL_EAXREVERB_DIFFUSION:
+ *pflValue = ALEffect->Reverb.Diffusion;
+ break;
+
+ case AL_EAXREVERB_GAIN:
+ *pflValue = ALEffect->Reverb.Gain;
+ break;
+
+ case AL_EAXREVERB_GAINHF:
+ *pflValue = ALEffect->Reverb.GainHF;
+ break;
+
+ case AL_EAXREVERB_GAINLF:
+ *pflValue = ALEffect->Reverb.GainLF;
+ break;
+
+ case AL_EAXREVERB_DECAY_TIME:
+ *pflValue = ALEffect->Reverb.DecayTime;
+ break;
+
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ *pflValue = ALEffect->Reverb.DecayHFRatio;
+ break;
+
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ *pflValue = ALEffect->Reverb.DecayLFRatio;
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ *pflValue = ALEffect->Reverb.ReflectionsGain;
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ *pflValue = ALEffect->Reverb.ReflectionsDelay;
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ *pflValue = ALEffect->Reverb.LateReverbGain;
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
+ *pflValue = ALEffect->Reverb.LateReverbDelay;
+ break;
+
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+ *pflValue = ALEffect->Reverb.AirAbsorptionGainHF;
+ break;
+
+ case AL_EAXREVERB_ECHO_TIME:
+ *pflValue = ALEffect->Reverb.EchoTime;
+ break;
+
+ case AL_EAXREVERB_ECHO_DEPTH:
+ *pflValue = ALEffect->Reverb.EchoDepth;
+ break;
+
+ case AL_EAXREVERB_MODULATION_TIME:
+ *pflValue = ALEffect->Reverb.ModulationTime;
+ break;
+
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ *pflValue = ALEffect->Reverb.ModulationDepth;
+ break;
+
+ case AL_EAXREVERB_HFREFERENCE:
+ *pflValue = ALEffect->Reverb.HFReference;
+ break;
+
+ case AL_EAXREVERB_LFREFERENCE:
+ *pflValue = ALEffect->Reverb.LFReference;
+ break;
+
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ *pflValue = ALEffect->Reverb.RoomRolloffFactor;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DENSITY:
+ *pflValue = ALEffect->Reverb.Density;
+ break;
+
+ case AL_REVERB_DIFFUSION:
+ *pflValue = ALEffect->Reverb.Diffusion;
+ break;
+
+ case AL_REVERB_GAIN:
+ *pflValue = ALEffect->Reverb.Gain;
+ break;
+
+ case AL_REVERB_GAINHF:
+ *pflValue = ALEffect->Reverb.GainHF;
+ break;
+
+ case AL_REVERB_DECAY_TIME:
+ *pflValue = ALEffect->Reverb.DecayTime;
+ break;
+
+ case AL_REVERB_DECAY_HFRATIO:
+ *pflValue = ALEffect->Reverb.DecayHFRatio;
+ break;
+
+ case AL_REVERB_REFLECTIONS_GAIN:
+ *pflValue = ALEffect->Reverb.ReflectionsGain;
+ break;
+
+ case AL_REVERB_REFLECTIONS_DELAY:
+ *pflValue = ALEffect->Reverb.ReflectionsDelay;
+ break;
+
+ case AL_REVERB_LATE_REVERB_GAIN:
+ *pflValue = ALEffect->Reverb.LateReverbGain;
+ break;
+
+ case AL_REVERB_LATE_REVERB_DELAY:
+ *pflValue = ALEffect->Reverb.LateReverbDelay;
+ break;
+
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
+ *pflValue = ALEffect->Reverb.AirAbsorptionGainHF;
+ break;
+
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+ *pflValue = ALEffect->Reverb.RoomRolloffFactor;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ case AL_ECHO_DELAY:
+ *pflValue = ALEffect->Echo.Delay;
+ break;
+
+ case AL_ECHO_LRDELAY:
+ *pflValue = ALEffect->Echo.LRDelay;
+ break;
+
+ case AL_ECHO_DAMPING:
+ *pflValue = ALEffect->Echo.Damping;
+ break;
+
+ case AL_ECHO_FEEDBACK:
+ *pflValue = ALEffect->Echo.Feedback;
+ break;
+
+ case AL_ECHO_SPREAD:
+ *pflValue = ALEffect->Echo.Spread;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ *pflValue = ALEffect->Modulator.Frequency;
+ break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ *pflValue = ALEffect->Modulator.HighPassCutoff;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+ {
+ if(ALEffect->type == AL_EFFECT_EAXREVERB)
+ {
+ switch(param)
+ {
+ case AL_EAXREVERB_DENSITY:
+ case AL_EAXREVERB_DIFFUSION:
+ case AL_EAXREVERB_GAIN:
+ case AL_EAXREVERB_GAINHF:
+ case AL_EAXREVERB_GAINLF:
+ case AL_EAXREVERB_DECAY_TIME:
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+ case AL_EAXREVERB_ECHO_TIME:
+ case AL_EAXREVERB_ECHO_DEPTH:
+ case AL_EAXREVERB_MODULATION_TIME:
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ case AL_EAXREVERB_HFREFERENCE:
+ case AL_EAXREVERB_LFREFERENCE:
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ alGetEffectf(effect, param, pflValues);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_PAN:
+ pflValues[0] = ALEffect->Reverb.ReflectionsPan[0];
+ pflValues[1] = ALEffect->Reverb.ReflectionsPan[1];
+ pflValues[2] = ALEffect->Reverb.ReflectionsPan[2];
+ break;
+ case AL_EAXREVERB_LATE_REVERB_PAN:
+ pflValues[0] = ALEffect->Reverb.LateReverbPan[0];
+ pflValues[1] = ALEffect->Reverb.LateReverbPan[1];
+ pflValues[2] = ALEffect->Reverb.LateReverbPan[2];
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_REVERB)
+ {
+ switch(param)
+ {
+ case AL_REVERB_DENSITY:
+ case AL_REVERB_DIFFUSION:
+ case AL_REVERB_GAIN:
+ case AL_REVERB_GAINHF:
+ case AL_REVERB_DECAY_TIME:
+ case AL_REVERB_DECAY_HFRATIO:
+ case AL_REVERB_REFLECTIONS_GAIN:
+ case AL_REVERB_REFLECTIONS_DELAY:
+ case AL_REVERB_LATE_REVERB_GAIN:
+ case AL_REVERB_LATE_REVERB_DELAY:
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+ alGetEffectf(effect, param, pflValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_ECHO)
+ {
+ switch(param)
+ {
+ case AL_ECHO_DELAY:
+ case AL_ECHO_LRDELAY:
+ case AL_ECHO_DAMPING:
+ case AL_ECHO_FEEDBACK:
+ case AL_ECHO_SPREAD:
+ alGetEffectf(effect, param, pflValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+ {
+ switch(param)
+ {
+ case AL_RING_MODULATOR_FREQUENCY:
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ alGetEffectf(effect, param, pflValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_ENUM);
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+
+ALvoid ReleaseALEffects(ALCdevice *device)
+{
+ ALsizei i;
+ for(i = 0;i < device->EffectMap.size;i++)
+ {
+ ALeffect *temp = device->EffectMap.array[i].value;
+ device->EffectMap.array[i].value = NULL;
+
+ // Release effect structure
+ ALTHUNK_REMOVEENTRY(temp->effect);
+ memset(temp, 0, sizeof(ALeffect));
+ free(temp);
+ }
+}
+
+
+static void InitEffectParams(ALeffect *effect, ALenum type)
+{
+ effect->type = type;
+ switch(type)
+ {
+ /* NOTE: Standard reverb and EAX reverb use the same defaults for the
+ * shared parameters, and EAX's additional parameters default to
+ * values assumed by standard reverb.
+ */
+ case AL_EFFECT_EAXREVERB:
+ case AL_EFFECT_REVERB:
+ effect->Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
+ effect->Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
+ effect->Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
+ effect->Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
+ effect->Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
+ effect->Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
+ effect->Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
+ effect->Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
+ effect->Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
+ effect->Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
+ effect->Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ effect->Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ effect->Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+ effect->Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
+ effect->Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
+ effect->Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ effect->Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ effect->Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+ effect->Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
+ effect->Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
+ effect->Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
+ effect->Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
+ effect->Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+ effect->Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
+ effect->Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
+ effect->Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
+ effect->Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
+ break;
+ case AL_EFFECT_ECHO:
+ effect->Echo.Delay = AL_ECHO_DEFAULT_DELAY;
+ effect->Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
+ effect->Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
+ effect->Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
+ effect->Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
+ break;
+ case AL_EFFECT_RING_MODULATOR:
+ effect->Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
+ effect->Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
+ effect->Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
+ break;
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2000 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include "alMain.h"
+#include "AL/alc.h"
+#include "alError.h"
+
+AL_API ALenum AL_APIENTRY alGetError(ALvoid)
+{
+ ALCcontext *Context;
+ ALenum errorCode;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_INVALID_OPERATION;
+
+ errorCode = Context->LastError;
+ Context->LastError = AL_NO_ERROR;
+
+ ProcessContext(Context);
+
+ return errorCode;
+}
+
+ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
+{
+ if(Context->LastError == AL_NO_ERROR)
+ Context->LastError = errorCode;
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "alError.h"
+#include "alMain.h"
+#include "alFilter.h"
+#include "alEffect.h"
+#include "alAuxEffectSlot.h"
+#include "alDatabuffer.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+typedef struct ALenums {
+ const ALchar *enumName;
+ ALenum value;
+} ALenums;
+
+
+static const ALenums enumeration[] = {
+ // Types
+ { "AL_INVALID", AL_INVALID },
+ { "AL_NONE", AL_NONE },
+ { "AL_FALSE", AL_FALSE },
+ { "AL_TRUE", AL_TRUE },
+
+ // Source and Listener Properties
+ { "AL_SOURCE_RELATIVE", AL_SOURCE_RELATIVE },
+ { "AL_CONE_INNER_ANGLE", AL_CONE_INNER_ANGLE },
+ { "AL_CONE_OUTER_ANGLE", AL_CONE_OUTER_ANGLE },
+ { "AL_PITCH", AL_PITCH },
+ { "AL_POSITION", AL_POSITION },
+ { "AL_DIRECTION", AL_DIRECTION },
+ { "AL_VELOCITY", AL_VELOCITY },
+ { "AL_LOOPING", AL_LOOPING },
+ { "AL_BUFFER", AL_BUFFER },
+ { "AL_GAIN", AL_GAIN },
+ { "AL_MIN_GAIN", AL_MIN_GAIN },
+ { "AL_MAX_GAIN", AL_MAX_GAIN },
+ { "AL_ORIENTATION", AL_ORIENTATION },
+ { "AL_REFERENCE_DISTANCE", AL_REFERENCE_DISTANCE },
+ { "AL_ROLLOFF_FACTOR", AL_ROLLOFF_FACTOR },
+ { "AL_CONE_OUTER_GAIN", AL_CONE_OUTER_GAIN },
+ { "AL_MAX_DISTANCE", AL_MAX_DISTANCE },
+ { "AL_SEC_OFFSET", AL_SEC_OFFSET },
+ { "AL_SAMPLE_OFFSET", AL_SAMPLE_OFFSET },
+ { "AL_SAMPLE_RW_OFFSETS_SOFT", AL_SAMPLE_RW_OFFSETS_SOFT },
+ { "AL_BYTE_OFFSET", AL_BYTE_OFFSET },
+ { "AL_BYTE_RW_OFFSETS_SOFT", AL_BYTE_RW_OFFSETS_SOFT },
+ { "AL_SOURCE_TYPE", AL_SOURCE_TYPE },
+ { "AL_STATIC", AL_STATIC },
+ { "AL_STREAMING", AL_STREAMING },
+ { "AL_UNDETERMINED", AL_UNDETERMINED },
+ { "AL_METERS_PER_UNIT", AL_METERS_PER_UNIT },
+
+ // Source EFX Properties
+ { "AL_DIRECT_FILTER", AL_DIRECT_FILTER },
+ { "AL_AUXILIARY_SEND_FILTER", AL_AUXILIARY_SEND_FILTER },
+ { "AL_AIR_ABSORPTION_FACTOR", AL_AIR_ABSORPTION_FACTOR },
+ { "AL_ROOM_ROLLOFF_FACTOR", AL_ROOM_ROLLOFF_FACTOR },
+ { "AL_CONE_OUTER_GAINHF", AL_CONE_OUTER_GAINHF },
+ { "AL_DIRECT_FILTER_GAINHF_AUTO", AL_DIRECT_FILTER_GAINHF_AUTO },
+ { "AL_AUXILIARY_SEND_FILTER_GAIN_AUTO", AL_AUXILIARY_SEND_FILTER_GAIN_AUTO },
+ { "AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO", AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO},
+
+ // Source State information
+ { "AL_SOURCE_STATE", AL_SOURCE_STATE },
+ { "AL_INITIAL", AL_INITIAL },
+ { "AL_PLAYING", AL_PLAYING },
+ { "AL_PAUSED", AL_PAUSED },
+ { "AL_STOPPED", AL_STOPPED },
+
+ // Queue information
+ { "AL_BUFFERS_QUEUED", AL_BUFFERS_QUEUED },
+ { "AL_BUFFERS_PROCESSED", AL_BUFFERS_PROCESSED },
+
+ // Buffer Formats
+ { "AL_FORMAT_MONO8", AL_FORMAT_MONO8 },
+ { "AL_FORMAT_MONO16", AL_FORMAT_MONO16 },
+ { "AL_FORMAT_MONO_FLOAT32", AL_FORMAT_MONO_FLOAT32 },
+ { "AL_FORMAT_MONO_DOUBLE_EXT", AL_FORMAT_MONO_DOUBLE_EXT },
+ { "AL_FORMAT_STEREO8", AL_FORMAT_STEREO8 },
+ { "AL_FORMAT_STEREO16", AL_FORMAT_STEREO16 },
+ { "AL_FORMAT_STEREO_FLOAT32", AL_FORMAT_STEREO_FLOAT32 },
+ { "AL_FORMAT_STEREO_DOUBLE_EXT", AL_FORMAT_STEREO_DOUBLE_EXT },
+ { "AL_FORMAT_MONO_IMA4", AL_FORMAT_MONO_IMA4 },
+ { "AL_FORMAT_STEREO_IMA4", AL_FORMAT_STEREO_IMA4 },
+ { "AL_FORMAT_QUAD8_LOKI", AL_FORMAT_QUAD8_LOKI },
+ { "AL_FORMAT_QUAD16_LOKI", AL_FORMAT_QUAD16_LOKI },
+ { "AL_FORMAT_QUAD8", AL_FORMAT_QUAD8 },
+ { "AL_FORMAT_QUAD16", AL_FORMAT_QUAD16 },
+ { "AL_FORMAT_QUAD32", AL_FORMAT_QUAD32 },
+ { "AL_FORMAT_51CHN8", AL_FORMAT_51CHN8 },
+ { "AL_FORMAT_51CHN16", AL_FORMAT_51CHN16 },
+ { "AL_FORMAT_51CHN32", AL_FORMAT_51CHN32 },
+ { "AL_FORMAT_61CHN8", AL_FORMAT_61CHN8 },
+ { "AL_FORMAT_61CHN16", AL_FORMAT_61CHN16 },
+ { "AL_FORMAT_61CHN32", AL_FORMAT_61CHN32 },
+ { "AL_FORMAT_71CHN8", AL_FORMAT_71CHN8 },
+ { "AL_FORMAT_71CHN16", AL_FORMAT_71CHN16 },
+ { "AL_FORMAT_71CHN32", AL_FORMAT_71CHN32 },
+ { "AL_FORMAT_REAR8", AL_FORMAT_REAR8 },
+ { "AL_FORMAT_REAR16", AL_FORMAT_REAR16 },
+ { "AL_FORMAT_REAR32", AL_FORMAT_REAR32 },
+ { "AL_FORMAT_MONO_MULAW", AL_FORMAT_MONO_MULAW },
+ { "AL_FORMAT_MONO_MULAW_EXT", AL_FORMAT_MONO_MULAW },
+ { "AL_FORMAT_STEREO_MULAW", AL_FORMAT_STEREO_MULAW },
+ { "AL_FORMAT_STEREO_MULAW_EXT", AL_FORMAT_STEREO_MULAW },
+ { "AL_FORMAT_QUAD_MULAW", AL_FORMAT_QUAD_MULAW },
+ { "AL_FORMAT_51CHN_MULAW", AL_FORMAT_51CHN_MULAW },
+ { "AL_FORMAT_61CHN_MULAW", AL_FORMAT_61CHN_MULAW },
+ { "AL_FORMAT_71CHN_MULAW", AL_FORMAT_71CHN_MULAW },
+ { "AL_FORMAT_REAR_MULAW", AL_FORMAT_REAR_MULAW },
+
+ // Buffer attributes
+ { "AL_FREQUENCY", AL_FREQUENCY },
+ { "AL_BITS", AL_BITS },
+ { "AL_CHANNELS", AL_CHANNELS },
+ { "AL_SIZE", AL_SIZE },
+
+ // Buffer States (not supported yet)
+ { "AL_UNUSED", AL_UNUSED },
+ { "AL_PENDING", AL_PENDING },
+ { "AL_PROCESSED", AL_PROCESSED },
+
+ // AL Error Messages
+ { "AL_NO_ERROR", AL_NO_ERROR },
+ { "AL_INVALID_NAME", AL_INVALID_NAME },
+ { "AL_INVALID_ENUM", AL_INVALID_ENUM },
+ { "AL_INVALID_VALUE", AL_INVALID_VALUE },
+ { "AL_INVALID_OPERATION", AL_INVALID_OPERATION },
+ { "AL_OUT_OF_MEMORY", AL_OUT_OF_MEMORY },
+
+ // Context strings
+ { "AL_VENDOR", AL_VENDOR },
+ { "AL_VERSION", AL_VERSION },
+ { "AL_RENDERER", AL_RENDERER },
+ { "AL_EXTENSIONS", AL_EXTENSIONS },
+
+ // Global states
+ { "AL_DOPPLER_FACTOR", AL_DOPPLER_FACTOR },
+ { "AL_DOPPLER_VELOCITY", AL_DOPPLER_VELOCITY },
+ { "AL_DISTANCE_MODEL", AL_DISTANCE_MODEL },
+ { "AL_SPEED_OF_SOUND", AL_SPEED_OF_SOUND },
+ { "AL_SOURCE_DISTANCE_MODEL", AL_SOURCE_DISTANCE_MODEL },
+
+ // Distance Models
+ { "AL_INVERSE_DISTANCE", AL_INVERSE_DISTANCE },
+ { "AL_INVERSE_DISTANCE_CLAMPED", AL_INVERSE_DISTANCE_CLAMPED },
+ { "AL_LINEAR_DISTANCE", AL_LINEAR_DISTANCE },
+ { "AL_LINEAR_DISTANCE_CLAMPED", AL_LINEAR_DISTANCE_CLAMPED },
+ { "AL_EXPONENT_DISTANCE", AL_EXPONENT_DISTANCE },
+ { "AL_EXPONENT_DISTANCE_CLAMPED", AL_EXPONENT_DISTANCE_CLAMPED },
+
+ // Filter types
+ { "AL_FILTER_TYPE", AL_FILTER_TYPE },
+ { "AL_FILTER_NULL", AL_FILTER_NULL },
+ { "AL_FILTER_LOWPASS", AL_FILTER_LOWPASS },
+#if 0
+ { "AL_FILTER_HIGHPASS", AL_FILTER_HIGHPASS },
+ { "AL_FILTER_BANDPASS", AL_FILTER_BANDPASS },
+#endif
+
+ // Filter params
+ { "AL_LOWPASS_GAIN", AL_LOWPASS_GAIN },
+ { "AL_LOWPASS_GAINHF", AL_LOWPASS_GAINHF },
+
+ // Effect types
+ { "AL_EFFECT_TYPE", AL_EFFECT_TYPE },
+ { "AL_EFFECT_NULL", AL_EFFECT_NULL },
+ { "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
+ { "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
+#if 0
+ { "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
+ { "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
+#endif
+ { "AL_EFFECT_ECHO", AL_EFFECT_ECHO },
+#if 0
+ { "AL_EFFECT_FLANGER", AL_EFFECT_FLANGER },
+ { "AL_EFFECT_FREQUENCY_SHIFTER", AL_EFFECT_FREQUENCY_SHIFTER },
+ { "AL_EFFECT_VOCAL_MORPHER", AL_EFFECT_VOCAL_MORPHER },
+ { "AL_EFFECT_PITCH_SHIFTER", AL_EFFECT_PITCH_SHIFTER },
+#endif
+ { "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR },
+#if 0
+ { "AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH },
+ { "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
+ { "AL_EFFECT_EQUALIZER", AL_EFFECT_EQUALIZER },
+#endif
+
+ // Reverb params
+ { "AL_REVERB_DENSITY", AL_REVERB_DENSITY },
+ { "AL_REVERB_DIFFUSION", AL_REVERB_DIFFUSION },
+ { "AL_REVERB_GAIN", AL_REVERB_GAIN },
+ { "AL_REVERB_GAINHF", AL_REVERB_GAINHF },
+ { "AL_REVERB_DECAY_TIME", AL_REVERB_DECAY_TIME },
+ { "AL_REVERB_DECAY_HFRATIO", AL_REVERB_DECAY_HFRATIO },
+ { "AL_REVERB_REFLECTIONS_GAIN", AL_REVERB_REFLECTIONS_GAIN },
+ { "AL_REVERB_REFLECTIONS_DELAY", AL_REVERB_REFLECTIONS_DELAY },
+ { "AL_REVERB_LATE_REVERB_GAIN", AL_REVERB_LATE_REVERB_GAIN },
+ { "AL_REVERB_LATE_REVERB_DELAY", AL_REVERB_LATE_REVERB_DELAY },
+ { "AL_REVERB_AIR_ABSORPTION_GAINHF", AL_REVERB_AIR_ABSORPTION_GAINHF },
+ { "AL_REVERB_ROOM_ROLLOFF_FACTOR", AL_REVERB_ROOM_ROLLOFF_FACTOR },
+ { "AL_REVERB_DECAY_HFLIMIT", AL_REVERB_DECAY_HFLIMIT },
+
+ // EAX Reverb params
+ { "AL_EAXREVERB_DENSITY", AL_EAXREVERB_DENSITY },
+ { "AL_EAXREVERB_DIFFUSION", AL_EAXREVERB_DIFFUSION },
+ { "AL_EAXREVERB_GAIN", AL_EAXREVERB_GAIN },
+ { "AL_EAXREVERB_GAINHF", AL_EAXREVERB_GAINHF },
+ { "AL_EAXREVERB_GAINLF", AL_EAXREVERB_GAINLF },
+ { "AL_EAXREVERB_DECAY_TIME", AL_EAXREVERB_DECAY_TIME },
+ { "AL_EAXREVERB_DECAY_HFRATIO", AL_EAXREVERB_DECAY_HFRATIO },
+ { "AL_EAXREVERB_DECAY_LFRATIO", AL_EAXREVERB_DECAY_LFRATIO },
+ { "AL_EAXREVERB_REFLECTIONS_GAIN", AL_EAXREVERB_REFLECTIONS_GAIN },
+ { "AL_EAXREVERB_REFLECTIONS_DELAY", AL_EAXREVERB_REFLECTIONS_DELAY },
+ { "AL_EAXREVERB_REFLECTIONS_PAN", AL_EAXREVERB_REFLECTIONS_PAN },
+ { "AL_EAXREVERB_LATE_REVERB_GAIN", AL_EAXREVERB_LATE_REVERB_GAIN },
+ { "AL_EAXREVERB_LATE_REVERB_DELAY", AL_EAXREVERB_LATE_REVERB_DELAY },
+ { "AL_EAXREVERB_LATE_REVERB_PAN", AL_EAXREVERB_LATE_REVERB_PAN },
+ { "AL_EAXREVERB_ECHO_TIME", AL_EAXREVERB_ECHO_TIME },
+ { "AL_EAXREVERB_ECHO_DEPTH", AL_EAXREVERB_ECHO_DEPTH },
+ { "AL_EAXREVERB_MODULATION_TIME", AL_EAXREVERB_MODULATION_TIME },
+ { "AL_EAXREVERB_MODULATION_DEPTH", AL_EAXREVERB_MODULATION_DEPTH },
+ { "AL_EAXREVERB_AIR_ABSORPTION_GAINHF", AL_EAXREVERB_AIR_ABSORPTION_GAINHF },
+ { "AL_EAXREVERB_HFREFERENCE", AL_EAXREVERB_HFREFERENCE },
+ { "AL_EAXREVERB_LFREFERENCE", AL_EAXREVERB_LFREFERENCE },
+ { "AL_EAXREVERB_ROOM_ROLLOFF_FACTOR", AL_EAXREVERB_ROOM_ROLLOFF_FACTOR },
+ { "AL_EAXREVERB_DECAY_HFLIMIT", AL_EAXREVERB_DECAY_HFLIMIT },
+
+ // Echo params
+ { "AL_ECHO_DELAY", AL_ECHO_DELAY },
+ { "AL_ECHO_LRDELAY", AL_ECHO_LRDELAY },
+ { "AL_ECHO_DAMPING", AL_ECHO_DAMPING },
+ { "AL_ECHO_FEEDBACK", AL_ECHO_FEEDBACK },
+ { "AL_ECHO_SPREAD", AL_ECHO_SPREAD },
+
+ // Ring Modulator params
+ { "AL_RING_MODULATOR_FREQUENCY", AL_RING_MODULATOR_FREQUENCY },
+ { "AL_RING_MODULATOR_HIGHPASS_CUTOFF", AL_RING_MODULATOR_HIGHPASS_CUTOFF },
+ { "AL_RING_MODULATOR_WAVEFORM", AL_RING_MODULATOR_WAVEFORM },
+
+
+ // Default
+ { NULL, (ALenum)0 }
+};
+
+
+
+AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
+{
+ ALboolean bIsSupported = AL_FALSE;
+ ALCcontext *pContext;
+ const char *ptr;
+ size_t len;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return AL_FALSE;
+
+ if(!extName)
+ {
+ alSetError(pContext, AL_INVALID_VALUE);
+ ProcessContext(pContext);
+ return AL_FALSE;
+ }
+
+ len = strlen(extName);
+ ptr = pContext->ExtensionList;
+ while(ptr && *ptr)
+ {
+ if(strncasecmp(ptr, extName, len) == 0 &&
+ (ptr[len] == '\0' || isspace(ptr[len])))
+ {
+ bIsSupported = AL_TRUE;
+ break;
+ }
+ if((ptr=strchr(ptr, ' ')) != NULL)
+ {
+ do {
+ ++ptr;
+ } while(isspace(*ptr));
+ }
+ }
+
+ ProcessContext(pContext);
+
+ return bIsSupported;
+}
+
+
+AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName)
+{
+ if(!funcName)
+ return NULL;
+ return alcGetProcAddress(NULL, funcName);
+}
+
+AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName)
+{
+ ALsizei i = 0;
+
+ while(enumeration[i].enumName &&
+ strcmp(enumeration[i].enumName, enumName) != 0)
+ i++;
+
+ return enumeration[i].value;
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alFilter.h"
+#include "alThunk.h"
+#include "alError.h"
+
+
+static void InitFilterParams(ALfilter *filter, ALenum type);
+
+#define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
+{
+ ALCcontext *Context;
+ ALsizei i=0;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0 || IsBadWritePtr((void*)filters, n * sizeof(ALuint)))
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ ALCdevice *device = Context->Device;
+ ALenum err;
+
+ while(i < n)
+ {
+ ALfilter *filter = calloc(1, sizeof(ALfilter));
+ if(!filter)
+ {
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ alDeleteFilters(i, filters);
+ break;
+ }
+
+ filter->filter = ALTHUNK_ADDENTRY(filter);
+ err = InsertUIntMapEntry(&device->FilterMap, filter->filter, filter);
+ if(err != AL_NO_ERROR)
+ {
+ ALTHUNK_REMOVEENTRY(filter->filter);
+ memset(filter, 0, sizeof(ALfilter));
+ free(filter);
+
+ alSetError(Context, err);
+ alDeleteFilters(i, filters);
+ break;
+ }
+
+ filters[i++] = filter->filter;
+ InitFilterParams(filter, AL_FILTER_NULL);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
+{
+ ALCcontext *Context;
+ ALCdevice *device;
+ ALfilter *ALFilter;
+ ALboolean Failed;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Failed = AL_TRUE;
+ device = Context->Device;
+ if(n < 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ Failed = AL_FALSE;
+ // Check that all filters are valid
+ for(i = 0;i < n;i++)
+ {
+ if(!filters[i])
+ continue;
+
+ if(LookupFilter(device->FilterMap, filters[i]) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ Failed = AL_TRUE;
+ break;
+ }
+ }
+ }
+
+ if(!Failed)
+ {
+ // All filters are valid
+ for(i = 0;i < n;i++)
+ {
+ // Recheck that the filter is valid, because there could be duplicated names
+ if((ALFilter=LookupFilter(device->FilterMap, filters[i])) == NULL)
+ continue;
+
+ RemoveUIntMapKey(&device->FilterMap, ALFilter->filter);
+ ALTHUNK_REMOVEENTRY(ALFilter->filter);
+
+ memset(ALFilter, 0, sizeof(ALfilter));
+ free(ALFilter);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
+{
+ ALCcontext *Context;
+ ALboolean result;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ result = ((!filter || LookupFilter(Context->Device->FilterMap, filter)) ?
+ AL_TRUE : AL_FALSE);
+
+ ProcessContext(Context);
+
+ return result;
+}
+
+AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALfilter *ALFilter;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+ {
+ switch(param)
+ {
+ case AL_FILTER_TYPE:
+ if(iValue == AL_FILTER_NULL ||
+ iValue == AL_FILTER_LOWPASS)
+ InitFilterParams(ALFilter, iValue);
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if(LookupFilter(Device->FilterMap, filter) != NULL)
+ {
+ switch(param)
+ {
+ case AL_FILTER_TYPE:
+ alFilteri(filter, param, piValues[0]);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALfilter *ALFilter;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+ {
+ switch(ALFilter->type)
+ {
+ case AL_FILTER_LOWPASS:
+ switch(param)
+ {
+ case AL_LOWPASS_GAIN:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ ALFilter->Gain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_LOWPASS_GAINHF:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ ALFilter->GainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if(LookupFilter(Device->FilterMap, filter) != NULL)
+ {
+ switch(param)
+ {
+ default:
+ alFilterf(filter, param, pflValues[0]);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALfilter *ALFilter;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+ {
+ switch(param)
+ {
+ case AL_FILTER_TYPE:
+ *piValue = ALFilter->type;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if(LookupFilter(Device->FilterMap, filter) != NULL)
+ {
+ switch(param)
+ {
+ case AL_FILTER_TYPE:
+ alGetFilteri(filter, param, piValues);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALfilter *ALFilter;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+ {
+ switch(ALFilter->type)
+ {
+ case AL_FILTER_LOWPASS:
+ switch(param)
+ {
+ case AL_LOWPASS_GAIN:
+ *pflValue = ALFilter->Gain;
+ break;
+
+ case AL_LOWPASS_GAINHF:
+ *pflValue = ALFilter->GainHF;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if(LookupFilter(Device->FilterMap, filter) != NULL)
+ {
+ switch(param)
+ {
+ default:
+ alGetFilterf(filter, param, pflValues);
+ break;
+ }
+ }
+ else
+ alSetError(Context, AL_INVALID_NAME);
+
+ ProcessContext(Context);
+}
+
+
+ALvoid ReleaseALFilters(ALCdevice *device)
+{
+ ALsizei i;
+ for(i = 0;i < device->FilterMap.size;i++)
+ {
+ ALfilter *temp = device->FilterMap.array[i].value;
+ device->FilterMap.array[i].value = NULL;
+
+ // Release filter structure
+ ALTHUNK_REMOVEENTRY(temp->filter);
+ memset(temp, 0, sizeof(ALfilter));
+ free(temp);
+ }
+}
+
+
+static void InitFilterParams(ALfilter *filter, ALenum type)
+{
+ filter->type = type;
+
+ filter->Gain = 1.0;
+ filter->GainHF = 1.0;
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2000 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include "alMain.h"
+#include "AL/alc.h"
+#include "alError.h"
+#include "alListener.h"
+#include "alSource.h"
+
+AL_API ALvoid AL_APIENTRY alListenerf(ALenum eParam, ALfloat flValue)
+{
+ ALCcontext *pContext;
+ ALboolean updateAll = AL_FALSE;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ switch(eParam)
+ {
+ case AL_GAIN:
+ if(flValue >= 0.0f)
+ {
+ pContext->Listener.Gain = flValue;
+ updateAll = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_METERS_PER_UNIT:
+ if(flValue > 0.0f)
+ {
+ pContext->Listener.MetersPerUnit = flValue;
+ updateAll = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+
+ // Force updating the sources for these parameters, since even head-
+ // relative sources are affected
+ if(updateAll)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < pContext->SourceMap.size;pos++)
+ {
+ ALsource *source = pContext->SourceMap.array[pos].value;
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alListener3f(ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3)
+{
+ ALCcontext *pContext;
+ ALboolean updateWorld = AL_FALSE;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ switch(eParam)
+ {
+ case AL_POSITION:
+ pContext->Listener.Position[0] = flValue1;
+ pContext->Listener.Position[1] = flValue2;
+ pContext->Listener.Position[2] = flValue3;
+ updateWorld = AL_TRUE;
+ break;
+
+ case AL_VELOCITY:
+ pContext->Listener.Velocity[0] = flValue1;
+ pContext->Listener.Velocity[1] = flValue2;
+ pContext->Listener.Velocity[2] = flValue3;
+ updateWorld = AL_TRUE;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+
+ if(updateWorld)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < pContext->SourceMap.size;pos++)
+ {
+ ALsource *source = pContext->SourceMap.array[pos].value;
+ if(!source->bHeadRelative)
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues)
+{
+ ALCcontext *pContext;
+ ALboolean updateWorld = AL_FALSE;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValues)
+ {
+ switch(eParam)
+ {
+ case AL_GAIN:
+ case AL_METERS_PER_UNIT:
+ alListenerf(eParam, pflValues[0]);
+ break;
+
+ case AL_POSITION:
+ case AL_VELOCITY:
+ alListener3f(eParam, pflValues[0], pflValues[1], pflValues[2]);
+ break;
+
+ case AL_ORIENTATION:
+ // AT then UP
+ pContext->Listener.Forward[0] = pflValues[0];
+ pContext->Listener.Forward[1] = pflValues[1];
+ pContext->Listener.Forward[2] = pflValues[2];
+ pContext->Listener.Up[0] = pflValues[3];
+ pContext->Listener.Up[1] = pflValues[4];
+ pContext->Listener.Up[2] = pflValues[5];
+ updateWorld = AL_TRUE;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ if(updateWorld)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < pContext->SourceMap.size;pos++)
+ {
+ ALsource *source = pContext->SourceMap.array[pos].value;
+ if(!source->bHeadRelative)
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alListeneri(ALenum eParam, ALint lValue)
+{
+ ALCcontext *pContext;
+
+ (void)lValue;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alListener3i(ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ switch(eParam)
+ {
+ case AL_POSITION:
+ case AL_VELOCITY:
+ alListener3f(eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alListeneriv( ALenum eParam, const ALint* plValues )
+{
+ ALCcontext *pContext;
+ ALfloat flValues[6];
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValues)
+ {
+ switch(eParam)
+ {
+ case AL_POSITION:
+ case AL_VELOCITY:
+ flValues[0] = (ALfloat)plValues[0];
+ flValues[1] = (ALfloat)plValues[1];
+ flValues[2] = (ALfloat)plValues[2];
+ alListenerfv(eParam, flValues);
+ break;
+
+ case AL_ORIENTATION:
+ flValues[0] = (ALfloat)plValues[0];
+ flValues[1] = (ALfloat)plValues[1];
+ flValues[2] = (ALfloat)plValues[2];
+ flValues[3] = (ALfloat)plValues[3];
+ flValues[4] = (ALfloat)plValues[4];
+ flValues[5] = (ALfloat)plValues[5];
+ alListenerfv(eParam, flValues);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum eParam, ALfloat *pflValue)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValue)
+ {
+ switch(eParam)
+ {
+ case AL_GAIN:
+ *pflValue = pContext->Listener.Gain;
+ break;
+
+ case AL_METERS_PER_UNIT:
+ *pflValue = pContext->Listener.MetersPerUnit;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum eParam, ALfloat *pflValue1, ALfloat *pflValue2, ALfloat *pflValue3)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValue1 && pflValue2 && pflValue3)
+ {
+ switch(eParam)
+ {
+ case AL_POSITION:
+ *pflValue1 = pContext->Listener.Position[0];
+ *pflValue2 = pContext->Listener.Position[1];
+ *pflValue3 = pContext->Listener.Position[2];
+ break;
+
+ case AL_VELOCITY:
+ *pflValue1 = pContext->Listener.Velocity[0];
+ *pflValue2 = pContext->Listener.Velocity[1];
+ *pflValue3 = pContext->Listener.Velocity[2];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum eParam, ALfloat *pflValues)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValues)
+ {
+ switch(eParam)
+ {
+ case AL_GAIN:
+ pflValues[0] = pContext->Listener.Gain;
+ break;
+
+ case AL_METERS_PER_UNIT:
+ pflValues[0] = pContext->Listener.MetersPerUnit;
+ break;
+
+ case AL_POSITION:
+ pflValues[0] = pContext->Listener.Position[0];
+ pflValues[1] = pContext->Listener.Position[1];
+ pflValues[2] = pContext->Listener.Position[2];
+ break;
+
+ case AL_VELOCITY:
+ pflValues[0] = pContext->Listener.Velocity[0];
+ pflValues[1] = pContext->Listener.Velocity[1];
+ pflValues[2] = pContext->Listener.Velocity[2];
+ break;
+
+ case AL_ORIENTATION:
+ // AT then UP
+ pflValues[0] = pContext->Listener.Forward[0];
+ pflValues[1] = pContext->Listener.Forward[1];
+ pflValues[2] = pContext->Listener.Forward[2];
+ pflValues[3] = pContext->Listener.Up[0];
+ pflValues[4] = pContext->Listener.Up[1];
+ pflValues[5] = pContext->Listener.Up[2];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum eParam, ALint *plValue)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValue)
+ {
+ switch(eParam)
+ {
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetListener3i(ALenum eParam, ALint *plValue1, ALint *plValue2, ALint *plValue3)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValue1 && plValue2 && plValue3)
+ {
+ switch (eParam)
+ {
+ case AL_POSITION:
+ *plValue1 = (ALint)pContext->Listener.Position[0];
+ *plValue2 = (ALint)pContext->Listener.Position[1];
+ *plValue3 = (ALint)pContext->Listener.Position[2];
+ break;
+
+ case AL_VELOCITY:
+ *plValue1 = (ALint)pContext->Listener.Velocity[0];
+ *plValue2 = (ALint)pContext->Listener.Velocity[1];
+ *plValue3 = (ALint)pContext->Listener.Velocity[2];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetListeneriv(ALenum eParam, ALint* plValues)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValues)
+ {
+ switch(eParam)
+ {
+ case AL_POSITION:
+ plValues[0] = (ALint)pContext->Listener.Position[0];
+ plValues[1] = (ALint)pContext->Listener.Position[1];
+ plValues[2] = (ALint)pContext->Listener.Position[2];
+ break;
+
+ case AL_VELOCITY:
+ plValues[0] = (ALint)pContext->Listener.Velocity[0];
+ plValues[1] = (ALint)pContext->Listener.Velocity[1];
+ plValues[2] = (ALint)pContext->Listener.Velocity[2];
+ break;
+
+ case AL_ORIENTATION:
+ // AT then UP
+ plValues[0] = (ALint)pContext->Listener.Forward[0];
+ plValues[1] = (ALint)pContext->Listener.Forward[1];
+ plValues[2] = (ALint)pContext->Listener.Forward[2];
+ plValues[3] = (ALint)pContext->Listener.Up[0];
+ plValues[4] = (ALint)pContext->Listener.Up[1];
+ plValues[5] = (ALint)pContext->Listener.Up[2];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alError.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alThunk.h"
+#include "alAuxEffectSlot.h"
+
+
+resampler_t DefaultResampler;
+const ALsizei ResamplerPadding[RESAMPLER_MAX] = {
+ 0, /* Point */
+ 1, /* Linear */
+ 2, /* Cubic */
+};
+const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
+ 0, /* Point */
+ 0, /* Linear */
+ 1, /* Cubic */
+};
+
+
+static ALvoid InitSourceParams(ALsource *Source);
+static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
+static ALboolean ApplyOffset(ALsource *Source);
+static ALint GetByteOffset(ALsource *Source);
+
+#define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
+#define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
+#define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
+#define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ Device = Context->Device;
+ if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
+ alSetError(Context, AL_INVALID_VALUE);
+ else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ ALenum err;
+ ALsizei i;
+
+ // Add additional sources to the list
+ i = 0;
+ while(i < n)
+ {
+ ALsource *source = calloc(1, sizeof(ALsource));
+ if(!source)
+ {
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ alDeleteSources(i, sources);
+ break;
+ }
+
+ source->source = (ALuint)ALTHUNK_ADDENTRY(source);
+ err = InsertUIntMapEntry(&Context->SourceMap, source->source,
+ source);
+ if(err != AL_NO_ERROR)
+ {
+ ALTHUNK_REMOVEENTRY(source->source);
+ memset(source, 0, sizeof(ALsource));
+ free(source);
+
+ alSetError(Context, err);
+ alDeleteSources(i, sources);
+ break;
+ }
+
+ sources[i++] = source->source;
+ InitSourceParams(source);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+
+AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
+{
+ ALCcontext *Context;
+ ALsource *Source;
+ ALsizei i, j;
+ ALbufferlistitem *BufferList;
+ ALboolean SourcesValid = AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ alSetError(Context, AL_INVALID_VALUE);
+ else
+ {
+ SourcesValid = AL_TRUE;
+ // Check that all Sources are valid (and can therefore be deleted)
+ for(i = 0;i < n;i++)
+ {
+ if(LookupSource(Context->SourceMap, sources[i]) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ SourcesValid = AL_FALSE;
+ break;
+ }
+ }
+ }
+
+ if(SourcesValid)
+ {
+ // All Sources are valid, and can be deleted
+ for(i = 0;i < n;i++)
+ {
+ // Recheck that the Source is valid, because there could be duplicated Source names
+ if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
+ continue;
+
+ for(j = 0;j < Context->ActiveSourceCount;j++)
+ {
+ if(Context->ActiveSources[j] == Source)
+ {
+ ALsizei end = --(Context->ActiveSourceCount);
+ Context->ActiveSources[j] = Context->ActiveSources[end];
+ break;
+ }
+ }
+
+ // For each buffer in the source's queue...
+ while(Source->queue != NULL)
+ {
+ BufferList = Source->queue;
+ Source->queue = BufferList->next;
+
+ if(BufferList->buffer != NULL)
+ BufferList->buffer->refcount--;
+ free(BufferList);
+ }
+
+ for(j = 0;j < MAX_SENDS;++j)
+ {
+ if(Source->Send[j].Slot)
+ Source->Send[j].Slot->refcount--;
+ Source->Send[j].Slot = NULL;
+ }
+
+ // Remove Source from list of Sources
+ RemoveUIntMapKey(&Context->SourceMap, Source->source);
+ ALTHUNK_REMOVEENTRY(Source->source);
+
+ memset(Source,0,sizeof(ALsource));
+ free(Source);
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+
+AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
+{
+ ALCcontext *Context;
+ ALboolean result;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
+
+ ProcessContext(Context);
+
+ return result;
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_PITCH:
+ if(flValue >= 0.0f)
+ {
+ Source->flPitch = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_CONE_INNER_ANGLE:
+ if(flValue >= 0.0f && flValue <= 360.0f)
+ {
+ Source->flInnerAngle = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_CONE_OUTER_ANGLE:
+ if(flValue >= 0.0f && flValue <= 360.0f)
+ {
+ Source->flOuterAngle = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_GAIN:
+ if(flValue >= 0.0f)
+ {
+ Source->flGain = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_MAX_DISTANCE:
+ if(flValue >= 0.0f)
+ {
+ Source->flMaxDistance = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_ROLLOFF_FACTOR:
+ if(flValue >= 0.0f)
+ {
+ Source->flRollOffFactor = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_REFERENCE_DISTANCE:
+ if(flValue >= 0.0f)
+ {
+ Source->flRefDistance = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_MIN_GAIN:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ {
+ Source->flMinGain = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_MAX_GAIN:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ {
+ Source->flMaxGain = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_CONE_OUTER_GAIN:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ {
+ Source->flOuterGain = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_CONE_OUTER_GAINHF:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ {
+ Source->OuterGainHF = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_AIR_ABSORPTION_FACTOR:
+ if(flValue >= 0.0f && flValue <= 10.0f)
+ {
+ Source->AirAbsorptionFactor = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_ROOM_ROLLOFF_FACTOR:
+ if(flValue >= 0.0f && flValue <= 10.0f)
+ {
+ Source->RoomRolloffFactor = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_DOPPLER_FACTOR:
+ if(flValue >= 0.0f && flValue <= 1.0f)
+ {
+ Source->DopplerFactor = flValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ if(flValue >= 0.0f)
+ {
+ Source->lOffsetType = eParam;
+
+ // Store Offset (convert Seconds into Milliseconds)
+ if(eParam == AL_SEC_OFFSET)
+ Source->lOffset = (ALint)(flValue * 1000.0f);
+ else
+ Source->lOffset = (ALint)flValue;
+
+ if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
+ {
+ if(ApplyOffset(Source) == AL_FALSE)
+ alSetError(pContext, AL_INVALID_VALUE);
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ {
+ // Invalid Source Name
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_POSITION:
+ Source->vPosition[0] = flValue1;
+ Source->vPosition[1] = flValue2;
+ Source->vPosition[2] = flValue3;
+ Source->NeedsUpdate = AL_TRUE;
+ break;
+
+ case AL_VELOCITY:
+ Source->vVelocity[0] = flValue1;
+ Source->vVelocity[1] = flValue2;
+ Source->vVelocity[2] = flValue3;
+ Source->NeedsUpdate = AL_TRUE;
+ break;
+
+ case AL_DIRECTION:
+ Source->vOrientation[0] = flValue1;
+ Source->vOrientation[1] = flValue2;
+ Source->vOrientation[2] = flValue3;
+ Source->NeedsUpdate = AL_TRUE;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValues)
+ {
+ if(LookupSource(pContext->SourceMap, source) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_PITCH:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_REFERENCE_DISTANCE:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_CONE_OUTER_GAIN:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ alSourcef(source, eParam, pflValues[0]);
+ break;
+
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
+ alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+ ALbufferlistitem *BufferListItem;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ ALCdevice *device = pContext->Device;
+
+ switch(eParam)
+ {
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_REFERENCE_DISTANCE:
+ alSourcef(source, eParam, (ALfloat)lValue);
+ break;
+
+ case AL_SOURCE_RELATIVE:
+ if(lValue == AL_FALSE || lValue == AL_TRUE)
+ {
+ Source->bHeadRelative = (ALboolean)lValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_LOOPING:
+ if(lValue == AL_FALSE || lValue == AL_TRUE)
+ Source->bLooping = (ALboolean)lValue;
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_BUFFER:
+ if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
+ {
+ ALbuffer *buffer = NULL;
+
+ if(lValue == 0 ||
+ (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
+ {
+ // Remove all elements in the queue
+ while(Source->queue != NULL)
+ {
+ BufferListItem = Source->queue;
+ Source->queue = BufferListItem->next;
+
+ if(BufferListItem->buffer)
+ BufferListItem->buffer->refcount--;
+ free(BufferListItem);
+ }
+ Source->BuffersInQueue = 0;
+
+ // Add the buffer to the queue (as long as it is NOT the NULL buffer)
+ if(buffer != NULL)
+ {
+ // Source is now in STATIC mode
+ Source->lSourceType = AL_STATIC;
+
+ // Add the selected buffer to the queue
+ BufferListItem = malloc(sizeof(ALbufferlistitem));
+ BufferListItem->buffer = buffer;
+ BufferListItem->next = NULL;
+ BufferListItem->prev = NULL;
+
+ Source->queue = BufferListItem;
+ Source->BuffersInQueue = 1;
+
+ if(buffer->FmtChannels == FmtMono)
+ Source->Update = CalcSourceParams;
+ else
+ Source->Update = CalcNonAttnSourceParams;
+
+ // Increment reference counter for buffer
+ buffer->refcount++;
+ }
+ else
+ {
+ // Source is now in UNDETERMINED mode
+ Source->lSourceType = AL_UNDETERMINED;
+ }
+ Source->BuffersPlayed = 0;
+
+ // Update AL_BUFFER parameter
+ Source->Buffer = buffer;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ }
+ else
+ alSetError(pContext, AL_INVALID_OPERATION);
+ break;
+
+ case AL_SOURCE_STATE:
+ // Query only
+ alSetError(pContext, AL_INVALID_OPERATION);
+ break;
+
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ if(lValue >= 0)
+ {
+ Source->lOffsetType = eParam;
+
+ // Store Offset (convert Seconds into Milliseconds)
+ if(eParam == AL_SEC_OFFSET)
+ Source->lOffset = lValue * 1000;
+ else
+ Source->lOffset = lValue;
+
+ if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
+ {
+ if(ApplyOffset(Source) == AL_FALSE)
+ alSetError(pContext, AL_INVALID_VALUE);
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_DIRECT_FILTER: {
+ ALfilter *filter = NULL;
+
+ if(lValue == 0 ||
+ (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
+ {
+ if(!filter)
+ {
+ Source->DirectFilter.type = AL_FILTER_NULL;
+ Source->DirectFilter.filter = 0;
+ }
+ else
+ memcpy(&Source->DirectFilter, filter, sizeof(*filter));
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ } break;
+
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ if(lValue == AL_TRUE || lValue == AL_FALSE)
+ {
+ Source->DryGainHFAuto = lValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ if(lValue == AL_TRUE || lValue == AL_FALSE)
+ {
+ Source->WetGainAuto = lValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ if(lValue == AL_TRUE || lValue == AL_FALSE)
+ {
+ Source->WetGainHFAuto = lValue;
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ if(lValue == AL_NONE ||
+ lValue == AL_INVERSE_DISTANCE ||
+ lValue == AL_INVERSE_DISTANCE_CLAMPED ||
+ lValue == AL_LINEAR_DISTANCE ||
+ lValue == AL_LINEAR_DISTANCE_CLAMPED ||
+ lValue == AL_EXPONENT_DISTANCE ||
+ lValue == AL_EXPONENT_DISTANCE_CLAMPED)
+ {
+ Source->DistanceModel = lValue;
+ if(pContext->SourceDistanceModel)
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ ALCdevice *device = pContext->Device;
+
+ switch (eParam)
+ {
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
+ alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
+ break;
+
+ case AL_AUXILIARY_SEND_FILTER: {
+ ALeffectslot *ALEffectSlot = NULL;
+ ALfilter *ALFilter = NULL;
+
+ if((ALuint)lValue2 < device->NumAuxSends &&
+ (lValue1 == 0 ||
+ (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
+ (lValue3 == 0 ||
+ (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
+ {
+ /* Release refcount on the previous slot, and add one for
+ * the new slot */
+ if(Source->Send[lValue2].Slot)
+ Source->Send[lValue2].Slot->refcount--;
+ Source->Send[lValue2].Slot = ALEffectSlot;
+ if(Source->Send[lValue2].Slot)
+ Source->Send[lValue2].Slot->refcount++;
+
+ if(!ALFilter)
+ {
+ /* Disable filter */
+ Source->Send[lValue2].WetFilter.type = 0;
+ Source->Send[lValue2].WetFilter.filter = 0;
+ }
+ else
+ memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ } break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
+{
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValues)
+ {
+ if(LookupSource(pContext->SourceMap, source) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_SOURCE_RELATIVE:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_LOOPING:
+ case AL_BUFFER:
+ case AL_SOURCE_STATE:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_REFERENCE_DISTANCE:
+ case AL_DIRECT_FILTER:
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ case AL_DISTANCE_MODEL:
+ alSourcei(source, eParam, plValues[0]);
+ break;
+
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
+ case AL_AUXILIARY_SEND_FILTER:
+ alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+ ALdouble Offsets[2];
+ ALdouble updateLen;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValue)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_PITCH:
+ *pflValue = Source->flPitch;
+ break;
+
+ case AL_GAIN:
+ *pflValue = Source->flGain;
+ break;
+
+ case AL_MIN_GAIN:
+ *pflValue = Source->flMinGain;
+ break;
+
+ case AL_MAX_GAIN:
+ *pflValue = Source->flMaxGain;
+ break;
+
+ case AL_MAX_DISTANCE:
+ *pflValue = Source->flMaxDistance;
+ break;
+
+ case AL_ROLLOFF_FACTOR:
+ *pflValue = Source->flRollOffFactor;
+ break;
+
+ case AL_CONE_OUTER_GAIN:
+ *pflValue = Source->flOuterGain;
+ break;
+
+ case AL_CONE_OUTER_GAINHF:
+ *pflValue = Source->OuterGainHF;
+ break;
+
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ updateLen = (ALdouble)pContext->Device->UpdateSize /
+ pContext->Device->Frequency;
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ *pflValue = Offsets[0];
+ break;
+
+ case AL_CONE_INNER_ANGLE:
+ *pflValue = Source->flInnerAngle;
+ break;
+
+ case AL_CONE_OUTER_ANGLE:
+ *pflValue = Source->flOuterAngle;
+ break;
+
+ case AL_REFERENCE_DISTANCE:
+ *pflValue = Source->flRefDistance;
+ break;
+
+ case AL_AIR_ABSORPTION_FACTOR:
+ *pflValue = Source->AirAbsorptionFactor;
+ break;
+
+ case AL_ROOM_ROLLOFF_FACTOR:
+ *pflValue = Source->RoomRolloffFactor;
+ break;
+
+ case AL_DOPPLER_FACTOR:
+ *pflValue = Source->DopplerFactor;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValue1 && pflValue2 && pflValue3)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_POSITION:
+ *pflValue1 = Source->vPosition[0];
+ *pflValue2 = Source->vPosition[1];
+ *pflValue3 = Source->vPosition[2];
+ break;
+
+ case AL_VELOCITY:
+ *pflValue1 = Source->vVelocity[0];
+ *pflValue2 = Source->vVelocity[1];
+ *pflValue3 = Source->vVelocity[2];
+ break;
+
+ case AL_DIRECTION:
+ *pflValue1 = Source->vOrientation[0];
+ *pflValue2 = Source->vOrientation[1];
+ *pflValue3 = Source->vOrientation[2];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+ ALdouble Offsets[2];
+ ALdouble updateLen;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValues)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_DOPPLER_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_REFERENCE_DISTANCE:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ alGetSourcef(source, eParam, pflValues);
+ break;
+
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
+ alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
+ break;
+
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ updateLen = (ALdouble)pContext->Device->UpdateSize /
+ pContext->Device->Frequency;
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ pflValues[0] = Offsets[0];
+ pflValues[1] = Offsets[1];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+ ALdouble Offsets[2];
+ ALdouble updateLen;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValue)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_MAX_DISTANCE:
+ *plValue = (ALint)Source->flMaxDistance;
+ break;
+
+ case AL_ROLLOFF_FACTOR:
+ *plValue = (ALint)Source->flRollOffFactor;
+ break;
+
+ case AL_REFERENCE_DISTANCE:
+ *plValue = (ALint)Source->flRefDistance;
+ break;
+
+ case AL_SOURCE_RELATIVE:
+ *plValue = Source->bHeadRelative;
+ break;
+
+ case AL_CONE_INNER_ANGLE:
+ *plValue = (ALint)Source->flInnerAngle;
+ break;
+
+ case AL_CONE_OUTER_ANGLE:
+ *plValue = (ALint)Source->flOuterAngle;
+ break;
+
+ case AL_LOOPING:
+ *plValue = Source->bLooping;
+ break;
+
+ case AL_BUFFER:
+ *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
+ break;
+
+ case AL_SOURCE_STATE:
+ *plValue = Source->state;
+ break;
+
+ case AL_BUFFERS_QUEUED:
+ *plValue = Source->BuffersInQueue;
+ break;
+
+ case AL_BUFFERS_PROCESSED:
+ if(Source->bLooping || Source->lSourceType != AL_STREAMING)
+ {
+ /* Buffers on a looping source are in a perpetual state
+ * of PENDING, so don't report any as PROCESSED */
+ *plValue = 0;
+ }
+ else
+ *plValue = Source->BuffersPlayed;
+ break;
+
+ case AL_SOURCE_TYPE:
+ *plValue = Source->lSourceType;
+ break;
+
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ updateLen = (ALdouble)pContext->Device->UpdateSize /
+ pContext->Device->Frequency;
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ *plValue = (ALint)Offsets[0];
+ break;
+
+ case AL_DIRECT_FILTER:
+ *plValue = Source->DirectFilter.filter;
+ break;
+
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ *plValue = Source->DryGainHFAuto;
+ break;
+
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ *plValue = Source->WetGainAuto;
+ break;
+
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ *plValue = Source->WetGainHFAuto;
+ break;
+
+ case AL_DOPPLER_FACTOR:
+ *plValue = (ALint)Source->DopplerFactor;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *plValue = Source->DistanceModel;
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValue1 && plValue2 && plValue3)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_POSITION:
+ *plValue1 = (ALint)Source->vPosition[0];
+ *plValue2 = (ALint)Source->vPosition[1];
+ *plValue3 = (ALint)Source->vPosition[2];
+ break;
+
+ case AL_VELOCITY:
+ *plValue1 = (ALint)Source->vVelocity[0];
+ *plValue2 = (ALint)Source->vVelocity[1];
+ *plValue3 = (ALint)Source->vVelocity[2];
+ break;
+
+ case AL_DIRECTION:
+ *plValue1 = (ALint)Source->vOrientation[0];
+ *plValue2 = (ALint)Source->vOrientation[1];
+ *plValue3 = (ALint)Source->vOrientation[2];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
+{
+ ALCcontext *pContext;
+ ALsource *Source;
+ ALdouble Offsets[2];
+ ALdouble updateLen;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValues)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_SOURCE_RELATIVE:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_LOOPING:
+ case AL_BUFFER:
+ case AL_SOURCE_STATE:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_DOPPLER_FACTOR:
+ case AL_REFERENCE_DISTANCE:
+ case AL_SOURCE_TYPE:
+ case AL_DIRECT_FILTER:
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ case AL_DISTANCE_MODEL:
+ alGetSourcei(source, eParam, plValues);
+ break;
+
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
+ alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
+ break;
+
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ updateLen = (ALdouble)pContext->Device->UpdateSize /
+ pContext->Device->Frequency;
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ plValues[0] = (ALint)Offsets[0];
+ plValues[1] = (ALint)Offsets[1];
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_NAME);
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
+{
+ alSourcePlayv(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
+{
+ ALCcontext *Context;
+ ALsource *Source;
+ ALbufferlistitem *BufferList;
+ ALsizei i, j;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+ if(n > 0 && !sources)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+
+ // Check that all the Sources are valid
+ for(i = 0;i < n;i++)
+ {
+ if(!LookupSource(Context->SourceMap, sources[i]))
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ goto done;
+ }
+ }
+
+ while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
+ {
+ void *temp = NULL;
+ ALsizei newcount;
+
+ newcount = Context->MaxActiveSources << 1;
+ if(newcount > 0)
+ temp = realloc(Context->ActiveSources,
+ sizeof(*Context->ActiveSources) * newcount);
+ if(!temp)
+ {
+ alSetError(Context, AL_OUT_OF_MEMORY);
+ goto done;
+ }
+
+ Context->ActiveSources = temp;
+ Context->MaxActiveSources = newcount;
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+
+ // Check that there is a queue containing at least one non-null, non zero length AL Buffer
+ BufferList = Source->queue;
+ while(BufferList)
+ {
+ if(BufferList->buffer != NULL && BufferList->buffer->size)
+ break;
+ BufferList = BufferList->next;
+ }
+
+ if(!BufferList)
+ {
+ Source->state = AL_STOPPED;
+ Source->BuffersPlayed = Source->BuffersInQueue;
+ Source->position = 0;
+ Source->position_fraction = 0;
+ Source->lOffset = 0;
+ continue;
+ }
+
+ if(Source->state != AL_PAUSED)
+ {
+ Source->state = AL_PLAYING;
+ Source->position = 0;
+ Source->position_fraction = 0;
+ Source->BuffersPlayed = 0;
+
+ Source->Buffer = Source->queue->buffer;
+ }
+ else
+ Source->state = AL_PLAYING;
+
+ // Check if an Offset has been set
+ if(Source->lOffset)
+ ApplyOffset(Source);
+
+ // If device is disconnected, go right to stopped
+ if(!Context->Device->Connected)
+ {
+ Source->state = AL_STOPPED;
+ Source->BuffersPlayed = Source->BuffersInQueue;
+ Source->position = 0;
+ Source->position_fraction = 0;
+ }
+ else
+ {
+ for(j = 0;j < Context->ActiveSourceCount;j++)
+ {
+ if(Context->ActiveSources[j] == Source)
+ break;
+ }
+ if(j == Context->ActiveSourceCount)
+ Context->ActiveSources[Context->ActiveSourceCount++] = Source;
+ }
+ }
+
+done:
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
+{
+ alSourcePausev(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
+{
+ ALCcontext *Context;
+ ALsource *Source;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+ if(n > 0 && !sources)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+
+ // Check all the Sources are valid
+ for(i = 0;i < n;i++)
+ {
+ if(!LookupSource(Context->SourceMap, sources[i]))
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ goto done;
+ }
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+ if(Source->state == AL_PLAYING)
+ Source->state = AL_PAUSED;
+ }
+
+done:
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
+{
+ alSourceStopv(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
+{
+ ALCcontext *Context;
+ ALsource *Source;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+ if(n > 0 && !sources)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+
+ // Check all the Sources are valid
+ for(i = 0;i < n;i++)
+ {
+ if(!LookupSource(Context->SourceMap, sources[i]))
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ goto done;
+ }
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+ if(Source->state != AL_INITIAL)
+ {
+ Source->state = AL_STOPPED;
+ Source->BuffersPlayed = Source->BuffersInQueue;
+ }
+ Source->lOffset = 0;
+ }
+
+done:
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
+{
+ alSourceRewindv(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
+{
+ ALCcontext *Context;
+ ALsource *Source;
+ ALsizei i;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+ if(n > 0 && !sources)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+
+ // Check all the Sources are valid
+ for(i = 0;i < n;i++)
+ {
+ if(!LookupSource(Context->SourceMap, sources[i]))
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ goto done;
+ }
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+ if(Source->state != AL_INITIAL)
+ {
+ Source->state = AL_INITIAL;
+ Source->position = 0;
+ Source->position_fraction = 0;
+ Source->BuffersPlayed = 0;
+ if(Source->queue)
+ Source->Buffer = Source->queue->buffer;
+ }
+ Source->lOffset = 0;
+ }
+
+done:
+ ProcessContext(Context);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
+{
+ ALCcontext *Context;
+ ALCdevice *device;
+ ALsource *Source;
+ ALbuffer *buffer;
+ ALsizei i;
+ ALbufferlistitem *BufferListStart;
+ ALbufferlistitem *BufferList;
+ ALbuffer *BufferFmt;
+
+ if(n == 0)
+ return;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+
+ // Check that all buffers are valid or zero and that the source is valid
+
+ // Check that this is a valid source
+ if((Source=LookupSource(Context->SourceMap, source)) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ goto done;
+ }
+
+ // Check that this is not a STATIC Source
+ if(Source->lSourceType == AL_STATIC)
+ {
+ // Invalid Source Type (can't queue on a Static Source)
+ alSetError(Context, AL_INVALID_OPERATION);
+ goto done;
+ }
+
+ device = Context->Device;
+
+ BufferFmt = NULL;
+
+ // Check existing Queue (if any) for a valid Buffers and get its frequency and format
+ BufferList = Source->queue;
+ while(BufferList)
+ {
+ if(BufferList->buffer)
+ {
+ BufferFmt = BufferList->buffer;
+ break;
+ }
+ BufferList = BufferList->next;
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ if(!buffers[i])
+ continue;
+
+ if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ goto done;
+ }
+
+ if(BufferFmt == NULL)
+ {
+ BufferFmt = buffer;
+
+ if(buffer->FmtChannels == FmtMono)
+ Source->Update = CalcSourceParams;
+ else
+ Source->Update = CalcNonAttnSourceParams;
+
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else if(BufferFmt->Frequency != buffer->Frequency ||
+ BufferFmt->OriginalChannels != buffer->OriginalChannels ||
+ BufferFmt->OriginalType != buffer->OriginalType)
+ {
+ alSetError(Context, AL_INVALID_OPERATION);
+ goto done;
+ }
+ }
+
+ // Change Source Type
+ Source->lSourceType = AL_STREAMING;
+
+ buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
+
+ // All buffers are valid - so add them to the list
+ BufferListStart = malloc(sizeof(ALbufferlistitem));
+ BufferListStart->buffer = buffer;
+ BufferListStart->next = NULL;
+ BufferListStart->prev = NULL;
+
+ // Increment reference counter for buffer
+ if(buffer) buffer->refcount++;
+
+ BufferList = BufferListStart;
+
+ for(i = 1;i < n;i++)
+ {
+ buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
+
+ BufferList->next = malloc(sizeof(ALbufferlistitem));
+ BufferList->next->buffer = buffer;
+ BufferList->next->next = NULL;
+ BufferList->next->prev = BufferList;
+
+ // Increment reference counter for buffer
+ if(buffer) buffer->refcount++;
+
+ BufferList = BufferList->next;
+ }
+
+ if(Source->queue == NULL)
+ {
+ Source->queue = BufferListStart;
+ // Update Current Buffer
+ Source->Buffer = BufferListStart->buffer;
+ }
+ else
+ {
+ // Find end of queue
+ BufferList = Source->queue;
+ while(BufferList->next != NULL)
+ BufferList = BufferList->next;
+
+ BufferList->next = BufferListStart;
+ BufferList->next->prev = BufferList;
+ }
+
+ // Update number of buffers in queue
+ Source->BuffersInQueue += n;
+
+done:
+ ProcessContext(Context);
+}
+
+
+// Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
+// an array of buffer IDs that are to be filled with the names of the buffers removed
+AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
+{
+ ALCcontext *Context;
+ ALsource *Source;
+ ALsizei i;
+ ALbufferlistitem *BufferList;
+
+ if(n == 0)
+ return;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(n < 0)
+ {
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+
+ if((Source=LookupSource(Context->SourceMap, source)) == NULL)
+ {
+ alSetError(Context, AL_INVALID_NAME);
+ goto done;
+ }
+
+ if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
+ (ALuint)n > Source->BuffersPlayed)
+ {
+ // Some buffers can't be unqueue because they have not been processed
+ alSetError(Context, AL_INVALID_VALUE);
+ goto done;
+ }
+
+ for(i = 0;i < n;i++)
+ {
+ BufferList = Source->queue;
+ Source->queue = BufferList->next;
+
+ if(BufferList->buffer)
+ {
+ // Record name of buffer
+ buffers[i] = BufferList->buffer->buffer;
+ // Decrement buffer reference counter
+ BufferList->buffer->refcount--;
+ }
+ else
+ buffers[i] = 0;
+
+ // Release memory for buffer list item
+ free(BufferList);
+ Source->BuffersInQueue--;
+ }
+ if(Source->queue)
+ Source->queue->prev = NULL;
+
+ if(Source->state != AL_PLAYING)
+ {
+ if(Source->queue)
+ Source->Buffer = Source->queue->buffer;
+ else
+ Source->Buffer = NULL;
+ }
+ Source->BuffersPlayed -= n;
+
+done:
+ ProcessContext(Context);
+}
+
+
+static ALvoid InitSourceParams(ALsource *Source)
+{
+ Source->flInnerAngle = 360.0f;
+ Source->flOuterAngle = 360.0f;
+ Source->flPitch = 1.0f;
+ Source->vPosition[0] = 0.0f;
+ Source->vPosition[1] = 0.0f;
+ Source->vPosition[2] = 0.0f;
+ Source->vOrientation[0] = 0.0f;
+ Source->vOrientation[1] = 0.0f;
+ Source->vOrientation[2] = 0.0f;
+ Source->vVelocity[0] = 0.0f;
+ Source->vVelocity[1] = 0.0f;
+ Source->vVelocity[2] = 0.0f;
+ Source->flRefDistance = 1.0f;
+ Source->flMaxDistance = FLT_MAX;
+ Source->flRollOffFactor = 1.0f;
+ Source->bLooping = AL_FALSE;
+ Source->flGain = 1.0f;
+ Source->flMinGain = 0.0f;
+ Source->flMaxGain = 1.0f;
+ Source->flOuterGain = 0.0f;
+ Source->OuterGainHF = 1.0f;
+
+ Source->DryGainHFAuto = AL_TRUE;
+ Source->WetGainAuto = AL_TRUE;
+ Source->WetGainHFAuto = AL_TRUE;
+ Source->AirAbsorptionFactor = 0.0f;
+ Source->RoomRolloffFactor = 0.0f;
+ Source->DopplerFactor = 1.0f;
+
+ Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
+
+ Source->Resampler = DefaultResampler;
+
+ Source->state = AL_INITIAL;
+ Source->lSourceType = AL_UNDETERMINED;
+
+ Source->NeedsUpdate = AL_TRUE;
+
+ Source->Buffer = NULL;
+}
+
+
+/*
+ GetSourceOffset
+
+ Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
+ The offset is relative to the start of the queue (not the start of the current buffer)
+*/
+static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
+{
+ const ALbufferlistitem *BufferList;
+ const ALbuffer *Buffer = NULL;
+ enum UserFmtType OriginalType;
+ ALsizei BufferFreq;
+ ALint Channels, Bytes;
+ ALuint readPos, writePos;
+ ALuint TotalBufferDataSize;
+ ALuint i;
+
+ // Find the first non-NULL Buffer in the Queue
+ BufferList = Source->queue;
+ while(BufferList)
+ {
+ if(BufferList->buffer)
+ {
+ Buffer = BufferList->buffer;
+ break;
+ }
+ BufferList = BufferList->next;
+ }
+
+ if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
+ {
+ offset[0] = 0.0;
+ offset[1] = 0.0;
+ return;
+ }
+
+ // Get Current Buffer Size and frequency (in milliseconds)
+ BufferFreq = Buffer->Frequency;
+ OriginalType = Buffer->OriginalType;
+ Channels = ChannelsFromFmt(Buffer->FmtChannels);
+ Bytes = BytesFromFmt(Buffer->FmtType);
+
+ // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
+ readPos = Source->position * Channels * Bytes;
+ // Add byte length of any processed buffers in the queue
+ TotalBufferDataSize = 0;
+ BufferList = Source->queue;
+ for(i = 0;BufferList;i++)
+ {
+ if(BufferList->buffer)
+ {
+ if(i < Source->BuffersPlayed)
+ readPos += BufferList->buffer->size;
+ TotalBufferDataSize += BufferList->buffer->size;
+ }
+ BufferList = BufferList->next;
+ }
+ if(Source->state == AL_PLAYING)
+ writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
+ else
+ writePos = readPos;
+
+ if(Source->bLooping)
+ {
+ readPos %= TotalBufferDataSize;
+ writePos %= TotalBufferDataSize;
+ }
+ else
+ {
+ // Wrap positions back to 0
+ if(readPos >= TotalBufferDataSize)
+ readPos = 0;
+ if(writePos >= TotalBufferDataSize)
+ writePos = 0;
+ }
+
+ switch(name)
+ {
+ case AL_SEC_OFFSET:
+ offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
+ offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
+ break;
+ case AL_SAMPLE_OFFSET:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ offset[0] = (ALdouble)(readPos / (Channels * Bytes));
+ offset[1] = (ALdouble)(writePos / (Channels * Bytes));
+ break;
+ case AL_BYTE_OFFSET:
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ // Take into account the original format of the Buffer
+ if(OriginalType == UserFmtIMA4)
+ {
+ ALuint FrameBlockSize = 65 * Bytes * Channels;
+ ALuint BlockSize = 36 * Channels;
+
+ // Round down to nearest ADPCM block
+ offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
+ if(Source->state != AL_PLAYING)
+ offset[1] = offset[0];
+ else
+ {
+ // Round up to nearest ADPCM block
+ offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
+ FrameBlockSize * BlockSize);
+ }
+ }
+ else
+ {
+ ALuint OrigBytes = BytesFromUserFmt(OriginalType);
+ offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
+ offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
+ }
+ break;
+ }
+}
+
+
+/*
+ ApplyOffset
+
+ Apply a playback offset to the Source. This function will update the queue (to correctly
+ mark buffers as 'pending' or 'processed' depending upon the new offset.
+*/
+static ALboolean ApplyOffset(ALsource *Source)
+{
+ const ALbufferlistitem *BufferList;
+ const ALbuffer *Buffer;
+ ALint lBufferSize, lTotalBufferSize;
+ ALint BuffersPlayed;
+ ALint lByteOffset;
+
+ // Get true byte offset
+ lByteOffset = GetByteOffset(Source);
+
+ // If the offset is invalid, don't apply it
+ if(lByteOffset == -1)
+ return AL_FALSE;
+
+ // Sort out the queue (pending and processed states)
+ BufferList = Source->queue;
+ lTotalBufferSize = 0;
+ BuffersPlayed = 0;
+
+ while(BufferList)
+ {
+ Buffer = BufferList->buffer;
+ lBufferSize = Buffer ? Buffer->size : 0;
+
+ if(lBufferSize <= lByteOffset-lTotalBufferSize)
+ {
+ // Offset is past this buffer so increment BuffersPlayed
+ BuffersPlayed++;
+ }
+ else if(lTotalBufferSize <= lByteOffset)
+ {
+ // Offset is within this buffer
+ // Set Current Buffer
+ Source->Buffer = BufferList->buffer;
+ Source->BuffersPlayed = BuffersPlayed;
+
+ // SW Mixer Positions are in Samples
+ Source->position = (lByteOffset - lTotalBufferSize) /
+ FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+ return AL_TRUE;
+ }
+
+ // Increment the TotalBufferSize
+ lTotalBufferSize += lBufferSize;
+
+ // Move on to next buffer in the Queue
+ BufferList = BufferList->next;
+ }
+ // Offset is out of range of the buffer queue
+ return AL_FALSE;
+}
+
+
+/*
+ GetByteOffset
+
+ Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
+ offset supplied by the application). This takes into account the fact that the buffer format
+ may have been modifed by AL (e.g 8bit samples are converted to float)
+*/
+static ALint GetByteOffset(ALsource *Source)
+{
+ const ALbuffer *Buffer = NULL;
+ const ALbufferlistitem *BufferList;
+ ALint ByteOffset = -1;
+
+ // Find the first non-NULL Buffer in the Queue
+ BufferList = Source->queue;
+ while(BufferList)
+ {
+ if(BufferList->buffer)
+ {
+ Buffer = BufferList->buffer;
+ break;
+ }
+ BufferList = BufferList->next;
+ }
+
+ if(!Buffer)
+ {
+ Source->lOffset = 0;
+ return -1;
+ }
+
+ // Determine the ByteOffset (and ensure it is block aligned)
+ switch(Source->lOffsetType)
+ {
+ case AL_BYTE_OFFSET:
+ // Take into consideration the original format
+ ByteOffset = Source->lOffset;
+ if(Buffer->OriginalType == UserFmtIMA4)
+ {
+ // Round down to nearest ADPCM block
+ ByteOffset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
+ // Multiply by compression rate (65 sample frames per block)
+ ByteOffset *= 65;
+ }
+ else
+ ByteOffset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
+ ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+ break;
+
+ case AL_SAMPLE_OFFSET:
+ ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+ break;
+
+ case AL_SEC_OFFSET:
+ // Note - lOffset is internally stored as Milliseconds
+ ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
+ ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+ break;
+ }
+ // Clear Offset
+ Source->lOffset = 0;
+
+ return ByteOffset;
+}
+
+
+ALvoid ReleaseALSources(ALCcontext *Context)
+{
+ ALsizei pos;
+ ALuint j;
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ ALsource *temp = Context->SourceMap.array[pos].value;
+ Context->SourceMap.array[pos].value = NULL;
+
+ // For each buffer in the source's queue, decrement its reference counter and remove it
+ while(temp->queue != NULL)
+ {
+ ALbufferlistitem *BufferList = temp->queue;
+ temp->queue = BufferList->next;
+
+ if(BufferList->buffer != NULL)
+ BufferList->buffer->refcount--;
+ free(BufferList);
+ }
+
+ for(j = 0;j < MAX_SENDS;++j)
+ {
+ if(temp->Send[j].Slot)
+ temp->Send[j].Slot->refcount--;
+ temp->Send[j].Slot = NULL;
+ }
+
+ // Release source structure
+ ALTHUNK_REMOVEENTRY(temp->source);
+ memset(temp, 0, sizeof(ALsource));
+ free(temp);
+ }
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2000 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include "alMain.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+#include "alError.h"
+#include "alSource.h"
+#include "alState.h"
+#include "alDatabuffer.h"
+
+static const ALchar alVendor[] = "OpenAL Community";
+static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION;
+static const ALchar alRenderer[] = "OpenAL Soft";
+
+// Error Messages
+static const ALchar alNoError[] = "No Error";
+static const ALchar alErrInvalidName[] = "Invalid Name";
+static const ALchar alErrInvalidEnum[] = "Invalid Enum";
+static const ALchar alErrInvalidValue[] = "Invalid Value";
+static const ALchar alErrInvalidOp[] = "Invalid Operation";
+static const ALchar alErrOutOfMemory[] = "Out of Memory";
+
+AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
+{
+ ALCcontext *Context;
+ ALboolean updateSources = AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ switch(capability)
+ {
+ case AL_SOURCE_DISTANCE_MODEL:
+ Context->SourceDistanceModel = AL_TRUE;
+ updateSources = AL_TRUE;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+
+ if(updateSources)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ ALsource *source = Context->SourceMap.array[pos].value;
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
+{
+ ALCcontext *Context;
+ ALboolean updateSources = AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ switch(capability)
+ {
+ case AL_SOURCE_DISTANCE_MODEL:
+ Context->SourceDistanceModel = AL_FALSE;
+ updateSources = AL_TRUE;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+
+ if(updateSources)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ ALsource *source = Context->SourceMap.array[pos].value;
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
+{
+ ALCcontext *Context;
+ ALboolean value=AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ switch(capability)
+ {
+ case AL_SOURCE_DISTANCE_MODEL:
+ value = Context->SourceDistanceModel;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(Context);
+
+ return value;
+}
+
+AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
+{
+ ALCcontext *Context;
+ ALboolean value=AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return AL_FALSE;
+
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ if(Context->DopplerFactor != 0.0f)
+ value = AL_TRUE;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ if(Context->DopplerVelocity != 0.0f)
+ value = AL_TRUE;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ if(Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
+ value = AL_TRUE;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ if(Context->flSpeedOfSound != 0.0f)
+ value = AL_TRUE;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(Context);
+
+ return value;
+}
+
+AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
+{
+ ALCcontext *Context;
+ ALdouble value = 0.0;
+
+ Context = GetContextSuspended();
+ if(!Context) return 0.0;
+
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ value = (double)Context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = (double)Context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (double)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = (double)Context->flSpeedOfSound;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(Context);
+
+ return value;
+}
+
+AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
+{
+ ALCcontext *Context;
+ ALfloat value = 0.0f;
+
+ Context = GetContextSuspended();
+ if(!Context) return 0.0f;
+
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ value = Context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = Context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (float)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = Context->flSpeedOfSound;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(Context);
+
+ return value;
+}
+
+AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
+{
+ ALCcontext *Context;
+ ALint value = 0;
+
+ Context = GetContextSuspended();
+ if(!Context) return 0;
+
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ value = (ALint)Context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = (ALint)Context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (ALint)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = (ALint)Context->flSpeedOfSound;
+ break;
+
+ case AL_SAMPLE_SOURCE_EXT:
+ if(Context->SampleSource)
+ value = (ALint)Context->SampleSource->databuffer;
+ else
+ value = 0;
+ break;
+
+ case AL_SAMPLE_SINK_EXT:
+ if(Context->SampleSink)
+ value = (ALint)Context->SampleSink->databuffer;
+ else
+ value = 0;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(Context);
+
+ return value;
+}
+
+AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname,ALboolean *data)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(data)
+ {
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ *data = (ALboolean)((Context->DopplerFactor != 0.0f) ? AL_TRUE : AL_FALSE);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = (ALboolean)((Context->DopplerVelocity != 0.0f) ? AL_TRUE : AL_FALSE);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *data = (ALboolean)((Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) ? AL_TRUE : AL_FALSE);
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ *data = (ALboolean)((Context->flSpeedOfSound != 0.0f) ? AL_TRUE : AL_FALSE);
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ {
+ // data is a NULL pointer
+ alSetError(Context, AL_INVALID_VALUE);
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname,ALdouble *data)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(data)
+ {
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ *data = (double)Context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = (double)Context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *data = (double)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ *data = (double)Context->flSpeedOfSound;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ {
+ // data is a NULL pointer
+ alSetError(Context, AL_INVALID_VALUE);
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname,ALfloat *data)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(data)
+ {
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ *data = Context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = Context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *data = (float)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ *data = Context->flSpeedOfSound;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ {
+ // data is a NULL pointer
+ alSetError(Context, AL_INVALID_VALUE);
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname,ALint *data)
+{
+ ALCcontext *Context;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(data)
+ {
+ switch(pname)
+ {
+ case AL_DOPPLER_FACTOR:
+ *data = (ALint)Context->DopplerFactor;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = (ALint)Context->DopplerVelocity;
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *data = (ALint)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ *data = (ALint)Context->flSpeedOfSound;
+ break;
+
+ case AL_SAMPLE_SOURCE_EXT:
+ if(Context->SampleSource)
+ *data = (ALint)Context->SampleSource->databuffer;
+ else
+ *data = 0;
+ break;
+
+ case AL_SAMPLE_SINK_EXT:
+ if(Context->SampleSink)
+ *data = (ALint)Context->SampleSink->databuffer;
+ else
+ *data = 0;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ {
+ // data is a NULL pointer
+ alSetError(Context, AL_INVALID_VALUE);
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
+{
+ const ALchar *value;
+ ALCcontext *pContext;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return NULL;
+
+ switch(pname)
+ {
+ case AL_VENDOR:
+ value=alVendor;
+ break;
+
+ case AL_VERSION:
+ value=alVersion;
+ break;
+
+ case AL_RENDERER:
+ value=alRenderer;
+ break;
+
+ case AL_EXTENSIONS:
+ value=pContext->ExtensionList;//alExtensions;
+ break;
+
+ case AL_NO_ERROR:
+ value=alNoError;
+ break;
+
+ case AL_INVALID_NAME:
+ value=alErrInvalidName;
+ break;
+
+ case AL_INVALID_ENUM:
+ value=alErrInvalidEnum;
+ break;
+
+ case AL_INVALID_VALUE:
+ value=alErrInvalidValue;
+ break;
+
+ case AL_INVALID_OPERATION:
+ value=alErrInvalidOp;
+ break;
+
+ case AL_OUT_OF_MEMORY:
+ value=alErrOutOfMemory;
+ break;
+
+ default:
+ value=NULL;
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+
+ ProcessContext(pContext);
+
+ return value;
+}
+
+AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
+{
+ ALCcontext *Context;
+ ALboolean updateSources = AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(value >= 0.0f)
+ {
+ Context->DopplerFactor = value;
+ updateSources = AL_TRUE;
+ }
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+
+ // Force updating the sources for these parameters, since even head-
+ // relative sources are affected
+ if(updateSources)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ ALsource *source = Context->SourceMap.array[pos].value;
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
+{
+ ALCcontext *Context;
+ ALboolean updateSources = AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if(value > 0.0f)
+ {
+ Context->DopplerVelocity=value;
+ updateSources = AL_TRUE;
+ }
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+
+ if(updateSources)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ ALsource *source = Context->SourceMap.array[pos].value;
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat flSpeedOfSound)
+{
+ ALCcontext *pContext;
+ ALboolean updateSources = AL_FALSE;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(flSpeedOfSound > 0.0f)
+ {
+ pContext->flSpeedOfSound = flSpeedOfSound;
+ updateSources = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ if(updateSources)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < pContext->SourceMap.size;pos++)
+ {
+ ALsource *source = pContext->SourceMap.array[pos].value;
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
+{
+ ALCcontext *Context;
+ ALboolean updateSources = AL_FALSE;
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ switch(value)
+ {
+ case AL_NONE:
+ case AL_INVERSE_DISTANCE:
+ case AL_INVERSE_DISTANCE_CLAMPED:
+ case AL_LINEAR_DISTANCE:
+ case AL_LINEAR_DISTANCE_CLAMPED:
+ case AL_EXPONENT_DISTANCE:
+ case AL_EXPONENT_DISTANCE_CLAMPED:
+ Context->DistanceModel = value;
+ updateSources = !Context->SourceDistanceModel;
+ break;
+
+ default:
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+ }
+
+ if(updateSources)
+ {
+ ALsizei pos;
+ for(pos = 0;pos < Context->SourceMap.size;pos++)
+ {
+ ALsource *source = Context->SourceMap.array[pos].value;
+ source->NeedsUpdate = AL_TRUE;
+ }
+ }
+
+ ProcessContext(Context);
+}
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alThunk.h"
+
+typedef struct {
+ ALvoid *ptr;
+ ALboolean InUse;
+} ThunkEntry;
+
+static ThunkEntry *g_ThunkArray;
+static ALuint g_ThunkArraySize;
+
+static CRITICAL_SECTION g_ThunkLock;
+
+void alThunkInit(void)
+{
+ InitializeCriticalSection(&g_ThunkLock);
+ g_ThunkArraySize = 1;
+ g_ThunkArray = calloc(1, g_ThunkArraySize * sizeof(ThunkEntry));
+}
+
+void alThunkExit(void)
+{
+ free(g_ThunkArray);
+ g_ThunkArray = NULL;
+ g_ThunkArraySize = 0;
+ DeleteCriticalSection(&g_ThunkLock);
+}
+
+ALuint alThunkAddEntry(ALvoid *ptr)
+{
+ ALuint index;
+
+ EnterCriticalSection(&g_ThunkLock);
+
+ for(index = 0;index < g_ThunkArraySize;index++)
+ {
+ if(g_ThunkArray[index].InUse == AL_FALSE)
+ break;
+ }
+
+ if(index == g_ThunkArraySize)
+ {
+ ThunkEntry *NewList;
+
+ NewList = realloc(g_ThunkArray, g_ThunkArraySize*2 * sizeof(ThunkEntry));
+ if(!NewList)
+ {
+ LeaveCriticalSection(&g_ThunkLock);
+ AL_PRINT("Realloc failed to increase to %u enties!\n", g_ThunkArraySize*2);
+ return 0;
+ }
+ memset(&NewList[g_ThunkArraySize], 0, g_ThunkArraySize*sizeof(ThunkEntry));
+ g_ThunkArraySize *= 2;
+ g_ThunkArray = NewList;
+ }
+
+ g_ThunkArray[index].ptr = ptr;
+ g_ThunkArray[index].InUse = AL_TRUE;
+
+ LeaveCriticalSection(&g_ThunkLock);
+
+ return index+1;
+}
+
+void alThunkRemoveEntry(ALuint index)
+{
+ EnterCriticalSection(&g_ThunkLock);
+
+ if(index > 0 && index <= g_ThunkArraySize)
+ g_ThunkArray[index-1].InUse = AL_FALSE;
+
+ LeaveCriticalSection(&g_ThunkLock);
+}
+
+ALvoid *alThunkLookupEntry(ALuint index)
+{
+ ALvoid *ptr = NULL;
+
+ EnterCriticalSection(&g_ThunkLock);
+
+ if(index > 0 && index <= g_ThunkArraySize)
+ ptr = g_ThunkArray[index-1].ptr;
+
+ LeaveCriticalSection(&g_ThunkLock);
+
+ return ptr;
+}
--- /dev/null
+Source Install
+==============
+
+To install OpenAL Soft, use your favorite shell to go into the build/
+directory, and run:
+
+cmake ..
+
+Assuming configuration went well, you can then build it, typically using GNU
+Make (KDevelop, MSVC, and others are possible depending on your system setup
+and CMake configuration).
+
+Please Note: Double check that the appropriate backends were detected. Often,
+complaints of no sound, crashing, and missing devices can be solved by making
+sure the correct backends are being used. CMake's output will identify which
+backends were enabled.
+
+For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio
+were detected (if your target system uses them). For Windows, make sure
+DirectSound was detected.
+
+
+Utilities
+=========
+
+The source package comes with an informational utility, openal-info, and is
+built by default. It prints out information provided by the ALC and AL sub-
+systems, including discovered devices, version information, and extensions.
+
+
+Configuration
+=============
+
+OpenAL Soft can be configured on a per-user and per-system basis. This allows
+users and sysadmins to control information provided to applications, as well
+as application-agnostic behavior of the library. See alsoftrc.sample for
+available settings.
+
+
+Acknowledgements
+================
+
+Special thanks go to:
+
+Creative Labs for the original source code this is based off of.
+
+Christopher Fitzgerald for the current reverb effect implementation, and
+helping with the low-pass filter.
+
+Christian Borss for the 3D panning code the current implementation is heavilly
+based on.
+
+Ben Davis for the idea behind the current click-removal code.
--- /dev/null
+# Cross-compiling requires CMake 2.6 or newer. To cross-compile, first modify
+# this file to set the proper settings and paths. Then use it from build/ like:
+# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt \
+# -DCMAKE_INSTALL_PREFIX=/usr/mingw32/mingw
+# If you already have a toolchain file setup, you may use that instead of this
+# file.
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Windows)
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER mingw32-gcc)
+SET(CMAKE_CXX_COMPILER mingw32-g++)
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH /usr/mingw32/mingw)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
--- /dev/null
+# OpenAL config file. Options that are not under a block or are under the
+# [general] block are for general, non-backend-specific options. Blocks may
+# appear multiple times, and duplicated options will take the last value
+# specified.
+# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
+# specific override settings in ~/.alsoftrc.
+# For Windows, these settings should go into %AppData%\alsoft.ini
+# The environment variable ALSOFT_CONF can be used to specify another config
+# override
+
+# Option and block names are case-insenstive. The supplied values are only
+# hints and may not be honored (though generally it'll try to get as close as
+# possible). Note: options that are left unset may default to app- or system-
+# specified values. These are the current available settings:
+
+## format:
+# Sets the output format. Can be one of:
+# AL_FORMAT_MONO8 (8-bit mono)
+# AL_FORMAT_STEREO8 (8-bit stereo)
+# AL_FORMAT_QUAD8 (8-bit 4-channel)
+# AL_FORMAT_51CHN8 (8-bit 5.1 output)
+# AL_FORMAT_61CHN8 (8-bit 6.1 output)
+# AL_FORMAT_71CHN8 (8-bit 7.1 output)
+# AL_FORMAT_MONO16 (16-bit mono)
+# AL_FORMAT_STEREO16 (16-bit stereo)
+# AL_FORMAT_QUAD16 (16-bit 4-channel)
+# AL_FORMAT_51CHN16 (16-bit 5.1 output)
+# AL_FORMAT_61CHN16 (16-bit 6.1 output)
+# AL_FORMAT_71CHN16 (16-bit 7.1 output)
+# AL_FORMAT_MONO32 (32-bit float mono)
+# AL_FORMAT_STEREO32 (32-bit float stereo)
+# AL_FORMAT_QUAD32 (32-bit float 4-channel)
+# AL_FORMAT_51CHN32 (32-bit float 5.1 output)
+# AL_FORMAT_61CHN32 (32-bit float 6.1 output)
+# AL_FORMAT_71CHN32 (32-bit float 7.1 output)
+#format = AL_FORMAT_STEREO16
+
+## cf_level:
+# Sets the crossfeed level for stereo output. Valid values are:
+# 0 - No crossfeed
+# 1 - Low crossfeed
+# 2 - Middle crossfeed
+# 3 - High crossfeed (virtual speakers are closer to itself)
+# 4 - Low easy crossfeed
+# 5 - Middle easy crossfeed
+# 6 - High easy crossfeed
+# Users of headphones may want to try various settings. Has no effect on non-
+# stereo modes.
+#cf_level = 0
+
+## head_dampen:
+# Sets the amount of dampening on sounds emanating from behind the listener.
+# This is used to simulate the natural occlusion of the head, which is
+# typically missing with mono and stereo output, and as such, only works on
+# mono and stereo output modes. Valid values range from 0 to 1 (inclusive),
+# and higher values provide a stronger effect.
+#head_dampen = 0.25
+
+## frequency:
+# Sets the output frequency.
+#frequency = 44100
+
+## resampler:
+# Selects the resampler used when mixing sources. Valid values are:
+# 0 - None (nearest sample, no interpolation)
+# 1 - Linear (extrapolates samples using a linear slope between samples)
+# 2 - Cubic (extrapolates samples using a Catmull-Rom spline)
+# Specifying other values will result in using the default (linear).
+#resampler = 1
+resampler = 0
+
+## rt-prio:
+# Sets real-time priority for the mixing thread. Not all drivers may use this
+# (eg. PortAudio) as they already control the priority of the mixing thread.
+# 0 and negative values will disable it. Note that this may constitute a
+# security risk since a real-time priority thread can indefinitely block
+# normal-priority threads if it fails to wait. As such, the default is
+# disabled.
+#rt-prio = 0
+
+## period_size:
+# Sets the update period size, in frames. This is the number of frames needed
+# for each mixing update.
+#period_size = 1024
+period_size = 2048
+
+## periods:
+# Sets the number of update periods. Higher values create a larger mix ahead,
+# which helps protect against skips when the CPU is under load, but increases
+# the delay between a sound getting mixed and being heard.
+#periods = 4
+periods = 8
+
+## sources:
+# Sets the maximum number of allocatable sources. Lower values may help for
+# systems with apps that try to play more sounds than the CPU can handle.
+#sources = 256
+sources = 32
+
+## stereodup:
+# Sets whether to duplicate stereo sounds on the rear and side speakers for 4+
+# channel output. This provides a "fuller" playback quality for 4+ channel
+# output modes, although each individual speaker will have a slight reduction
+# in volume to compensate for the extra output speakers. True, yes, on, and
+# non-0 values will duplicate stereo sources. 0 and anything else will cause
+# stereo sounds to only play out the front speakers. This only has an effect
+# when a suitable output format is used (ie. those that contain side and/or
+# rear speakers).
+#stereodup = true
+
+## scalemix:
+# Sets whether to scale the remixed output. When the final mix is written to
+# the device, the multi-channel data is remixed so pure-virtual channels (eg.
+# front-center on stereo output) are remixed and added to available channels
+# (eg. front-left and front-right). Scaling helps ensure that no single source
+# will put out more than 100% on a given physical channel. This can cause a
+# noticeable reduction in overall volume, however, so it is off by default.
+#scalemix = false
+
+## drivers:
+# Sets the backend driver list order, comma-seperated. Unknown backends and
+# duplicated names are ignored. Unlisted backends won't be considered for use
+# unless the list is ended with a comma (eg. 'oss,' will list OSS first
+# followed by all other available backends, while 'oss' will list OSS only).
+# An empty list means the default.
+#drivers = pulse,alsa,oss,solaris,dsound,winmm,port,wave
+drivers = avsystem
+
+## excludefx:
+# Sets which effects to exclude, preventing apps from using them. This can
+# help for apps that try to use effects which are too CPU intensive for the
+# system to handle. Available effects are: eaxreverb,reverb,echo
+#excludefx =
+excludefx = eaxreverb,reverb,echo
+
+## slots:
+# Sets the maximum number of Auxiliary Effect Slots an app can create. A slot
+# can use a non-negligible amount of CPU time if an effect is set on it even
+# if no sources are feeding it, so this may help when apps use more than the
+# system can handle.
+#slots = 4
+
+## sends:
+# Sets the number of auxiliary sends per source. When not specified (default),
+# it allows the app to request how many it wants. The maximum value currently
+# possible is 4.
+#sends =
+
+## layout:
+# Sets the virtual speaker layout. Values are specified in degrees, where 0 is
+# straight in front, negative goes left, and positive goes right. Unspecified
+# speakers will remain at their default positions (which are dependant on the
+# output format). Available speakers are back-left(bl), side-left(sl), front-
+# left(fl), front-center(fc), front-right(fr), side-right(sr), back-right(br),
+# and back-center(bc).
+#layout =
+
+## layout_*:
+# Channel-specific layouts may be specified to override the layout option. The
+# same speakers as the layout option are available, and the default settings
+# are shown below.
+#layout_STEREO = fl=-90, fr=90
+#layout_QUAD = fl=-45, fr=45, bl=-135, br=135
+#layout_51CHN = fl=-30, fr=30, fc=0, bl=-110, br=110
+#layout_61CHN = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180
+#layout_71CHN = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150
+
+##
+## ALSA backend stuff
+##
+[alsa]
+
+## device:
+# Sets the device name for the default playback device.
+#device = default
+
+## capture:
+# Sets the device name for the default capture device.
+#capture = default
+
+## mmap:
+# Sets whether to try using mmap mode (helps reduce latencies and CPU
+# consumption). If mmap isn't available, it will automatically fall back to
+# non-mmap mode. True, yes, on, and non-0 values will attempt to use mmap. 0
+# and anything else will force mmap off.
+#mmap = true
+
+##
+## OSS backend stuff
+##
+[oss]
+
+## device:
+# Sets the device name for OSS output.
+#device = /dev/dsp
+
+## capture:
+# Sets the device name for OSS capture.
+#capture = /dev/dsp
+
+##
+## Solaris backend stuff
+##
+[solaris]
+
+## device:
+# Sets the device name for Solaris output.
+#device = /dev/audio
+
+##
+## DirectSound backend stuff
+##
+[dsound]
+
+##
+## Windows Multimedia backend stuff
+##
+[winmm]
+
+##
+## PortAudio backend stuff
+##
+[port]
+
+## device:
+# Sets the device index for output. Negative values will use the default as
+# given by PortAudio itself.
+#device = -1
+
+## capture:
+# Sets the device index for capture. Negative values will use the default as
+# given by PortAudio itself.
+#capture = -1
+
+##
+## PulseAudio backend stuff
+##
+[pulse]
+
+## spawn-server:
+# Attempts to spawn a PulseAudio server when requesting to open a PulseAudio
+# device. Note that some apps may open and probe all enumerated devices on
+# startup, causing a server to spawn even if a PulseAudio device is not
+# actually selected. Setting autospawn to false in Pulse's client.conf will
+# still prevent autospawning even if this is set to true.
+#spawn-server = false
+
+##
+## Wave File Writer stuff
+##
+[wave]
+
+## file:
+# Sets the filename of the wave file to write to. An empty name prevents the
+# backend from opening, even when explicitly requested.
+# THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION!
+#file =
+
+[avsystem]
+device = avsystem_playback
--- /dev/null
+# - Check if the C source code provided in the SOURCE argument compiles.
+# CHECK_C_SOURCE_COMPILES(SOURCE VAR)
+#
+# FLAG - compiler flag to check
+# VAR - variable to store whether the source code compiled
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_INCLUDES = list of include directories
+# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+MACRO(CHECK_C_COMPILER_FLAG FLAG VAR)
+ IF("${VAR}" MATCHES "^${VAR}$")
+ SET(MACRO_CHECK_FUNCTION_DEFINITIONS
+ "${FLAG} ${CMAKE_REQUIRED_FLAGS}")
+ IF(CMAKE_REQUIRED_LIBRARIES)
+ SET(CHECK_C_COMPILER_FLAG_ADD_LIBRARIES
+ "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+ ELSE(CMAKE_REQUIRED_LIBRARIES)
+ SET(CHECK_C_COMPILER_FLAG_ADD_LIBRARIES)
+ ENDIF(CMAKE_REQUIRED_LIBRARIES)
+ IF(CMAKE_REQUIRED_INCLUDES)
+ SET(CHECK_C_COMPILER_FLAG_ADD_INCLUDES
+ "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+ ELSE(CMAKE_REQUIRED_INCLUDES)
+ SET(CHECK_C_COMPILER_FLAG_ADD_INCLUDES)
+ ENDIF(CMAKE_REQUIRED_INCLUDES)
+ FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
+ "int main() {return 0;}\n")
+
+ MESSAGE(STATUS "Checking if C compiler supports ${FLAG}")
+ TRY_COMPILE(${VAR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ "${CHECK_C_COMPILER_FLAG_ADD_LIBRARIES}"
+ "${CHECK_C_COMPILER_FLAG_ADD_INCLUDES}"
+ OUTPUT_VARIABLE OUTPUT)
+ IF(${VAR})
+ SET(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+ MESSAGE(STATUS "Checking if C compiler supports ${FLAG} - Success")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
+ "${OUTPUT}\n"
+ "Source file was:\n${SOURCE}\n")
+ ELSE(${VAR})
+ MESSAGE(STATUS "Checking if C compiler supports ${FLAG} - Failed")
+ SET(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
+ "${OUTPUT}\n"
+ "Source file was:\n${SOURCE}\n")
+ ENDIF(${VAR})
+ ENDIF("${VAR}" MATCHES "^${VAR}$")
+ENDMACRO(CHECK_C_COMPILER_FLAG)
--- /dev/null
+#ifdef CHECK_SHARED_FUNCTION_EXISTS
+
+#include <stdlib.h>
+
+#ifndef CALLSTACK
+#define CALLSTACK
+#endif
+
+#ifdef _WIN32
+#ifdef ARGSTACK
+char __stdcall CHECK_SHARED_FUNCTION_EXISTS(ARGSTACK);
+#else
+char __stdcall CHECK_SHARED_FUNCTION_EXISTS(void);
+#endif
+#else
+char CHECK_SHARED_FUNCTION_EXISTS();
+#endif
+
+#ifdef __CLASSIC_C__
+int main(){
+ int ac;
+ char*av[];
+#else
+int main(int ac, char*av[]){
+#endif
+ CHECK_SHARED_FUNCTION_EXISTS(CALLSTACK);
+ if(ac > 1000)
+ {
+ return *av[0];
+ }
+ return 0;
+}
+
+#else /* CHECK_SHARED_FUNCTION_EXISTS */
+
+# error "CHECK_SHARED_FUNCTION_EXISTS has to specify the function"
+
+#endif /* CHECK_SHARED_FUNCTION_EXISTS */
--- /dev/null
+# - Check if the function exists.
+# CHECK_LIBRARY_EXISTS (LIBRARY FUNCTION LOCATION VARIABLE)
+#
+# LIBRARY - the name of the library you are looking for
+# FUNCTION - the name of the function
+# ARGCOUNT - number of arguments for stdcall functions
+# LOCATION - location where the library should be found
+# VARIABLE - variable to store the result
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+# CMAKE_REQUIRED_FLAGS = string of compile command line flags
+# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+MACRO(CHECK_SHARED_LIBRARY_EXISTS LIBRARY FUNCTION ARGCOUNT LOCATION VARIABLE)
+ IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
+ SET(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION
+ "-DCHECK_SHARED_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
+ IF(WIN32)
+ IF(${ARGCOUNT} GREATER 0)
+ SET(ARGSTACK "void*")
+ SET(CALLSTACK "NULL")
+ SET(CURARG 1)
+ WHILE(${ARGCOUNT} GREATER ${CURARG})
+ SET(ARGSTACK "${ARGSTACK},void*")
+ SET(CALLSTACK "${CALLSTACK},NULL")
+ MATH(EXPR CURARG "${CURARG} + 1")
+ ENDWHILE(${ARGCOUNT} GREATER ${CURARG})
+ SET(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION
+ "-D_WIN32 -DARGSTACK=\"${ARGSTACK}\" -DCALLSTACK=\"${CALLSTACK}\" ${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}")
+ ELSE(${ARGCOUNT} GREATER 0)
+ SET(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION
+ "-D_WIN32 ${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}")
+ ENDIF(${ARGCOUNT} GREATER 0)
+ ENDIF(WIN32)
+ MESSAGE(STATUS "Looking for ${FUNCTION} in ${LIBRARY}")
+ SET(CHECK_LIBRARY_EXISTS_LIBRARIES ${LIBRARY})
+ IF(CMAKE_REQUIRED_LIBRARIES)
+ SET(CHECK_LIBRARY_EXISTS_LIBRARIES
+ ${CHECK_LIBRARY_EXISTS_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES})
+ ENDIF(CMAKE_REQUIRED_LIBRARIES)
+ TRY_COMPILE(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/cmake/CheckSharedFunctionExists.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+ CMAKE_FLAGS
+ -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}
+ -DLINK_DIRECTORIES:STRING=${LOCATION}
+ "-DLINK_LIBRARIES:STRING=${CHECK_LIBRARY_EXISTS_LIBRARIES}"
+ OUTPUT_VARIABLE OUTPUT)
+
+ IF(${VARIABLE})
+ MESSAGE(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - found")
+ SET(${VARIABLE} 1 CACHE INTERNAL "Have library ${LIBRARY}")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the function ${FUNCTION} exists in the ${LIBRARY} "
+ "passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ ELSE(${VARIABLE})
+ MESSAGE(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - not found")
+ SET(${VARIABLE} "" CACHE INTERNAL "Have library ${LIBRARY}")
+ FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the function ${FUNCTION} exists in the ${LIBRARY} "
+ "failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ ENDIF(${VARIABLE})
+ ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
+ENDMACRO(CHECK_SHARED_LIBRARY_EXISTS)
--- /dev/null
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Define to the library version */
+#define ALSOFT_VERSION "${LIB_VERSION}"
+
+/* Define if we have the ALSA backend */
+#cmakedefine HAVE_ALSA
+
+/* Define if we have the OSS backend */
+#cmakedefine HAVE_OSS
+
+/* Define if we have the Solaris backend */
+#cmakedefine HAVE_SOLARIS
+
+/* Define if we have the DSound backend */
+#cmakedefine HAVE_DSOUND
+
+/* Define if we have the Windows Multimedia backend */
+#cmakedefine HAVE_WINMM
+
+/* Define if we have the PortAudio backend */
+#cmakedefine HAVE_PORTAUDIO
+
+/* Define if we have the PulseAudio backend */
+#cmakedefine HAVE_PULSEAUDIO
+
+/* Define if we have the Wave Writer backend */
+#cmakedefine HAVE_WAVE
+
+/* Define if we have the AVSYSTEM backend */
+#cmakedefine HAVE_AVSYSTEM
+
+/* Define if we have dlfcn.h */
+#cmakedefine HAVE_DLFCN_H
+
+/* Define if we have the stat function */
+#cmakedefine HAVE_STAT
+
+/* Define if we have the powf function */
+#cmakedefine HAVE_POWF
+
+/* Define if we have the sqrtf function */
+#cmakedefine HAVE_SQRTF
+
+/* Define if we have the acosf function */
+#cmakedefine HAVE_ACOSF
+
+/* Define if we have the atanf function */
+#cmakedefine HAVE_ATANF
+
+/* Define if we have the fabsf function */
+#cmakedefine HAVE_FABSF
+
+/* Define if we have the strtof function */
+#cmakedefine HAVE_STRTOF
+
+/* Define if we have stdint.h */
+#cmakedefine HAVE_STDINT_H
+
+/* Define if we have the __int64 type */
+#cmakedefine HAVE___INT64
+
+/* Define to the size of a long int type */
+#cmakedefine SIZEOF_LONG ${SIZEOF_LONG}
+
+/* Define to the size of a long long int type */
+#cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG}
+
+/* Define to the size of an unsigned int type */
+#cmakedefine SIZEOF_UINT ${SIZEOF_UINT}
+
+/* Define to the size of a void pointer type */
+#cmakedefine SIZEOF_VOIDP ${SIZEOF_VOIDP}
+
+/* Define if we have GCC's destructor attribute */
+#cmakedefine HAVE_GCC_DESTRUCTOR
+
+/* Define if we have GCC's format attribute */
+#cmakedefine HAVE_GCC_FORMAT
+
+/* Define if we have pthread_np.h */
+#cmakedefine HAVE_PTHREAD_NP_H
+
+/* Define if we have float.h */
+#cmakedefine HAVE_FLOAT_H
+
+/* Define if we have fenv.h */
+#cmakedefine HAVE_FENV_H
+
+/* Define if we have fesetround() */
+#cmakedefine HAVE_FESETROUND
+
+/* Define if we have _controlfp() */
+#cmakedefine HAVE__CONTROLFP
+
+/* Define if we have pthread_setschedparam() */
+#cmakedefine HAVE_PTHREAD_SETSCHEDPARAM
+
+#endif
--- /dev/null
+#ifndef AL_AL_H
+#define AL_AL_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(AL_LIBTYPE_STATIC)
+ #define AL_API
+#elif defined(_WIN32) && !defined(_XBOX)
+ #if defined(AL_BUILD_LIBRARY)
+ #define AL_API __declspec(dllexport)
+ #else
+ #define AL_API __declspec(dllimport)
+ #endif
+#else
+ #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY)
+ #define AL_API __attribute__((visibility("protected")))
+ #else
+ #define AL_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define AL_APIENTRY __cdecl
+#else
+ #define AL_APIENTRY
+#endif
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export on
+#endif
+
+/*
+ * The OPENAL, ALAPI, ALAPIENTRY, AL_INVALID, AL_ILLEGAL_ENUM, and
+ * AL_ILLEGAL_COMMAND macros are deprecated, but are included for
+ * applications porting code from AL 1.0
+ */
+#define OPENAL
+#define ALAPI AL_API
+#define ALAPIENTRY AL_APIENTRY
+#define AL_INVALID (-1)
+#define AL_ILLEGAL_ENUM AL_INVALID_ENUM
+#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION
+
+#define AL_VERSION_1_0
+#define AL_VERSION_1_1
+
+
+/** 8-bit boolean */
+typedef char ALboolean;
+
+/** character */
+typedef char ALchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALsizei;
+
+/** enumerated 32-bit value */
+typedef int ALenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/* "no distance model" or "no buffer" */
+#define AL_NONE 0
+
+/* Boolean False. */
+#define AL_FALSE 0
+
+/** Boolean True. */
+#define AL_TRUE 1
+
+/** Indicate Source has relative coordinates. */
+#define AL_SOURCE_RELATIVE 0x202
+
+
+
+/**
+ * Directional source, inner cone angle, in degrees.
+ * Range: [0-360]
+ * Default: 360
+ */
+#define AL_CONE_INNER_ANGLE 0x1001
+
+/**
+ * Directional source, outer cone angle, in degrees.
+ * Range: [0-360]
+ * Default: 360
+ */
+#define AL_CONE_OUTER_ANGLE 0x1002
+
+/**
+ * Specify the pitch to be applied at source.
+ * Range: [0.5-2.0]
+ * Default: 1.0
+ */
+#define AL_PITCH 0x1003
+
+/**
+ * Specify the current location in three dimensional space.
+ * OpenAL, like OpenGL, uses a right handed coordinate system,
+ * where in a frontal default view X (thumb) points right,
+ * Y points up (index finger), and Z points towards the
+ * viewer/camera (middle finger).
+ * To switch from a left handed coordinate system, flip the
+ * sign on the Z coordinate.
+ * Listener position is always in the world coordinate system.
+ */
+#define AL_POSITION 0x1004
+
+/** Specify the current direction. */
+#define AL_DIRECTION 0x1005
+
+/** Specify the current velocity in three dimensional space. */
+#define AL_VELOCITY 0x1006
+
+/**
+ * Indicate whether source is looping.
+ * Type: ALboolean?
+ * Range: [AL_TRUE, AL_FALSE]
+ * Default: FALSE.
+ */
+#define AL_LOOPING 0x1007
+
+/**
+ * Indicate the buffer to provide sound samples.
+ * Type: ALuint.
+ * Range: any valid Buffer id.
+ */
+#define AL_BUFFER 0x1009
+
+/**
+ * Indicate the gain (volume amplification) applied.
+ * Type: ALfloat.
+ * Range: ]0.0- ]
+ * A value of 1.0 means un-attenuated/unchanged.
+ * Each division by 2 equals an attenuation of -6dB.
+ * Each multiplicaton with 2 equals an amplification of +6dB.
+ * A value of 0.0 is meaningless with respect to a logarithmic
+ * scale; it is interpreted as zero volume - the channel
+ * is effectively disabled.
+ */
+#define AL_GAIN 0x100A
+
+/*
+ * Indicate minimum source attenuation
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ *
+ * Logarthmic
+ */
+#define AL_MIN_GAIN 0x100D
+
+/**
+ * Indicate maximum source attenuation
+ * Type: ALfloat
+ * Range: [0.0 - 1.0]
+ *
+ * Logarthmic
+ */
+#define AL_MAX_GAIN 0x100E
+
+/**
+ * Indicate listener orientation.
+ *
+ * at/up
+ */
+#define AL_ORIENTATION 0x100F
+
+/**
+ * Source state information.
+ */
+#define AL_SOURCE_STATE 0x1010
+#define AL_INITIAL 0x1011
+#define AL_PLAYING 0x1012
+#define AL_PAUSED 0x1013
+#define AL_STOPPED 0x1014
+
+/**
+ * Buffer Queue params
+ */
+#define AL_BUFFERS_QUEUED 0x1015
+#define AL_BUFFERS_PROCESSED 0x1016
+
+/**
+ * Source buffer position information
+ */
+#define AL_SEC_OFFSET 0x1024
+#define AL_SAMPLE_OFFSET 0x1025
+#define AL_BYTE_OFFSET 0x1026
+
+/*
+ * Source type (Static, Streaming or undetermined)
+ * Source is Static if a Buffer has been attached using AL_BUFFER
+ * Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers
+ * Source is undetermined when it has the NULL buffer attached
+ */
+#define AL_SOURCE_TYPE 0x1027
+#define AL_STATIC 0x1028
+#define AL_STREAMING 0x1029
+#define AL_UNDETERMINED 0x1030
+
+/** Sound samples: format specifier. */
+#define AL_FORMAT_MONO8 0x1100
+#define AL_FORMAT_MONO16 0x1101
+#define AL_FORMAT_STEREO8 0x1102
+#define AL_FORMAT_STEREO16 0x1103
+
+/**
+ * source specific reference distance
+ * Type: ALfloat
+ * Range: 0.0 - +inf
+ *
+ * At 0.0, no distance attenuation occurs. Default is
+ * 1.0.
+ */
+#define AL_REFERENCE_DISTANCE 0x1020
+
+/**
+ * source specific rolloff factor
+ * Type: ALfloat
+ * Range: 0.0 - +inf
+ *
+ */
+#define AL_ROLLOFF_FACTOR 0x1021
+
+/**
+ * Directional source, outer cone gain.
+ *
+ * Default: 0.0
+ * Range: [0.0 - 1.0]
+ * Logarithmic
+ */
+#define AL_CONE_OUTER_GAIN 0x1022
+
+/**
+ * Indicate distance above which sources are not
+ * attenuated using the inverse clamped distance model.
+ *
+ * Default: +inf
+ * Type: ALfloat
+ * Range: 0.0 - +inf
+ */
+#define AL_MAX_DISTANCE 0x1023
+
+/**
+ * Sound samples: frequency, in units of Hertz [Hz].
+ * This is the number of samples per second. Half of the
+ * sample frequency marks the maximum significant
+ * frequency component.
+ */
+#define AL_FREQUENCY 0x2001
+#define AL_BITS 0x2002
+#define AL_CHANNELS 0x2003
+#define AL_SIZE 0x2004
+
+/**
+ * Buffer state.
+ *
+ * Not supported for public use (yet).
+ */
+#define AL_UNUSED 0x2010
+#define AL_PENDING 0x2011
+#define AL_PROCESSED 0x2012
+
+
+/** Errors: No Error. */
+#define AL_NO_ERROR AL_FALSE
+
+/**
+ * Invalid Name paramater passed to AL call.
+ */
+#define AL_INVALID_NAME 0xA001
+
+/**
+ * Invalid parameter passed to AL call.
+ */
+#define AL_INVALID_ENUM 0xA002
+
+/**
+ * Invalid enum parameter value.
+ */
+#define AL_INVALID_VALUE 0xA003
+
+/**
+ * Illegal call.
+ */
+#define AL_INVALID_OPERATION 0xA004
+
+
+/**
+ * No mojo.
+ */
+#define AL_OUT_OF_MEMORY 0xA005
+
+
+/** Context strings: Vendor Name. */
+#define AL_VENDOR 0xB001
+#define AL_VERSION 0xB002
+#define AL_RENDERER 0xB003
+#define AL_EXTENSIONS 0xB004
+
+/** Global tweakage. */
+
+/**
+ * Doppler scale. Default 1.0
+ */
+#define AL_DOPPLER_FACTOR 0xC000
+
+/**
+ * Tweaks speed of propagation.
+ */
+#define AL_DOPPLER_VELOCITY 0xC001
+
+/**
+ * Speed of Sound in units per second
+ */
+#define AL_SPEED_OF_SOUND 0xC003
+
+/**
+ * Distance models
+ *
+ * used in conjunction with DistanceModel
+ *
+ * implicit: NONE, which disances distance attenuation.
+ */
+#define AL_DISTANCE_MODEL 0xD000
+#define AL_INVERSE_DISTANCE 0xD001
+#define AL_INVERSE_DISTANCE_CLAMPED 0xD002
+#define AL_LINEAR_DISTANCE 0xD003
+#define AL_LINEAR_DISTANCE_CLAMPED 0xD004
+#define AL_EXPONENT_DISTANCE 0xD005
+#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006
+
+/*
+ * Renderer State management
+ */
+AL_API void AL_APIENTRY alEnable( ALenum capability );
+
+AL_API void AL_APIENTRY alDisable( ALenum capability );
+
+AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability );
+
+
+/*
+ * State retrieval
+ */
+AL_API const ALchar* AL_APIENTRY alGetString( ALenum param );
+
+AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* data );
+
+AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* data );
+
+AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* data );
+
+AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* data );
+
+AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param );
+
+AL_API ALint AL_APIENTRY alGetInteger( ALenum param );
+
+AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param );
+
+AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param );
+
+
+/*
+ * Error support.
+ * Obtain the most recent error generated in the AL state machine.
+ */
+AL_API ALenum AL_APIENTRY alGetError( void );
+
+
+/*
+ * Extension support.
+ * Query for the presence of an extension, and obtain any appropriate
+ * function pointers and enum values.
+ */
+AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname );
+
+AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname );
+
+AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename );
+
+
+/*
+ * LISTENER
+ * Listener represents the location and orientation of the
+ * 'user' in 3D-space.
+ *
+ * Properties include: -
+ *
+ * Gain AL_GAIN ALfloat
+ * Position AL_POSITION ALfloat[3]
+ * Velocity AL_VELOCITY ALfloat[3]
+ * Orientation AL_ORIENTATION ALfloat[6] (Forward then Up vectors)
+*/
+
+/*
+ * Set Listener parameters
+ */
+AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value );
+
+AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+
+AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values );
+
+AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value );
+
+AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 );
+
+AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values );
+
+/*
+ * Get Listener parameters
+ */
+AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value );
+
+AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 );
+
+AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values );
+
+AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value );
+
+AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 );
+
+AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values );
+
+
+/**
+ * SOURCE
+ * Sources represent individual sound objects in 3D-space.
+ * Sources take the PCM data provided in the specified Buffer,
+ * apply Source-specific modifications, and then
+ * submit them to be mixed according to spatial arrangement etc.
+ *
+ * Properties include: -
+ *
+ * Gain AL_GAIN ALfloat
+ * Min Gain AL_MIN_GAIN ALfloat
+ * Max Gain AL_MAX_GAIN ALfloat
+ * Position AL_POSITION ALfloat[3]
+ * Velocity AL_VELOCITY ALfloat[3]
+ * Direction AL_DIRECTION ALfloat[3]
+ * Head Relative Mode AL_SOURCE_RELATIVE ALint (AL_TRUE or AL_FALSE)
+ * Reference Distance AL_REFERENCE_DISTANCE ALfloat
+ * Max Distance AL_MAX_DISTANCE ALfloat
+ * RollOff Factor AL_ROLLOFF_FACTOR ALfloat
+ * Inner Angle AL_CONE_INNER_ANGLE ALint or ALfloat
+ * Outer Angle AL_CONE_OUTER_ANGLE ALint or ALfloat
+ * Cone Outer Gain AL_CONE_OUTER_GAIN ALint or ALfloat
+ * Pitch AL_PITCH ALfloat
+ * Looping AL_LOOPING ALint (AL_TRUE or AL_FALSE)
+ * MS Offset AL_MSEC_OFFSET ALint or ALfloat
+ * Byte Offset AL_BYTE_OFFSET ALint or ALfloat
+ * Sample Offset AL_SAMPLE_OFFSET ALint or ALfloat
+ * Attached Buffer AL_BUFFER ALint
+ * State (Query only) AL_SOURCE_STATE ALint
+ * Buffers Queued (Query only) AL_BUFFERS_QUEUED ALint
+ * Buffers Processed (Query only) AL_BUFFERS_PROCESSED ALint
+ */
+
+/* Create Source objects */
+AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* sources );
+
+/* Delete Source objects */
+AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* sources );
+
+/* Verify a handle is a valid Source */
+AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid );
+
+/*
+ * Set Source parameters
+ */
+AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value );
+
+AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+
+AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values );
+
+AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value );
+
+AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 );
+
+AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values );
+
+/*
+ * Get Source parameters
+ */
+AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value );
+
+AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+
+AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values );
+
+AL_API void AL_APIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value );
+
+AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+
+AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values );
+
+
+/*
+ * Source vector based playback calls
+ */
+
+/* Play, replay, or resume (if paused) a list of Sources */
+AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids );
+
+/* Stop a list of Sources */
+AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids );
+
+/* Rewind a list of Sources */
+AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids );
+
+/* Pause a list of Sources */
+AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids );
+
+/*
+ * Source based playback calls
+ */
+
+/* Play, replay, or resume a Source */
+AL_API void AL_APIENTRY alSourcePlay( ALuint sid );
+
+/* Stop a Source */
+AL_API void AL_APIENTRY alSourceStop( ALuint sid );
+
+/* Rewind a Source (set playback postiton to beginning) */
+AL_API void AL_APIENTRY alSourceRewind( ALuint sid );
+
+/* Pause a Source */
+AL_API void AL_APIENTRY alSourcePause( ALuint sid );
+
+/*
+ * Source Queuing
+ */
+AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids );
+
+AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids );
+
+
+/**
+ * BUFFER
+ * Buffer objects are storage space for sample data.
+ * Buffers are referred to by Sources. One Buffer can be used
+ * by multiple Sources.
+ *
+ * Properties include: -
+ *
+ * Frequency (Query only) AL_FREQUENCY ALint
+ * Size (Query only) AL_SIZE ALint
+ * Bits (Query only) AL_BITS ALint
+ * Channels (Query only) AL_CHANNELS ALint
+ */
+
+/* Create Buffer objects */
+AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* buffers );
+
+/* Delete Buffer objects */
+AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers );
+
+/* Verify a handle is a valid Buffer */
+AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid );
+
+/* Specify the data to be copied into a buffer */
+AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq );
+
+/*
+ * Set Buffer parameters
+ */
+AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value );
+
+AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+
+AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values );
+
+AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value );
+
+AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 );
+
+AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values );
+
+/*
+ * Get Buffer parameters
+ */
+AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value );
+
+AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+
+AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values );
+
+AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value );
+
+AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+
+AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values );
+
+
+/*
+ * Global Parameters
+ */
+AL_API void AL_APIENTRY alDopplerFactor( ALfloat value );
+
+AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value );
+
+AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value );
+
+AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel );
+
+/*
+ * Pointer-to-function types, useful for dynamically getting AL entry points.
+ */
+typedef void (AL_APIENTRY *LPALENABLE)( ALenum capability );
+typedef void (AL_APIENTRY *LPALDISABLE)( ALenum capability );
+typedef ALboolean (AL_APIENTRY *LPALISENABLED)( ALenum capability );
+typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)( ALenum param );
+typedef void (AL_APIENTRY *LPALGETBOOLEANV)( ALenum param, ALboolean* data );
+typedef void (AL_APIENTRY *LPALGETINTEGERV)( ALenum param, ALint* data );
+typedef void (AL_APIENTRY *LPALGETFLOATV)( ALenum param, ALfloat* data );
+typedef void (AL_APIENTRY *LPALGETDOUBLEV)( ALenum param, ALdouble* data );
+typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)( ALenum param );
+typedef ALint (AL_APIENTRY *LPALGETINTEGER)( ALenum param );
+typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)( ALenum param );
+typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)( ALenum param );
+typedef ALenum (AL_APIENTRY *LPALGETERROR)( void );
+typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar* extname );
+typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)( const ALchar* fname );
+typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)( const ALchar* ename );
+typedef void (AL_APIENTRY *LPALLISTENERF)( ALenum param, ALfloat value );
+typedef void (AL_APIENTRY *LPALLISTENER3F)( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+typedef void (AL_APIENTRY *LPALLISTENERFV)( ALenum param, const ALfloat* values );
+typedef void (AL_APIENTRY *LPALLISTENERI)( ALenum param, ALint value );
+typedef void (AL_APIENTRY *LPALLISTENER3I)( ALenum param, ALint value1, ALint value2, ALint value3 );
+typedef void (AL_APIENTRY *LPALLISTENERIV)( ALenum param, const ALint* values );
+typedef void (AL_APIENTRY *LPALGETLISTENERF)( ALenum param, ALfloat* value );
+typedef void (AL_APIENTRY *LPALGETLISTENER3F)( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 );
+typedef void (AL_APIENTRY *LPALGETLISTENERFV)( ALenum param, ALfloat* values );
+typedef void (AL_APIENTRY *LPALGETLISTENERI)( ALenum param, ALint* value );
+typedef void (AL_APIENTRY *LPALGETLISTENER3I)( ALenum param, ALint *value1, ALint *value2, ALint *value3 );
+typedef void (AL_APIENTRY *LPALGETLISTENERIV)( ALenum param, ALint* values );
+typedef void (AL_APIENTRY *LPALGENSOURCES)( ALsizei n, ALuint* sources );
+typedef void (AL_APIENTRY *LPALDELETESOURCES)( ALsizei n, const ALuint* sources );
+typedef ALboolean (AL_APIENTRY *LPALISSOURCE)( ALuint sid );
+typedef void (AL_APIENTRY *LPALSOURCEF)( ALuint sid, ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALSOURCE3F)( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+typedef void (AL_APIENTRY *LPALSOURCEFV)( ALuint sid, ALenum param, const ALfloat* values );
+typedef void (AL_APIENTRY *LPALSOURCEI)( ALuint sid, ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALSOURCE3I)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 );
+typedef void (AL_APIENTRY *LPALSOURCEIV)( ALuint sid, ALenum param, const ALint* values );
+typedef void (AL_APIENTRY *LPALGETSOURCEF)( ALuint sid, ALenum param, ALfloat* value );
+typedef void (AL_APIENTRY *LPALGETSOURCE3F)( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+typedef void (AL_APIENTRY *LPALGETSOURCEFV)( ALuint sid, ALenum param, ALfloat* values );
+typedef void (AL_APIENTRY *LPALGETSOURCEI)( ALuint sid, ALenum param, ALint* value );
+typedef void (AL_APIENTRY *LPALGETSOURCE3I)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+typedef void (AL_APIENTRY *LPALGETSOURCEIV)( ALuint sid, ALenum param, ALint* values );
+typedef void (AL_APIENTRY *LPALSOURCEPLAYV)( ALsizei ns, const ALuint *sids );
+typedef void (AL_APIENTRY *LPALSOURCESTOPV)( ALsizei ns, const ALuint *sids );
+typedef void (AL_APIENTRY *LPALSOURCEREWINDV)( ALsizei ns, const ALuint *sids );
+typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)( ALsizei ns, const ALuint *sids );
+typedef void (AL_APIENTRY *LPALSOURCEPLAY)( ALuint sid );
+typedef void (AL_APIENTRY *LPALSOURCESTOP)( ALuint sid );
+typedef void (AL_APIENTRY *LPALSOURCEREWIND)( ALuint sid );
+typedef void (AL_APIENTRY *LPALSOURCEPAUSE)( ALuint sid );
+typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, const ALuint *bids );
+typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, ALuint *bids );
+typedef void (AL_APIENTRY *LPALGENBUFFERS)( ALsizei n, ALuint* buffers );
+typedef void (AL_APIENTRY *LPALDELETEBUFFERS)( ALsizei n, const ALuint* buffers );
+typedef ALboolean (AL_APIENTRY *LPALISBUFFER)( ALuint bid );
+typedef void (AL_APIENTRY *LPALBUFFERDATA)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq );
+typedef void (AL_APIENTRY *LPALBUFFERF)( ALuint bid, ALenum param, ALfloat value);
+typedef void (AL_APIENTRY *LPALBUFFER3F)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+typedef void (AL_APIENTRY *LPALBUFFERFV)( ALuint bid, ALenum param, const ALfloat* values );
+typedef void (AL_APIENTRY *LPALBUFFERI)( ALuint bid, ALenum param, ALint value);
+typedef void (AL_APIENTRY *LPALBUFFER3I)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 );
+typedef void (AL_APIENTRY *LPALBUFFERIV)( ALuint bid, ALenum param, const ALint* values );
+typedef void (AL_APIENTRY *LPALGETBUFFERF)( ALuint bid, ALenum param, ALfloat* value );
+typedef void (AL_APIENTRY *LPALGETBUFFER3F)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+typedef void (AL_APIENTRY *LPALGETBUFFERFV)( ALuint bid, ALenum param, ALfloat* values );
+typedef void (AL_APIENTRY *LPALGETBUFFERI)( ALuint bid, ALenum param, ALint* value );
+typedef void (AL_APIENTRY *LPALGETBUFFER3I)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+typedef void (AL_APIENTRY *LPALGETBUFFERIV)( ALuint bid, ALenum param, ALint* values );
+typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)( ALfloat value );
+typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)( ALfloat value );
+typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)( ALfloat value );
+typedef void (AL_APIENTRY *LPALDISTANCEMODEL)( ALenum distanceModel );
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export off
+#endif
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif
+
+#endif /* AL_AL_H */
--- /dev/null
+#ifndef AL_ALC_H
+#define AL_ALC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(AL_LIBTYPE_STATIC)
+ #define ALC_API
+#elif defined(_WIN32) && !defined(_XBOX)
+ #if defined(AL_BUILD_LIBRARY)
+ #define ALC_API __declspec(dllexport)
+ #else
+ #define ALC_API __declspec(dllimport)
+ #endif
+#else
+ #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY)
+ #define ALC_API __attribute__((visibility("protected")))
+ #else
+ #define ALC_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define ALC_APIENTRY __cdecl
+#else
+ #define ALC_APIENTRY
+#endif
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export on
+#endif
+
+/*
+ * The ALCAPI, ALCAPIENTRY, and ALC_INVALID macros are deprecated, but are
+ * included for applications porting code from AL 1.0
+ */
+#define ALCAPI ALC_API
+#define ALCAPIENTRY ALC_APIENTRY
+#define ALC_INVALID 0
+
+
+#define ALC_VERSION_0_1 1
+
+typedef struct ALCdevice_struct ALCdevice;
+typedef struct ALCcontext_struct ALCcontext;
+
+
+/** 8-bit boolean */
+typedef char ALCboolean;
+
+/** character */
+typedef char ALCchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALCbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALCubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALCshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALCushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALCint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALCuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALCsizei;
+
+/** enumerated 32-bit value */
+typedef int ALCenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALCfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALCdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALCvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/* Boolean False. */
+#define ALC_FALSE 0
+
+/* Boolean True. */
+#define ALC_TRUE 1
+
+/**
+ * followed by <int> Hz
+ */
+#define ALC_FREQUENCY 0x1007
+
+/**
+ * followed by <int> Hz
+ */
+#define ALC_REFRESH 0x1008
+
+/**
+ * followed by AL_TRUE, AL_FALSE
+ */
+#define ALC_SYNC 0x1009
+
+/**
+ * followed by <int> Num of requested Mono (3D) Sources
+ */
+#define ALC_MONO_SOURCES 0x1010
+
+/**
+ * followed by <int> Num of requested Stereo Sources
+ */
+#define ALC_STEREO_SOURCES 0x1011
+
+/**
+ * errors
+ */
+
+/**
+ * No error
+ */
+#define ALC_NO_ERROR ALC_FALSE
+
+/**
+ * No device
+ */
+#define ALC_INVALID_DEVICE 0xA001
+
+/**
+ * invalid context ID
+ */
+#define ALC_INVALID_CONTEXT 0xA002
+
+/**
+ * bad enum
+ */
+#define ALC_INVALID_ENUM 0xA003
+
+/**
+ * bad value
+ */
+#define ALC_INVALID_VALUE 0xA004
+
+/**
+ * Out of memory.
+ */
+#define ALC_OUT_OF_MEMORY 0xA005
+
+
+/**
+ * The Specifier string for default device
+ */
+#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004
+#define ALC_DEVICE_SPECIFIER 0x1005
+#define ALC_EXTENSIONS 0x1006
+
+#define ALC_MAJOR_VERSION 0x1000
+#define ALC_MINOR_VERSION 0x1001
+
+#define ALC_ATTRIBUTES_SIZE 0x1002
+#define ALC_ALL_ATTRIBUTES 0x1003
+
+
+/**
+ * Capture extension
+ */
+#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310
+#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311
+#define ALC_CAPTURE_SAMPLES 0x312
+
+
+/*
+ * Context Management
+ */
+ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist );
+
+ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context );
+
+ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context );
+
+ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context );
+
+ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context );
+
+ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void );
+
+ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context );
+
+
+/*
+ * Device Management
+ */
+ALC_API ALCdevice * ALC_APIENTRY alcOpenDevice( const ALCchar *devicename );
+
+ALC_API ALCboolean ALC_APIENTRY alcCloseDevice( ALCdevice *device );
+
+
+/*
+ * Error support.
+ * Obtain the most recent Context error
+ */
+ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device );
+
+
+/*
+ * Extension support.
+ * Query for the presence of an extension, and obtain any appropriate
+ * function pointers and enum values.
+ */
+ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname );
+
+ALC_API void * ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname );
+
+ALC_API ALCenum ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname );
+
+
+/*
+ * Query functions
+ */
+ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param );
+
+ALC_API void ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data );
+
+
+/*
+ * Capture functions
+ */
+ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
+
+ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device );
+
+ALC_API void ALC_APIENTRY alcCaptureStart( ALCdevice *device );
+
+ALC_API void ALC_APIENTRY alcCaptureStop( ALCdevice *device );
+
+ALC_API void ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
+
+/*
+ * Pointer-to-function types, useful for dynamically getting ALC entry points.
+ */
+typedef ALCcontext * (ALC_APIENTRY *LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist);
+typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)( ALCcontext *context );
+typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)( ALCcontext *context );
+typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)( ALCcontext *context );
+typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)( ALCcontext *context );
+typedef ALCcontext * (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)( void );
+typedef ALCdevice * (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)( ALCcontext *context );
+typedef ALCdevice * (ALC_APIENTRY *LPALCOPENDEVICE)( const ALCchar *devicename );
+typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)( ALCdevice *device );
+typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)( ALCdevice *device );
+typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)( ALCdevice *device, const ALCchar *extname );
+typedef void * (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname );
+typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname );
+typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)( ALCdevice *device, ALCenum param );
+typedef void (ALC_APIENTRY *LPALCGETINTEGERV)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest );
+typedef ALCdevice * (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
+typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)( ALCdevice *device );
+typedef void (ALC_APIENTRY *LPALCCAPTURESTART)( ALCdevice *device );
+typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)( ALCdevice *device );
+typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export off
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* AL_ALC_H */
--- /dev/null
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2008 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef AL_ALEXT_H
+#define AL_ALEXT_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef AL_LOKI_IMA_ADPCM_format
+#define AL_LOKI_IMA_ADPCM_format 1
+#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000
+#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001
+#endif
+
+#ifndef AL_LOKI_WAVE_format
+#define AL_LOKI_WAVE_format 1
+#define AL_FORMAT_WAVE_EXT 0x10002
+#endif
+
+#ifndef AL_EXT_vorbis
+#define AL_EXT_vorbis 1
+#define AL_FORMAT_VORBIS_EXT 0x10003
+#endif
+
+#ifndef AL_LOKI_quadriphonic
+#define AL_LOKI_quadriphonic 1
+#define AL_FORMAT_QUAD8_LOKI 0x10004
+#define AL_FORMAT_QUAD16_LOKI 0x10005
+#endif
+
+#ifndef AL_EXT_float32
+#define AL_EXT_float32 1
+#define AL_FORMAT_MONO_FLOAT32 0x10010
+#define AL_FORMAT_STEREO_FLOAT32 0x10011
+#endif
+
+#ifndef AL_EXT_double
+#define AL_EXT_double 1
+#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012
+#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013
+#endif
+
+#ifndef ALC_LOKI_audio_channel
+#define ALC_LOKI_audio_channel 1
+#define ALC_CHAN_MAIN_LOKI 0x500001
+#define ALC_CHAN_PCM_LOKI 0x500002
+#define ALC_CHAN_CD_LOKI 0x500003
+#endif
+
+#ifndef ALC_ENUMERATE_ALL_EXT
+#define ALC_ENUMERATE_ALL_EXT 1
+#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
+#define ALC_ALL_DEVICES_SPECIFIER 0x1013
+#endif
+
+#ifndef AL_EXT_MCFORMATS
+#define AL_EXT_MCFORMATS 1
+#define AL_FORMAT_QUAD8 0x1204
+#define AL_FORMAT_QUAD16 0x1205
+#define AL_FORMAT_QUAD32 0x1206
+#define AL_FORMAT_REAR8 0x1207
+#define AL_FORMAT_REAR16 0x1208
+#define AL_FORMAT_REAR32 0x1209
+#define AL_FORMAT_51CHN8 0x120A
+#define AL_FORMAT_51CHN16 0x120B
+#define AL_FORMAT_51CHN32 0x120C
+#define AL_FORMAT_61CHN8 0x120D
+#define AL_FORMAT_61CHN16 0x120E
+#define AL_FORMAT_61CHN32 0x120F
+#define AL_FORMAT_71CHN8 0x1210
+#define AL_FORMAT_71CHN16 0x1211
+#define AL_FORMAT_71CHN32 0x1212
+#endif
+
+#ifndef AL_EXT_MULAW_MCFORMATS
+#define AL_EXT_MULAW_MCFORMATS 1
+#define AL_FORMAT_MONO_MULAW 0x10014
+#define AL_FORMAT_STEREO_MULAW 0x10015
+#define AL_FORMAT_QUAD_MULAW 0x10021
+#define AL_FORMAT_REAR_MULAW 0x10022
+#define AL_FORMAT_51CHN_MULAW 0x10023
+#define AL_FORMAT_61CHN_MULAW 0x10024
+#define AL_FORMAT_71CHN_MULAW 0x10025
+#endif
+
+#ifndef AL_EXT_IMA4
+#define AL_EXT_IMA4 1
+#define AL_FORMAT_MONO_IMA4 0x1300
+#define AL_FORMAT_STEREO_IMA4 0x1301
+#endif
+
+#ifndef AL_EXT_STATIC_BUFFER
+#define AL_EXT_STATIC_BUFFER 1
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq);
+#endif
+#endif
+
+#ifndef ALC_EXT_EFX
+#define ALC_EXT_EFX 1
+#include "efx.h"
+#endif
+
+#ifndef ALC_EXT_disconnect
+#define ALC_EXT_disconnect 1
+#define ALC_CONNECTED 0x313
+#endif
+
+#ifndef ALC_EXT_thread_local_context
+#define ALC_EXT_thread_local_context 1
+typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context);
+typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context);
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void);
+#endif
+#endif
+
+#ifndef AL_EXT_source_distance_model
+#define AL_EXT_source_distance_model 1
+#define AL_SOURCE_DISTANCE_MODEL 0x200
+#endif
+
+#ifndef AL_SOFT_buffer_sub_data
+#define AL_SOFT_buffer_sub_data 1
+#define AL_BYTE_RW_OFFSETS_SOFT 0x1031
+#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
+#endif
+#endif
+
+#ifndef AL_SOFT_loop_points
+#define AL_SOFT_loop_points 1
+#define AL_LOOP_POINTS_SOFT 0x2015
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* The tokens that would be defined here are already defined in efx.h. This
+ * empty file is here to provide compatibility with Windows-based projects
+ * that would include it. */
--- /dev/null
+#ifndef AL_EFX_H
+#define AL_EFX_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ALC_EXT_EFX_NAME "ALC_EXT_EFX"
+
+#define ALC_EFX_MAJOR_VERSION 0x20001
+#define ALC_EFX_MINOR_VERSION 0x20002
+#define ALC_MAX_AUXILIARY_SENDS 0x20003
+
+
+/* Listener properties. */
+#define AL_METERS_PER_UNIT 0x20004
+
+/* Source properties. */
+#define AL_DIRECT_FILTER 0x20005
+#define AL_AUXILIARY_SEND_FILTER 0x20006
+#define AL_AIR_ABSORPTION_FACTOR 0x20007
+#define AL_ROOM_ROLLOFF_FACTOR 0x20008
+#define AL_CONE_OUTER_GAINHF 0x20009
+#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A
+#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B
+#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C
+
+
+/* Effect properties. */
+
+/* Reverb effect parameters */
+#define AL_REVERB_DENSITY 0x0001
+#define AL_REVERB_DIFFUSION 0x0002
+#define AL_REVERB_GAIN 0x0003
+#define AL_REVERB_GAINHF 0x0004
+#define AL_REVERB_DECAY_TIME 0x0005
+#define AL_REVERB_DECAY_HFRATIO 0x0006
+#define AL_REVERB_REFLECTIONS_GAIN 0x0007
+#define AL_REVERB_REFLECTIONS_DELAY 0x0008
+#define AL_REVERB_LATE_REVERB_GAIN 0x0009
+#define AL_REVERB_LATE_REVERB_DELAY 0x000A
+#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B
+#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C
+#define AL_REVERB_DECAY_HFLIMIT 0x000D
+
+/* EAX Reverb effect parameters */
+#define AL_EAXREVERB_DENSITY 0x0001
+#define AL_EAXREVERB_DIFFUSION 0x0002
+#define AL_EAXREVERB_GAIN 0x0003
+#define AL_EAXREVERB_GAINHF 0x0004
+#define AL_EAXREVERB_GAINLF 0x0005
+#define AL_EAXREVERB_DECAY_TIME 0x0006
+#define AL_EAXREVERB_DECAY_HFRATIO 0x0007
+#define AL_EAXREVERB_DECAY_LFRATIO 0x0008
+#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009
+#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A
+#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B
+#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C
+#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D
+#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E
+#define AL_EAXREVERB_ECHO_TIME 0x000F
+#define AL_EAXREVERB_ECHO_DEPTH 0x0010
+#define AL_EAXREVERB_MODULATION_TIME 0x0011
+#define AL_EAXREVERB_MODULATION_DEPTH 0x0012
+#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013
+#define AL_EAXREVERB_HFREFERENCE 0x0014
+#define AL_EAXREVERB_LFREFERENCE 0x0015
+#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
+#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
+
+/* Chorus effect parameters */
+#define AL_CHORUS_WAVEFORM 0x0001
+#define AL_CHORUS_PHASE 0x0002
+#define AL_CHORUS_RATE 0x0003
+#define AL_CHORUS_DEPTH 0x0004
+#define AL_CHORUS_FEEDBACK 0x0005
+#define AL_CHORUS_DELAY 0x0006
+
+/* Distortion effect parameters */
+#define AL_DISTORTION_EDGE 0x0001
+#define AL_DISTORTION_GAIN 0x0002
+#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003
+#define AL_DISTORTION_EQCENTER 0x0004
+#define AL_DISTORTION_EQBANDWIDTH 0x0005
+
+/* Echo effect parameters */
+#define AL_ECHO_DELAY 0x0001
+#define AL_ECHO_LRDELAY 0x0002
+#define AL_ECHO_DAMPING 0x0003
+#define AL_ECHO_FEEDBACK 0x0004
+#define AL_ECHO_SPREAD 0x0005
+
+/* Flanger effect parameters */
+#define AL_FLANGER_WAVEFORM 0x0001
+#define AL_FLANGER_PHASE 0x0002
+#define AL_FLANGER_RATE 0x0003
+#define AL_FLANGER_DEPTH 0x0004
+#define AL_FLANGER_FEEDBACK 0x0005
+#define AL_FLANGER_DELAY 0x0006
+
+/* Frequency shifter effect parameters */
+#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001
+#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002
+#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003
+
+/* Vocal morpher effect parameters */
+#define AL_VOCAL_MORPHER_PHONEMEA 0x0001
+#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002
+#define AL_VOCAL_MORPHER_PHONEMEB 0x0003
+#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004
+#define AL_VOCAL_MORPHER_WAVEFORM 0x0005
+#define AL_VOCAL_MORPHER_RATE 0x0006
+
+/* Pitchshifter effect parameters */
+#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001
+#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002
+
+/* Ringmodulator effect parameters */
+#define AL_RING_MODULATOR_FREQUENCY 0x0001
+#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002
+#define AL_RING_MODULATOR_WAVEFORM 0x0003
+
+/* Autowah effect parameters */
+#define AL_AUTOWAH_ATTACK_TIME 0x0001
+#define AL_AUTOWAH_RELEASE_TIME 0x0002
+#define AL_AUTOWAH_RESONANCE 0x0003
+#define AL_AUTOWAH_PEAK_GAIN 0x0004
+
+/* Compressor effect parameters */
+#define AL_COMPRESSOR_ONOFF 0x0001
+
+/* Equalizer effect parameters */
+#define AL_EQUALIZER_LOW_GAIN 0x0001
+#define AL_EQUALIZER_LOW_CUTOFF 0x0002
+#define AL_EQUALIZER_MID1_GAIN 0x0003
+#define AL_EQUALIZER_MID1_CENTER 0x0004
+#define AL_EQUALIZER_MID1_WIDTH 0x0005
+#define AL_EQUALIZER_MID2_GAIN 0x0006
+#define AL_EQUALIZER_MID2_CENTER 0x0007
+#define AL_EQUALIZER_MID2_WIDTH 0x0008
+#define AL_EQUALIZER_HIGH_GAIN 0x0009
+#define AL_EQUALIZER_HIGH_CUTOFF 0x000A
+
+/* Effect type */
+#define AL_EFFECT_FIRST_PARAMETER 0x0000
+#define AL_EFFECT_LAST_PARAMETER 0x8000
+#define AL_EFFECT_TYPE 0x8001
+
+/* Effect types, used with the AL_EFFECT_TYPE property */
+#define AL_EFFECT_NULL 0x0000
+#define AL_EFFECT_REVERB 0x0001
+#define AL_EFFECT_CHORUS 0x0002
+#define AL_EFFECT_DISTORTION 0x0003
+#define AL_EFFECT_ECHO 0x0004
+#define AL_EFFECT_FLANGER 0x0005
+#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
+#define AL_EFFECT_VOCAL_MORPHER 0x0007
+#define AL_EFFECT_PITCH_SHIFTER 0x0008
+#define AL_EFFECT_RING_MODULATOR 0x0009
+#define AL_EFFECT_AUTOWAH 0x000A
+#define AL_EFFECT_COMPRESSOR 0x000B
+#define AL_EFFECT_EQUALIZER 0x000C
+#define AL_EFFECT_EAXREVERB 0x8000
+
+/* Auxiliary Effect Slot properties. */
+#define AL_EFFECTSLOT_EFFECT 0x0001
+#define AL_EFFECTSLOT_GAIN 0x0002
+#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003
+
+/* NULL Auxiliary Slot ID to disable a source send. */
+#define AL_EFFECTSLOT_NULL 0x0000
+
+
+/* Filter properties. */
+
+/* Lowpass filter parameters */
+#define AL_LOWPASS_GAIN 0x0001
+#define AL_LOWPASS_GAINHF 0x0002
+
+/* Highpass filter parameters */
+#define AL_HIGHPASS_GAIN 0x0001
+#define AL_HIGHPASS_GAINLF 0x0002
+
+/* Bandpass filter parameters */
+#define AL_BANDPASS_GAIN 0x0001
+#define AL_BANDPASS_GAINLF 0x0002
+#define AL_BANDPASS_GAINHF 0x0003
+
+/* Filter type */
+#define AL_FILTER_FIRST_PARAMETER 0x0000
+#define AL_FILTER_LAST_PARAMETER 0x8000
+#define AL_FILTER_TYPE 0x8001
+
+/* Filter types, used with the AL_FILTER_TYPE property */
+#define AL_FILTER_NULL 0x0000
+#define AL_FILTER_LOWPASS 0x0001
+#define AL_FILTER_HIGHPASS 0x0002
+#define AL_FILTER_BANDPASS 0x0003
+
+
+/* Effect object function types. */
+typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint);
+typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*);
+
+/* Filter object function types. */
+typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint);
+typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*);
+
+/* Auxiliary Effect Slot object function types. */
+typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
+
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
+AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
+AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
+AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
+AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
+AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
+AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
+AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
+AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
+#endif
+
+/* Filter ranges and defaults. */
+
+/* Lowpass filter */
+#define LOWPASS_MIN_GAIN (0.0f)
+#define LOWPASS_MAX_GAIN (1.0f)
+#define LOWPASS_DEFAULT_GAIN (1.0f)
+
+#define LOWPASS_MIN_GAINHF (0.0f)
+#define LOWPASS_MAX_GAINHF (1.0f)
+#define LOWPASS_DEFAULT_GAINHF (1.0f)
+
+/* Highpass filter */
+#define HIGHPASS_MIN_GAIN (0.0f)
+#define HIGHPASS_MAX_GAIN (1.0f)
+#define HIGHPASS_DEFAULT_GAIN (1.0f)
+
+#define HIGHPASS_MIN_GAINLF (0.0f)
+#define HIGHPASS_MAX_GAINLF (1.0f)
+#define HIGHPASS_DEFAULT_GAINLF (1.0f)
+
+/* Bandpass filter */
+#define BANDPASS_MIN_GAIN (0.0f)
+#define BANDPASS_MAX_GAIN (1.0f)
+#define BANDPASS_DEFAULT_GAIN (1.0f)
+
+#define BANDPASS_MIN_GAINHF (0.0f)
+#define BANDPASS_MAX_GAINHF (1.0f)
+#define BANDPASS_DEFAULT_GAINHF (1.0f)
+
+#define BANDPASS_MIN_GAINLF (0.0f)
+#define BANDPASS_MAX_GAINLF (1.0f)
+#define BANDPASS_DEFAULT_GAINLF (1.0f)
+
+
+/* Effect parameter ranges and defaults. */
+
+/* Standard reverb effect */
+#define AL_REVERB_MIN_DENSITY (0.0f)
+#define AL_REVERB_MAX_DENSITY (1.0f)
+#define AL_REVERB_DEFAULT_DENSITY (1.0f)
+
+#define AL_REVERB_MIN_DIFFUSION (0.0f)
+#define AL_REVERB_MAX_DIFFUSION (1.0f)
+#define AL_REVERB_DEFAULT_DIFFUSION (1.0f)
+
+#define AL_REVERB_MIN_GAIN (0.0f)
+#define AL_REVERB_MAX_GAIN (1.0f)
+#define AL_REVERB_DEFAULT_GAIN (0.32f)
+
+#define AL_REVERB_MIN_GAINHF (0.0f)
+#define AL_REVERB_MAX_GAINHF (1.0f)
+#define AL_REVERB_DEFAULT_GAINHF (0.89f)
+
+#define AL_REVERB_MIN_DECAY_TIME (0.1f)
+#define AL_REVERB_MAX_DECAY_TIME (20.0f)
+#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f)
+
+#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f)
+#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f)
+#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f)
+
+#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
+
+#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
+
+#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
+
+#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
+
+#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
+#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
+#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
+
+#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE
+#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE
+#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
+
+/* EAX reverb effect */
+#define AL_EAXREVERB_MIN_DENSITY (0.0f)
+#define AL_EAXREVERB_MAX_DENSITY (1.0f)
+#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f)
+
+#define AL_EAXREVERB_MIN_DIFFUSION (0.0f)
+#define AL_EAXREVERB_MAX_DIFFUSION (1.0f)
+#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f)
+
+#define AL_EAXREVERB_MIN_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_GAIN (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAIN (0.32f)
+
+#define AL_EAXREVERB_MIN_GAINHF (0.0f)
+#define AL_EAXREVERB_MAX_GAINHF (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f)
+
+#define AL_EAXREVERB_MIN_GAINLF (0.0f)
+#define AL_EAXREVERB_MAX_GAINLF (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f)
+
+#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f)
+
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f)
+
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f)
+#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f)
+#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f)
+
+#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f)
+#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f)
+#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f)
+
+#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f)
+#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f)
+
+#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f)
+#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f)
+
+#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f)
+#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f)
+#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
+
+#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f)
+#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f)
+#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f)
+
+#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f)
+#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f)
+#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f)
+
+#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE
+#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE
+#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE
+
+/* Chorus effect */
+#define AL_CHORUS_WAVEFORM_SINUSOID (0)
+#define AL_CHORUS_WAVEFORM_TRIANGLE (1)
+
+#define AL_CHORUS_MIN_WAVEFORM (0)
+#define AL_CHORUS_MAX_WAVEFORM (1)
+#define AL_CHORUS_DEFAULT_WAVEFORM (1)
+
+#define AL_CHORUS_MIN_PHASE (-180)
+#define AL_CHORUS_MAX_PHASE (180)
+#define AL_CHORUS_DEFAULT_PHASE (90)
+
+#define AL_CHORUS_MIN_RATE (0.0f)
+#define AL_CHORUS_MAX_RATE (10.0f)
+#define AL_CHORUS_DEFAULT_RATE (1.1f)
+
+#define AL_CHORUS_MIN_DEPTH (0.0f)
+#define AL_CHORUS_MAX_DEPTH (1.0f)
+#define AL_CHORUS_DEFAULT_DEPTH (0.1f)
+
+#define AL_CHORUS_MIN_FEEDBACK (-1.0f)
+#define AL_CHORUS_MAX_FEEDBACK (1.0f)
+#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f)
+
+#define AL_CHORUS_MIN_DELAY (0.0f)
+#define AL_CHORUS_MAX_DELAY (0.016f)
+#define AL_CHORUS_DEFAULT_DELAY (0.016f)
+
+/* Distortion effect */
+#define AL_DISTORTION_MIN_EDGE (0.0f)
+#define AL_DISTORTION_MAX_EDGE (1.0f)
+#define AL_DISTORTION_DEFAULT_EDGE (0.2f)
+
+#define AL_DISTORTION_MIN_GAIN (0.01f)
+#define AL_DISTORTION_MAX_GAIN (1.0f)
+#define AL_DISTORTION_DEFAULT_GAIN (0.05f)
+
+#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f)
+#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f)
+#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f)
+
+#define AL_DISTORTION_MIN_EQCENTER (80.0f)
+#define AL_DISTORTION_MAX_EQCENTER (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f)
+
+#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f)
+#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f)
+
+/* Echo effect */
+#define AL_ECHO_MIN_DELAY (0.0f)
+#define AL_ECHO_MAX_DELAY (0.207f)
+#define AL_ECHO_DEFAULT_DELAY (0.1f)
+
+#define AL_ECHO_MIN_LRDELAY (0.0f)
+#define AL_ECHO_MAX_LRDELAY (0.404f)
+#define AL_ECHO_DEFAULT_LRDELAY (0.1f)
+
+#define AL_ECHO_MIN_DAMPING (0.0f)
+#define AL_ECHO_MAX_DAMPING (0.99f)
+#define AL_ECHO_DEFAULT_DAMPING (0.5f)
+
+#define AL_ECHO_MIN_FEEDBACK (0.0f)
+#define AL_ECHO_MAX_FEEDBACK (1.0f)
+#define AL_ECHO_DEFAULT_FEEDBACK (0.5f)
+
+#define AL_ECHO_MIN_SPREAD (-1.0f)
+#define AL_ECHO_MAX_SPREAD (1.0f)
+#define AL_ECHO_DEFAULT_SPREAD (-1.0f)
+
+/* Flanger effect */
+#define AL_FLANGER_WAVEFORM_SINUSOID (0)
+#define AL_FLANGER_WAVEFORM_TRIANGLE (1)
+
+#define AL_FLANGER_MIN_WAVEFORM (0)
+#define AL_FLANGER_MAX_WAVEFORM (1)
+#define AL_FLANGER_DEFAULT_WAVEFORM (1)
+
+#define AL_FLANGER_MIN_PHASE (-180)
+#define AL_FLANGER_MAX_PHASE (180)
+#define AL_FLANGER_DEFAULT_PHASE (0)
+
+#define AL_FLANGER_MIN_RATE (0.0f)
+#define AL_FLANGER_MAX_RATE (10.0f)
+#define AL_FLANGER_DEFAULT_RATE (0.27f)
+
+#define AL_FLANGER_MIN_DEPTH (0.0f)
+#define AL_FLANGER_MAX_DEPTH (1.0f)
+#define AL_FLANGER_DEFAULT_DEPTH (1.0f)
+
+#define AL_FLANGER_MIN_FEEDBACK (-1.0f)
+#define AL_FLANGER_MAX_FEEDBACK (1.0f)
+#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f)
+
+#define AL_FLANGER_MIN_DELAY (0.0f)
+#define AL_FLANGER_MAX_DELAY (0.004f)
+#define AL_FLANGER_DEFAULT_DELAY (0.002f)
+
+/* Frequency shifter effect */
+#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f)
+#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f)
+
+#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0)
+#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0)
+
+#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2)
+
+#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0)
+#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0)
+
+/* Vocal morpher effect */
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_PHONEME_A (0)
+#define AL_VOCAL_MORPHER_PHONEME_E (1)
+#define AL_VOCAL_MORPHER_PHONEME_I (2)
+#define AL_VOCAL_MORPHER_PHONEME_O (3)
+#define AL_VOCAL_MORPHER_PHONEME_U (4)
+#define AL_VOCAL_MORPHER_PHONEME_AA (5)
+#define AL_VOCAL_MORPHER_PHONEME_AE (6)
+#define AL_VOCAL_MORPHER_PHONEME_AH (7)
+#define AL_VOCAL_MORPHER_PHONEME_AO (8)
+#define AL_VOCAL_MORPHER_PHONEME_EH (9)
+#define AL_VOCAL_MORPHER_PHONEME_ER (10)
+#define AL_VOCAL_MORPHER_PHONEME_IH (11)
+#define AL_VOCAL_MORPHER_PHONEME_IY (12)
+#define AL_VOCAL_MORPHER_PHONEME_UH (13)
+#define AL_VOCAL_MORPHER_PHONEME_UW (14)
+#define AL_VOCAL_MORPHER_PHONEME_B (15)
+#define AL_VOCAL_MORPHER_PHONEME_D (16)
+#define AL_VOCAL_MORPHER_PHONEME_F (17)
+#define AL_VOCAL_MORPHER_PHONEME_G (18)
+#define AL_VOCAL_MORPHER_PHONEME_J (19)
+#define AL_VOCAL_MORPHER_PHONEME_K (20)
+#define AL_VOCAL_MORPHER_PHONEME_L (21)
+#define AL_VOCAL_MORPHER_PHONEME_M (22)
+#define AL_VOCAL_MORPHER_PHONEME_N (23)
+#define AL_VOCAL_MORPHER_PHONEME_P (24)
+#define AL_VOCAL_MORPHER_PHONEME_R (25)
+#define AL_VOCAL_MORPHER_PHONEME_S (26)
+#define AL_VOCAL_MORPHER_PHONEME_T (27)
+#define AL_VOCAL_MORPHER_PHONEME_V (28)
+#define AL_VOCAL_MORPHER_PHONEME_Z (29)
+
+#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0)
+#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1)
+#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2)
+
+#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0)
+#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2)
+#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0)
+
+#define AL_VOCAL_MORPHER_MIN_RATE (0.0f)
+#define AL_VOCAL_MORPHER_MAX_RATE (10.0f)
+#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f)
+
+/* Pitch shifter effect */
+#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12)
+#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12)
+#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12)
+
+#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50)
+#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50)
+#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0)
+
+/* Ring modulator effect */
+#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f)
+#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f)
+#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f)
+
+#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f)
+#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f)
+#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f)
+
+#define AL_RING_MODULATOR_SINUSOID (0)
+#define AL_RING_MODULATOR_SAWTOOTH (1)
+#define AL_RING_MODULATOR_SQUARE (2)
+
+#define AL_RING_MODULATOR_MIN_WAVEFORM (0)
+#define AL_RING_MODULATOR_MAX_WAVEFORM (2)
+#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0)
+
+/* Autowah effect */
+#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f)
+#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f)
+#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f)
+
+#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f)
+#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f)
+#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f)
+
+#define AL_AUTOWAH_MIN_RESONANCE (2.0f)
+#define AL_AUTOWAH_MAX_RESONANCE (1000.0f)
+#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f)
+
+#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f)
+#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f)
+#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f)
+
+/* Compressor effect */
+#define AL_COMPRESSOR_MIN_ONOFF (0)
+#define AL_COMPRESSOR_MAX_ONOFF (1)
+#define AL_COMPRESSOR_DEFAULT_ONOFF (1)
+
+/* Equalizer effect */
+#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f)
+#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f)
+#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f)
+
+#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f)
+#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f)
+
+#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f)
+#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f)
+#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f)
+
+#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f)
+#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f)
+#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f)
+#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f)
+#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f)
+#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f)
+
+
+/* Source parameter value ranges and defaults. */
+#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f)
+#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f)
+#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f)
+
+#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f)
+#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f)
+#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_MIN_CONE_OUTER_GAINHF (0.0f)
+#define AL_MAX_CONE_OUTER_GAINHF (1.0f)
+#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f)
+
+#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE
+#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
+#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+
+
+/* Listener parameter value ranges and defaults. */
+#define AL_MIN_METERS_PER_UNIT FLT_MIN
+#define AL_MAX_METERS_PER_UNIT FLT_MAX
+#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* AL_EFX_H */
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: OpenAL
+Description: OpenAL is a cross-platform 3D audio API
+Requires: @PKG_CONFIG_REQUIRES@
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -l@LIBNAME@ @PKG_CONFIG_LIBS@
+Cflags: -I${includedir} @PKG_CONFIG_CFLAGS@
--- /dev/null
+Name: openal-soft
+Summary: OpenAL library software implementation
+Version: 1.13
+Release: 6
+Group: Multimedia/openal-soft
+License: LGPLv2+
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: cmake
+BuildRequires: pkgconfig(avsysaudio)
+BuildRequires: pkgconfig(mm-session)
+BuildRequires: pkgconfig(audio-session-mgr)
+BuildRequires: pkgconfig(vconf)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+
+%description
+OpenAL library software implementation
+
+
+
+%package devel
+Summary: OpenAL library software implementation (devel)
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+OpenAL library software implementation development package
+
+
+%prep
+%setup -q
+
+%build
+
+%ifarch %arm
+export CFLAGS+=" -DARM_ARCH -O3 -ftree-vectorize -ffast-math -fsingle-precision-constant -DUSE_DLOG "
+%else
+export CFLAGS+=" -DI386_ARCH "
+%endif
+
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+
+
+%files
+%manifest openal-soft.manifest
+%{_libdir}/*.so*
+%{_bindir}/*
+/etc/openal/alsoft.conf
+
+%files devel
+%{_includedir}/*
+%{_libdir}/pkgconfig/*
+
--- /dev/null
+/*
+ * OpenAL Info Utility
+ *
+ * Copyright (c) 2010 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.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "AL/alext.h"
+
+#ifndef ALC_ENUMERATE_ALL_EXT
+#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
+#define ALC_ALL_DEVICES_SPECIFIER 0x1013
+#endif
+
+#ifndef ALC_EXT_EFX
+#define ALC_EFX_MAJOR_VERSION 0x20001
+#define ALC_EFX_MINOR_VERSION 0x20002
+#define ALC_MAX_AUXILIARY_SENDS 0x20003
+#define AL_FILTER_TYPE 0x8001
+#define AL_FILTER_NULL 0x0000
+#define AL_FILTER_LOWPASS 0x0001
+#define AL_FILTER_HIGHPASS 0x0002
+#define AL_FILTER_BANDPASS 0x0003
+#define AL_EFFECT_TYPE 0x8001
+#define AL_EFFECT_NULL 0x0000
+#define AL_EFFECT_EAXREVERB 0x8000
+#define AL_EFFECT_REVERB 0x0001
+#define AL_EFFECT_CHORUS 0x0002
+#define AL_EFFECT_DISTORTION 0x0003
+#define AL_EFFECT_ECHO 0x0004
+#define AL_EFFECT_FLANGER 0x0005
+#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
+#define AL_EFFECT_VOCAL_MORPHER 0x0007
+#define AL_EFFECT_PITCH_SHIFTER 0x0008
+#define AL_EFFECT_RING_MODULATOR 0x0009
+#define AL_EFFECT_AUTOWAH 0x000A
+#define AL_EFFECT_COMPRESSOR 0x000B
+#define AL_EFFECT_EQUALIZER 0x000C
+typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
+#endif
+static LPALGENFILTERS palGenFilters;
+static LPALDELETEFILTERS palDeleteFilters;
+static LPALFILTERI palFilteri;
+static LPALGENEFFECTS palGenEffects;
+static LPALDELETEEFFECTS palDeleteEffects;
+static LPALEFFECTI palEffecti;
+
+
+#define MAX_WIDTH 80
+
+static void printList(const char *list, char separator)
+{
+ size_t col = MAX_WIDTH, len;
+ const char *indent = " ";
+ const char *next;
+
+ if(!list || *list == '\0')
+ {
+ fprintf(stdout, "\n%s!!! none !!!\n", indent);
+ return;
+ }
+
+ do {
+ next = strchr(list, separator);
+ if(next)
+ {
+ len = next-list;
+ do {
+ next++;
+ } while(*next == separator);
+ }
+ else
+ len = strlen(list);
+
+ if(len + col + 2 >= MAX_WIDTH)
+ {
+ fprintf(stdout, "\n%s", indent);
+ col = strlen(indent);
+ }
+ else
+ {
+ fputc(' ', stdout);
+ col++;
+ }
+
+ len = fwrite(list, 1, len, stdout);
+ col += len;
+
+ if(!next || *next == '\0')
+ break;
+ fputc(',', stdout);
+ col++;
+
+ list = next;
+ } while(1);
+ fputc('\n', stdout);
+}
+
+static void printDeviceList(const char *list)
+{
+ if(!list || *list == '\0')
+ printf(" !!! none !!!\n");
+ else do {
+ printf(" %s\n", list);
+ list += strlen(list) + 1;
+ } while(*list != '\0');
+}
+
+
+static ALenum checkALErrors(int linenum)
+{
+ ALenum err = alGetError();
+ if(err != AL_NO_ERROR)
+ printf("OpenAL Error: %s (0x%x), @ %d\n", alGetString(err), err, linenum);
+ return err;
+}
+#define checkALErrors() checkALErrors(__LINE__)
+
+static ALCenum checkALCErrors(ALCdevice *device, int linenum)
+{
+ ALCenum err = alcGetError(device);
+ if(err != ALC_NO_ERROR)
+ printf("ALC Error: %s (0x%x), @ %d\n", alcGetString(device, err), err, linenum);
+ return err;
+}
+#define checkALCErrors(x) checkALCErrors((x),__LINE__)
+
+
+static void printALCInfo(ALCdevice *device)
+{
+ ALCint major, minor;
+
+ alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
+ alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
+ if(checkALCErrors(device) == ALC_NO_ERROR)
+ printf("ALC version: %d.%d\n", major, minor);
+ if(device)
+ {
+ printf("ALC extensions:");
+ printList(alcGetString(device, ALC_EXTENSIONS), ' ');
+ checkALCErrors(device);
+ }
+}
+
+static void printALInfo(void)
+{
+ printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR));
+ printf("OpenAL renderer string: %s\n", alGetString(AL_RENDERER));
+ printf("OpenAL version string: %s\n", alGetString(AL_VERSION));
+ printf("OpenAL extensions:");
+ printList(alGetString(AL_EXTENSIONS), ' ');
+ checkALErrors();
+}
+
+static void printEFXInfo(ALCdevice *device)
+{
+ ALCint major, minor, sends;
+ ALuint obj;
+ int i;
+ const ALenum filters[] = {
+ AL_FILTER_LOWPASS, AL_FILTER_HIGHPASS, AL_FILTER_BANDPASS,
+ AL_FILTER_NULL
+ };
+ char filterNames[] = "Low-pass,High-pass,Band-pass,";
+ const ALenum effects[] = {
+ AL_EFFECT_EAXREVERB, AL_EFFECT_REVERB, AL_EFFECT_CHORUS,
+ AL_EFFECT_DISTORTION, AL_EFFECT_ECHO, AL_EFFECT_FLANGER,
+ AL_EFFECT_FREQUENCY_SHIFTER, AL_EFFECT_VOCAL_MORPHER,
+ AL_EFFECT_PITCH_SHIFTER, AL_EFFECT_RING_MODULATOR, AL_EFFECT_AUTOWAH,
+ AL_EFFECT_COMPRESSOR, AL_EFFECT_EQUALIZER, AL_EFFECT_NULL
+ };
+ char effectNames[] = "EAX Reverb,Reverb,Chorus,Distortion,Echo,Flanger,"
+ "Frequency Shifter,Vocal Morpher,Pitch Shifter,"
+ "Ring Modulator,Autowah,Compressor,Equalizer,";
+ char *current;
+
+ if(alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_FALSE)
+ {
+ printf("EFX not available\n");
+ return;
+ }
+
+ alcGetIntegerv(device, ALC_EFX_MAJOR_VERSION, 1, &major);
+ alcGetIntegerv(device, ALC_EFX_MINOR_VERSION, 1, &minor);
+ if(checkALCErrors(device) == ALC_NO_ERROR)
+ printf("EFX version: %d.%d\n", major, minor);
+ alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
+ if(checkALCErrors(device) == ALC_NO_ERROR)
+ printf("Max auxiliary sends: %d\n", sends);
+
+ palGenFilters = alGetProcAddress("alGenFilters");
+ palDeleteFilters = alGetProcAddress("alDeleteFilters");
+ palFilteri = alGetProcAddress("alFilteri");
+ palGenEffects = alGetProcAddress("alGenEffects");
+ palDeleteEffects = alGetProcAddress("alDeleteEffects");
+ palEffecti = alGetProcAddress("alEffecti");
+ if(checkALErrors() != AL_NO_ERROR ||
+ !palGenFilters || !palDeleteFilters || !palFilteri ||
+ !palGenEffects || !palDeleteEffects || !palEffecti)
+ {
+ printf("!!! Missing EFX functions !!!\n");
+ return;
+ }
+
+ palGenFilters(1, &obj);
+ if(checkALErrors() == AL_NO_ERROR)
+ {
+ current = filterNames;
+ for(i = 0;filters[i] != AL_FILTER_NULL;i++)
+ {
+ char *next = strchr(current, ',');
+
+ palFilteri(obj, AL_FILTER_TYPE, filters[i]);
+ if(alGetError() == AL_NO_ERROR)
+ current = next+1;
+ else
+ memmove(current, next+1, strlen(next));
+ }
+ palDeleteFilters(1, &obj);
+ checkALErrors();
+
+ printf("Supported filters:");
+ printList(filterNames, ',');
+ }
+
+ palGenEffects(1, &obj);
+ if(checkALErrors() == AL_NO_ERROR)
+ {
+ current = effectNames;
+ for(i = 0;effects[i] != AL_EFFECT_NULL;i++)
+ {
+ char *next = strchr(current, ',');
+
+ palEffecti(obj, AL_EFFECT_TYPE, effects[i]);
+ if(alGetError() == AL_NO_ERROR)
+ current = next+1;
+ else
+ memmove(current, next+1, strlen(next));
+ }
+ palDeleteEffects(1, &obj);
+ checkALErrors();
+
+ printf("Supported effects:");
+ printList(effectNames, ',');
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ ALCdevice *device;
+ ALCcontext *context;
+
+ if(argc > 1 && (strcmp(argv[1], "--help") == 0 ||
+ strcmp(argv[1], "-h") == 0))
+ {
+ printf("Usage: %s [playback device]\n", argv[0]);
+ return 0;
+ }
+
+ printf("Available playback devices:\n");
+ if(alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
+ printDeviceList(alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER));
+ else
+ printDeviceList(alcGetString(NULL, ALC_DEVICE_SPECIFIER));
+ printf("Available capture devices:\n");
+ printDeviceList(alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER));
+
+ printf("Default playback device: %s\n",
+ alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));
+ printf("Default capture device: %s\n",
+ alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
+
+ printALCInfo(NULL);
+
+ device = alcOpenDevice((argc>1) ? argv[1] : NULL);
+ if(!device)
+ {
+ printf("\n!!! Failed to open %s !!!\n\n", ((argc>1) ? argv[1] : "default device"));
+ return 1;
+ }
+
+ printf("\n** Info for device \"%s\" **\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
+ printALCInfo(device);
+
+ context = alcCreateContext(device, NULL);
+ if(!context || alcMakeContextCurrent(context) == ALC_FALSE)
+ {
+ if(context)
+ alcDestroyContext(context);
+ alcCloseDevice(device);
+ printf("\n!!! Failed to set a context !!!\n\n");
+ return 1;
+ }
+
+ printALInfo();
+ printEFXInfo(device);
+
+ alcMakeContextCurrent(NULL);
+ alcDestroyContext(context);
+ alcCloseDevice(device);
+
+ return 0;
+}