diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..48ab82e
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build.properties b/build.properties
new file mode 100644
index 0000000..ee52d86
--- /dev/null
+++ b/build.properties
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..3520983
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/default.properties b/default.properties
new file mode 100644
index 0000000..e2e8061
--- /dev/null
+++ b/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100644
index 0000000..60ad9e4
--- /dev/null
+++ b/jni/Android.mk
@@ -0,0 +1,67 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+OPENAL_DIR := OpenAL
+
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := openal
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -I$(OPENAL_DIR) \
+ -I$(OPENAL_DIR)/include \
+ -I$(OPENAL_DIR)/OpenAL32/Include \
+ -DAL_BUILD_LIBRARY \
+ -DAL_ALEXT_PROTOTYPES \
+ -DANDROID \
+ -fpic \
+ -ffunction-sections \
+ -funwind-tables \
+ -fstack-protector \
+ -fno-short-enums \
+ -D__ARM_ARCH_5__ \
+ -D__ANDROID__ \
+ -march=armv5 \
+ -msoft-float \
+
+
+# -DVERDE_USE_REAL_FILE_IO \
+
+# FIXME
+LOCAL_CFLAGS += -I/Developer/AndroidNDK/platforms/android-8/arch-arm/usr/include
+
+# Default to Fixed-point math
+LOCAL_CFLAGS += -DOPENAL_FIXED_POINT -DOPENAL_FIXED_POINT_SHIFT=16
+
+LOCAL_SRC_FILES := $(OPENAL_DIR)/OpenAL32/alAuxEffectSlot.c \
+ $(OPENAL_DIR)/OpenAL32/alBuffer.c \
+ $(OPENAL_DIR)/OpenAL32/alDatabuffer.c \
+ $(OPENAL_DIR)/OpenAL32/alEffect.c \
+ $(OPENAL_DIR)/OpenAL32/alError.c \
+ $(OPENAL_DIR)/OpenAL32/alExtension.c \
+ $(OPENAL_DIR)/OpenAL32/alFilter.c \
+ $(OPENAL_DIR)/OpenAL32/alListener.c \
+ $(OPENAL_DIR)/OpenAL32/alSource.c \
+ $(OPENAL_DIR)/OpenAL32/alState.c \
+ $(OPENAL_DIR)/OpenAL32/alThunk.c \
+ $(OPENAL_DIR)/Alc/ALc.c \
+ $(OPENAL_DIR)/Alc/alcConfig.c \
+ $(OPENAL_DIR)/Alc/alcEcho.c \
+ $(OPENAL_DIR)/Alc/alcModulator.c \
+ $(OPENAL_DIR)/Alc/alcReverb.c \
+ $(OPENAL_DIR)/Alc/alcRing.c \
+ $(OPENAL_DIR)/Alc/alcThread.c \
+ $(OPENAL_DIR)/Alc/ALu.c \
+ $(OPENAL_DIR)/Alc/bs2b.c \
+ $(OPENAL_DIR)/Alc/null.c \
+ $(OPENAL_DIR)/Alc/panning.c \
+ $(OPENAL_DIR)/Alc/mixer.c \
+ $(OPENAL_DIR)/Alc/audiotrack.c \
+
+
+# If building for versions after FROYO
+#LOCAL_CFLAGS += -DPOST_FROYO
+#LOCAL_SRC_FILES += $(OPENAL_DIR)/Alc/opensles.o
+
+include $(BUILD_SHARED_LIBRARY)
+
+
diff --git a/jni/Application.mk b/jni/Application.mk
new file mode 100644
index 0000000..ed79cc6
--- /dev/null
+++ b/jni/Application.mk
@@ -0,0 +1 @@
+
APP_ABI ?= armeabi
\ No newline at end of file
diff --git a/jni/OpenAL/Alc/ALc.c b/jni/OpenAL/Alc/ALc.c
new file mode 100644
index 0000000..cf46706
--- /dev/null
+++ b/jni/OpenAL/Alc/ALc.c
@@ -0,0 +1,2343 @@
+/**
+ * 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
+#include
+#include
+#include
+#include
+
+#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"
+
+
+#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
+#ifdef HAVE_AUDIOTRACK
+ { "audiotrack", alc_audiotrack_init, alc_audiotrack_deinit, alc_audiotrack_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_OPENSLES
+ { "opensles", alc_opensles_init, alc_opensles_deinit, alc_opensles_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
+
+ { 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;
+
+ fprintf(LogFile, "%s", str);
+ 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] = int2ALfp(0);
+ device->PendingClicks[i] = int2ALfp(0);
+ }
+
+ 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 = float2ALfp(GetConfigValueFloat(NULL, "head_dampen", DEFAULT_HEAD_DAMPEN));
+ device->HeadDampen = __min(device->HeadDampen, int2ALfp(1));
+ device->HeadDampen = __max(device->HeadDampen, int2ALfp(0));
+ }
+ else
+ device->HeadDampen = int2ALfp(0);
+
+ 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 = int2ALfp(1);
+ pContext->Listener.MetersPerUnit = int2ALfp(1);
+ pContext->Listener.Position[0] = int2ALfp(0);
+ pContext->Listener.Position[1] = int2ALfp(0);
+ pContext->Listener.Position[2] = int2ALfp(0);
+ pContext->Listener.Velocity[0] = int2ALfp(0);
+ pContext->Listener.Velocity[1] = int2ALfp(0);
+ pContext->Listener.Velocity[2] = int2ALfp(0);
+ pContext->Listener.Forward[0] = int2ALfp(0);
+ pContext->Listener.Forward[1] = int2ALfp(0);
+ pContext->Listener.Forward[2] = int2ALfp(-1);
+ pContext->Listener.Up[0] = int2ALfp(0);
+ pContext->Listener.Up[1] = int2ALfp(1);
+ pContext->Listener.Up[2] = int2ALfp(0);
+
+ //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 = int2ALfp(1);
+ pContext->DopplerVelocity = int2ALfp(1);
+ pContext->flSpeedOfSound = float2ALfp(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 = int2ALfp(0);
+
+ // 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);
+ }
+}
+
+///////////////////////////////////////////////////////
diff --git a/jni/OpenAL/Alc/ALu.c b/jni/OpenAL/Alc/ALu.c
new file mode 100644
index 0000000..1f01b65
--- /dev/null
+++ b/jni/OpenAL/Alc/ALu.c
@@ -0,0 +1,1092 @@
+/**
+ * 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
+#include
+#include
+#include
+#include
+#include
+
+#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"
+
+#ifdef MAX_SOURCES_LOW
+// For throttling AlSource.c
+int alc_max_sources = MAX_SOURCES_LOW;
+int alc_active_sources = 0;
+int alc_num_cores = 0;
+#endif
+
+static __inline ALvoid aluCrossproduct(const ALfp *inVector1, const ALfp *inVector2, ALfp *outVector)
+{
+ outVector[0] = (ALfpMult(inVector1[1],inVector2[2]) - ALfpMult(inVector1[2],inVector2[1]));
+ outVector[1] = (ALfpMult(inVector1[2],inVector2[0]) - ALfpMult(inVector1[0],inVector2[2]));
+ outVector[2] = (ALfpMult(inVector1[0],inVector2[1]) - ALfpMult(inVector1[1],inVector2[0]));
+}
+
+static __inline ALfp aluDotproduct(const ALfp *inVector1, const ALfp *inVector2)
+{
+ return (ALfpMult(inVector1[0],inVector2[0]) + ALfpMult(inVector1[1],inVector2[1]) +
+ ALfpMult(inVector1[2],inVector2[2]));
+}
+
+static __inline ALvoid aluNormalize(ALfp *inVector)
+{
+ ALfp length, inverse_length;
+
+ length = aluSqrt(aluDotproduct(inVector, inVector));
+ if(length != int2ALfp(0))
+ {
+ inverse_length = ALfpDiv(int2ALfp(1),length);
+ inVector[0] = ALfpMult(inVector[0], inverse_length);
+ inVector[1] = ALfpMult(inVector[1], inverse_length);
+ inVector[2] = ALfpMult(inVector[2], inverse_length);
+ }
+}
+
+static __inline ALvoid aluMatrixVector(ALfp *vector,ALfp w,ALfp matrix[4][4])
+{
+ ALfp temp[4] = {
+ vector[0], vector[1], vector[2], w
+ };
+
+ vector[0] = ALfpMult(temp[0],matrix[0][0]) + ALfpMult(temp[1],matrix[1][0]) + ALfpMult(temp[2],matrix[2][0]) + ALfpMult(temp[3],matrix[3][0]);
+ vector[1] = ALfpMult(temp[0],matrix[0][1]) + ALfpMult(temp[1],matrix[1][1]) + ALfpMult(temp[2],matrix[2][1]) + ALfpMult(temp[3],matrix[3][1]);
+ vector[2] = ALfpMult(temp[0],matrix[0][2]) + ALfpMult(temp[1],matrix[1][2]) + ALfpMult(temp[2],matrix[2][2]) + ALfpMult(temp[3],matrix[3][2]);
+}
+
+
+ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+{
+ ALfp SourceVolume,ListenerGain,MinVolume,MaxVolume;
+ ALbufferlistitem *BufferListItem;
+ enum DevFmtChannels DevChans;
+ enum FmtChannels Channels;
+ ALfp DryGain, DryGainHF;
+ ALfp WetGain[MAX_SENDS];
+ ALfp WetGainHF[MAX_SENDS];
+ ALint NumSends, Frequency;
+ ALboolean DupStereo;
+ ALfp Pitch;
+ ALfp 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 = ALfpDiv(ALfpMult(Pitch, int2ALfp(ALBuffer->Frequency)), int2ALfp(Frequency));
+ if(Pitch > int2ALfp(maxstep))
+ ALSource->Params.Step = maxstep<Params.Step = ALfp2int(ALfpMult(Pitch, int2ALfp(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 = int2ALfp(1);
+
+ switch(ALSource->DirectFilter.type)
+ {
+ case AL_FILTER_LOWPASS:
+ DryGain = ALfpMult(DryGain, ALSource->DirectFilter.Gain);
+ DryGainHF = ALfpMult(DryGainHF, ALSource->DirectFilter.GainHF);
+ break;
+ }
+
+ for(i = 0;i < MAXCHANNELS;i++)
+ {
+ ALuint i2;
+ for(i2 = 0;i2 < MAXCHANNELS;i2++)
+ ALSource->Params.DryGains[i][i2] = int2ALfp(0);
+ }
+
+ switch(Channels)
+ {
+ case FmtMono:
+ ALSource->Params.DryGains[0][FRONT_CENTER] = ALfpMult(DryGain, ListenerGain);
+ break;
+ case FmtStereo:
+ if(DupStereo == AL_FALSE)
+ {
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ }
+ else
+ {
+ switch(DevChans)
+ {
+ case DevFmtMono:
+ case DevFmtStereo:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+
+ case DevFmtQuad:
+ case DevFmtX51:
+ DryGain = ALfpMult(DryGain, aluSqrt(float2ALfp(2.0f/4.0f)));
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[0][BACK_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][BACK_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+
+ case DevFmtX61:
+ DryGain = ALfpMult(DryGain, aluSqrt(float2ALfp(2.0f/4.0f)));
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[0][SIDE_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][SIDE_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+
+ case DevFmtX71:
+ DryGain = ALfpMult(DryGain, aluSqrt(float2ALfp(2.0f/6.0f)));
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[0][BACK_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][BACK_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[0][SIDE_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][SIDE_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+ }
+ }
+ break;
+
+ case FmtRear:
+ ALSource->Params.DryGains[0][BACK_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][BACK_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+
+ case FmtQuad:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[2][BACK_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[3][BACK_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+
+ case FmtX51:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[2][FRONT_CENTER] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[3][LFE] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[4][BACK_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[5][BACK_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+
+ case FmtX61:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[2][FRONT_CENTER] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[3][LFE] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[4][BACK_CENTER] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[5][SIDE_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[6][SIDE_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ break;
+
+ case FmtX71:
+ ALSource->Params.DryGains[0][FRONT_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[1][FRONT_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[2][FRONT_CENTER] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[3][LFE] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[4][BACK_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[5][BACK_RIGHT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[6][SIDE_LEFT] = ALfpMult(DryGain, ListenerGain);
+ ALSource->Params.DryGains[7][SIDE_RIGHT] = ALfpMult(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] = int2ALfp(1);
+
+ switch(ALSource->Send[i].WetFilter.type)
+ {
+ case AL_FILTER_LOWPASS:
+ WetGain[i] = ALfpMult(WetGain[i], ALSource->Send[i].WetFilter.Gain);
+ WetGainHF[i] = ALfpMult(WetGainHF[i], ALSource->Send[i].WetFilter.GainHF);
+ break;
+ }
+
+ ALSource->Params.Send[i].WetGain = ALfpMult(WetGain[i], ListenerGain);
+ }
+
+ /* Update filter coefficients. Calculations based on the I3DL2
+ * spec. */
+ cw = float2ALfp(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 */
+ ALfp a = lpCoeffCalc(ALfpMult(WetGainHF[i],WetGainHF[i]), cw);
+ ALSource->Params.Send[i].iirFilter.coeff = a;
+ }
+}
+
+ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+{
+ const ALCdevice *Device = ALContext->Device;
+ ALfp InnerAngle,OuterAngle,Angle,Distance,OrigDist;
+ ALfp Direction[3],Position[3],SourceToListener[3];
+ ALfp Velocity[3],ListenerVel[3];
+ ALfp MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
+ ALfp ConeVolume,ConeHF,SourceVolume,ListenerGain;
+ ALfp DopplerFactor, DopplerVelocity, SpeedOfSound;
+ ALfp AirAbsorptionFactor;
+ ALbufferlistitem *BufferListItem;
+ ALfp Attenuation, EffectiveDist;
+ ALfp RoomAttenuation[MAX_SENDS];
+ ALfp MetersPerUnit;
+ ALfp RoomRolloff[MAX_SENDS];
+ ALfp DryGain;
+ ALfp DryGainHF;
+ ALfp WetGain[MAX_SENDS];
+ ALfp WetGainHF[MAX_SENDS];
+ ALfp DirGain, AmbientGain;
+ const ALfp *SpeakerGain;
+ ALfp Pitch;
+ ALfp length;
+ ALuint Frequency;
+ ALint NumSends;
+ ALint pos, s, i;
+ ALfp cw;
+
+ DryGainHF = int2ALfp(1);
+ for(i = 0;i < MAX_SENDS;i++)
+ WetGainHF[i] = int2ALfp(1);
+
+ //Get context properties
+ DopplerFactor = ALfpMult(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)
+ {
+ ALfp U[3],V[3],N[3];
+ ALfp 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] = -1*N[0]; Matrix[0][3] = int2ALfp(0);
+ Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -1*N[1]; Matrix[1][3] = int2ALfp(0);
+ Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -1*N[2]; Matrix[2][3] = int2ALfp(0);
+ Matrix[3][0] = int2ALfp(0); Matrix[3][1] = int2ALfp(0); Matrix[3][2] = int2ALfp(0); Matrix[3][3] = int2ALfp(1);
+
+ // 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, int2ALfp(1), Matrix);
+ aluMatrixVector(Direction, int2ALfp(0), Matrix);
+ // Transform source and listener velocity into listener space
+ aluMatrixVector(Velocity, int2ALfp(0), Matrix);
+ aluMatrixVector(ListenerVel, int2ALfp(0), Matrix);
+ }
+ else
+ ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = int2ALfp(0);
+
+ SourceToListener[0] = -1*Position[0];
+ SourceToListener[1] = -1*Position[1];
+ SourceToListener[2] = -1*Position[2];
+ aluNormalize(SourceToListener);
+ aluNormalize(Direction);
+
+ //2. Calculate distance attenuation
+ Distance = aluSqrt(aluDotproduct(Position, Position));
+ OrigDist = Distance;
+
+ Attenuation = int2ALfp(1);
+ for(i = 0;i < NumSends;i++)
+ {
+ RoomAttenuation[i] = int2ALfp(1);
+
+ 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 > int2ALfp(0))
+ {
+ if((MinDist + ALfpMult(Rolloff, (Distance - MinDist))) > int2ALfp(0))
+ Attenuation = ALfpDiv(MinDist, (MinDist + ALfpMult(Rolloff, (Distance - MinDist))));
+ for(i = 0;i < NumSends;i++)
+ {
+ if((MinDist + ALfpMult(RoomRolloff[i], (Distance - MinDist))) > int2ALfp(0))
+ RoomAttenuation[i] = ALfpDiv(MinDist, (MinDist + ALfpMult(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 = int2ALfp(1) - ALfpDiv(ALfpMult(Rolloff,(Distance-MinDist)), (MaxDist - MinDist));
+ Attenuation = __max(Attenuation, int2ALfp(0));
+ for(i = 0;i < NumSends;i++)
+ {
+ RoomAttenuation[i] = int2ALfp(1) - ALfpDiv(ALfpMult(RoomRolloff[i],(Distance-MinDist)),(MaxDist - MinDist));
+ RoomAttenuation[i] = __max(RoomAttenuation[i], int2ALfp(0));
+ }
+ }
+ 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 > int2ALfp(0) && MinDist > int2ALfp(0))
+ {
+ Attenuation = aluPow(ALfpDiv(Distance,MinDist), (-1*Rolloff));
+ for(i = 0;i < NumSends;i++)
+ RoomAttenuation[i] = aluPow(ALfpDiv(Distance,MinDist), (-1*RoomRolloff[i]));
+ }
+ break;
+
+ case AL_NONE:
+ break;
+ }
+
+ // Source Gain + Attenuation
+ DryGain = ALfpMult(SourceVolume, Attenuation);
+ for(i = 0;i < NumSends;i++)
+ WetGain[i] = ALfpMult(SourceVolume, RoomAttenuation[i]);
+
+ EffectiveDist = int2ALfp(0);
+ if(MinDist > int2ALfp(0) && Attenuation < int2ALfp(1))
+ EffectiveDist = ALfpMult((ALfpDiv(MinDist,Attenuation) - MinDist),MetersPerUnit);
+
+ // Distance-based air absorption
+ if(AirAbsorptionFactor > int2ALfp(0) && EffectiveDist > int2ALfp(0))
+ {
+ ALfp absorb;
+
+ // Absorption calculation is done in dB
+ absorb = ALfpMult(ALfpMult(AirAbsorptionFactor,float2ALfp(AIRABSORBGAINDBHF)),
+ EffectiveDist);
+ // Convert dB to linear gain before applying
+ absorb = aluPow(int2ALfp(10), ALfpDiv(absorb,int2ALfp(20)));
+
+ DryGainHF = ALfpMult(DryGainHF,absorb);
+ }
+
+ //3. Apply directional soundcones
+ Angle = ALfpMult(aluAcos(aluDotproduct(Direction,SourceToListener)), float2ALfp(180.0f/M_PI));
+ if(Angle >= InnerAngle && Angle <= OuterAngle)
+ {
+ ALfp scale; scale = ALfpDiv((Angle-InnerAngle), (OuterAngle-InnerAngle));
+ ConeVolume = int2ALfp(1) + ALfpMult((ALSource->flOuterGain - int2ALfp(1)),scale);
+ ConeHF = (int2ALfp(1)+ALfpMult((OuterGainHF-int2ALfp(1)),scale));
+ }
+ else if(Angle > OuterAngle)
+ {
+ ConeVolume = (int2ALfp(1)+(ALSource->flOuterGain-int2ALfp(1)));
+ ConeHF = (int2ALfp(1)+(OuterGainHF-int2ALfp(1)));
+ }
+ else
+ {
+ ConeVolume = int2ALfp(1);
+ ConeHF = int2ALfp(1);
+ }
+
+ // 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 = ALfpMult(aluAcos(SourceToListener[2]), float2ALfp(180.0f/M_PI));
+ // Sources within the minimum distance attenuate less
+ if(OrigDist < MinDist)
+ Angle = ALfpMult(Angle, ALfpDiv(OrigDist,MinDist));
+ if(Angle > int2ALfp(90))
+ {
+ ALfp scale; scale = ALfpDiv((Angle-int2ALfp(90)), float2ALfp(180.1f-90.0f)); // .1 to account for fp errors
+ ConeHF = ALfpMult(ConeHF, (int2ALfp(1) - ALfpMult(Device->HeadDampen,scale)));
+ }
+
+ DryGain = ALfpMult(DryGain, ConeVolume);
+ if(ALSource->DryGainHFAuto)
+ DryGainHF = ALfpMult(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 = int2ALfp(0);
+ WetGainHF[i] = int2ALfp(1);
+ continue;
+ }
+
+ if(Slot->AuxSendAuto)
+ {
+ if(ALSource->WetGainAuto)
+ WetGain[i] = ALfpMult(WetGain[i], ConeVolume);
+ if(ALSource->WetGainHFAuto)
+ WetGainHF[i] = ALfpMult(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] = ALfpMult(WetGain[i],
+ aluPow(int2ALfp(10),
+ ALfpDiv(ALfpMult(ALfpDiv(EffectiveDist,
+ ALfpMult(float2ALfp(SPEEDOFSOUNDMETRESPERSEC), Slot->effect.Reverb.DecayTime)),
+ int2ALfp(-60)),
+ int2ALfp(20))));
+
+ WetGainHF[i] = ALfpMult(WetGainHF[i],
+ aluPow(Slot->effect.Reverb.AirAbsorptionGainHF,
+ ALfpMult(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] = ALfpMult(WetGain[i], ALSource->Send[i].WetFilter.Gain);
+ WetGainHF[i] = ALfpMult(WetGainHF[i], ALSource->Send[i].WetFilter.GainHF);
+ break;
+ }
+ ALSource->Params.Send[i].WetGain = ALfpMult(WetGain[i], ListenerGain);
+ }
+
+ // Apply filter gains and filters
+ switch(ALSource->DirectFilter.type)
+ {
+ case AL_FILTER_LOWPASS:
+ DryGain = ALfpMult(DryGain, ALSource->DirectFilter.Gain);
+ DryGainHF = ALfpMult(DryGainHF, ALSource->DirectFilter.GainHF);
+ break;
+ }
+ DryGain = ALfpMult(DryGain, ListenerGain);
+
+ // Calculate Velocity
+ Pitch = ALSource->flPitch;
+ if(DopplerFactor != int2ALfp(0))
+ {
+ ALfp VSS, VLS;
+ ALfp MaxVelocity; MaxVelocity = ALfpDiv(ALfpMult(SpeedOfSound,DopplerVelocity),
+ DopplerFactor);
+
+ VSS = aluDotproduct(Velocity, SourceToListener);
+ if(VSS >= MaxVelocity)
+ VSS = (MaxVelocity - int2ALfp(1));
+ else if(VSS <= -MaxVelocity)
+ VSS = (-MaxVelocity + int2ALfp(1));
+
+ VLS = aluDotproduct(ListenerVel, SourceToListener);
+ if(VLS >= MaxVelocity)
+ VLS = (MaxVelocity - int2ALfp(1));
+ else if(VLS <= -MaxVelocity)
+ VLS = -MaxVelocity + int2ALfp(1);
+
+ Pitch = ALfpMult(Pitch,
+ ALfpDiv((ALfpMult(SpeedOfSound,DopplerVelocity) - ALfpMult(DopplerFactor,VLS)),
+ (ALfpMult(SpeedOfSound,DopplerVelocity) - ALfpMult(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 = ALfpDiv(ALfpMult(Pitch, int2ALfp(ALBuffer->Frequency)), int2ALfp(Frequency));
+ if(Pitch > int2ALfp(maxstep))
+ ALSource->Params.Step = maxstep<Params.Step = ALfp2int(ALfpMult(Pitch,float2ALfp(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 > int2ALfp(0))
+ {
+ ALfp invlen = ALfpDiv(int2ALfp(1), length);
+ Position[0] = ALfpMult(Position[0],invlen);
+ Position[1] = ALfpMult(Position[1],invlen);
+ Position[2] = ALfpMult(Position[2],invlen);
+ }
+
+ pos = aluCart2LUTpos((-1*Position[2]), Position[0]);
+ SpeakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+
+ DirGain = aluSqrt((ALfpMult(Position[0],Position[0]) + ALfpMult(Position[2],Position[2])));
+ // elevation adjustment for directional gain. this sucks, but
+ // has low complexity
+ AmbientGain = aluSqrt(float2ALfp(1.0f/Device->NumChan));
+ for(s = 0;s < MAXCHANNELS;s++)
+ {
+ ALuint s2;
+ for(s2 = 0;s2 < MAXCHANNELS;s2++)
+ ALSource->Params.DryGains[s][s2] = int2ALfp(0);
+ }
+ for(s = 0;s < (ALsizei)Device->NumChan;s++)
+ {
+ Channel chan = Device->Speaker2Chan[s];
+ ALfp gain; gain = AmbientGain + ALfpMult((SpeakerGain[chan]-AmbientGain),DirGain);
+ ALSource->Params.DryGains[0][chan] = ALfpMult(DryGain, gain);
+ }
+
+ /* Update filter coefficients. */
+ cw = __cos(ALfpDiv(float2ALfp(2.0*M_PI*LOWPASSFREQCUTOFF), int2ALfp(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(ALfp val)
+{
+ return ALfp2float(val);
+}
+static __inline ALushort aluF2US(ALfp val)
+{
+ if(val > int2ALfp(1)) return 65535;
+ if(val < int2ALfp(-1)) return 0;
+ return (ALushort)(ALfp2int(ALfpMult(val,int2ALfp(32767))) + 32768);
+}
+static __inline ALshort aluF2S(ALfp val)
+{
+ if(val > int2ALfp(1)) return 32767;
+ if(val < int2ALfp(-1)) return -32768;
+ return (ALshort)(ALfp2int(ALfpMult(val,int2ALfp(32767))));
+}
+static __inline ALubyte aluF2UB(ALfp val)
+{
+ ALushort i = aluF2US(val);
+ return i>>8;
+}
+static __inline ALbyte aluF2B(ALfp 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)\
+{ \
+ ALfp (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
+ ALfp (*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++) \
+ { \
+ ALfp samp; samp = int2ALfp(0); \
+ for(c = 0;c < MAXCHANNELS;c++) { \
+ ALfp m = Matrix[c][chans[j]]; \
+ if (m != 0) \
+ samp += ALfpMult(DryBuffer[i][c], m); \
+ } \
+ ((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)\
+{ \
+ ALfp (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
+ ALfp (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
+ const ALuint *ChanMap = device->DevChannels; \
+ ALuint i, j, c; \
+ \
+ if(device->Bs2b) \
+ { \
+ for(i = 0;i < SamplesToDo;i++) \
+ { \
+ ALfp samples[2] = { int2ALfp(0), int2ALfp(0) }; \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ { \
+ samples[0] += ALfpMult(DryBuffer[i][c],Matrix[c][FRONT_LEFT]); \
+ samples[1] += ALfpMult(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++) \
+ { \
+ ALfp samp = int2ALfp(0); \
+ for(c = 0;c < MAXCHANNELS;c++) \
+ samp += ALfpMult(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
+
+static __inline ALvoid aluMixDataPrivate(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(ALfp));
+
+ 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] -= ALfpDiv(ALEffectSlot->ClickRemoval[0], int2ALfp(256));
+ ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
+ }
+ for(i = 0;i < 1;i++)
+ {
+ ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
+ ALEffectSlot->PendingClicks[i] = int2ALfp(0);
+ }
+
+ ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
+ SamplesToDo, ALEffectSlot->WetBuffer,
+ device->DryBuffer);
+
+ for(i = 0;i < SamplesToDo;i++)
+ ALEffectSlot->WetBuffer[i] = int2ALfp(0);
+ }
+
+ ProcessContext(*ctx);
+ ctx++;
+ }
+ ProcessContext(NULL);
+
+ //Post processing loop
+ for(i = 0;i < SamplesToDo;i++)
+ {
+ for(c = 0;c < MAXCHANNELS;c++)
+ {
+ device->ClickRemoval[c] -= ALfpDiv(device->ClickRemoval[c], int2ALfp(256));
+ device->DryBuffer[i][c] += device->ClickRemoval[c];
+ }
+ }
+ for(i = 0;i < MAXCHANNELS;i++)
+ {
+ device->ClickRemoval[i] += device->PendingClicks[i];
+ device->PendingClicks[i] = int2ALfp(0);
+ }
+
+ 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 aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
+{
+#ifdef MAX_SOURCES_LOW
+ // Profile aluMixDataPrivate to set admission control parameters
+ clock_t ts_start;
+ clock_t ts_end;
+ clock_t ts_diff;
+ int time_per_source;
+ int max_sources_within_deadline;
+ int mix_deadline_usec;
+ int max;
+
+ if (alc_num_cores == 0) {
+ // FIXME(Apportable) this is Linux specific
+ alc_num_cores = sysconf( _SC_NPROCESSORS_ONLN );
+ LOGI("_SC_NPROCESSORS_ONLN=%d", alc_num_cores);
+ }
+
+ if (alc_num_cores > 1) {
+ // Allow OpenAL to monopolize one core
+ mix_deadline_usec = ((size*1000000) / device->Frequency) - 2000;
+ } else {
+ // Try to cap mixing at 20% CPU
+ mix_deadline_usec = ((size*1000000) / device->Frequency) / 5;
+ }
+
+ ts_start = clock();
+ aluMixDataPrivate(device, buffer, size);
+ ts_end = clock();
+
+ // Time in micro-seconds that aluMixData has taken to run
+ ts_diff = ((ts_end-ts_start)*1000) / (CLOCKS_PER_SEC/1000);
+
+ // Try to adjust the max sources limit adaptively, within a range
+ if (alc_active_sources > 0) {
+ time_per_source = max(1, ts_diff / alc_active_sources);
+ max_sources_within_deadline = mix_deadline_usec / time_per_source;
+ max = min(max(max_sources_within_deadline, MAX_SOURCES_LOW), MAX_SOURCES_HIGH);
+ if (max > alc_max_sources) {
+ alc_max_sources++;
+ } else if (max < alc_max_sources) {
+ alc_max_sources--;
+ }
+ } else {
+ alc_max_sources = MAX_SOURCES_LOW;
+ }
+#else
+ aluMixDataPrivate(device, buffer, size);
+#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);
+}
diff --git a/jni/OpenAL/Alc/alcConfig.c b/jni/OpenAL/Alc/alcConfig.c
new file mode 100644
index 0000000..847e5d1
--- /dev/null
+++ b/jni/OpenAL/Alc/alcConfig.c
@@ -0,0 +1,338 @@
+/**
+ * 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
+#include
+#include
+#include
+
+#include "alMain.h"
+
+#ifdef _WIN32_IE
+#include
+#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);
+}
diff --git a/jni/OpenAL/Alc/alcEcho.c b/jni/OpenAL/Alc/alcEcho.c
new file mode 100644
index 0000000..1abf0b2
--- /dev/null
+++ b/jni/OpenAL/Alc/alcEcho.c
@@ -0,0 +1,203 @@
+/**
+ * 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
+#include
+
+#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;
+
+ ALfp *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
+ ALfp GainL;
+ ALfp GainR;
+
+ ALfp FeedGain;
+
+ ALfp Gain[MAXCHANNELS];
+
+ FILTER iirFilter;
+ ALfp 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(ALfp));
+ if(!temp)
+ return AL_FALSE;
+ state->SampleBuffer = temp;
+ state->BufferLength = maxlen;
+ }
+ for(i = 0;i < state->BufferLength;i++)
+ state->SampleBuffer[i] = int2ALfp(0);
+
+ for(i = 0;i < MAXCHANNELS;i++)
+ state->Gain[i] = int2ALfp(0);
+ for(i = 0;i < Device->NumChan;i++)
+ {
+ Channel chan = Device->Speaker2Chan[i];
+ state->Gain[chan] = int2ALfp(1);
+ }
+
+ return AL_TRUE;
+}
+
+static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+ ALechoState *state = (ALechoState*)effect;
+ ALuint frequency = Context->Device->Frequency;
+ ALfp lrpan, cw, a, g;
+
+ state->Tap[0].delay = (ALuint)ALfp2int((ALfpMult(Effect->Echo.Delay, int2ALfp(frequency)) + int2ALfp(1)));
+ state->Tap[1].delay = (ALuint)ALfp2int(ALfpMult(Effect->Echo.LRDelay, int2ALfp(frequency)));
+ state->Tap[1].delay += state->Tap[0].delay;
+
+ lrpan = (ALfpMult(Effect->Echo.Spread, float2ALfp(0.5f)) + float2ALfp(0.5f));
+ state->GainL = aluSqrt( lrpan);
+ state->GainR = aluSqrt((int2ALfp(1)-lrpan));
+
+ state->FeedGain = Effect->Echo.Feedback;
+
+ cw = __cos(ALfpDiv(float2ALfp(2.0*M_PI * LOWPASSFREQCUTOFF), int2ALfp(frequency)));
+ g = (int2ALfp(1) - Effect->Echo.Damping);
+ a = int2ALfp(0);
+ if(g < float2ALfp(0.9999f)) /* 1-epsilon */ {
+ // a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
+ a = ALfpDiv((int2ALfp(1) - ALfpMult(g,cw) - aluSqrt((ALfpMult(ALfpMult(int2ALfp(2),g),(int2ALfp(1)-cw)) -
+ ALfpMult(ALfpMult(g,g),(int2ALfp(1) - ALfpMult(cw,cw)))))),
+ (int2ALfp(1) - g));
+ }
+ state->iirFilter.coeff = a;
+}
+
+static ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfp *SamplesIn, ALfp (*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 ALfp gain = Slot->Gain;
+ ALfp samp[2], smp;
+ ALuint i;
+
+ for(i = 0;i < SamplesToDo;i++,offset++)
+ {
+ // Sample first tap
+ smp = state->SampleBuffer[(offset-tap1) & mask];
+ samp[0] = ALfpMult(smp, state->GainL);
+ samp[1] = ALfpMult(smp, state->GainR);
+ // Sample second tap. Reverse LR panning
+ smp = state->SampleBuffer[(offset-tap2) & mask];
+ samp[0] += ALfpMult(smp, state->GainR);
+ samp[1] += ALfpMult(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] = ALfpMult(smp, state->FeedGain);
+
+ // Apply slot gain
+ samp[0] = ALfpMult(samp[0], gain);
+ samp[1] = ALfpMult(samp[1], gain);
+
+ SamplesOut[i][FRONT_LEFT] += ALfpMult(state->Gain[FRONT_LEFT], samp[0]);
+ SamplesOut[i][FRONT_RIGHT] += ALfpMult(state->Gain[FRONT_RIGHT], samp[1]);
+#ifdef APPORTABLE_OPTIMIZED_OUT
+ SamplesOut[i][SIDE_LEFT] += ALfpMult(state->Gain[SIDE_LEFT], samp[0]);
+ SamplesOut[i][SIDE_RIGHT] += ALfpMult(state->Gain[SIDE_RIGHT], samp[1]);
+ SamplesOut[i][BACK_LEFT] += ALfpMult(state->Gain[BACK_LEFT], samp[0]);
+ SamplesOut[i][BACK_RIGHT] += ALfpMult(state->Gain[BACK_RIGHT], samp[1]);
+#endif
+
+ }
+ 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 = int2ALfp(0);
+ state->GainR = int2ALfp(0);
+
+ state->iirFilter.coeff = int2ALfp(0);
+ state->iirFilter.history[0] = int2ALfp(0);
+ state->iirFilter.history[1] = int2ALfp(0);
+
+ return &state->state;
+}
diff --git a/jni/OpenAL/Alc/alcModulator.c b/jni/OpenAL/Alc/alcModulator.c
new file mode 100644
index 0000000..445bf13
--- /dev/null
+++ b/jni/OpenAL/Alc/alcModulator.c
@@ -0,0 +1,229 @@
+/**
+ * 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
+#include
+
+#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;
+
+ ALfp Gain[MAXCHANNELS];
+
+ FILTER iirFilter;
+ ALfp history[1];
+} ALmodulatorState;
+
+#define WAVEFORM_FRACBITS 16
+#define WAVEFORM_FRACMASK ((1<>(WAVEFORM_FRACBITS-1))&1) ? -1 : 1);
+}
+
+
+static __inline ALfp hpFilter1P(FILTER *iir, ALuint offset, ALfp input)
+{
+ ALfp *history = &iir->history[offset];
+ ALfp a = iir->coeff;
+ ALfp output = input;
+
+ output = (output + ALfpMult((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] = int2ALfp(0);
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ state->Gain[chan] = int2ALfp(1);
+ }
+
+ return AL_TRUE;
+}
+
+static ALvoid ModulatorUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+ ALmodulatorState *state = (ALmodulatorState*)effect;
+ ALfp cw, a;
+ a = int2ALfp(0);
+
+ 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 = ALfp2int(ALfpDiv(ALfpMult(Effect->Modulator.Frequency,
+ int2ALfp(1<Device->Frequency)));
+ if(!state->step)
+ state->step = 1;
+
+ cw = __cos(ALfpDiv(ALfpMult(float2ALfp(2.0*M_PI),
+ Effect->Modulator.HighPassCutoff),
+ int2ALfp(Context->Device->Frequency)));
+ a = ((int2ALfp(2)-cw) -
+ aluSqrt((aluPow((int2ALfp(2)-cw), int2ALfp(2)) - int2ALfp(1))));
+ state->iirFilter.coeff = a;
+}
+
+static ALvoid ModulatorProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfp *SamplesIn, ALfp (*SamplesOut)[MAXCHANNELS])
+{
+ ALmodulatorState *state = (ALmodulatorState*)effect;
+ const ALfp gain = Slot->Gain;
+ const ALuint step = state->step;
+ ALuint index = state->index;
+ ALfp samp;
+ ALuint i;
+
+ switch(state->Waveform)
+ {
+ case SINUSOID:
+ for(i = 0;i < SamplesToDo;i++)
+ {
+#ifdef APPORTABLE_OPTIMIZED_OUT
+#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)
+#else
+//Apportable optimized version
+#define FILTER_OUT(func) do { \
+ samp = SamplesIn[i]; \
+ \
+ index += step; \
+ index &= WAVEFORM_FRACMASK; \
+ samp = ALfpMult(samp, func(index)); \
+ \
+ samp = hpFilter1P(&state->iirFilter, 0, samp); \
+ \
+ /* Apply slot gain */ \
+ samp = ALfpMult(samp, gain); \
+ \
+ SamplesOut[i][FRONT_LEFT] += ALfpMult(state->Gain[FRONT_LEFT], samp); \
+ SamplesOut[i][FRONT_RIGHT] += ALfpMult(state->Gain[FRONT_RIGHT], samp); \
+} while(0)
+#endif
+ 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;
+ state->step = 1;
+
+ state->iirFilter.coeff = int2ALfp(0);
+ state->iirFilter.history[0] = int2ALfp(0);
+
+ return &state->state;
+}
diff --git a/jni/OpenAL/Alc/alcReverb.c b/jni/OpenAL/Alc/alcReverb.c
new file mode 100644
index 0000000..496a15d
--- /dev/null
+++ b/jni/OpenAL/Alc/alcReverb.c
@@ -0,0 +1,1371 @@
+/**
+ * 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
+#include
+#include
+
+#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;
+ ALfp *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.
+ ALfp *SampleBuffer;
+ ALuint TotalSamples;
+ // Master effect low-pass filter (2 chained 1-pole filters).
+ FILTER LpFilter;
+ ALfp 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.
+ ALfp Depth;
+ ALfp Coeff;
+ ALfp 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.
+ ALfp Gain;
+ // Early reflections are done with 4 delay lines.
+ ALfp Coeff[4];
+ DelayLine Delay[4];
+ ALuint Offset[4];
+ // The gain for each output channel based on 3D panning (only for the
+ // EAX path).
+ ALfp 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.
+ ALfp Gain;
+ // Attenuation to compensate for the modal density and decay rate of
+ // the late lines.
+ ALfp DensityGain;
+ // The feed-back and feed-forward all-pass coefficient.
+ ALfp ApFeedCoeff;
+ // Mixing matrix coefficient.
+ ALfp MixCoeff;
+ // Late reverb has 4 parallel all-pass filters.
+ ALfp ApCoeff[4];
+ DelayLine ApDelay[4];
+ ALuint ApOffset[4];
+ // In addition to 4 cyclical delay lines.
+ ALfp Coeff[4];
+ DelayLine Delay[4];
+ ALuint Offset[4];
+ // The cyclical delay lines are 1-pole low-pass filtered.
+ ALfp LpCoeff[4];
+ ALfp LpSample[4];
+ // The gain for each output channel based on 3D panning (only for the
+ // EAX path).
+ ALfp PanGain[MAXCHANNELS];
+ } Late;
+ struct {
+ // Attenuation to compensate for the modal density and decay rate of
+ // the echo line.
+ ALfp DensityGain;
+ // Echo delay and all-pass lines.
+ DelayLine Delay;
+ DelayLine ApDelay;
+ ALfp Coeff;
+ ALfp ApFeedCoeff;
+ ALfp ApCoeff;
+ ALuint Offset;
+ ALuint ApOffset;
+ // The echo line is 1-pole low-pass filtered.
+ ALfp LpCoeff;
+ ALfp LpSample;
+ // Echo mixing coefficients.
+ ALfp 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)
+ ALfp *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 ALfp MODULATION_DEPTH_COEFF = toALfpConst(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 ALfp MODULATION_FILTER_COEFF = toALfpConst(0.048f);
+static const ALfp MODULATION_FILTER_CONST = toALfpConst(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 ALfp ECHO_ALLPASS_LENGTH = toALfpConst(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 ALfp DECO_FRACTION = toALfpConst(0.15f);
+static const ALfp DECO_MULTIPLIER = toALfpConst(2.0f);
+
+// All delay line lengths are specified in seconds.
+
+// The lengths of the early delay lines.
+static const ALfp EARLY_LINE_LENGTH[4] =
+{
+ toALfpConst(0.0015f), toALfpConst(0.0045f), toALfpConst(0.0135f), toALfpConst(0.0405f)
+};
+
+// The lengths of the late all-pass delay lines.
+static const ALfp ALLPASS_LINE_LENGTH[4] =
+{
+ toALfpConst(0.0151f), toALfpConst(0.0167f), toALfpConst(0.0183f), toALfpConst(0.0200f),
+};
+
+// The lengths of the late cyclical delay lines.
+static const ALfp LATE_LINE_LENGTH[4] =
+{
+ toALfpConst(0.0211f), toALfpConst(0.0311f), toALfpConst(0.0461f), toALfpConst(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 ALfp LATE_LINE_MULTIPLIER = toALfpConst(4.0f);
+
+// Calculate the length of a delay line and store its mask and offset.
+static ALuint CalcLineLength(ALfp 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)(ALfp2int(ALfpMult(length, int2ALfp(frequency)))) + 1);
+ // All lines share a single sample buffer.
+ Delay->Mask = samples - 1;
+ Delay->Line = (ALfp*)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(ALfp * 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;
+ ALfp length;
+ ALfp *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 = ((ALfpDiv(ALfpMult(float2ALfp(AL_EAXREVERB_MAX_MODULATION_TIME), MODULATION_DEPTH_COEFF),
+ int2ALfp(2))) +
+ ALfpDiv(int2ALfp(1), int2ALfp(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 = float2ALfp(AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
+ AL_EAXREVERB_MAX_LATE_REVERB_DELAY);
+ else
+ length = float2ALfp(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 = ALfpMult(ALfpMult(ALfpMult(ALfpMult(DECO_FRACTION,
+ DECO_MULTIPLIER),
+ DECO_MULTIPLIER),
+ LATE_LINE_LENGTH[0]),
+ (int2ALfp(1) + 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 = ALfpMult(LATE_LINE_LENGTH[index], (int2ALfp(1) + 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(float2ALfp(AL_EAXREVERB_MAX_ECHO_TIME), totalSamples,
+ frequency, &State->Echo.Delay);
+ }
+
+ if(totalSamples != State->TotalSamples)
+ {
+ newBuffer = realloc(State->SampleBuffer, sizeof(ALfp) * 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] = int2ALfp(0);
+
+ return AL_TRUE;
+}
+
+// Calculate a decay coefficient given the length of each cycle and the time
+// until the decay reaches -60 dB.
+static __inline ALfp CalcDecayCoeff(ALfp length, ALfp decayTime)
+{
+ return aluPow(int2ALfp(10), ALfpDiv(length,
+ ALfpDiv(ALfpMult(decayTime,
+ int2ALfp(-60)),
+ int2ALfp(20))));
+}
+
+// Calculate a decay length from a coefficient and the time until the decay
+// reaches -60 dB.
+static __inline ALfp CalcDecayLength(ALfp coeff, ALfp decayTime)
+{
+ return ALfpMult(ALfpMult(ALfpDiv(__log10(coeff), int2ALfp(-60)), int2ALfp(20)), decayTime);
+}
+
+// Calculate the high frequency parameter for the I3DL2 coefficient
+// calculation.
+static __inline ALfp CalcI3DL2HFreq(ALfp hfRef, ALuint frequency)
+{
+ return __cos(ALfpDiv(ALfpMult(float2ALfp(2.0f * M_PI), hfRef), int2ALfp(frequency)));
+}
+
+// Calculate an attenuation to be applied to the input of any echo models to
+// compensate for modal density and decay time.
+static __inline ALfp CalcDensityGain(ALfp 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((int2ALfp(1) - ALfpMult(a, a)));
+}
+
+// Calculate the mixing matrix coefficients given a diffusion factor.
+static __inline ALvoid CalcMatrixCoeffs(ALfp diffusion, ALfp *x, ALfp *y)
+{
+ ALfp n, t;
+
+ // The matrix is of order 4, so n is sqrt (4 - 1).
+ n = aluSqrt(int2ALfp(3));
+ t = ALfpMult(diffusion, __atan(n));
+
+ // Calculate the first mixing matrix coefficient.
+ *x = __cos(t);
+ // Calculate the second mixing matrix coefficient.
+ *y = ALfpDiv(__sin(t), n);
+}
+
+// Calculate the limited HF ratio for use with the late reverb low-pass
+// filters.
+static ALfp CalcLimitedHfRatio(ALfp hfRatio, ALfp airAbsorptionGainHF, ALfp decayTime)
+{
+ ALfp 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 = ALfpDiv(int2ALfp(1),
+ ALfpMult(CalcDecayLength(airAbsorptionGainHF, decayTime),
+ float2ALfp(SPEEDOFSOUNDMETRESPERSEC)));
+ // Need to limit the result to a minimum of 0.1, just like the HF ratio
+ // parameter.
+ limitRatio = __max(limitRatio, float2ALfp(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 ALfp CalcDampingCoeff(ALfp hfRatio, ALfp length, ALfp decayTime, ALfp decayCoeff, ALfp cw)
+{
+ ALfp coeff, g;
+
+ // Eventually this should boost the high frequencies when the ratio
+ // exceeds 1.
+ coeff = int2ALfp(0);
+ if (hfRatio < int2ALfp(1))
+ {
+ // Calculate the low-pass coefficient by dividing the HF decay
+ // coefficient by the full decay coefficient.
+ g = ALfpDiv(CalcDecayCoeff(length, ALfpMult(decayTime, hfRatio)), decayCoeff);
+
+ // Damping is done with a 1-pole filter, so g needs to be squared.
+ g = ALfpMult(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, float2ALfp(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(ALfp modTime, ALfp modDepth, ALuint frequency, ALverbState *State)
+{
+ ALfp 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 = ALfpMult(modTime, int2ALfp(frequency));
+ if (length >= int2ALfp(1)) {
+ State->Mod.Index = (ALuint)(ALfp2int(ALfpDiv(ALfpMult(int2ALfp(State->Mod.Index),
+ length),
+ int2ALfp(State->Mod.Range))));
+ State->Mod.Range = (ALuint)ALfp2int(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 = ALfpMult(ALfpDiv(ALfpDiv(ALfpMult(ALfpMult(modDepth,
+ MODULATION_DEPTH_COEFF),
+ modTime),
+ int2ALfp(2)),
+ int2ALfp(2)),
+ int2ALfp(frequency));
+}
+
+// Update the offsets for the initial effect delay line.
+static ALvoid UpdateDelayLine(ALfp earlyDelay, ALfp lateDelay, ALuint frequency, ALverbState *State)
+{
+ // Calculate the initial delay taps.
+ State->DelayTap[0] = (ALuint)(ALfp2int(ALfpMult(earlyDelay, int2ALfp(frequency))));
+ State->DelayTap[1] = (ALuint)(ALfp2int(ALfpMult((earlyDelay + lateDelay), int2ALfp(frequency))));
+}
+
+// Update the early reflections gain and line coefficients.
+static ALvoid UpdateEarlyLines(ALfp reverbGain, ALfp earlyGain, ALfp 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 = ALfpMult(ALfpMult(float2ALfp(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(ALfp density, ALuint frequency, ALverbState *State)
+{
+ ALuint index;
+ ALfp 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 = ALfpMult(ALfpMult(ALfpMult(DECO_FRACTION,
+ aluPow(DECO_MULTIPLIER, int2ALfp(index))),
+ LATE_LINE_LENGTH[0]),
+ (int2ALfp(1) + ALfpMult(density, LATE_LINE_MULTIPLIER)));
+ State->DecoTap[index] = (ALuint)ALfp2int(ALfpMult(length, int2ALfp(frequency)));
+ }
+}
+
+// Update the late reverb gains, line lengths, and line coefficients.
+static ALvoid UpdateLateLines(ALfp reverbGain, ALfp lateGain, ALfp xMix, ALfp density, ALfp decayTime, ALfp diffusion, ALfp hfRatio, ALfp cw, ALuint frequency, ALverbState *State)
+{
+ ALfp 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 = ALfpMult(ALfpMult(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 = ALfpDiv((LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
+ LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]),
+ int2ALfp(4));
+ length = ALfpMult(length, (int2ALfp(1) + ALfpMult(density, LATE_LINE_MULTIPLIER)));
+ State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length,
+ decayTime));
+
+ // Calculate the all-pass feed-back and feed-forward coefficient.
+ State->Late.ApFeedCoeff = ALfpMult(float2ALfp(0.5f), aluPow(diffusion, int2ALfp(2)));
+
+ 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 = ALfpMult(LATE_LINE_LENGTH[index],
+ (int2ALfp(1) + ALfpMult(density, LATE_LINE_MULTIPLIER)));
+
+ // Calculate the delay offset for each cyclical delay line.
+ State->Late.Offset[index] = (ALuint)(ALfp2int(ALfpMult(length, int2ALfp(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] = ALfpMult(State->Late.Coeff[index], xMix);
+ }
+}
+
+// Update the echo gain, line offset, line coefficients, and mixing
+// coefficients.
+static ALvoid UpdateEchoLine(ALfp reverbGain, ALfp lateGain, ALfp echoTime, ALfp decayTime, ALfp diffusion, ALfp echoDepth, ALfp hfRatio, ALfp cw, ALuint frequency, ALverbState *State)
+{
+ // Update the offset and coefficient for the echo delay line.
+ State->Echo.Offset = (ALuint)(ALfp2int(ALfpMult(echoTime, int2ALfp(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 = ALfpMult(float2ALfp(0.5f), aluPow(diffusion, int2ALfp(2)));
+
+ // 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] = ALfpMult(ALfpMult(reverbGain, lateGain), echoDepth);
+ State->Echo.MixCoeff[1] = (int2ALfp(1) - ALfpMult(ALfpMult(echoDepth, float2ALfp(0.5f)), (int2ALfp(1) - diffusion)));
+}
+
+// Update the early and late 3D panning gains.
+static ALvoid Update3DPanning(const ALCdevice *Device, const ALfp *ReflectionsPan, const ALfp *LateReverbPan, ALverbState *State)
+{
+ ALfp earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
+ ReflectionsPan[2] };
+ ALfp latePan[3] = { LateReverbPan[0], LateReverbPan[1],
+ LateReverbPan[2] };
+ const ALfp *speakerGain;
+ ALfp dirGain;
+ ALfp length;
+ ALuint index;
+ ALint pos;
+
+ // Calculate the 3D-panning gains for the early reflections and late
+ // reverb.
+ length = (ALfpMult(earlyPan[0],earlyPan[0]) + ALfpMult(earlyPan[1],earlyPan[1]) + ALfpMult(earlyPan[2],earlyPan[2]));
+ if(length > int2ALfp(1))
+ {
+ length = ALfpDiv(int2ALfp(1), aluSqrt(length));
+ earlyPan[0] = ALfpMult(earlyPan[0], length);
+ earlyPan[1] = ALfpMult(earlyPan[1], length);
+ earlyPan[2] = ALfpMult(earlyPan[2], length);
+ }
+ length = (ALfpMult(latePan[0],latePan[0]) + ALfpMult(latePan[1],latePan[1]) + ALfpMult(latePan[2],latePan[2]));
+ if(length > int2ALfp(1))
+ {
+ length = ALfpDiv(int2ALfp(1), aluSqrt(length));
+ latePan[0] = ALfpMult(latePan[0], length);
+ latePan[1] = ALfpMult(latePan[1], length);
+ latePan[2] = ALfpMult(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((ALfpMult(earlyPan[0], earlyPan[0]) + ALfpMult(earlyPan[2], earlyPan[2])));
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ State->Early.PanGain[index] = int2ALfp(0);
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ State->Early.PanGain[chan] = (int2ALfp(1) + ALfpMult((speakerGain[chan]-int2ALfp(1)),dirGain));
+ }
+
+
+ pos = aluCart2LUTpos(latePan[2], latePan[0]);
+ speakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+ dirGain = aluSqrt((ALfpMult(latePan[0], latePan[0]) + ALfpMult(latePan[2], latePan[2])));
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ State->Late.PanGain[index] = int2ALfp(0);
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ State->Late.PanGain[chan] = (int2ALfp(1) + ALfpMult((speakerGain[chan]-int2ALfp(1)),dirGain));
+ }
+}
+
+// Basic delay line input/output routines.
+static __inline ALfp DelayLineOut(DelayLine *Delay, ALuint offset)
+{
+ return Delay->Line[offset&Delay->Mask];
+}
+
+static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfp in)
+{
+ Delay->Line[offset&Delay->Mask] = in;
+}
+
+// Attenuated delay line output routine.
+static __inline ALfp AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfp coeff)
+{
+ return ALfpMult(coeff, Delay->Line[offset&Delay->Mask]);
+}
+
+// Basic attenuated all-pass input/output routine.
+static __inline ALfp AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfp in, ALfp feedCoeff, ALfp coeff)
+{
+ ALfp out, feed;
+
+ out = DelayLineOut(Delay, outOffset);
+ feed = ALfpMult(feedCoeff, in);
+ DelayLineIn(Delay, inOffset, (ALfpMult(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 (ALfpMult(coeff, out) - feed);
+}
+
+// Given an input sample, this function produces modulation for the late
+// reverb.
+static __inline ALfp EAXModulation(ALverbState *State, ALfp in)
+{
+ ALfp sinus, frac;
+ ALuint offset;
+ ALfp 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 = (int2ALfp(1) - __cos(ALfpDiv(ALfpMult(float2ALfp(2.0f * M_PI), int2ALfp(State->Mod.Index)), int2ALfp(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 = (int2ALfp(1) + ALfpMult(State->Mod.Filter, sinus));
+ offset = (ALuint)ALfp2int(frac);
+ frac = (frac - int2ALfp(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 ALfp 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, ALfp in, ALfp *out)
+{
+ ALfp 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 = ALfpMult((d[0] + d[1] + d[2] + d[3]), float2ALfp(0.5f));
+ // The junction is loaded with the input here.
+ v = (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] = ALfpMult(State->Early.Gain, f[0]);
+ out[1] = ALfpMult(State->Early.Gain, f[1]);
+ out[2] = ALfpMult(State->Early.Gain, f[2]);
+ out[3] = ALfpMult(State->Early.Gain, f[3]);
+}
+
+// All-pass input/output routine for late reverb.
+static __inline ALfp LateAllPassInOut(ALverbState *State, ALuint index, ALfp 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 ALfp 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 ALfp LateLowPassInOut(ALverbState *State, ALuint index, ALfp 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, ALfp *in, ALfp *out)
+{
+ ALfp 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] + ALfpMult(State->Late.MixCoeff, ( d[1] + -1*d[2] + d[3])));
+ f[1] = (d[1] + ALfpMult(State->Late.MixCoeff, (-1*d[0] + d[2] + d[3])));
+ f[2] = (d[2] + ALfpMult(State->Late.MixCoeff, ( d[0] + -1*d[1] + d[3])));
+ f[3] = (d[3] + ALfpMult(State->Late.MixCoeff, (-1*d[0] + -1*d[1] + -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] = ALfpMult(State->Late.Gain, f[0]);
+ out[1] = ALfpMult(State->Late.Gain, f[1]);
+ out[2] = ALfpMult(State->Late.Gain, f[2]);
+ out[3] = ALfpMult(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, ALfp in, ALfp *late)
+{
+ ALfp 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 = ALfpMult(State->Echo.MixCoeff[0], feed);
+ late[0] = (ALfpMult(State->Echo.MixCoeff[1], late[0]) + out);
+ late[1] = (ALfpMult(State->Echo.MixCoeff[1], late[1]) + out);
+ late[2] = (ALfpMult(State->Echo.MixCoeff[1], late[2]) + out);
+ late[3] = (ALfpMult(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 = (feed + ALfpMult(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, ALfp in, ALfp *early, ALfp *late)
+{
+ ALfp 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 = ALfpMult(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, ALfp in, ALfp *early, ALfp *late)
+{
+ ALfp 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 = ALfpMult(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] = ALfp2int(ALfpMult(EARLY_LINE_LENGTH[index],
+ int2ALfp(frequency)));
+ State->Late.ApOffset[index] = ALfp2int(ALfpMult(ALLPASS_LINE_LENGTH[index],
+ int2ALfp(frequency)));
+ }
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ State->Gain[index] = int2ALfp(0);
+ for(index = 0;index < Device->NumChan;index++)
+ {
+ Channel chan = Device->Speaker2Chan[index];
+ State->Gain[chan] = int2ALfp(1);
+ }
+
+ 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,
+ ALfpDiv(MODULATION_FILTER_CONST, int2ALfp(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] = ALfp2int(ALfpMult(EARLY_LINE_LENGTH[index],
+ int2ALfp(frequency)));
+ State->Late.ApOffset[index] = ALfp2int(ALfpMult(ALLPASS_LINE_LENGTH[index],
+ int2ALfp(frequency)));
+ }
+
+ // The echo all-pass filter line length is static, so its offset only
+ // needs to be calculated once.
+ State->Echo.ApOffset = ALfp2int(ALfpMult(ECHO_ALLPASS_LENGTH, int2ALfp(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;
+ ALfp 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 = ALfpDiv(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 < int2ALfp(1))
+ 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;
+ ALfp 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 = ALfpDiv(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 < int2ALfp(1))
+ 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 ALfp *SamplesIn, ALfp (*SamplesOut)[MAXCHANNELS])
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint index;
+ ALfp early[4], late[4], out[4];
+ ALfp gain = Slot->Gain;
+ const ALfp *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] = ALfpMult((early[0] + late[0]), gain);
+ out[1] = ALfpMult((early[1] + late[1]), gain);
+#ifdef APPORTABLE_OPTIMIZED_OUT
+ out[2] = ALfpMult((early[2] + late[2]), gain);
+ out[3] = ALfpMult((early[3] + late[3]), gain);
+#endif
+
+ // Output the results.
+ SamplesOut[index][FRONT_LEFT] = (SamplesOut[index][FRONT_LEFT] + ALfpMult(panGain[FRONT_LEFT] , out[0]));
+ SamplesOut[index][FRONT_RIGHT] = (SamplesOut[index][FRONT_RIGHT] + ALfpMult(panGain[FRONT_RIGHT] , out[1]));
+#ifdef APPORTABLE_OPTIMIZED_OUT
+ SamplesOut[index][FRONT_CENTER] = (SamplesOut[index][FRONT_CENTER] + ALfpMult(panGain[FRONT_CENTER] , out[3]));
+ SamplesOut[index][SIDE_LEFT] = (SamplesOut[index][SIDE_LEFT] + ALfpMult(panGain[SIDE_LEFT] , out[0]));
+ SamplesOut[index][SIDE_RIGHT] = (SamplesOut[index][SIDE_RIGHT] + ALfpMult(panGain[SIDE_RIGHT] , out[1]));
+ SamplesOut[index][BACK_LEFT] = (SamplesOut[index][BACK_LEFT] + ALfpMult(panGain[BACK_LEFT] , out[0]));
+ SamplesOut[index][BACK_RIGHT] = (SamplesOut[index][BACK_RIGHT] + ALfpMult(panGain[BACK_RIGHT] , out[1]));
+ SamplesOut[index][BACK_CENTER] = (SamplesOut[index][BACK_CENTER] + ALfpMult(panGain[BACK_CENTER] , out[2]));
+#endif
+ }
+}
+
+// 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 ALfp *SamplesIn, ALfp (*SamplesOut)[MAXCHANNELS])
+{
+ ALverbState *State = (ALverbState*)effect;
+ ALuint index;
+ ALfp early[4], late[4];
+ ALfp 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] = (SamplesOut[index][FRONT_LEFT] +
+ ALfpMult((ALfpMult(State->Early.PanGain[FRONT_LEFT],early[0]) +
+ ALfpMult(State->Late.PanGain[FRONT_LEFT],late[0])), gain));
+ SamplesOut[index][FRONT_RIGHT] = (SamplesOut[index][FRONT_RIGHT] +
+ ALfpMult((ALfpMult(State->Early.PanGain[FRONT_RIGHT],early[1]) +
+ ALfpMult(State->Late.PanGain[FRONT_RIGHT],late[1])), gain));
+#ifdef APPORTABLE_OPTIMIZED_OUT
+ SamplesOut[index][FRONT_CENTER] = (SamplesOut[index][FRONT_CENTER] +
+ ALfpMult((ALfpMult(State->Early.PanGain[FRONT_LEFT],early[3]) +
+ ALfpMult(State->Late.PanGain[FRONT_CENTER],late[3])), gain));
+ SamplesOut[index][SIDE_LEFT] = (SamplesOut[index][SIDE_LEFT] +
+ ALfpMult((ALfpMult(State->Early.PanGain[SIDE_LEFT],early[0]) +
+ ALfpMult(State->Late.PanGain[SIDE_LEFT],late[0])), gain));
+ SamplesOut[index][SIDE_RIGHT] = (SamplesOut[index][SIDE_RIGHT] +
+ ALfpMult((ALfpMult(State->Early.PanGain[SIDE_RIGHT],early[1]) +
+ ALfpMult(State->Late.PanGain[SIDE_RIGHT],late[1])), gain));
+ SamplesOut[index][BACK_LEFT] = (SamplesOut[index][BACK_LEFT] +
+ ALfpMult((ALfpMult(State->Early.PanGain[BACK_LEFT],early[0]) +
+ ALfpMult(State->Late.PanGain[BACK_LEFT],late[0])), gain));
+ SamplesOut[index][BACK_RIGHT] = (SamplesOut[index][BACK_RIGHT] +
+ ALfpMult((ALfpMult(State->Early.PanGain[BACK_RIGHT],early[1]) +
+ ALfpMult(State->Late.PanGain[BACK_RIGHT],late[1])), gain));
+ SamplesOut[index][BACK_CENTER] = (SamplesOut[index][BACK_CENTER] +
+ ALfpMult((ALfpMult(State->Early.PanGain[BACK_CENTER],early[2]) +
+ ALfpMult(State->Late.PanGain[BACK_CENTER],late[2])), gain));
+#endif
+
+ }
+}
+
+// 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 = int2ALfp(0);
+ State->LpFilter.history[0] = int2ALfp(0);
+ State->LpFilter.history[1] = int2ALfp(0);
+
+ State->Mod.Delay.Mask = 0;
+ State->Mod.Delay.Line = NULL;
+ State->Mod.Index = 0;
+ State->Mod.Range = 1;
+ State->Mod.Depth = int2ALfp(0);
+ State->Mod.Coeff = int2ALfp(0);
+ State->Mod.Filter = int2ALfp(0);
+
+ State->Delay.Mask = 0;
+ State->Delay.Line = NULL;
+ State->DelayTap[0] = 0;
+ State->DelayTap[1] = 0;
+
+ State->Early.Gain = int2ALfp(0);
+ for(index = 0;index < 4;index++)
+ {
+ State->Early.Coeff[index] = int2ALfp(0);
+ 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 = int2ALfp(0);
+ State->Late.DensityGain = int2ALfp(0);
+ State->Late.ApFeedCoeff = int2ALfp(0);
+ State->Late.MixCoeff = int2ALfp(0);
+ for(index = 0;index < 4;index++)
+ {
+ State->Late.ApCoeff[index] = int2ALfp(0);
+ State->Late.ApDelay[index].Mask = 0;
+ State->Late.ApDelay[index].Line = NULL;
+ State->Late.ApOffset[index] = 0;
+
+ State->Late.Coeff[index] = int2ALfp(0);
+ State->Late.Delay[index].Mask = 0;
+ State->Late.Delay[index].Line = NULL;
+ State->Late.Offset[index] = 0;
+
+ State->Late.LpCoeff[index] = int2ALfp(0);
+ State->Late.LpSample[index] = int2ALfp(0);
+ }
+
+ for(index = 0;index < MAXCHANNELS;index++)
+ {
+ State->Early.PanGain[index] = int2ALfp(0);
+ State->Late.PanGain[index] = int2ALfp(0);
+ }
+
+ State->Echo.DensityGain = int2ALfp(0);
+ State->Echo.Delay.Mask = 0;
+ State->Echo.Delay.Line = NULL;
+ State->Echo.ApDelay.Mask = 0;
+ State->Echo.ApDelay.Line = NULL;
+ State->Echo.Coeff = int2ALfp(0);
+ State->Echo.ApFeedCoeff = int2ALfp(0);
+ State->Echo.ApCoeff = int2ALfp(0);
+ State->Echo.Offset = 0;
+ State->Echo.ApOffset = 0;
+ State->Echo.LpCoeff = int2ALfp(0);
+ State->Echo.LpSample = int2ALfp(0);
+ State->Echo.MixCoeff[0] = int2ALfp(0);
+ State->Echo.MixCoeff[1] = int2ALfp(0);
+
+ 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;
+}
diff --git a/jni/OpenAL/Alc/alcRing.c b/jni/OpenAL/Alc/alcRing.c
new file mode 100644
index 0000000..3361eb6
--- /dev/null
+++ b/jni/OpenAL/Alc/alcRing.c
@@ -0,0 +1,131 @@
+/**
+ * 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
+#include
+
+#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);
+}
diff --git a/jni/OpenAL/Alc/alcThread.c b/jni/OpenAL/Alc/alcThread.c
new file mode 100644
index 0000000..582dfd8
--- /dev/null
+++ b/jni/OpenAL/Alc/alcThread.c
@@ -0,0 +1,128 @@
+/**
+ * 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
+
+#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
+
+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
diff --git a/jni/OpenAL/Alc/alsa.c b/jni/OpenAL/Alc/alsa.c
new file mode 100644
index 0000000..a7e8758
--- /dev/null
+++ b/jni/OpenAL/Alc/alsa.c
@@ -0,0 +1,1048 @@
+/**
+ * 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
+#include
+#include
+#ifdef HAVE_DLFCN_H
+#include
+#endif
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include
+
+
+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);
+ }
+}
diff --git a/jni/OpenAL/Alc/apportable_openal_funcs.h b/jni/OpenAL/Alc/apportable_openal_funcs.h
new file mode 100644
index 0000000..f970e60
--- /dev/null
+++ b/jni/OpenAL/Alc/apportable_openal_funcs.h
@@ -0,0 +1,11 @@
+typedef struct {
+ void (*alc_android_suspend)();
+ void (*alc_android_resume)();
+ void (*alc_android_set_java_vm)(JavaVM*);
+#ifdef HAVE_OPENSLES
+ SLEngineItf (*alc_opensles_get_native_audio_engine_engine)();
+ SLEngineItf (*alc_opensles_get_native_audio_output_mix)();
+ SLresult (*alc_opensles_create_native_audio_engine)();
+#endif
+} ApportableOpenALFuncs;
+ApportableOpenALFuncs apportableOpenALFuncs;
diff --git a/jni/OpenAL/Alc/audiotrack.c b/jni/OpenAL/Alc/audiotrack.c
new file mode 100755
index 0000000..536b628
--- /dev/null
+++ b/jni/OpenAL/Alc/audiotrack.c
@@ -0,0 +1,320 @@
+/**
+ * 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
+#include
+#include
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include "apportable_openal_funcs.h"
+
+static const ALCchar android_device[] = "Android Default";
+
+static JavaVM* javaVM = NULL;
+static JNIEnv* env;
+
+static jclass cAudioTrack = NULL;
+
+static jmethodID mAudioTrack;
+static jmethodID mGetMinBufferSize;
+static jmethodID mPlay;
+static jmethodID mPause;
+static jmethodID mStop;
+static jmethodID mRelease;
+static jmethodID mWrite;
+
+static int suspended = 0;
+static int audioTrackPlaying = 0;
+
+typedef struct
+{
+ pthread_t thread;
+ volatile int running;
+} AndroidData;
+
+#define STREAM_MUSIC 3
+#define CHANNEL_CONFIGURATION_MONO 2
+#define CHANNEL_CONFIGURATION_STEREO 3
+#define ENCODING_PCM_8BIT 3
+#define ENCODING_PCM_16BIT 2
+#define MODE_STREAM 1
+
+static void* thread_function(void* arg)
+{
+ ALCdevice* device = (ALCdevice*)arg;
+ AndroidData* data = (AndroidData*)device->ExtraData;
+
+ JNIEnv* env;
+ (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
+
+ (*env)->PushLocalFrame(env, 2);
+
+ int sampleRateInHz = device->Frequency;
+ int channelConfig = ChannelsFromDevFmt(device->FmtChans) == 1 ? CHANNEL_CONFIGURATION_MONO : CHANNEL_CONFIGURATION_STEREO;
+ int audioFormat = BytesFromDevFmt(device->FmtType) == 1 ? ENCODING_PCM_8BIT : ENCODING_PCM_16BIT;
+
+ int bufferSizeInBytes = (*env)->CallStaticIntMethod(env, cAudioTrack,
+ mGetMinBufferSize, sampleRateInHz, channelConfig, audioFormat);
+
+ // Suggestion from Eric Wing
+ /* According to the author Martins Mozelko, I should multiply bufferSizeInBytes to tune performance.
+ Say, multiply by 2.
+ But making this number smaller seems to reduce latency...
+ I have tried dividing by 2, 4, and 8. 8 refuses to play any sound.
+ It seems that this just divides out the multiplication of NumUpdates (default=4)
+ which returns it to min buffer size.
+ bufferSizeInBytes is used in multiple places and
+ bufferSizeInSamples is tied directly to bufferSizeInBytes though, so we need to be careful
+ about what we want to change.
+ I'm assuming Martins is correct and this is the indeed the place we want to change it.
+ Dividing out the bufferSizeInSamples separately and skipping the multiply did not work.
+ Omitting the multiply and not dividing did work, but the buffers may be unnecessarily large.
+ */
+ bufferSizeInBytes = bufferSizeInBytes / device->NumUpdates;
+
+ int bufferSizeInSamples = bufferSizeInBytes / FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+
+ jobject track = (*env)->NewObject(env, cAudioTrack, mAudioTrack,
+ STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat, device->NumUpdates * bufferSizeInBytes, MODE_STREAM);
+
+ (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay);
+ audioTrackPlaying = 1;
+
+ jarray buffer = (*env)->NewByteArray(env, bufferSizeInBytes);
+
+ while (data->running)
+ {
+ if (suspended) {
+ if (audioTrackPlaying) {
+ (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mPause);
+ audioTrackPlaying = 0;
+ }
+ usleep(5000);
+ continue;
+ } else if (!audioTrackPlaying) {
+ (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay);
+ audioTrackPlaying = 1;
+ }
+
+ void* pBuffer = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL);
+
+ if (pBuffer)
+ {
+ aluMixData(device, pBuffer, bufferSizeInSamples);
+ (*env)->ReleasePrimitiveArrayCritical(env, buffer, pBuffer, 0);
+
+ (*env)->CallNonvirtualIntMethod(env, track, cAudioTrack, mWrite, buffer, 0, bufferSizeInBytes);
+ }
+ else
+ {
+ AL_PRINT("Failed to get pointer to array bytes");
+ }
+ }
+
+ (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop);
+ (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease);
+
+ (*env)->PopLocalFrame(env, NULL);
+
+ (*javaVM)->DetachCurrentThread(javaVM);
+ return NULL;
+}
+
+static ALCboolean android_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+ (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
+ AndroidData* data;
+ int channels;
+ int bytes;
+
+ if (!cAudioTrack)
+ {
+ /* Cache AudioTrack class and it's method id's
+ * And do this only once!
+ */
+
+ cAudioTrack = (*env)->FindClass(env, "android/media/AudioTrack");
+ if (!cAudioTrack)
+ {
+ AL_PRINT("android.media.AudioTrack class is not found. Are you running at least 1.5 version?");
+ return ALC_FALSE;
+ }
+
+ cAudioTrack = (*env)->NewGlobalRef(env, cAudioTrack);
+
+ mAudioTrack = (*env)->GetMethodID(env, cAudioTrack, "", "(IIIIII)V");
+ mGetMinBufferSize = (*env)->GetStaticMethodID(env, cAudioTrack, "getMinBufferSize", "(III)I");
+ mPlay = (*env)->GetMethodID(env, cAudioTrack, "play", "()V");
+ mPause = (*env)->GetMethodID(env, cAudioTrack, "pause", "()V");
+ mStop = (*env)->GetMethodID(env, cAudioTrack, "stop", "()V");
+ mRelease = (*env)->GetMethodID(env, cAudioTrack, "release", "()V");
+ mWrite = (*env)->GetMethodID(env, cAudioTrack, "write", "([BII)I");
+ }
+
+ if (!deviceName)
+ {
+ deviceName = android_device;
+ }
+ else if (strcmp(deviceName, android_device) != 0)
+ {
+ return ALC_FALSE;
+ }
+
+ data = (AndroidData*)calloc(1, sizeof(*data));
+ device->szDeviceName = strdup(deviceName);
+ device->ExtraData = data;
+ return ALC_TRUE;
+}
+
+static void android_close_playback(ALCdevice *device)
+{
+ AndroidData* data = (AndroidData*)device->ExtraData;
+ if (data != NULL)
+ {
+ free(data);
+ device->ExtraData = NULL;
+ }
+}
+
+static ALCboolean android_reset_playback(ALCdevice *device)
+{
+ AndroidData* data = (AndroidData*)device->ExtraData;
+
+ // if (ChannelsFromDevFmt(device->FmtChans) >= 2)
+ // {
+ // device->Format = BytesFromDevFmt(device->FmtType) >= 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8;
+ // }
+ // else
+ // {
+ // device->Format = BytesFromDevFmt(device->FmtType) >= 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8;
+ // }
+
+ SetDefaultChannelOrder(device);
+
+ data->running = 1;
+ pthread_create(&data->thread, NULL, thread_function, device);
+
+ return ALC_TRUE;
+}
+
+static void android_stop_playback(ALCdevice *device)
+{
+ AndroidData* data = (AndroidData*)device->ExtraData;
+
+ if (data->running)
+ {
+ data->running = 0;
+ pthread_join(data->thread, NULL);
+ }
+}
+
+static ALCboolean android_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ (void)pDevice;
+ (void)deviceName;
+ return ALC_FALSE;
+}
+
+static void android_close_capture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void android_start_capture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void android_stop_capture(ALCdevice *pDevice)
+{
+ (void)pDevice;
+}
+
+static void android_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+ (void)pDevice;
+ (void)pBuffer;
+ (void)lSamples;
+}
+
+static ALCuint android_available_samples(ALCdevice *pDevice)
+{
+ (void)pDevice;
+ return 0;
+}
+
+static const BackendFuncs android_funcs = {
+ android_open_playback,
+ android_close_playback,
+ android_reset_playback,
+ android_stop_playback,
+ android_open_capture,
+ android_close_capture,
+ android_start_capture,
+ android_stop_capture,
+ android_capture_samples,
+ android_available_samples
+};
+
+static void alc_audiotrack_suspend()
+{
+ suspended = 1;
+}
+
+static void alc_audiotrack_resume()
+{
+ suspended = 0;
+}
+
+static void alc_audiotrack_set_java_vm(JavaVM *vm)
+{
+ javaVM = vm;
+}
+
+void alc_audiotrack_init(BackendFuncs *func_list)
+{
+ *func_list = android_funcs;
+ apportableOpenALFuncs.alc_android_suspend = alc_audiotrack_suspend;
+ apportableOpenALFuncs.alc_android_resume = alc_audiotrack_resume;
+ apportableOpenALFuncs.alc_android_set_java_vm = alc_audiotrack_set_java_vm;
+}
+
+void alc_audiotrack_deinit(void)
+{
+ /* release cached AudioTrack class */
+ (*env)->DeleteGlobalRef(env, cAudioTrack);
+ (*javaVM)->DetachCurrentThread(javaVM);
+}
+
+void alc_audiotrack_probe(int type)
+{
+ if (type == DEVICE_PROBE)
+ {
+ AppendDeviceList(android_device);
+ }
+ else if (type == ALL_DEVICE_PROBE)
+ {
+ AppendAllDeviceList(android_device);
+ }
+}
diff --git a/jni/OpenAL/Alc/bs2b.c b/jni/OpenAL/Alc/bs2b.c
new file mode 100644
index 0000000..36f946a
--- /dev/null
+++ b/jni/OpenAL/Alc/bs2b.c
@@ -0,0 +1,209 @@
+/*-
+ * 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
+
+#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, ALfp *ALsample)
+{
+ //FIXME fully convert to fixed point math
+ float sample[2];
+ sample[0] = ALfp2float(ALsample[0]);
+ sample[1] = ALfp2float(ALsample[1]);
+
+ /* 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
+
+ ALsample[0] = float2ALfp(sample[0]);
+ ALsample[1] = float2ALfp(sample[1]);
+} /* bs2b_cross_feed */
diff --git a/jni/OpenAL/Alc/dsound.c b/jni/OpenAL/Alc/dsound.c
new file mode 100644
index 0000000..26e6d46
--- /dev/null
+++ b/jni/OpenAL/Alc/dsound.c
@@ -0,0 +1,612 @@
+/**
+ * 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
+#include
+#include
+
+#include
+#include
+#include
+#ifndef _WAVEFORMATEXTENSIBLE_
+#include
+#include
+#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);
+ }
+ }
+}
diff --git a/jni/OpenAL/Alc/mixer.c b/jni/OpenAL/Alc/mixer.c
new file mode 100644
index 0000000..036441f
--- /dev/null
+++ b/jni/OpenAL/Alc/mixer.c
@@ -0,0 +1,813 @@
+/**
+ * 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
+#include
+#include
+#include
+#include
+
+#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 ALdfp point32(const ALfp *vals, ALint step, ALint frac)
+{ return vals[0]; (void)step; (void)frac; }
+static __inline ALdfp lerp32(const ALfp *vals, ALint step, ALint frac)
+{ return lerp(vals[0], vals[step], ALfpMult(int2ALfp(frac), ALfpDiv(int2ALfp(1),int2ALfp(FRACTIONONE)))); }
+static __inline ALdfp cubic32(const ALfp *vals, ALint step, ALint frac)
+{ return cubic(vals[-step], vals[0], vals[step], vals[step+step],
+ ALfpMult(int2ALfp(frac), ALfpDiv(int2ALfp(1),int2ALfp(FRACTIONONE)))); }
+
+static __inline ALdfp point16(const ALshort *vals, ALint step, ALint frac)
+{ return ALfpMult(int2ALfp(vals[0]), float2ALfp(1.0/32767.0)); (void)step; (void)frac; }
+static __inline ALdfp lerp16(const ALshort *vals, ALint step, ALint frac)
+{ return ALfpMult(lerp(int2ALfp(vals[0]), int2ALfp(vals[step]), ALfpMult(int2ALfp(frac), ALfpDiv(int2ALfp(1),int2ALfp(FRACTIONONE)))),
+ float2ALfp(1.0/32767.0)); }
+static __inline ALdfp cubic16(const ALshort *vals, ALint step, ALint frac)
+{ return ALfpMult(cubic(int2ALfp(vals[-step]), int2ALfp(vals[0]), int2ALfp(vals[step]), int2ALfp(vals[step+step]),
+ ALfpMult(int2ALfp(frac), ALfpDiv(int2ALfp(1),int2ALfp(FRACTIONONE)))), float2ALfp(1.0/32767.0)); }
+
+static __inline ALdfp point8(const ALubyte *vals, ALint step, ALint frac)
+{ return ALfpMult(int2ALfp((int)vals[0]-128), float2ALfp(1.0/127.0)); (void)step; (void)frac; }
+static __inline ALdfp lerp8(const ALubyte *vals, ALint step, ALint frac)
+{ return ALfpMult((lerp(int2ALfp(vals[0]), int2ALfp(vals[step]),
+ ALfpMult(int2ALfp(frac), ALfpDiv(int2ALfp(1),int2ALfp(FRACTIONONE))))-
+ int2ALfp(128)),
+ float2ALfp(1.0/127.0)); }
+static __inline ALdfp cubic8(const ALubyte *vals, ALint step, ALint frac)
+{ return ALfpMult((cubic(int2ALfp(vals[-step]), int2ALfp(vals[0]), int2ALfp(vals[step]), int2ALfp(vals[step+step]),
+ ALfpMult(int2ALfp(frac), ALfpDiv(int2ALfp(1),int2ALfp(FRACTIONONE))))-
+ int2ALfp(128)),
+ float2ALfp(1.0/127.0)); }
+
+
+#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) \
+{ \
+ ALfp (*DryBuffer)[MAXCHANNELS]; \
+ ALfp *ClickRemoval, *PendingClicks; \
+ ALuint pos, frac; \
+ ALfp DrySend[MAXCHANNELS]; \
+ FILTER *DryFilter; \
+ ALuint BufferIdx; \
+ ALuint increment; \
+ ALuint out, c; \
+ ALfp 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] = (ClickRemoval[c] - ALfpMult(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] = (DryBuffer[OutPos][c] + ALfpMult(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] = (PendingClicks[c] + ALfpMult(value,DrySend[c])); \
+ } \
+ \
+ for(out = 0;out < Device->NumAuxSends;out++) \
+ { \
+ ALfp WetSend; \
+ ALfp *WetBuffer; \
+ ALfp *WetClickRemoval; \
+ ALfp *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] = (WetClickRemoval[0] - ALfpMult(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] = (WetBuffer[OutPos] + ALfpMult(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] = (WetPendingClicks[0] + ALfpMult(value,WetSend)); \
+ } \
+ } \
+ *DataPosInt += pos; \
+ *DataPosFrac = frac; \
+}
+
+DECL_TEMPLATE(ALfp, point32)
+DECL_TEMPLATE(ALfp, lerp32)
+DECL_TEMPLATE(ALfp, 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) \
+{ \
+ const ALuint Channels = chnct; \
+ const ALfp scaler = ALfpDiv(int2ALfp(1),int2ALfp(chnct)); \
+ ALfp (*DryBuffer)[MAXCHANNELS]; \
+ ALfp *ClickRemoval, *PendingClicks; \
+ ALuint pos, frac; \
+ ALfp DrySend[chnct][MAXCHANNELS]; \
+ FILTER *DryFilter; \
+ ALuint BufferIdx; \
+ ALuint increment; \
+ ALuint i, out, c; \
+ ALfp 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] = (ClickRemoval[c] - ALfpMult(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] = (DryBuffer[OutPos][c] + ALfpMult(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] = (PendingClicks[c] + ALfpMult(value,DrySend[i][c])); \
+ } \
+ } \
+ \
+ for(out = 0;out < Device->NumAuxSends;out++) \
+ { \
+ ALfp WetSend; \
+ ALfp *WetBuffer; \
+ ALfp *WetClickRemoval; \
+ ALfp *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] = (WetClickRemoval[0] - ALfpMult(ALfpMult(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] = (WetBuffer[OutPos] + ALfpMult(ALfpMult(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] = (WetPendingClicks[0] + ALfpMult(ALfpMult(value,WetSend), scaler)); \
+ } \
+ } \
+ } \
+ *DataPosInt += pos; \
+ *DataPosFrac = frac; \
+}
+
+DECL_TEMPLATE(ALfp, 2, point32)
+DECL_TEMPLATE(ALfp, 2, lerp32)
+DECL_TEMPLATE(ALfp, 2, cubic32)
+
+DECL_TEMPLATE(ALshort, 2, point16)
+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(ALfp, 4, point32)
+DECL_TEMPLATE(ALfp, 4, lerp32)
+DECL_TEMPLATE(ALfp, 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(ALfp, 6, point32)
+DECL_TEMPLATE(ALfp, 6, lerp32)
+DECL_TEMPLATE(ALfp, 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(ALfp, 7, point32)
+DECL_TEMPLATE(ALfp, 7, lerp32)
+DECL_TEMPLATE(ALfp, 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(ALfp, 8, point32)
+DECL_TEMPLATE(ALfp, 8, lerp32)
+DECL_TEMPLATE(ALfp, 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(ALfp, point32)
+DECL_TEMPLATE(ALfp, lerp32)
+DECL_TEMPLATE(ALfp, 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_ALfp_##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;
+}
diff --git a/jni/OpenAL/Alc/null.c b/jni/OpenAL/Alc/null.c
new file mode 100644
index 0000000..75fc883
--- /dev/null
+++ b/jni/OpenAL/Alc/null.c
@@ -0,0 +1,182 @@
+/**
+ * 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
+#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 = ((ALuint)((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);
+}
diff --git a/jni/OpenAL/Alc/opensles.c b/jni/OpenAL/Alc/opensles.c
new file mode 100644
index 0000000..44cedea
--- /dev/null
+++ b/jni/OpenAL/Alc/opensles.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This is an OpenAL backend for Android using the native audio APIs based on OpenSL ES 1.0.1.
+ * It is based on source code for the native-audio sample app bundled with NDK.
+ */
+
+#include
+#include
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include "verde/verde_helpers.h"
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "OpenAL"
+
+// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
+#if 1
+#define LOGV(...) VERDE_DEBUG(__VA_ARGS__)
+#endif
+
+// for native audio
+#include
+#include
+
+#include "apportable_openal_funcs.h"
+
+// engine interfaces
+static SLObjectItf engineObject = NULL;
+static SLEngineItf engineEngine;
+
+// output mix interfaces
+static SLObjectItf outputMixObject = NULL;
+
+// buffer queue player interfaces
+static SLObjectItf bqPlayerObject = NULL;
+static SLPlayItf bqPlayerPlay;
+static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
+
+// this callback handler is called every time a buffer finishes playing
+static void opensles_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
+{
+ // LOGV("opensles_callback");
+#define bufferSize (1024*4)
+ static char buffer0[bufferSize], buffer1[bufferSize];
+ static char * const buffers[2] = {buffer0, buffer1};
+ static unsigned bufferIndex = 0;
+#if 0
+ static unsigned nextCount = ~0;
+ static char nextBuffer[1024] = "Hello, world!";
+ static unsigned nextSize = 1024;
+#endif
+
+ assert(bq == bqPlayerBufferQueue);
+ assert(NULL != context);
+ ALCdevice *pDevice = (ALCdevice *) context;
+ ALint frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+ void *buffer = buffers[bufferIndex];
+ // LOGV("bq=%p, pDevice=%p, frameSize=%u, buffer=%p, bufferIndex=%u, bufferSize=%u", bq, pDevice, frameSize, buffer, bufferIndex, bufferSize);
+ bufferIndex ^= 1;
+ // LOGV("aluMixData");
+
+ aluMixData(pDevice, buffer, bufferSize/frameSize);
+
+ // LOGV("Enqueue2");
+#if 0
+ // for streaming playback, replace this test by logic to find and fill the next buffer
+ if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) {
+ SLresult result;
+ // enqueue another buffer
+ result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
+ // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
+ // which for this code example would indicate a programming error
+ assert(SL_RESULT_SUCCESS == result);
+ }
+#else
+ SLresult result;
+ result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer, bufferSize);
+ assert(SL_RESULT_SUCCESS == result);
+#endif
+}
+
+
+static const ALCchar opensles_device[] = "OpenSL ES";
+
+// Apportable extensions
+SLEngineItf alc_opensles_get_native_audio_engine_engine()
+{
+ return engineEngine;
+}
+
+SLEngineItf alc_opensles_get_native_audio_output_mix()
+{
+ return outputMixObject;
+}
+
+SLresult alc_opensles_create_native_audio_engine()
+{
+ if (engineObject)
+ return SL_RESULT_SUCCESS;
+
+ SLresult result;
+
+ // create engine
+ result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // realize the engine
+ result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // get the engine interface, which is needed in order to create other objects
+ result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // create output mix
+ result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // realize the output mix
+ result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+
+ return result;
+}
+
+// Backend functions, in same order as type BackendFuncs
+static ALCboolean opensles_open_playback(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ LOGV("opensles_open_playback pDevice=%p, deviceName=%s", pDevice, deviceName);
+
+ // create the engine and output mix objects
+ SLresult result = alc_opensles_create_native_audio_engine();
+
+ // create buffer queue audio player
+
+ // configure audio source
+ SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
+ SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_44_1,
+ SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN};
+ SLDataSource audioSrc = {&loc_bufq, &format_pcm};
+
+ // configure audio sink
+ SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
+ SLDataSink audioSnk = {&loc_outmix, NULL};
+
+ // create audio player
+ LOGV("create audio player");
+ const SLInterfaceID ids[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
+ const SLboolean req[1] = {SL_BOOLEAN_TRUE};
+ result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
+ 1, ids, req);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // realize the player
+ result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // get the play interface
+ result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // get the buffer queue interface
+ result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
+ &bqPlayerBufferQueue);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // register callback on the buffer queue
+ result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, opensles_callback, (void *) pDevice);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // set the player's state to playing
+ result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
+ assert(SL_RESULT_SUCCESS == result);
+
+ // enqueue the first buffer to kick off the callbacks
+ LOGV("enqueue");
+ result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1);
+ assert(SL_RESULT_SUCCESS == result);
+
+ return ALC_TRUE;
+}
+
+
+static void opensles_close_playback(ALCdevice *pDevice)
+{
+ LOGV("opensles_close_playback pDevice=%p", pDevice);
+
+ // shut down the native audio system
+
+ // destroy buffer queue audio player object, and invalidate all associated interfaces
+ if (bqPlayerObject != NULL) {
+ (*bqPlayerObject)->Destroy(bqPlayerObject);
+ bqPlayerObject = NULL;
+ bqPlayerPlay = NULL;
+ bqPlayerBufferQueue = NULL;
+ }
+
+ // destroy output mix object, and invalidate all associated interfaces
+ if (outputMixObject != NULL) {
+ (*outputMixObject)->Destroy(outputMixObject);
+ outputMixObject = NULL;
+ }
+
+ // destroy engine object, and invalidate all associated interfaces
+ if (engineObject != NULL) {
+ (*engineObject)->Destroy(engineObject);
+ engineObject = NULL;
+ engineEngine = NULL;
+ }
+
+}
+
+static ALCboolean opensles_reset_playback(ALCdevice *pDevice)
+{
+ LOGV("opensles_reset_playback pDevice=%p", pDevice);
+ unsigned bits = BytesFromDevFmt(pDevice->FmtType) * 8;
+ unsigned channels = ChannelsFromDevFmt(pDevice->FmtChans);
+ unsigned samples = pDevice->UpdateSize;
+ unsigned size = samples * channels * bits / 8;
+ LOGV("bits=%u, channels=%u, samples=%u, size=%u, freq=%u", bits, channels, samples, size, pDevice->Frequency);
+ SetDefaultWFXChannelOrder(pDevice);
+
+#if 0
+ if (pSDL_WasInit(SDL_INIT_AUDIO))
+ {
+ pSDL_PauseAudio(1);
+ pSDL_CloseAudio();
+ pSDL_QuitSubSystem(SDL_INIT_AUDIO);
+ }
+
+ switch (aluBytesFromFormat(device->Format))
+ {
+ case 1:
+ desired.format = AUDIO_U8;
+ break;
+ case 4:
+ switch (ChannelsFromDevFormat(device->DevFmt))
+ {
+ case 1: device->Format = AL_FORMAT_MONO16; break;
+ case 2: device->Format = AL_FORMAT_STEREO16; break;
+ case 4: device->Format = AL_FORMAT_QUAD16; break;
+ case 6: device->Format = AL_FORMAT_51CHN16; break;
+ case 7: device->Format = AL_FORMAT_61CHN16; break;
+ case 8: device->Format = AL_FORMAT_71CHN16; break;
+ }
+ /* fall-through */
+ case 2:
+ desired.format = AUDIO_S16;
+ break;
+ default:
+ AL_PRINT("Unknown format: 0x%x\n", device->Format);
+ return ALC_FALSE;
+ }
+
+ desired.freq = device->Frequency;
+ desired.channels = aluChannelsFromFormat(device->Format);
+ desired.samples = device->UpdateSize * desired.channels;
+ desired.callback = opensles_callback;
+ desired.userdata = device;
+
+ device->NumUpdates = 2;
+
+ if (pSDL_InitSubSystem(SDL_INIT_AUDIO) == -1)
+ {
+ AL_PRINT("SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s\n", pSDL_GetError());
+ return ALC_FALSE;
+ }
+
+ if (pSDL_OpenAudio(&desired, NULL) == -1)
+ {
+ AL_PRINT("SDL_OpenAudio failed: %s\n", pSDL_GetError());
+ pSDL_QuitSubSystem(SDL_INIT_AUDIO);
+ return ALC_FALSE;
+ }
+
+ pSDL_PauseAudio(0);
+#endif
+
+ return ALC_TRUE;
+}
+
+
+static void opensles_stop_playback(ALCdevice *pDevice)
+{
+ LOGV("opensles_stop_playback device=%p", pDevice);
+}
+
+static ALCboolean opensles_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+ LOGV("opensles_open_capture device=%p, deviceName=%s", pDevice, deviceName);
+ return ALC_FALSE;
+}
+
+static void opensles_close_capture(ALCdevice *pDevice)
+{
+ LOGV("opensles_closed_capture device=%p", pDevice);
+}
+
+static void opensles_start_capture(ALCdevice *pDevice)
+{
+ LOGV("opensles_start_capture device=%p", pDevice);
+}
+
+static void opensles_stop_capture(ALCdevice *pDevice)
+{
+ LOGV("opensles_stop_capture device=%p", pDevice);
+}
+
+static void opensles_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+ LOGV("opensles_capture_samples device=%p, pBuffer=%p, lSamples=%u", pDevice, pBuffer, lSamples);
+}
+
+static ALCuint opensles_available_samples(ALCdevice *pDevice)
+{
+ LOGV("opensles_available_samples device=%p", pDevice);
+ return 0;
+}
+
+// table of backend function pointers
+
+BackendFuncs opensles_funcs = {
+ opensles_open_playback,
+ opensles_close_playback,
+ opensles_reset_playback,
+ opensles_stop_playback,
+ opensles_open_capture,
+ opensles_close_capture,
+ opensles_start_capture,
+ opensles_stop_capture,
+ opensles_capture_samples,
+ opensles_available_samples
+};
+
+// global entry points called from XYZZY
+
+
+void alc_opensles_suspend()
+{
+ SLresult result;
+
+ if (bqPlayerPlay) {
+ result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
+ assert(SL_RESULT_SUCCESS == result);
+ result = (*bqPlayerBufferQueue)->Clear(bqPlayerBufferQueue);
+ assert(SL_RESULT_SUCCESS == result);
+ }
+}
+
+void alc_opensles_resume()
+{
+ SLresult result;
+
+ if (bqPlayerPlay) {
+ result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
+ assert(SL_RESULT_SUCCESS == result);
+ // Pump some blank data into the buffer to stimulate the callback
+ result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, "\0", 1);
+ assert(SL_RESULT_SUCCESS == result);
+ }
+}
+
+void alc_opensles_init(BackendFuncs *func_list)
+{
+ LOGV("alc_opensles_init");
+ *func_list = opensles_funcs;
+ apportableOpenALFuncs.alc_android_suspend = alc_opensles_suspend;
+ apportableOpenALFuncs.alc_android_resume = alc_opensles_resume;
+ apportableOpenALFuncs.alc_opensles_get_native_audio_engine_engine = alc_opensles_get_native_audio_engine_engine;
+ apportableOpenALFuncs.alc_opensles_get_native_audio_output_mix = alc_opensles_get_native_audio_output_mix;
+ apportableOpenALFuncs.alc_opensles_create_native_audio_engine = alc_opensles_create_native_audio_engine;
+}
+
+void alc_opensles_deinit(void)
+{
+ LOGV("alc_opensles_deinit");
+}
+
+void alc_opensles_probe(int type)
+{
+ switch (type) {
+ case DEVICE_PROBE:
+ LOGV("alc_opensles_probe DEVICE_PROBE");
+ AppendDeviceList(opensles_device);
+ break;
+ case ALL_DEVICE_PROBE:
+ LOGV("alc_opensles_probe ALL_DEVICE_PROBE");
+ AppendAllDeviceList(opensles_device);
+ break;
+ default:
+ LOGV("alc_opensles_probe type=%d", type);
+ break;
+ }
+}
diff --git a/jni/OpenAL/Alc/oss.c b/jni/OpenAL/Alc/oss.c
new file mode 100644
index 0000000..ea18689
--- /dev/null
+++ b/jni/OpenAL/Alc/oss.c
@@ -0,0 +1,521 @@
+/**
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include
+
+/*
+ * 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);
+ }
+}
diff --git a/jni/OpenAL/Alc/panning.c b/jni/OpenAL/Alc/panning.c
new file mode 100644
index 0000000..54921d5
--- /dev/null
+++ b/jni/OpenAL/Alc/panning.c
@@ -0,0 +1,364 @@
+/**
+ * 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
+#include
+#include
+#include
+#include
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alu.h"
+
+static void SetSpeakerArrangement(const char *name, ALfp 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] = ALfpMult(int2ALfp(angle), float2ALfp(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)
+ {
+ ALfp tmpf;
+ Channel tmpc;
+
+ tmpf = SpeakerAngle[i];
+ SpeakerAngle[i] = SpeakerAngle[min];
+ SpeakerAngle[min] = tmpf;
+
+ tmpc = Speaker2Chan[i];
+ Speaker2Chan[i] = Speaker2Chan[min];
+ Speaker2Chan[min] = tmpc;
+ }
+ }
+}
+
+static ALfp aluLUTpos2Angle(ALint pos)
+{
+ if(pos < QUADRANT_NUM)
+ return aluAtan(ALfpDiv(int2ALfp(pos), int2ALfp(QUADRANT_NUM - pos)));
+ if(pos < 2 * QUADRANT_NUM)
+ return (float2ALfp(M_PI_2) + aluAtan(ALfpDiv(int2ALfp(pos - QUADRANT_NUM),int2ALfp(2 * QUADRANT_NUM - pos))));
+ if(pos < 3 * QUADRANT_NUM)
+ return (aluAtan(ALfpDiv(int2ALfp(pos - 2 * QUADRANT_NUM), int2ALfp(3 * QUADRANT_NUM - pos))) - float2ALfp(M_PI));
+ return (aluAtan(ALfpDiv(int2ALfp(pos - 3 * QUADRANT_NUM), int2ALfp(4 * QUADRANT_NUM - pos))) - float2ALfp(M_PI));
+}
+
+ALint aluCart2LUTpos(ALfp re, ALfp im)
+{
+ ALint pos = 0;
+ ALfp denom = (aluFabs(re) + aluFabs(im));
+ if(denom > int2ALfp(0))
+ pos = (ALint)ALfp2int(ALfpDiv(ALfpMult(int2ALfp(QUADRANT_NUM),aluFabs(im)), (denom + float2ALfp(0.5))));
+
+ if(re < int2ALfp(0))
+ pos = 2 * QUADRANT_NUM - pos;
+ if(im < int2ALfp(0))
+ pos = LUT_NUM - pos;
+ return pos%LUT_NUM;
+}
+
+ALvoid aluInitPanning(ALCdevice *Device)
+{
+ ALfp SpeakerAngle[MAXCHANNELS];
+ ALfp (*Matrix)[MAXCHANNELS];
+ Channel *Speaker2Chan;
+ ALfp Alpha, Theta;
+ ALfp *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) ? int2ALfp(1) : int2ALfp(0));
+ }
+
+ Speaker2Chan = Device->Speaker2Chan;
+ Matrix = Device->ChannelMatrix;
+ switch(Device->FmtChans)
+ {
+ case DevFmtMono:
+ Matrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_CENTER][FRONT_CENTER] = int2ALfp(1);
+ Device->NumChan = 1;
+ Speaker2Chan[0] = FRONT_CENTER;
+ SpeakerAngle[0] = int2ALfp(0);
+ break;
+
+ case DevFmtStereo:
+#ifdef APPORTABLE_OPTIMIZED_OUT
+ // Leave as identity matrix if Apportable-optimized
+ Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_LEFT][FRONT_LEFT] = int2ALfp(1);
+ Matrix[SIDE_RIGHT][FRONT_RIGHT] = int2ALfp(1);
+ Matrix[BACK_LEFT][FRONT_LEFT] = int2ALfp(1);
+ Matrix[BACK_RIGHT][FRONT_RIGHT] = int2ALfp(1);
+ Matrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(float2ALfp(0.5));
+#endif
+ Device->NumChan = 2;
+ Speaker2Chan[0] = FRONT_LEFT;
+ Speaker2Chan[1] = FRONT_RIGHT;
+ SpeakerAngle[0] = float2ALfp(-90.0f * M_PI/180.0f);
+ SpeakerAngle[1] = float2ALfp( 90.0f * M_PI/180.0f);
+ SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtQuad:
+ Matrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(float2ALfp(0.5));
+ Device->NumChan = 4;
+ Speaker2Chan[0] = BACK_LEFT;
+ Speaker2Chan[1] = FRONT_LEFT;
+ Speaker2Chan[2] = FRONT_RIGHT;
+ Speaker2Chan[3] = BACK_RIGHT;
+ SpeakerAngle[0] = float2ALfp(-135.0f * M_PI/180.0f);
+ SpeakerAngle[1] = float2ALfp( -45.0f * M_PI/180.0f);
+ SpeakerAngle[2] = float2ALfp( 45.0f * M_PI/180.0f);
+ SpeakerAngle[3] = float2ALfp( 135.0f * M_PI/180.0f);
+ SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtX51:
+ Matrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(float2ALfp(0.5));
+ Matrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(float2ALfp(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] = float2ALfp(-110.0f * M_PI/180.0f);
+ SpeakerAngle[1] = float2ALfp( -30.0f * M_PI/180.0f);
+ SpeakerAngle[2] = float2ALfp( 0.0f * M_PI/180.0f);
+ SpeakerAngle[3] = float2ALfp( 30.0f * M_PI/180.0f);
+ SpeakerAngle[4] = float2ALfp( 110.0f * M_PI/180.0f);
+ SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtX61:
+ Matrix[BACK_LEFT][BACK_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(float2ALfp(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] = float2ALfp(-90.0f * M_PI/180.0f);
+ SpeakerAngle[1] = float2ALfp(-30.0f * M_PI/180.0f);
+ SpeakerAngle[2] = float2ALfp( 0.0f * M_PI/180.0f);
+ SpeakerAngle[3] = float2ALfp( 30.0f * M_PI/180.0f);
+ SpeakerAngle[4] = float2ALfp( 90.0f * M_PI/180.0f);
+ SpeakerAngle[5] = float2ALfp(180.0f * M_PI/180.0f);
+ SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+
+ case DevFmtX71:
+ Matrix[BACK_CENTER][BACK_LEFT] = aluSqrt(float2ALfp(0.5));
+ Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(float2ALfp(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] = float2ALfp(-150.0f * M_PI/180.0f);
+ SpeakerAngle[1] = float2ALfp( -90.0f * M_PI/180.0f);
+ SpeakerAngle[2] = float2ALfp( -30.0f * M_PI/180.0f);
+ SpeakerAngle[3] = float2ALfp( 0.0f * M_PI/180.0f);
+ SpeakerAngle[4] = float2ALfp( 30.0f * M_PI/180.0f);
+ SpeakerAngle[5] = float2ALfp( 90.0f * M_PI/180.0f);
+ SpeakerAngle[6] = float2ALfp( 150.0f * M_PI/180.0f);
+ SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+ break;
+ }
+
+ if(GetConfigValueBool(NULL, "scalemix", 0))
+ {
+ ALfp maxout = int2ALfp(1);;
+ for(s = 0;s < MAXCHANNELS;s++)
+ {
+ ALfp out = int2ALfp(0);
+ for(s2 = 0;s2 < MAXCHANNELS;s2++)
+ out = (out + Device->ChannelMatrix[s2][s]);
+ maxout = __max(maxout, out);
+ }
+
+ maxout = ALfpDiv(int2ALfp(1),maxout);
+ for(s = 0;s < MAXCHANNELS;s++)
+ {
+ for(s2 = 0;s2 < MAXCHANNELS;s2++)
+ Device->ChannelMatrix[s2][s] = ALfpMult(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] = int2ALfp(0);
+
+ if(Device->NumChan == 1)
+ {
+ PanningLUT[offset + Speaker2Chan[0]] = int2ALfp(1);
+ 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 = ALfpDiv(ALfpMult(float2ALfp(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 = (Theta + float2ALfp(2.0f * M_PI));
+ Alpha = ALfpDiv(ALfpMult(float2ALfp(M_PI_2), (Theta-SpeakerAngle[s])),
+ (float2ALfp(2.0f * M_PI) + SpeakerAngle[0]-SpeakerAngle[s]));
+ PanningLUT[offset + Speaker2Chan[s]] = __cos(Alpha);
+ PanningLUT[offset + Speaker2Chan[0]] = __sin(Alpha);
+ }
+ }
+}
diff --git a/jni/OpenAL/Alc/portaudio.c b/jni/OpenAL/Alc/portaudio.c
new file mode 100644
index 0000000..77c7236
--- /dev/null
+++ b/jni/OpenAL/Alc/portaudio.c
@@ -0,0 +1,442 @@
+/**
+ * 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
+#include
+#include
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#ifdef HAVE_DLFCN_H
+#include
+#endif
+
+#include
+
+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);
+}
diff --git a/jni/OpenAL/Alc/pulseaudio.c b/jni/OpenAL/Alc/pulseaudio.c
new file mode 100644
index 0000000..348f2d5
--- /dev/null
+++ b/jni/OpenAL/Alc/pulseaudio.c
@@ -0,0 +1,1358 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Konstantinos Natsakis
+ * 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 "alMain.h"
+#ifdef HAVE_DLFCN_H
+#include
+#endif
+
+#include
+
+#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);
+ }
+} //}}}
+//}}}
diff --git a/jni/OpenAL/Alc/solaris.c b/jni/OpenAL/Alc/solaris.c
new file mode 100644
index 0000000..18c7334
--- /dev/null
+++ b/jni/OpenAL/Alc/solaris.c
@@ -0,0 +1,304 @@
+/**
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include
+
+
+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);
+}
diff --git a/jni/OpenAL/Alc/wave.c b/jni/OpenAL/Alc/wave.c
new file mode 100644
index 0000000..6ba662c
--- /dev/null
+++ b/jni/OpenAL/Alc/wave.c
@@ -0,0 +1,355 @@
+/**
+ * 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
+#include
+#include
+#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);
+}
diff --git a/jni/OpenAL/Alc/winmm.c b/jni/OpenAL/Alc/winmm.c
new file mode 100644
index 0000000..10d0c28
--- /dev/null
+++ b/jni/OpenAL/Alc/winmm.c
@@ -0,0 +1,784 @@
+/**
+ * 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
+#include
+#include
+
+#include
+#include
+
+#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]);
+ }
+ }
+}
diff --git a/jni/OpenAL/Makefile b/jni/OpenAL/Makefile
new file mode 100644
index 0000000..1f84440
--- /dev/null
+++ b/jni/OpenAL/Makefile
@@ -0,0 +1,5 @@
+ROOTDIR = ../..
+TARGET = System/OpenAL
+DEPS =
+
+include $(ROOTDIR)/library.mk
diff --git a/jni/OpenAL/OpenAL32/Include/alAuxEffectSlot.h b/jni/OpenAL/OpenAL32/Include/alAuxEffectSlot.h
new file mode 100644
index 0000000..1c592ac
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alAuxEffectSlot.h
@@ -0,0 +1,63 @@
+#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;
+
+ ALfp Gain;
+ ALboolean AuxSendAuto;
+
+ ALeffectState *EffectState;
+
+ ALfp WetBuffer[BUFFERSIZE];
+
+ ALfp ClickRemoval[1];
+ ALfp 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 ALfp *SamplesIn, ALfp (*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
diff --git a/jni/OpenAL/OpenAL32/Include/alBuffer.h b/jni/OpenAL/OpenAL32/Include/alBuffer.h
new file mode 100644
index 0000000..e22d839
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alBuffer.h
@@ -0,0 +1,98 @@
+#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
diff --git a/jni/OpenAL/OpenAL32/Include/alDatabuffer.h b/jni/OpenAL/OpenAL32/Include/alDatabuffer.h
new file mode 100644
index 0000000..2218552
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alDatabuffer.h
@@ -0,0 +1,33 @@
+#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
diff --git a/jni/OpenAL/OpenAL32/Include/alEffect.h b/jni/OpenAL/OpenAL32/Include/alEffect.h
new file mode 100644
index 0000000..041aa3e
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alEffect.h
@@ -0,0 +1,83 @@
+// 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
+ ALfp Density;
+ ALfp Diffusion;
+ ALfp Gain;
+ ALfp GainHF;
+ ALfp DecayTime;
+ ALfp DecayHFRatio;
+ ALfp ReflectionsGain;
+ ALfp ReflectionsDelay;
+ ALfp LateReverbGain;
+ ALfp LateReverbDelay;
+ ALfp AirAbsorptionGainHF;
+ ALfp RoomRolloffFactor;
+ ALboolean DecayHFLimit;
+
+ // Additional EAX Reverb Properties
+ ALfp GainLF;
+ ALfp DecayLFRatio;
+ ALfp ReflectionsPan[3];
+ ALfp LateReverbPan[3];
+ ALfp EchoTime;
+ ALfp EchoDepth;
+ ALfp ModulationTime;
+ ALfp ModulationDepth;
+ ALfp HFReference;
+ ALfp LFReference;
+ } Reverb;
+
+ struct {
+ ALfp Delay;
+ ALfp LRDelay;
+
+ ALfp Damping;
+ ALfp Feedback;
+
+ ALfp Spread;
+ } Echo;
+
+ struct {
+ ALfp Frequency;
+ ALfp HighPassCutoff;
+ ALint Waveform;
+ } Modulator;
+
+ // Index to itself
+ ALuint effect;
+} ALeffect;
+
+
+ALvoid ReleaseALEffects(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/jni/OpenAL/OpenAL32/Include/alError.h b/jni/OpenAL/OpenAL32/Include/alError.h
new file mode 100644
index 0000000..7976e50
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alError.h
@@ -0,0 +1,17 @@
+#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
diff --git a/jni/OpenAL/OpenAL32/Include/alFilter.h b/jni/OpenAL/OpenAL32/Include/alFilter.h
new file mode 100644
index 0000000..3b17b1f
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alFilter.h
@@ -0,0 +1,139 @@
+#ifndef _AL_FILTER_H_
+#define _AL_FILTER_H_
+
+#include "AL/al.h"
+#include "alu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ ALfp coeff;
+#ifndef _MSC_VER
+ ALfp history[0];
+#else
+ ALfp history[1];
+#endif
+} FILTER;
+
+static __inline ALfp lpFilter4P(FILTER *iir, ALuint offset, ALfp input)
+{
+ ALfp *history = &iir->history[offset];
+ ALfp a = iir->coeff;
+ ALfp output = input;
+
+ output = output + ALfpMult((history[0]-output),a);
+ history[0] = output;
+ output = output + ALfpMult((history[1]-output),a);
+ history[1] = output;
+ output = output + ALfpMult((history[2]-output),a);
+ history[2] = output;
+ output = output + ALfpMult((history[3]-output),a);
+ history[3] = output;
+
+ return output;
+}
+
+static __inline ALfp lpFilter2P(FILTER *iir, ALuint offset, ALfp input)
+{
+ ALfp *history = &iir->history[offset];
+ ALfp a = iir->coeff;
+ ALfp output = input;
+
+ output = output + ALfpMult((history[0]-output),a);
+ history[0] = output;
+ output = output + ALfpMult((history[1]-output),a);
+ history[1] = output;
+
+ return output;
+}
+
+static __inline ALfp lpFilter1P(FILTER *iir, ALuint offset, ALfp input)
+{
+ ALfp *history = &iir->history[offset];
+ ALfp a = iir->coeff;
+ ALfp output = input;
+
+ output = output + ALfpMult((history[0]-output),a);
+ history[0] = output;
+
+ return output;
+}
+
+static __inline ALfp lpFilter4PC(const FILTER *iir, ALuint offset, ALfp input)
+{
+ const ALfp *history = &iir->history[offset];
+ ALfp a = iir->coeff;
+ ALfp output = input;
+
+ output = output + ALfpMult((history[0]-output),a);
+ output = output + ALfpMult((history[1]-output),a);
+ output = output + ALfpMult((history[2]-output),a);
+ output = output + ALfpMult((history[3]-output),a);
+
+ return output;
+}
+
+static __inline ALfp lpFilter2PC(const FILTER *iir, ALuint offset, ALfp input)
+{
+ const ALfp *history = &iir->history[offset];
+ ALfp a = iir->coeff;
+ ALfp output = input;
+
+ output = output + ALfpMult((history[0]-output),a);
+ output = output + ALfpMult((history[1]-output),a);
+
+ return output;
+}
+
+static __inline ALfp lpFilter1PC(FILTER *iir, ALuint offset, ALfp input)
+{
+ const ALfp *history = &iir->history[offset];
+ ALfp a = iir->coeff;
+ ALfp output = input;
+
+ output = output + ALfpMult((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 ALfp lpCoeffCalc(ALfp g, ALfp cw)
+{
+ ALfp a = int2ALfp(0);
+
+ /* Be careful with gains < 0.01, as that causes the coefficient
+ * head towards 1, which will flatten the signal */
+ g = __max(g, float2ALfp(0.01f));
+ if(g < float2ALfp(0.9999f)) /* 1-epsilon */ {
+ ALfp tmp; tmp = ALfpMult(ALfpMult(int2ALfp(2),g),(int2ALfp(1)-cw)) - ALfpMult(ALfpMult(g,g),(int2ALfp(1) - ALfpMult(cw,cw)));
+ a = ALfpDiv((int2ALfp(1) - ALfpMult(g,cw) - aluSqrt(tmp)), (int2ALfp(1) - g));
+ }
+
+ return a;
+}
+
+
+typedef struct ALfilter
+{
+ // Filter type (AL_FILTER_NULL, ...)
+ ALenum type;
+
+ ALfp Gain;
+ ALfp GainHF;
+
+ // Index to itself
+ ALuint filter;
+} ALfilter;
+
+
+ALvoid ReleaseALFilters(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/jni/OpenAL/OpenAL32/Include/alListener.h b/jni/OpenAL/OpenAL32/Include/alListener.h
new file mode 100644
index 0000000..a2fc3ba
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alListener.h
@@ -0,0 +1,24 @@
+#ifndef _AL_LISTENER_H_
+#define _AL_LISTENER_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ALlistener_struct
+{
+ ALfp Position[3];
+ ALfp Velocity[3];
+ ALfp Forward[3];
+ ALfp Up[3];
+ ALfp Gain;
+ ALfp MetersPerUnit;
+} ALlistener;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/jni/OpenAL/OpenAL32/Include/alMain.h b/jni/OpenAL/OpenAL32/Include/alMain.h
new file mode 100644
index 0000000..53497b4
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alMain.h
@@ -0,0 +1,500 @@
+#ifndef AL_MAIN_H
+#define AL_MAIN_H
+
+#include
+#include
+#include
+
+#ifdef HAVE_FENV_H
+#include
+#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
+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
+
+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
+#include
+#include
+#ifdef HAVE_PTHREAD_NP_H
+#include
+#endif
+#include
+#include
+#include
+
+#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_audiotrack_init(BackendFuncs *func_list);
+void alc_audiotrack_deinit(void);
+void alc_audiotrack_probe(int type);
+void alc_opensles_init(BackendFuncs *func_list);
+void alc_opensles_deinit(void);
+void alc_opensles_probe(int type);
+void alc_null_init(BackendFuncs *func_list);
+void alc_null_deinit(void);
+void alc_null_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
+ ALfp HeadDampen;
+
+ // Duplicate stereo sources on the side/rear channels
+ ALboolean DuplicateStereo;
+
+ // Dry path buffer mix
+ ALfp DryBuffer[BUFFERSIZE][MAXCHANNELS];
+
+ ALuint DevChannels[MAXCHANNELS];
+
+ ALfp ChannelMatrix[MAXCHANNELS][MAXCHANNELS];
+
+ Channel Speaker2Chan[MAXCHANNELS];
+ ALfp PanningLUT[MAXCHANNELS * LUT_NUM];
+ ALuint NumChan;
+
+ ALfp ClickRemoval[MAXCHANNELS];
+ ALfp 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;
+
+ ALfp DopplerFactor;
+ ALfp DopplerVelocity;
+ ALfp 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
diff --git a/jni/OpenAL/OpenAL32/Include/alSource.h b/jni/OpenAL/OpenAL32/Include/alSource.h
new file mode 100644
index 0000000..c802212
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alSource.h
@@ -0,0 +1,121 @@
+#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
+{
+ ALfp flPitch;
+ ALfp flGain;
+ ALfp flOuterGain;
+ ALfp flMinGain;
+ ALfp flMaxGain;
+ ALfp flInnerAngle;
+ ALfp flOuterAngle;
+ ALfp flRefDistance;
+ ALfp flMaxDistance;
+ ALfp flRollOffFactor;
+ ALfp vPosition[3];
+ ALfp vVelocity[3];
+ ALfp 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;
+ ALfp OuterGainHF;
+
+ ALfp AirAbsorptionFactor;
+ ALfp RoomRolloffFactor;
+ ALfp 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) */
+ ALfp DryGains[MAXCHANNELS][MAXCHANNELS];
+ FILTER iirFilter;
+ ALfp history[MAXCHANNELS*2];
+
+ struct {
+ ALfp WetGain;
+ FILTER iirFilter;
+ ALfp 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
diff --git a/jni/OpenAL/OpenAL32/Include/alState.h b/jni/OpenAL/OpenAL32/Include/alState.h
new file mode 100644
index 0000000..332176b
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alState.h
@@ -0,0 +1,14 @@
+#ifndef _AL_STATE_H_
+#define _AL_STATE_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/jni/OpenAL/OpenAL32/Include/alThunk.h b/jni/OpenAL/OpenAL32/Include/alThunk.h
new file mode 100644
index 0000000..902f00e
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alThunk.h
@@ -0,0 +1,42 @@
+#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_
+
diff --git a/jni/OpenAL/OpenAL32/Include/alu.h b/jni/OpenAL/OpenAL32/Include/alu.h
new file mode 100644
index 0000000..89e51fb
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/Include/alu.h
@@ -0,0 +1,135 @@
+#ifndef _ALU_H_
+#define _ALU_H_
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include
+#include
+#ifdef HAVE_FLOAT_H
+#include
+#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) (float2ALfp(powf(ALfp2float(x), ALfp2float(y))))
+#else
+#define aluPow(x,y) (float2ALfp((float)pow((double)ALfp2float(x), (double)ALfp2float(y))))
+#endif
+
+#ifdef HAVE_SQRTF
+#define aluSqrt(x) (float2ALfp(sqrtf(ALfp2float(x))))
+#else
+#define aluSqrt(x) (float2ALfp((float)sqrt((double)ALfp2float(x))))
+#endif
+
+#ifdef HAVE_ACOSF
+#define aluAcos(x) (float2ALfp(acosf(ALfp2float(x))))
+#else
+#define aluAcos(x) (float2ALfp((float)acos((double)ALfp2float(x))))
+#endif
+
+#ifdef HAVE_ATANF
+#define aluAtan(x) (float2ALfp(atanf(ALfp2float(x))))
+#else
+#define aluAtan(x) (float2ALfp((float)atan((double)ALfp2float(x))))
+#endif
+
+#ifdef HAVE_FABSF
+#define aluFabs(x) (float2ALfp(fabsf(ALfp2float(x))))
+#else
+#define aluFabs(x) (float2ALfp((float)fabs((double)ALfp2float(x))))
+#endif
+
+// FIXME make this better
+#if defined(max) && !defined(__max)
+#define __max(x,y) float2ALfp(max(ALfp2float(x),ALfp2float(y)))
+#endif
+#if defined(min) && !defined(__min)
+#define __min(x,y) float2ALfp(min(ALfp2float(x),ALfp2float(y)))
+#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<
+#include
+
+#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 = int2ALfp(1);
+ slot->AuxSendAuto = AL_TRUE;
+ for(j = 0;j < BUFFERSIZE;j++)
+ slot->WetBuffer[j] = int2ALfp(0);
+ for(j = 0;j < 1;j++)
+ {
+ slot->ClickRemoval[j] = int2ALfp(0);
+ slot->PendingClicks[j] = int2ALfp(0);
+ }
+ 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 flArg)
+{
+ ALCcontext *Context;
+ ALeffectslot *EffectSlot;
+ ALfp flValue = float2ALfp(flArg);
+
+ Context = GetContextSuspended();
+ if(!Context) return;
+
+ if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+ {
+ switch(param)
+ {
+ case AL_EFFECTSLOT_GAIN:
+ if(flValue >= int2ALfp(0) && flValue <= int2ALfp(1))
+ 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 = ALfp2float(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 ALfp *SamplesIn, ALfp (*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);
+ }
+}
diff --git a/jni/OpenAL/OpenAL32/alBuffer.c b/jni/OpenAL/OpenAL32/alBuffer.c
new file mode 100644
index 0000000..fafd974
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alBuffer.c
@@ -0,0 +1,1898 @@
+/**
+ * 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
+#include
+#include
+#include
+
+#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_ALfp(ALfp val)
+{
+ if(val > int2ALfp(1)) return 127;
+ if(val < int2ALfp(-1)) return -128;
+ return ALfp2int(ALfpMult(val, int2ALfp(127)));
+}
+static __inline ALbyte Conv_ALbyte_ALdfp(ALdfp val)
+{
+ if(val > int2ALdfp(1)) return 127;
+ if(val < int2ALdfp(-1)) return -128;
+ return ALdfp2int(ALdfpMult(val, int2ALdfp(127)));
+}
+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_ALfp(ALfp val)
+{
+ if(val > int2ALfp(1)) return 255;
+ if(val < int2ALfp(-1)) return 0;
+ return ALfp2int(ALfpMult(val, int2ALfp(127))) + 128;
+}
+static __inline ALubyte Conv_ALubyte_ALdfp(ALdfp val)
+{
+ if(val > int2ALdfp(1)) return 255;
+ if(val < int2ALdfp(-1)) return 0;
+ return ALdfp2int(ALdfpMult(val, int2ALdfp(127))) + 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_ALfp(ALfp val)
+{
+ if(val > int2ALfp(1)) return 32767;
+ if(val < int2ALfp(-1)) return -32768;
+ return ALfp2int(ALfpMult(val, int2ALfp(32767)));
+}
+static __inline ALshort Conv_ALshort_ALdfp(ALdfp val)
+{
+ if(val > int2ALdfp(1)) return 32767;
+ if(val < int2ALdfp(-1)) return -32768;
+ return ALdfp2int(ALdfpMult(val, int2ALdfp(32767)));
+}
+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_ALfp(ALfp val)
+{
+ if(val > int2ALfp(1)) return 65535;
+ if(val < int2ALfp(-1)) return 0;
+ return ALfp2int(ALfpMult(val, int2ALfp(32767))) + 32768;
+}
+static __inline ALushort Conv_ALushort_ALdfp(ALdfp val)
+{
+ if(val > int2ALdfp(1)) return 65535;
+ if(val < int2ALdfp(-1)) return 0;
+ return ALdfp2int(ALdfpMult(val, int2ALdfp(32767))) + 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_ALfp(ALfp val)
+{
+ if(val > int2ALfp(1)) return 2147483647;
+ if(val < int2ALfp(-1)) return -2147483647-1;
+ return ALfp2int(ALfpMult(val, int2ALfp(2147483647)));
+}
+static __inline ALint Conv_ALint_ALdfp(ALdfp val)
+{
+ if(val > int2ALdfp(1)) return 2147483647;
+ if(val < int2ALdfp(-1)) return -2147483647-1;
+ return ALdfp2int(ALdfpMult(val, int2ALdfp(2147483647)));
+}
+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_ALfp(ALfp val)
+{
+ if(val > int2ALfp(1)) return 4294967295u;
+ if(val < int2ALfp(-1)) return 0;
+ return ALfp2int(ALfpMult(val, int2ALfp(2147483647))) + 2147483648u;
+}
+static __inline ALuint Conv_ALuint_ALdfp(ALdfp val)
+{
+ if(val > int2ALdfp(1)) return 4294967295u;
+ if(val < int2ALdfp(-1)) return 0;
+ return ALdfp2int(ALdfpMult(val, int2ALdfp(2147483647))) + 2147483648u;
+}
+static __inline ALuint Conv_ALuint_ALmulaw(ALmulaw val)
+{ return Conv_ALuint_ALshort(DecodeMuLaw(val)); }
+
+// FIXME(apportable) make this more efficient with shifts for integer input
+static __inline ALfp Conv_ALfp_ALbyte(ALbyte val)
+{ return float2ALfp(val * (1.0f/127.0f)); }
+static __inline ALfp Conv_ALfp_ALubyte(ALubyte val)
+{ return float2ALfp((val-128) * (1.0f/127.0f)); }
+static __inline ALfp Conv_ALfp_ALshort(ALshort val)
+{ return float2ALfp(val * (1.0f/32767.0f)); }
+static __inline ALfp Conv_ALfp_ALushort(ALushort val)
+{ return float2ALfp((val-32768) * (1.0f/32767.0f)); }
+static __inline ALfp Conv_ALfp_ALint(ALint val)
+{ return float2ALfp(val * (1.0/2147483647.0)); }
+static __inline ALfp Conv_ALfp_ALuint(ALuint val)
+{ return float2ALfp((ALint)(val-2147483648u) * (1.0/2147483647.0)); }
+static __inline ALfp Conv_ALfp_ALfp(ALfp val)
+{ return val; }
+static __inline ALfp Conv_ALfp_ALdfp(ALdfp val)
+{ return (ALfp)val; }
+static __inline ALfp Conv_ALfp_ALmulaw(ALmulaw val)
+{ return Conv_ALfp_ALshort(DecodeMuLaw(val)); }
+
+// FIXME replace with shifts for integer args
+static __inline ALdfp Conv_ALdfp_ALbyte(ALbyte val)
+{ return double2ALdfp(val * (1.0/127.0)); }
+static __inline ALdfp Conv_ALdfp_ALubyte(ALubyte val)
+{ return double2ALdfp((val-128) * (1.0/127.0)); }
+static __inline ALdfp Conv_ALdfp_ALshort(ALshort val)
+{ return double2ALdfp(val * (1.0/32767.0)); }
+static __inline ALdfp Conv_ALdfp_ALushort(ALushort val)
+{ return double2ALdfp((val-32768) * (1.0/32767.0)); }
+static __inline ALdfp Conv_ALdfp_ALint(ALint val)
+{ return double2ALdfp(val * (1.0/2147483647.0)); }
+static __inline ALdfp Conv_ALdfp_ALuint(ALuint val)
+{ return double2ALdfp((ALint)(val-2147483648u) * (1.0/2147483647.0)); }
+static __inline ALdfp Conv_ALdfp_ALfp(ALfp val)
+{ return (ALdfp)val; }
+static __inline ALdfp Conv_ALdfp_ALdfp(ALdfp val)
+{ return val; }
+static __inline ALdfp Conv_ALdfp_ALmulaw(ALmulaw val)
+{ return Conv_ALdfp_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(ALfp)
+DECL_TEMPLATE(ALdfp)
+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, ALfp)
+DECL_TEMPLATE(ALbyte, ALdfp)
+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, ALfp)
+DECL_TEMPLATE(ALubyte, ALdfp)
+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, ALfp)
+DECL_TEMPLATE(ALshort, ALdfp)
+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, ALfp)
+DECL_TEMPLATE(ALushort, ALdfp)
+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, ALfp)
+DECL_TEMPLATE(ALint, ALdfp)
+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, ALfp)
+DECL_TEMPLATE(ALuint, ALdfp)
+DECL_TEMPLATE(ALuint, ALmulaw)
+
+DECL_TEMPLATE(ALfp, ALbyte)
+DECL_TEMPLATE(ALfp, ALubyte)
+DECL_TEMPLATE(ALfp, ALshort)
+DECL_TEMPLATE(ALfp, ALushort)
+DECL_TEMPLATE(ALfp, ALint)
+DECL_TEMPLATE(ALfp, ALuint)
+DECL_TEMPLATE(ALfp, ALfp)
+DECL_TEMPLATE(ALfp, ALdfp)
+DECL_TEMPLATE(ALfp, ALmulaw)
+
+DECL_TEMPLATE(ALdfp, ALbyte)
+DECL_TEMPLATE(ALdfp, ALubyte)
+DECL_TEMPLATE(ALdfp, ALshort)
+DECL_TEMPLATE(ALdfp, ALushort)
+DECL_TEMPLATE(ALdfp, ALint)
+DECL_TEMPLATE(ALdfp, ALuint)
+DECL_TEMPLATE(ALdfp, ALfp)
+DECL_TEMPLATE(ALdfp, ALdfp)
+DECL_TEMPLATE(ALdfp, 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, ALfp)
+DECL_TEMPLATE(ALmulaw, ALdfp)
+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(ALfp)
+DECL_TEMPLATE(ALdfp)
+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(ALfp)
+DECL_TEMPLATE(ALdfp)
+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##_ALfp(dst, src, len); \
+ break; \
+ case UserFmtDouble: \
+ Convert_##T##_ALdfp(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(ALfp)
+DECL_TEMPLATE(ALdfp)
+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_ALfp(dst, src, chans, len);
+ break;
+ case UserFmtDouble:
+ Convert_IMA4_ALdfp(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_ALfp(dst, src, srcType, len);
+ break;
+ (void)Convert_ALdfp;
+ (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_ALfp_IMA4(dst, src, chans, len);
+ break;
+ (void)Convert_ALdfp_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(ALfp);
+ case UserFmtDouble: return sizeof(ALdfp);
+ 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(ALfp);
+ }
+ 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);
+ }
+}
diff --git a/jni/OpenAL/OpenAL32/alDatabuffer.c b/jni/OpenAL/OpenAL32/alDatabuffer.c
new file mode 100644
index 0000000..cbe65a0
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alDatabuffer.c
@@ -0,0 +1,648 @@
+/**
+ * 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
+#include
+#include
+#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);
+ }
+}
diff --git a/jni/OpenAL/OpenAL32/alEffect.c b/jni/OpenAL/OpenAL32/alEffect.c
new file mode 100644
index 0000000..cb07e21
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alEffect.c
@@ -0,0 +1,1377 @@
+/**
+ * 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
+#include
+
+#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 flArg)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALeffect *ALEffect;
+ ALfp flValue = float2ALfp(flArg);
+
+ 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 >= float2ALfp(AL_EAXREVERB_MIN_DENSITY) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_DENSITY))
+ ALEffect->Reverb.Density = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DIFFUSION:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_DIFFUSION) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_DIFFUSION))
+ ALEffect->Reverb.Diffusion = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_GAIN:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_GAIN) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_GAIN))
+ ALEffect->Reverb.Gain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_GAINHF:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_GAINHF) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_GAIN))
+ ALEffect->Reverb.GainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_GAINLF:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_GAINLF) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_GAINLF))
+ ALEffect->Reverb.GainLF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DECAY_TIME:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_DECAY_TIME) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_DECAY_TIME))
+ ALEffect->Reverb.DecayTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_DECAY_HFRATIO) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_DECAY_HFRATIO))
+ ALEffect->Reverb.DecayHFRatio = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_DECAY_LFRATIO) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_DECAY_LFRATIO))
+ ALEffect->Reverb.DecayLFRatio = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_REFLECTIONS_GAIN) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_REFLECTIONS_GAIN))
+ ALEffect->Reverb.ReflectionsGain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_REFLECTIONS_DELAY) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_REFLECTIONS_DELAY))
+ ALEffect->Reverb.ReflectionsDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_LATE_REVERB_GAIN) &&
+ flValue <= float2ALfp(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 >= float2ALfp(AL_EAXREVERB_MIN_LATE_REVERB_DELAY) &&
+ flValue <= float2ALfp(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 >= float2ALfp(AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF))
+ ALEffect->Reverb.AirAbsorptionGainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_ECHO_TIME:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_ECHO_TIME) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_ECHO_TIME))
+ ALEffect->Reverb.EchoTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_ECHO_DEPTH:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_ECHO_DEPTH) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_ECHO_DEPTH))
+ ALEffect->Reverb.EchoDepth = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_MODULATION_TIME:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_MODULATION_TIME) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_MODULATION_TIME))
+ ALEffect->Reverb.ModulationTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_MODULATION_DEPTH) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_MODULATION_DEPTH))
+ ALEffect->Reverb.ModulationDepth = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_HFREFERENCE:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_HFREFERENCE) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_HFREFERENCE))
+ ALEffect->Reverb.HFReference = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_LFREFERENCE:
+ if(flValue >= float2ALfp(AL_EAXREVERB_MIN_LFREFERENCE) &&
+ flValue <= float2ALfp(AL_EAXREVERB_MAX_LFREFERENCE))
+ ALEffect->Reverb.LFReference = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ if(flValue >= float2ALfp(0.0f) && flValue <= float2ALfp(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 >= float2ALfp(AL_REVERB_MIN_DENSITY) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_DENSITY))
+ ALEffect->Reverb.Density = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_DIFFUSION:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_DIFFUSION) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_DIFFUSION))
+ ALEffect->Reverb.Diffusion = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_GAIN:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_GAIN) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_GAIN))
+ ALEffect->Reverb.Gain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_GAINHF:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_GAINHF) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_GAINHF))
+ ALEffect->Reverb.GainHF = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_DECAY_TIME:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_DECAY_TIME) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_DECAY_TIME))
+ ALEffect->Reverb.DecayTime = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_DECAY_HFRATIO:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_DECAY_HFRATIO) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_DECAY_HFRATIO))
+ ALEffect->Reverb.DecayHFRatio = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_REFLECTIONS_GAIN:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_REFLECTIONS_GAIN) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_REFLECTIONS_GAIN))
+ ALEffect->Reverb.ReflectionsGain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_REFLECTIONS_DELAY:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_REFLECTIONS_DELAY) &&
+ flValue <= float2ALfp(AL_REVERB_MAX_REFLECTIONS_DELAY))
+ ALEffect->Reverb.ReflectionsDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_REVERB_LATE_REVERB_GAIN:
+ if(flValue >= float2ALfp(AL_REVERB_MIN_LATE_REVERB_GAIN) &&
+ flValue <= float2ALfp(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 >= float2ALfp(AL_REVERB_MIN_LATE_REVERB_DELAY) &&
+ flValue <= float2ALfp(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 >= float2ALfp(AL_REVERB_MIN_AIR_ABSORPTION_GAINHF) &&
+ flValue <= float2ALfp(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 >= float2ALfp(AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR) &&
+ flValue <= float2ALfp(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 >= float2ALfp(AL_ECHO_MIN_DELAY) && flValue <= float2ALfp(AL_ECHO_MAX_DELAY))
+ ALEffect->Echo.Delay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_LRDELAY:
+ if(flValue >= float2ALfp(AL_ECHO_MIN_LRDELAY) && flValue <= float2ALfp(AL_ECHO_MAX_LRDELAY))
+ ALEffect->Echo.LRDelay = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_DAMPING:
+ if(flValue >= float2ALfp(AL_ECHO_MIN_DAMPING) && flValue <= float2ALfp(AL_ECHO_MAX_DAMPING))
+ ALEffect->Echo.Damping = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_FEEDBACK:
+ if(flValue >= float2ALfp(AL_ECHO_MIN_FEEDBACK) && flValue <= float2ALfp(AL_ECHO_MAX_FEEDBACK))
+ ALEffect->Echo.Feedback = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_ECHO_SPREAD:
+ if(flValue >= float2ALfp(AL_ECHO_MIN_SPREAD) && flValue <= float2ALfp(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 >= float2ALfp(AL_RING_MODULATOR_MIN_FREQUENCY) &&
+ flValue <= float2ALfp(AL_RING_MODULATOR_MAX_FREQUENCY))
+ ALEffect->Modulator.Frequency = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ if(flValue >= float2ALfp(AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF) &&
+ flValue <= float2ALfp(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] = float2ALfp(pflValues[0]);
+ ALEffect->Reverb.ReflectionsPan[1] = float2ALfp(pflValues[1]);
+ ALEffect->Reverb.ReflectionsPan[2] = float2ALfp(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] = float2ALfp(pflValues[0]);
+ ALEffect->Reverb.LateReverbPan[1] = float2ALfp(pflValues[1]);
+ ALEffect->Reverb.LateReverbPan[2] = float2ALfp(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)ALfp2float(ALEffect->Modulator.Frequency);
+ break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ *piValue = (ALint)ALfp2float(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 = ALfp2float(ALEffect->Reverb.Density);
+ break;
+
+ case AL_EAXREVERB_DIFFUSION:
+ *pflValue = ALfp2float(ALEffect->Reverb.Diffusion);
+ break;
+
+ case AL_EAXREVERB_GAIN:
+ *pflValue = ALfp2float(ALEffect->Reverb.Gain);
+ break;
+
+ case AL_EAXREVERB_GAINHF:
+ *pflValue = ALfp2float(ALEffect->Reverb.GainHF);
+ break;
+
+ case AL_EAXREVERB_GAINLF:
+ *pflValue = ALfp2float(ALEffect->Reverb.GainLF);
+ break;
+
+ case AL_EAXREVERB_DECAY_TIME:
+ *pflValue = ALfp2float(ALEffect->Reverb.DecayTime);
+ break;
+
+ case AL_EAXREVERB_DECAY_HFRATIO:
+ *pflValue = ALfp2float(ALEffect->Reverb.DecayHFRatio);
+ break;
+
+ case AL_EAXREVERB_DECAY_LFRATIO:
+ *pflValue = ALfp2float(ALEffect->Reverb.DecayLFRatio);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_GAIN:
+ *pflValue = ALfp2float(ALEffect->Reverb.ReflectionsGain);
+ break;
+
+ case AL_EAXREVERB_REFLECTIONS_DELAY:
+ *pflValue = ALfp2float(ALEffect->Reverb.ReflectionsDelay);
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_GAIN:
+ *pflValue = ALfp2float(ALEffect->Reverb.LateReverbGain);
+ break;
+
+ case AL_EAXREVERB_LATE_REVERB_DELAY:
+ *pflValue = ALfp2float(ALEffect->Reverb.LateReverbDelay);
+ break;
+
+ case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+ *pflValue = ALfp2float(ALEffect->Reverb.AirAbsorptionGainHF);
+ break;
+
+ case AL_EAXREVERB_ECHO_TIME:
+ *pflValue = ALfp2float(ALEffect->Reverb.EchoTime);
+ break;
+
+ case AL_EAXREVERB_ECHO_DEPTH:
+ *pflValue = ALfp2float(ALEffect->Reverb.EchoDepth);
+ break;
+
+ case AL_EAXREVERB_MODULATION_TIME:
+ *pflValue = ALfp2float(ALEffect->Reverb.ModulationTime);
+ break;
+
+ case AL_EAXREVERB_MODULATION_DEPTH:
+ *pflValue = ALfp2float(ALEffect->Reverb.ModulationDepth);
+ break;
+
+ case AL_EAXREVERB_HFREFERENCE:
+ *pflValue = ALfp2float(ALEffect->Reverb.HFReference);
+ break;
+
+ case AL_EAXREVERB_LFREFERENCE:
+ *pflValue = ALfp2float(ALEffect->Reverb.LFReference);
+ break;
+
+ case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+ *pflValue = ALfp2float(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 = ALfp2float(ALEffect->Reverb.Density);
+ break;
+
+ case AL_REVERB_DIFFUSION:
+ *pflValue = ALfp2float(ALEffect->Reverb.Diffusion);
+ break;
+
+ case AL_REVERB_GAIN:
+ *pflValue = ALfp2float(ALEffect->Reverb.Gain);
+ break;
+
+ case AL_REVERB_GAINHF:
+ *pflValue = ALfp2float(ALEffect->Reverb.GainHF);
+ break;
+
+ case AL_REVERB_DECAY_TIME:
+ *pflValue = ALfp2float(ALEffect->Reverb.DecayTime);
+ break;
+
+ case AL_REVERB_DECAY_HFRATIO:
+ *pflValue = ALfp2float(ALEffect->Reverb.DecayHFRatio);
+ break;
+
+ case AL_REVERB_REFLECTIONS_GAIN:
+ *pflValue = ALfp2float(ALEffect->Reverb.ReflectionsGain);
+ break;
+
+ case AL_REVERB_REFLECTIONS_DELAY:
+ *pflValue = ALfp2float(ALEffect->Reverb.ReflectionsDelay);
+ break;
+
+ case AL_REVERB_LATE_REVERB_GAIN:
+ *pflValue = ALfp2float(ALEffect->Reverb.LateReverbGain);
+ break;
+
+ case AL_REVERB_LATE_REVERB_DELAY:
+ *pflValue = ALfp2float(ALEffect->Reverb.LateReverbDelay);
+ break;
+
+ case AL_REVERB_AIR_ABSORPTION_GAINHF:
+ *pflValue = ALfp2float(ALEffect->Reverb.AirAbsorptionGainHF);
+ break;
+
+ case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+ *pflValue = ALfp2float(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 = ALfp2float(ALEffect->Echo.Delay);
+ break;
+
+ case AL_ECHO_LRDELAY:
+ *pflValue = ALfp2float(ALEffect->Echo.LRDelay);
+ break;
+
+ case AL_ECHO_DAMPING:
+ *pflValue = ALfp2float(ALEffect->Echo.Damping);
+ break;
+
+ case AL_ECHO_FEEDBACK:
+ *pflValue = ALfp2float(ALEffect->Echo.Feedback);
+ break;
+
+ case AL_ECHO_SPREAD:
+ *pflValue = ALfp2float(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 = ALfp2float(ALEffect->Modulator.Frequency);
+ break;
+ case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+ *pflValue = ALfp2float(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] = ALfp2float(ALEffect->Reverb.ReflectionsPan[0]);
+ pflValues[1] = ALfp2float(ALEffect->Reverb.ReflectionsPan[1]);
+ pflValues[2] = ALfp2float(ALEffect->Reverb.ReflectionsPan[2]);
+ break;
+ case AL_EAXREVERB_LATE_REVERB_PAN:
+ pflValues[0] = ALfp2float(ALEffect->Reverb.LateReverbPan[0]);
+ pflValues[1] = ALfp2float(ALEffect->Reverb.LateReverbPan[1]);
+ pflValues[2] = ALfp2float(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 = float2ALfp(AL_EAXREVERB_DEFAULT_DENSITY);
+ effect->Reverb.Diffusion = float2ALfp(AL_EAXREVERB_DEFAULT_DIFFUSION);
+ effect->Reverb.Gain = float2ALfp(AL_EAXREVERB_DEFAULT_GAIN);
+ effect->Reverb.GainHF = float2ALfp(AL_EAXREVERB_DEFAULT_GAINHF);
+ effect->Reverb.GainLF = float2ALfp(AL_EAXREVERB_DEFAULT_GAINLF);
+ effect->Reverb.DecayTime = float2ALfp(AL_EAXREVERB_DEFAULT_DECAY_TIME);
+ effect->Reverb.DecayHFRatio = float2ALfp(AL_EAXREVERB_DEFAULT_DECAY_HFRATIO);
+ effect->Reverb.DecayLFRatio = float2ALfp(AL_EAXREVERB_DEFAULT_DECAY_LFRATIO);
+ effect->Reverb.ReflectionsGain = float2ALfp(AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN);
+ effect->Reverb.ReflectionsDelay = float2ALfp(AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY);
+ effect->Reverb.ReflectionsPan[0] = float2ALfp(AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ);
+ effect->Reverb.ReflectionsPan[1] = float2ALfp(AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ);
+ effect->Reverb.ReflectionsPan[2] = float2ALfp(AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ);
+ effect->Reverb.LateReverbGain = float2ALfp(AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN);
+ effect->Reverb.LateReverbDelay = float2ALfp(AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY);
+ effect->Reverb.LateReverbPan[0] = float2ALfp(AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ);
+ effect->Reverb.LateReverbPan[1] = float2ALfp(AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ);
+ effect->Reverb.LateReverbPan[2] = float2ALfp(AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ);
+ effect->Reverb.EchoTime = float2ALfp(AL_EAXREVERB_DEFAULT_ECHO_TIME);
+ effect->Reverb.EchoDepth = float2ALfp(AL_EAXREVERB_DEFAULT_ECHO_DEPTH);
+ effect->Reverb.ModulationTime = float2ALfp(AL_EAXREVERB_DEFAULT_MODULATION_TIME);
+ effect->Reverb.ModulationDepth = float2ALfp(AL_EAXREVERB_DEFAULT_MODULATION_DEPTH);
+ effect->Reverb.AirAbsorptionGainHF = float2ALfp(AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF);
+ effect->Reverb.HFReference = float2ALfp(AL_EAXREVERB_DEFAULT_HFREFERENCE);
+ effect->Reverb.LFReference = float2ALfp(AL_EAXREVERB_DEFAULT_LFREFERENCE);
+ effect->Reverb.RoomRolloffFactor = float2ALfp(AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR);
+ effect->Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
+ break;
+ case AL_EFFECT_ECHO:
+ effect->Echo.Delay = float2ALfp(AL_ECHO_DEFAULT_DELAY);
+ effect->Echo.LRDelay = float2ALfp(AL_ECHO_DEFAULT_LRDELAY);
+ effect->Echo.Damping = float2ALfp(AL_ECHO_DEFAULT_DAMPING);
+ effect->Echo.Feedback = float2ALfp(AL_ECHO_DEFAULT_FEEDBACK);
+ effect->Echo.Spread = float2ALfp(AL_ECHO_DEFAULT_SPREAD);
+ break;
+ case AL_EFFECT_RING_MODULATOR:
+ effect->Modulator.Frequency = float2ALfp(AL_RING_MODULATOR_DEFAULT_FREQUENCY);
+ effect->Modulator.HighPassCutoff = float2ALfp(AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF);
+ effect->Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
+ break;
+ }
+}
diff --git a/jni/OpenAL/OpenAL32/alError.c b/jni/OpenAL/OpenAL32/alError.c
new file mode 100644
index 0000000..43b8e44
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alError.c
@@ -0,0 +1,47 @@
+/**
+ * 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;
+}
diff --git a/jni/OpenAL/OpenAL32/alExtension.c b/jni/OpenAL/OpenAL32/alExtension.c
new file mode 100644
index 0000000..0febf22
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alExtension.c
@@ -0,0 +1,331 @@
+/**
+ * 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
+#include
+#include
+
+#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;
+}
diff --git a/jni/OpenAL/OpenAL32/alFilter.c b/jni/OpenAL/OpenAL32/alFilter.c
new file mode 100644
index 0000000..7d6cda8
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alFilter.c
@@ -0,0 +1,432 @@
+/**
+ * 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
+
+#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 flArg)
+{
+ ALCcontext *Context;
+ ALCdevice *Device;
+ ALfilter *ALFilter;
+ ALfp flValue = float2ALfp(flArg);
+
+ 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 >= int2ALfp(0) && flValue <= int2ALfp(1))
+ ALFilter->Gain = flValue;
+ else
+ alSetError(Context, AL_INVALID_VALUE);
+ break;
+
+ case AL_LOWPASS_GAINHF:
+ if(flValue >= int2ALfp(0) && flValue <= int2ALfp(1))
+ 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 = ALfp2float(ALFilter->Gain);
+ break;
+
+ case AL_LOWPASS_GAINHF:
+ *pflValue = ALfp2float(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 = int2ALfp(1);
+ filter->GainHF = int2ALfp(1);
+}
diff --git a/jni/OpenAL/OpenAL32/alListener.c b/jni/OpenAL/OpenAL32/alListener.c
new file mode 100644
index 0000000..c21c605
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alListener.c
@@ -0,0 +1,489 @@
+/**
+ * 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 flArg)
+{
+ ALCcontext *pContext;
+ ALboolean updateAll = AL_FALSE;
+ ALfp flValue = float2ALfp(flArg);
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ switch(eParam)
+ {
+ case AL_GAIN:
+ if(flValue >= int2ALfp(0))
+ {
+ pContext->Listener.Gain = flValue;
+ updateAll = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_METERS_PER_UNIT:
+ if(flValue > int2ALfp(0))
+ {
+ 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 flArg1, ALfloat flArg2, ALfloat flArg3)
+{
+ ALCcontext *pContext;
+ ALboolean updateWorld = AL_FALSE;
+ ALfp flValue1 = float2ALfp(flArg1);
+ ALfp flValue2 = float2ALfp(flArg2);
+ ALfp flValue3 = float2ALfp(flArg3);
+
+
+ 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] = float2ALfp(pflValues[0]);
+ pContext->Listener.Forward[1] = float2ALfp(pflValues[1]);
+ pContext->Listener.Forward[2] = float2ALfp(pflValues[2]);
+ pContext->Listener.Up[0] = float2ALfp(pflValues[3]);
+ pContext->Listener.Up[1] = float2ALfp(pflValues[4]);
+ pContext->Listener.Up[2] = float2ALfp(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 = ALfp2float(pContext->Listener.Gain);
+ break;
+
+ case AL_METERS_PER_UNIT:
+ *pflValue = ALfp2float(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 = ALfp2float(pContext->Listener.Position[0]);
+ *pflValue2 = ALfp2float(pContext->Listener.Position[1]);
+ *pflValue3 = ALfp2float(pContext->Listener.Position[2]);
+ break;
+
+ case AL_VELOCITY:
+ *pflValue1 = ALfp2float(pContext->Listener.Velocity[0]);
+ *pflValue2 = ALfp2float(pContext->Listener.Velocity[1]);
+ *pflValue3 = ALfp2float(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] = ALfp2float(pContext->Listener.Gain);
+ break;
+
+ case AL_METERS_PER_UNIT:
+ pflValues[0] = ALfp2float(pContext->Listener.MetersPerUnit);
+ break;
+
+ case AL_POSITION:
+ pflValues[0] = ALfp2float(pContext->Listener.Position[0]);
+ pflValues[1] = ALfp2float(pContext->Listener.Position[1]);
+ pflValues[2] = ALfp2float(pContext->Listener.Position[2]);
+ break;
+
+ case AL_VELOCITY:
+ pflValues[0] = ALfp2float(pContext->Listener.Velocity[0]);
+ pflValues[1] = ALfp2float(pContext->Listener.Velocity[1]);
+ pflValues[2] = ALfp2float(pContext->Listener.Velocity[2]);
+ break;
+
+ case AL_ORIENTATION:
+ // AT then UP
+ pflValues[0] = ALfp2float(pContext->Listener.Forward[0]);
+ pflValues[1] = ALfp2float(pContext->Listener.Forward[1]);
+ pflValues[2] = ALfp2float(pContext->Listener.Forward[2]);
+ pflValues[3] = ALfp2float(pContext->Listener.Up[0]);
+ pflValues[4] = ALfp2float(pContext->Listener.Up[1]);
+ pflValues[5] = ALfp2float(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)ALfp2int(pContext->Listener.Position[0]);
+ *plValue2 = (ALint)ALfp2int(pContext->Listener.Position[1]);
+ *plValue3 = (ALint)ALfp2int(pContext->Listener.Position[2]);
+ break;
+
+ case AL_VELOCITY:
+ *plValue1 = (ALint)ALfp2int(pContext->Listener.Velocity[0]);
+ *plValue2 = (ALint)ALfp2int(pContext->Listener.Velocity[1]);
+ *plValue3 = (ALint)ALfp2int(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)ALfp2int(pContext->Listener.Position[0]);
+ plValues[1] = (ALint)ALfp2int(pContext->Listener.Position[1]);
+ plValues[2] = (ALint)ALfp2int(pContext->Listener.Position[2]);
+ break;
+
+ case AL_VELOCITY:
+ plValues[0] = (ALint)ALfp2int(pContext->Listener.Velocity[0]);
+ plValues[1] = (ALint)ALfp2int(pContext->Listener.Velocity[1]);
+ plValues[2] = (ALint)ALfp2int(pContext->Listener.Velocity[2]);
+ break;
+
+ case AL_ORIENTATION:
+ // AT then UP
+ plValues[0] = (ALint)ALfp2int(pContext->Listener.Forward[0]);
+ plValues[1] = (ALint)ALfp2int(pContext->Listener.Forward[1]);
+ plValues[2] = (ALint)ALfp2int(pContext->Listener.Forward[2]);
+ plValues[3] = (ALint)ALfp2int(pContext->Listener.Up[0]);
+ plValues[4] = (ALint)ALfp2int(pContext->Listener.Up[1]);
+ plValues[5] = (ALint)ALfp2int(pContext->Listener.Up[2]);
+ break;
+
+ default:
+ alSetError(pContext, AL_INVALID_ENUM);
+ break;
+ }
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+
+ ProcessContext(pContext);
+}
diff --git a/jni/OpenAL/OpenAL32/alSource.c b/jni/OpenAL/OpenAL32/alSource.c
new file mode 100644
index 0000000..b5d6ede
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alSource.c
@@ -0,0 +1,2091 @@
+/**
+ * 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
+#include
+#include
+#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"
+
+#ifdef ANDROID
+//#include
+
+// Apportable: Defines a cap on the maximum number of playing sources
+extern int alc_max_sources;
+extern int alc_active_sources;
+#endif
+
+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, ALdfp *Offsets, ALdfp 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 = float2ALfp(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 = float2ALfp(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 = float2ALfp(flValue);
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_GAIN:
+ if(flValue >= 0.0f)
+ {
+ Source->flGain = float2ALfp(flValue);
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_MAX_DISTANCE:
+ if(flValue >= 0.0f)
+ {
+ Source->flMaxDistance = float2ALfp(flValue);
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_ROLLOFF_FACTOR:
+ if(flValue >= 0.0f)
+ {
+ Source->flRollOffFactor = float2ALfp(flValue);
+ Source->NeedsUpdate = AL_TRUE;
+ }
+ else
+ alSetError(pContext, AL_INVALID_VALUE);
+ break;
+
+ case AL_REFERENCE_DISTANCE:
+ if(flValue >= 0.0f)
+ {
+ Source->flRefDistance = float2ALfp(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 = float2ALfp(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 = float2ALfp(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 = float2ALfp(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 = float2ALfp(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 = float2ALfp(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 = float2ALfp(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 = float2ALfp(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] = float2ALfp(flValue1);
+ Source->vPosition[1] = float2ALfp(flValue2);
+ Source->vPosition[2] = float2ALfp(flValue3);
+ Source->NeedsUpdate = AL_TRUE;
+ break;
+
+ case AL_VELOCITY:
+ Source->vVelocity[0] = float2ALfp(flValue1);
+ Source->vVelocity[1] = float2ALfp(flValue2);
+ Source->vVelocity[2] = float2ALfp(flValue3);
+ Source->NeedsUpdate = AL_TRUE;
+ break;
+
+ case AL_DIRECTION:
+ Source->vOrientation[0] = float2ALfp(flValue1);
+ Source->vOrientation[1] = float2ALfp(flValue2);
+ Source->vOrientation[2] = float2ALfp(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;
+ ALdfp Offsets[2];
+ ALdfp updateLen;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(pflValue)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_PITCH:
+ *pflValue = ALfp2float(Source->flPitch);
+ break;
+
+ case AL_GAIN:
+ *pflValue = ALfp2float(Source->flGain);
+ break;
+
+ case AL_MIN_GAIN:
+ *pflValue = ALfp2float(Source->flMinGain);
+ break;
+
+ case AL_MAX_GAIN:
+ *pflValue = ALfp2float(Source->flMaxGain);
+ break;
+
+ case AL_MAX_DISTANCE:
+ *pflValue = ALfp2float(Source->flMaxDistance);
+ break;
+
+ case AL_ROLLOFF_FACTOR:
+ *pflValue = ALfp2float(Source->flRollOffFactor);
+ break;
+
+ case AL_CONE_OUTER_GAIN:
+ *pflValue = ALfp2float(Source->flOuterGain);
+ break;
+
+ case AL_CONE_OUTER_GAINHF:
+ *pflValue = ALfp2float(Source->OuterGainHF);
+ break;
+
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ updateLen = ALdfpDiv(int2ALdfp(pContext->Device->UpdateSize),
+ int2ALdfp(pContext->Device->Frequency));
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ *pflValue = (ALfloat)ALdfp2double(Offsets[0]);
+ break;
+
+ case AL_CONE_INNER_ANGLE:
+ *pflValue = ALfp2float(Source->flInnerAngle);
+ break;
+
+ case AL_CONE_OUTER_ANGLE:
+ *pflValue = ALfp2float(Source->flOuterAngle);
+ break;
+
+ case AL_REFERENCE_DISTANCE:
+ *pflValue = ALfp2float(Source->flRefDistance);
+ break;
+
+ case AL_AIR_ABSORPTION_FACTOR:
+ *pflValue = ALfp2float(Source->AirAbsorptionFactor);
+ break;
+
+ case AL_ROOM_ROLLOFF_FACTOR:
+ *pflValue = ALfp2float(Source->RoomRolloffFactor);
+ break;
+
+ case AL_DOPPLER_FACTOR:
+ *pflValue = ALfp2float(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 = ALfp2float(Source->vPosition[0]);
+ *pflValue2 = ALfp2float(Source->vPosition[1]);
+ *pflValue3 = ALfp2float(Source->vPosition[2]);
+ break;
+
+ case AL_VELOCITY:
+ *pflValue1 = ALfp2float(Source->vVelocity[0]);
+ *pflValue2 = ALfp2float(Source->vVelocity[1]);
+ *pflValue3 = ALfp2float(Source->vVelocity[2]);
+ break;
+
+ case AL_DIRECTION:
+ *pflValue1 = ALfp2float(Source->vOrientation[0]);
+ *pflValue2 = ALfp2float(Source->vOrientation[1]);
+ *pflValue3 = ALfp2float(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;
+ ALdfp Offsets[2];
+ ALdfp 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 = ALdfpDiv(int2ALdfp(pContext->Device->UpdateSize),
+ int2ALdfp(pContext->Device->Frequency));
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ pflValues[0] = (ALfloat)ALdfp2double(Offsets[0]);
+ pflValues[1] = (ALfloat)ALdfp2double(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;
+ ALdfp Offsets[2];
+ ALdfp updateLen;
+
+ pContext = GetContextSuspended();
+ if(!pContext) return;
+
+ if(plValue)
+ {
+ if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+ {
+ switch(eParam)
+ {
+ case AL_MAX_DISTANCE:
+ *plValue = (ALint)ALfp2int(Source->flMaxDistance);
+ break;
+
+ case AL_ROLLOFF_FACTOR:
+ *plValue = (ALint)ALfp2int(Source->flRollOffFactor);
+ break;
+
+ case AL_REFERENCE_DISTANCE:
+ *plValue = (ALint)ALfp2int(Source->flRefDistance);
+ break;
+
+ case AL_SOURCE_RELATIVE:
+ *plValue = Source->bHeadRelative;
+ break;
+
+ case AL_CONE_INNER_ANGLE:
+ *plValue = (ALint)ALfp2int(Source->flInnerAngle);
+ break;
+
+ case AL_CONE_OUTER_ANGLE:
+ *plValue = (ALint)ALfp2int(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 = ALdfpDiv(int2ALdfp(pContext->Device->UpdateSize),
+ int2ALdfp(pContext->Device->Frequency));
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ *plValue = (ALint)ALfp2int(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)ALfp2int(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)ALfp2int(Source->vPosition[0]);
+ *plValue2 = (ALint)ALfp2int(Source->vPosition[1]);
+ *plValue3 = (ALint)ALfp2int(Source->vPosition[2]);
+ break;
+
+ case AL_VELOCITY:
+ *plValue1 = (ALint)ALfp2int(Source->vVelocity[0]);
+ *plValue2 = (ALint)ALfp2int(Source->vVelocity[1]);
+ *plValue3 = (ALint)ALfp2int(Source->vVelocity[2]);
+ break;
+
+ case AL_DIRECTION:
+ *plValue1 = (ALint)ALfp2int(Source->vOrientation[0]);
+ *plValue2 = (ALint)ALfp2int(Source->vOrientation[1]);
+ *plValue3 = (ALint)ALfp2int(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;
+ ALdfp Offsets[2];
+ ALdfp 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 = ALdfpDiv(int2ALdfp(pContext->Device->UpdateSize),
+ int2ALdfp(pContext->Device->Frequency));
+ GetSourceOffset(Source, eParam, Offsets, updateLen);
+ plValues[0] = (ALint)ALdfp2int(Offsets[0]);
+ plValues[1] = (ALint)ALdfp2int(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;
+ }
+ }
+
+#ifdef MAX_SOURCES_LOW
+ // Apportable: Cap the number of active source that are playing
+ if (Context->ActiveSourceCount + n > alc_max_sources) {
+ if (Context->ActiveSourceCount > alc_max_sources) {
+ n = 0;
+ } else {
+ n = alc_max_sources - Context->ActiveSourceCount;
+ }
+ }
+#endif
+
+ 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;
+ }
+
+#ifdef MAX_SOURCES_LOW
+ //Apportable Need to give the ALC platform code a hint for setting Source limit based on performance
+ // LOGI("Playing %d/%d ActiveSources", Context->ActiveSourceCount, alc_max_sources);
+ alc_active_sources = Context->ActiveSourceCount;
+#endif
+
+ 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 = int2ALfp(360);
+ Source->flOuterAngle = int2ALfp(360);
+ Source->flPitch = int2ALfp(1);
+ Source->vPosition[0] = int2ALfp(0);
+ Source->vPosition[1] = int2ALfp(0);
+ Source->vPosition[2] = int2ALfp(0);
+ Source->vOrientation[0] = int2ALfp(0);
+ Source->vOrientation[1] = int2ALfp(0);
+ Source->vOrientation[2] = int2ALfp(0);
+ Source->vVelocity[0] = int2ALfp(0);
+ Source->vVelocity[1] = int2ALfp(0);
+ Source->vVelocity[2] = int2ALfp(0);
+ Source->flRefDistance = int2ALfp(1);
+ Source->flMaxDistance = int2ALfp(FLT_MAX);
+ Source->flRollOffFactor = int2ALfp(1);
+ Source->bLooping = AL_FALSE;
+ Source->flGain = int2ALfp(1);
+ Source->flMinGain = int2ALfp(0);
+ Source->flMaxGain = int2ALfp(1);
+ Source->flOuterGain = int2ALfp(0);
+ Source->OuterGainHF = int2ALfp(1);
+
+ Source->DryGainHFAuto = AL_TRUE;
+ Source->WetGainAuto = AL_TRUE;
+ Source->WetGainHFAuto = AL_TRUE;
+ Source->AirAbsorptionFactor = int2ALfp(0);
+ Source->RoomRolloffFactor = int2ALfp(0);
+ Source->DopplerFactor = int2ALfp(1);
+
+ 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, ALdfp *offset, ALdfp 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] = int2ALdfp(0);
+ offset[1] = int2ALdfp(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)(ALdfp2int(ALdfpMult(updateLen,int2ALdfp(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] = ALdfpDiv(readPos, int2ALdfp(Channels * Bytes * BufferFreq));
+ offset[1] = ALdfpDiv(writePos, int2ALdfp(Channels * Bytes * BufferFreq));
+ break;
+ case AL_SAMPLE_OFFSET:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ offset[0] = int2ALdfp(readPos / (Channels * Bytes));
+ offset[1] = int2ALdfp(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] = int2ALdfp(readPos / FrameBlockSize * BlockSize);
+ if(Source->state != AL_PLAYING)
+ offset[1] = offset[0];
+ else
+ {
+ // Round up to nearest ADPCM block
+ offset[1] = int2ALdfp((writePos+FrameBlockSize-1) /
+ (FrameBlockSize * BlockSize));
+ }
+ }
+ else
+ {
+ ALuint OrigBytes = BytesFromUserFmt(OriginalType);
+ offset[0] = int2ALdfp(readPos / Bytes * OrigBytes);
+ offset[1] = int2ALdfp(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);
+ }
+}
diff --git a/jni/OpenAL/OpenAL32/alState.c b/jni/OpenAL/OpenAL32/alState.c
new file mode 100644
index 0000000..74c6a40
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alState.c
@@ -0,0 +1,661 @@
+/**
+ * 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
+#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 != int2ALfp(0))
+ value = AL_TRUE;
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ if(Context->DopplerVelocity != int2ALfp(0))
+ 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 != int2ALfp(0))
+ 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)ALfp2float(Context->DopplerFactor);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = (double)ALfp2float(Context->DopplerVelocity);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (double)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = (double)ALfp2float(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 = ALfp2float(Context->DopplerFactor);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = ALfp2float(Context->DopplerVelocity);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (float)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = ALfp2float(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)ALfp2int(Context->DopplerFactor);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ value = (ALint)ALfp2int(Context->DopplerVelocity);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ value = (ALint)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ value = (ALint)ALfp2int(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 != int2ALfp(0)) ? AL_TRUE : AL_FALSE);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = (ALboolean)((Context->DopplerVelocity != int2ALfp(0)) ? 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 != int2ALfp(0)) ? 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)ALfp2float(Context->DopplerFactor);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = (double)ALfp2float(Context->DopplerVelocity);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *data = (double)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ *data = (double)ALfp2float(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 = ALfp2float(Context->DopplerFactor);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = ALfp2float(Context->DopplerVelocity);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *data = (float)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ *data = ALfp2float(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)ALfp2int(Context->DopplerFactor);
+ break;
+
+ case AL_DOPPLER_VELOCITY:
+ *data = (ALint)ALfp2int(Context->DopplerVelocity);
+ break;
+
+ case AL_DISTANCE_MODEL:
+ *data = (ALint)Context->DistanceModel;
+ break;
+
+ case AL_SPEED_OF_SOUND:
+ *data = (ALint)ALfp2int(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 = float2ALfp(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=float2ALfp(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 = float2ALfp(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);
+}
diff --git a/jni/OpenAL/OpenAL32/alThunk.c b/jni/OpenAL/OpenAL32/alThunk.c
new file mode 100644
index 0000000..08b80b0
--- /dev/null
+++ b/jni/OpenAL/OpenAL32/alThunk.c
@@ -0,0 +1,111 @@
+/**
+ * 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
+
+#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;
+}
diff --git a/jni/OpenAL/al.h b/jni/OpenAL/al.h
new file mode 100644
index 0000000..44db779
--- /dev/null
+++ b/jni/OpenAL/al.h
@@ -0,0 +1,724 @@
+#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 */
diff --git a/jni/OpenAL/alc.h b/jni/OpenAL/alc.h
new file mode 100644
index 0000000..04543a0
--- /dev/null
+++ b/jni/OpenAL/alc.h
@@ -0,0 +1,277 @@
+#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 Hz
+ */
+#define ALC_FREQUENCY 0x1007
+
+/**
+ * followed by Hz
+ */
+#define ALC_REFRESH 0x1008
+
+/**
+ * followed by AL_TRUE, AL_FALSE
+ */
+#define ALC_SYNC 0x1009
+
+/**
+ * followed by Num of requested Mono (3D) Sources
+ */
+#define ALC_MONO_SOURCES 0x1010
+
+/**
+ * followed by 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 */
diff --git a/jni/OpenAL/build.mk b/jni/OpenAL/build.mk
new file mode 100644
index 0000000..6ffe5a2
--- /dev/null
+++ b/jni/OpenAL/build.mk
@@ -0,0 +1,54 @@
+MODULE = System/OpenAL
+
+CCFLAGS = \
+ -I$(SYSDIR) \
+ -I$(SYSDIR)/OpenAL/include \
+ -I$(SYSDIR)/OpenAL/OpenAL32/Include \
+ -DAL_BUILD_LIBRARY \
+ -DAL_ALEXT_PROTOTYPES \
+ -DVERDE_USE_REAL_FILE_IO \
+
+OBJECTS = \
+
+ifneq ($(OS), mac)
+OBJECTS += \
+ OpenAL32/alAuxEffectSlot.o \
+ OpenAL32/alBuffer.o \
+ OpenAL32/alDatabuffer.o \
+ OpenAL32/alEffect.o \
+ OpenAL32/alError.o \
+ OpenAL32/alExtension.o \
+ OpenAL32/alFilter.o \
+ OpenAL32/alListener.o \
+ OpenAL32/alSource.o \
+ OpenAL32/alState.o \
+ OpenAL32/alThunk.o \
+ Alc/ALc.o \
+ Alc/alcConfig.o \
+ Alc/alcEcho.o \
+ Alc/alcModulator.o \
+ Alc/alcReverb.o \
+ Alc/alcRing.o \
+ Alc/alcThread.o \
+ Alc/ALu.o \
+ Alc/bs2b.o \
+ Alc/null.o \
+ Alc/panning.o \
+ Alc/mixer.o \
+
+endif
+
+ifeq ($(TARGET_OS), android)
+OBJECTS += Alc/audiotrack.o
+ifdef POST_FROYO
+OBJECTS += Alc/opensles.o
+endif
+CCFLAGS += -I/Developer/AndroidNDK/platforms/android-9/arch-arm/usr/include
+CCFLAGS += -DOPENAL_FIXED_POINT -DOPENAL_FIXED_POINT_SHIFT=16
+endif
+
+ifeq ($(OS), linux)
+OBJECTS += Alc/oss.o
+endif
+
+include $(ROOTDIR)/module.mk
diff --git a/jni/OpenAL/include/AL/al.h b/jni/OpenAL/include/AL/al.h
new file mode 100644
index 0000000..e3a1bc5
--- /dev/null
+++ b/jni/OpenAL/include/AL/al.h
@@ -0,0 +1,814 @@
+#ifndef AL_AL_H
+#define AL_AL_H
+
+#ifdef ANDROID
+#include
+#ifndef LOGI
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"OpenAL",__VA_ARGS__)
+#endif
+#ifndef LOGE
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"OpenAL",__VA_ARGS__)
+#endif
+#endif
+
+#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;
+
+#ifdef OPENAL_FIXED_POINT
+/** Types and Macros for fixed-point math */
+#ifndef INT64_MAX
+typedef long long int64_t;
+#define INT64_MAX 9223372036854775807LL
+
+#endif
+#ifndef INT32_MAX
+typedef int int32_t;
+#define INT32_MAX 2147483647
+#endif
+
+// FIXME(apportable) make this int32_t
+typedef int64_t ALfp;
+typedef int64_t ALdfp;
+
+#define ONE (1<=0 ? 0.5 : -0.5)))
+#define ALfp2float(x) ((float)(x) / (1<=0 ? 0.5 : -0.5)))
+#define ALdfp2double(x) ((double)(x) / (1<> OPENAL_FIXED_POINT_SHIFT))
+
+#define int2ALdfp(x) ((ALdfp)(x) << OPENAL_FIXED_POINT_SHIFT)
+#define ALdfp2int(x) ((ALint)((x) >> OPENAL_FIXED_POINT_SHIFT))
+
+#define ALfpMult(x,y) ((ALfp)((((int64_t)(x))*((int64_t)(y)))>>OPENAL_FIXED_POINT_SHIFT))
+#define ALfpDiv(x,y) ((ALfp)(((int64_t)(x) << OPENAL_FIXED_POINT_SHIFT) / (y)))
+
+#define ALdfpMult(x,y) ALfpMult(x,y)
+#define ALdfpDiv(x,y) ALfpDiv(x,y)
+
+#define __isnan(x) (0)
+#define __cos(x) (float2ALfp(cos(ALfp2float(x))))
+#define __sin(x) (float2ALfp(sin(ALfp2float(x))))
+#define __log10(x) (float2ALfp(log10(ALfp2float(x))))
+#define __atan(x) (float2ALfp(atan(ALfp2float(x))))
+
+#define toALfpConst(x) ((x)*(1< Hz
+ */
+#define ALC_FREQUENCY 0x1007
+
+/**
+ * followed by Hz
+ */
+#define ALC_REFRESH 0x1008
+
+/**
+ * followed by AL_TRUE, AL_FALSE
+ */
+#define ALC_SYNC 0x1009
+
+/**
+ * followed by Num of requested Mono (3D) Sources
+ */
+#define ALC_MONO_SOURCES 0x1010
+
+/**
+ * followed by 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 */
diff --git a/jni/OpenAL/include/AL/alext.h b/jni/OpenAL/include/AL/alext.h
new file mode 100644
index 0000000..f3c7bca
--- /dev/null
+++ b/jni/OpenAL/include/AL/alext.h
@@ -0,0 +1,165 @@
+/**
+ * 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
+
+#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
diff --git a/jni/OpenAL/include/AL/efx-creative.h b/jni/OpenAL/include/AL/efx-creative.h
new file mode 100644
index 0000000..0a04c98
--- /dev/null
+++ b/jni/OpenAL/include/AL/efx-creative.h
@@ -0,0 +1,3 @@
+/* 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. */
diff --git a/jni/OpenAL/include/AL/efx.h b/jni/OpenAL/include/AL/efx.h
new file mode 100644
index 0000000..0ccef95
--- /dev/null
+++ b/jni/OpenAL/include/AL/efx.h
@@ -0,0 +1,758 @@
+#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 */
diff --git a/jni/OpenAL/include/config.h b/jni/OpenAL/include/config.h
new file mode 100755
index 0000000..83acafa
--- /dev/null
+++ b/jni/OpenAL/include/config.h
@@ -0,0 +1,110 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Define to the library version */
+#define ALSOFT_VERSION "1.12.854"
+
+/* Define if we have the Android backend */
+#if defined(ANDROID)
+#if defined(POST_FROYO)
+#define HAVE_OPENSLES 1
+#endif
+
+#define HAVE_AUDIOTRACK 1
+
+// For throttling AlSource.c
+#define MAX_SOURCES_LOW 8
+#define MAX_SOURCES_HIGH 64
+#endif
+
+/* 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 Wave Writer backend */
+/* #cmakedefine HAVE_WAVE */
+
+/* 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 dlfcn.h */
+#define HAVE_DLFCN_H 1
+
+/* Define if we have the stat function */
+#define HAVE_STAT 1
+
+/* Define if we have the powf function */
+#define HAVE_POWF 1
+
+/* Define if we have the sqrtf function */
+#define HAVE_SQRTF 1
+
+/* Define if we have the acosf function */
+#define HAVE_ACOSF 1
+
+/* Define if we have the atanf function */
+#define HAVE_ATANF 1
+
+/* Define if we have the fabsf function */
+#define HAVE_FABSF 1
+
+/* Define if we have the strtof function */
+#define HAVE_STRTOF 1
+
+/* Define if we have stdint.h */
+#define HAVE_STDINT_H 1
+
+/* Define if we have the __int64 type */
+/* #cmakedefine HAVE___INT64 */
+
+/* Define to the size of a long int type */
+#define SIZEOF_LONG 4
+
+/* Define to the size of a long long int type */
+#define SIZEOF_LONG_LONG 8
+
+/* Define to the size of an unsigned int type */
+#define SIZEOF_UINT 4
+
+/* Define to the size of a void pointer type */
+#define SIZEOF_VOIDP 4
+
+/* Define if we have GCC's destructor attribute */
+#define HAVE_GCC_DESTRUCTOR 1
+
+/* Define if we have GCC's format attribute */
+#define HAVE_GCC_FORMAT 1
+
+/* 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 */
+#define HAVE_FENV_H 1
+
+/* Define if we have fesetround() */
+/* #cmakedefine HAVE_FESETROUND */
+
+/* Define if we have _controlfp() */
+/* #cmakedefine HAVE__CONTROLFP */
+
+/* Define if we have pthread_setschedparam() */
+#define HAVE_PTHREAD_SETSCHEDPARAM 1
+
+#endif
diff --git a/jni/OpenAL/oalStaticBufferExtension.h b/jni/OpenAL/oalStaticBufferExtension.h
new file mode 100644
index 0000000..e69de29
diff --git a/libs/armeabi/libopenal.so b/libs/armeabi/libopenal.so
new file mode 100755
index 0000000..f63f359
Binary files /dev/null and b/libs/armeabi/libopenal.so differ
diff --git a/local.properties b/local.properties
new file mode 100644
index 0000000..f93af5b
--- /dev/null
+++ b/local.properties
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/Developer/AndroidSDK
diff --git a/proguard.cfg b/proguard.cfg
new file mode 100644
index 0000000..b1cdf17
--- /dev/null
+++ b/proguard.cfg
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+-keepclasseswithmembers class * {
+ public (android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+ public (android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
Binary files /dev/null and b/res/drawable-hdpi/icon.png differ
diff --git a/res/drawable-ldpi/icon.png b/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..1095584
Binary files /dev/null and b/res/drawable-ldpi/icon.png differ
diff --git a/res/drawable-mdpi/icon.png b/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
Binary files /dev/null and b/res/drawable-mdpi/icon.png differ
diff --git a/res/layout/main.xml b/res/layout/main.xml
new file mode 100644
index 0000000..b042858
--- /dev/null
+++ b/res/layout/main.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..127a314
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ openal_soft
+
diff --git a/src/com/apportable/openal_soft/openal_soft.java b/src/com/apportable/openal_soft/openal_soft.java
new file mode 100644
index 0000000..e3662e4
--- /dev/null
+++ b/src/com/apportable/openal_soft/openal_soft.java
@@ -0,0 +1,15 @@
+package com.apportable.openal_soft;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class openal_soft extends Activity
+{
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+}