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); + } +}