diff --git a/.hgignore b/.hgignore index ba6495930..e37274a4b 100644 --- a/.hgignore +++ b/.hgignore @@ -5,6 +5,7 @@ obj/** libs/** make/** bin/** +assets/** projects/windows/vc2010/eepp/cdeps/Debug/** projects/windows/vc2010/eepp/cdeps/Release/** projects/windows/vc2010/empty_window/Debug/** diff --git a/include/eepp/audio/csound.hpp b/include/eepp/audio/csound.hpp index 58e7d8c52..a1ffef773 100755 --- a/include/eepp/audio/csound.hpp +++ b/include/eepp/audio/csound.hpp @@ -14,7 +14,7 @@ enum EE_SOUND_STATE { SOUND_PLAYING }; -class EE_API cSound : public cAudioResource { +class EE_API cSound { public : cSound(); diff --git a/include/eepp/audio/csoundbuffer.hpp b/include/eepp/audio/csoundbuffer.hpp index 466cf0289..a8d642f3f 100755 --- a/include/eepp/audio/csoundbuffer.hpp +++ b/include/eepp/audio/csoundbuffer.hpp @@ -10,7 +10,7 @@ namespace EE { namespace Audio { class cSound; -class EE_API cSoundBuffer : public cAudioResource { +class EE_API cSoundBuffer { public : cSoundBuffer(); diff --git a/include/eepp/system/cpack.hpp b/include/eepp/system/cpack.hpp index 3efd69561..6c29192c9 100755 --- a/include/eepp/system/cpack.hpp +++ b/include/eepp/system/cpack.hpp @@ -65,6 +65,9 @@ class EE_API cPack : protected cMutex { /** @return If the pack file is open */ virtual bool IsOpen() const; + + /** @return The file path of the opened package */ + virtual std::string GetPackPath() = 0; protected: bool mIsOpen; }; diff --git a/include/eepp/system/cpackmanager.hpp b/include/eepp/system/cpackmanager.hpp index bcfaee40e..b140d58f2 100644 --- a/include/eepp/system/cpackmanager.hpp +++ b/include/eepp/system/cpackmanager.hpp @@ -17,6 +17,8 @@ class EE_API cPackManager : public tContainer { cPack * Exists( std::string& path ); + cPack * GetPackByPath( std::string path ); + const bool& FallbackToPacks() const; void FallbackToPacks( const bool& fallback ); diff --git a/include/eepp/system/cpak.hpp b/include/eepp/system/cpak.hpp index d0a1d6236..3815eab9a 100755 --- a/include/eepp/system/cpak.hpp +++ b/include/eepp/system/cpak.hpp @@ -63,7 +63,10 @@ class EE_API cPak : public cPack { std::vector GetFileList(); /** @return If the PAK file is open */ - bool IsOpen() const { return mIsOpen; } + bool IsOpen() const; + + /** @return The file path of the opened package */ + std::string GetPackPath(); protected: private: diff --git a/include/eepp/system/czip.hpp b/include/eepp/system/czip.hpp index 204e848ec..66236e945 100644 --- a/include/eepp/system/czip.hpp +++ b/include/eepp/system/czip.hpp @@ -63,6 +63,9 @@ class EE_API cZip : public cPack { /** Add a new file from memory */ bool AddFile( std::vector& data, const std::string& inpack ); + + /** @return The file path of the opened package */ + std::string GetPackPath(); protected: struct zip * mZip; diff --git a/include/eepp/version.hpp b/include/eepp/version.hpp index 5e94ff777..442f39631 100644 --- a/include/eepp/version.hpp +++ b/include/eepp/version.hpp @@ -22,6 +22,8 @@ #define EEPP_VERSION_ATLEAST(X, Y, Z) (EEPP_COMPILEDVERSION >= EEPP_VERSIONNUM(X, Y, Z)) +#define EEPP_CODENAME "Sakkaya" + namespace EE { class EE_API Version { @@ -38,6 +40,9 @@ class EE_API Version { /** @return The library version name: "eepp version major.minor.patch" */ static std::string GetVersionName(); + + /** @return The version codename */ + static std::string GetCodename(); }; } diff --git a/projects/android-project/jni/Android.mk b/projects/android-project/jni/Android.mk index 429e5a89d..f7f5613a1 100644 --- a/projects/android-project/jni/Android.mk +++ b/projects/android-project/jni/Android.mk @@ -71,7 +71,7 @@ LOCAL_C_INCLUDES := $(MY_C_INCLUDES) LOCAL_SRC_FILES := $(foreach F, $(CODE_SRCS), $(addprefix $(dir $(F)),$(notdir $(wildcard $(LOCAL_PATH)/$(F))))) -LOCAL_STATIC_LIBRARIES := SDL2 chipmunk freetype openal +LOCAL_STATIC_LIBRARIES := openal SDL2 chipmunk freetype include $(BUILD_STATIC_LIBRARY) #*************** EEPP *************** @@ -122,20 +122,36 @@ include $(BUILD_STATIC_LIBRARY) #*************** OPENAL ***************** include $(CLEAR_VARS) -LOCAL_PATH := $(MY_PATH)/helper/android/openal +LOCAL_PATH := $(MY_PATH)/helper/android/openal-soft LOCAL_MODULE := openal -APP_SUBDIRS := $(patsubst $(LOCAL_PATH)/%, %, $(shell find $(LOCAL_PATH)/src -type d)) +LOCAL_CFLAGS := -O3 -DHAVE_CONFIG_H -DAL_ALEXT_PROTOTYPES -DHAVE_OPENSL -LOCAL_C_INCLUDES := $(foreach D, $(APP_SUBDIRS), $(LOCAL_PATH)/$(D)) $(LOCAL_PATH)/include -LOCAL_CFLAGS := -O3 -DHAVE_CONFIG_H -DAL_ALEXT_PROTOTYPES +LOCAL_C_INCLUDES := $(LOCAL_PATH)/ \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/OpenAL32/Include -LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.c)))) +LOCAL_SRC_FILES := \ + $(subst $(LOCAL_PATH)/,, \ + $(wildcard $(LOCAL_PATH)/OpenAL32/*.c) \ + $(wildcard $(LOCAL_PATH)/Alc/AL*.c) \ + $(wildcard $(LOCAL_PATH)/Alc/alc*.c) \ + $(LOCAL_PATH)/Alc/bs2b.c \ + $(LOCAL_PATH)/Alc/helpers.c \ + $(LOCAL_PATH)/Alc/hrtf.c \ + $(LOCAL_PATH)/Alc/mixer.c \ + $(LOCAL_PATH)/Alc/mixer_c.c \ + $(LOCAL_PATH)/Alc/panning.c \ + $(LOCAL_PATH)/Alc/backends/opensl.c \ + $(LOCAL_PATH)/Alc/backends/loopback.c \ + $(LOCAL_PATH)/Alc/backends/wave.c \ + $(LOCAL_PATH)/Alc/backends/null.c \ + $(wildcard $(LOCAL_PATH)/src/video/android/*.c)) -LOCAL_LDLIBS := -llog +LOCAL_LDLIBS := -llog -lOpenSLES -include $(BUILD_STATIC_LIBRARY) +include $(BUILD_SHARED_LIBRARY) #*************** OPENAL ***************** #**************** SDL 2 *************** @@ -191,7 +207,7 @@ include $(CLEAR_VARS) LOCAL_PATH := $(MY_PATH) -LOCAL_MODULE := empty_window +LOCAL_MODULE := main LOCAL_LDLIBS := $(MY_LDLIBS) @@ -215,7 +231,7 @@ include $(CLEAR_VARS) LOCAL_PATH := $(MY_PATH) -LOCAL_MODULE := main +LOCAL_MODULE := external_shader LOCAL_LDLIBS := $(MY_LDLIBS) diff --git a/projects/android-project/jni/Application.mk b/projects/android-project/jni/Application.mk index db731041d..523fbdf63 100644 --- a/projects/android-project/jni/Application.mk +++ b/projects/android-project/jni/Application.mk @@ -10,7 +10,7 @@ EE_GLES_LINK := -lGLESv1_CM APP_STL := stlport_static -APP_LDLIBS := -llog $(EE_GLES_LINK) -lm -lz +APP_LDLIBS := -llog $(EE_GLES_LINK) -lm -lz -lOpenSLES #Debug Build #APP_CFLAGS := -g -DDEBUG -DEE_DEBUG -DEE_MEMORY_MANAGER # arm-linux-androideabi-4.4.3 crashes in -O0 mode on SDL sources diff --git a/projects/android-project/src/org/libsdl/app/SDLActivity.java b/projects/android-project/src/org/libsdl/app/SDLActivity.java index 5fc6d33b8..ec3cb233e 100644 --- a/projects/android-project/src/org/libsdl/app/SDLActivity.java +++ b/projects/android-project/src/org/libsdl/app/SDLActivity.java @@ -58,10 +58,7 @@ public class SDLActivity extends Activity { // Load the .so static { - //System.loadLibrary("SDL2"); - //System.loadLibrary("SDL2_image"); - //System.loadLibrary("SDL2_mixer"); - //System.loadLibrary("SDL2_ttf"); + System.loadLibrary("openal"); System.loadLibrary("main"); } diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index 91201682b..0cdd2154b 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + ProjectExplorer.Project.ActiveTarget @@ -48,7 +48,7 @@ Desktop Desktop {388e5431-b31b-42b3-b9ad-9002d279d75d} - 0 + 8 0 2 @@ -497,7 +497,7 @@ false - -j4 -e DEBUGBUILD=yes + -j4 -e DEBUGBUILD=yes ew true Make @@ -512,7 +512,7 @@ true - -e DEBUGBUILD=yes + -e DEBUGBUILD=yes ew /usr/bin/make %{buildDir} Custom Process Step diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 094618491..586d5d56c 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -570,3 +570,5 @@ ../../include/eepp/graphics/glhelper.hpp ../../include/eepp/window/windowhandle.hpp ../../include/eepp/window/windowcontext.hpp +../../include/eepp/version.hpp +../../src/eepp/base/version.cpp diff --git a/src/eepp/audio/caudiodevice.cpp b/src/eepp/audio/caudiodevice.cpp index 9297cd288..45c51e68c 100755 --- a/src/eepp/audio/caudiodevice.cpp +++ b/src/eepp/audio/caudiodevice.cpp @@ -20,8 +20,10 @@ cAudioDevice::cAudioDevice() { alcMakeContextCurrent( mContext ); // Initialize the listener, located at the origin and looking along the Z axis - //cAudioListener::Position(0.f, 0.f, 0.f); - //cAudioListener::Target(0.f, 0.f, -1.f); + ALCheck( alListenerf( AL_GAIN, 1.f ) ); + ALCheck( alListener3f( AL_POSITION, 0.f, 0.f, 0.f ) ); + ALfloat Orientation[] = {0.f, 0.f, -1.f, 0.f, 1.f, 0.f}; + ALCheck( alListenerfv( AL_ORIENTATION, Orientation ) ); std::string log( "OpenAL current device:\n" ); log += "\t" + std::string( (const char *)alcGetString(mDevice, ALC_DEVICE_SPECIFIER) ); diff --git a/src/eepp/audio/cmusic.cpp b/src/eepp/audio/cmusic.cpp index 041df49a9..e0ba58cbd 100755 --- a/src/eepp/audio/cmusic.cpp +++ b/src/eepp/audio/cmusic.cpp @@ -55,6 +55,7 @@ bool cMusic::OpenFromFile( const std::string& Filename ) { Initialize( mFile->GetChannelsCount(), mFile->GetSampleRate() ); cLog::instance()->Write( "Music file " + Filename + " loaded." ); + return true; } @@ -75,6 +76,7 @@ bool cMusic::OpenFromMemory( const char * Data, std::size_t SizeInBytes ) { Initialize( mFile->GetChannelsCount(), mFile->GetSampleRate() ); // Initialize the stream cLog::instance()->Write( "Music file loaded from memory." ); + return true; } diff --git a/src/eepp/audio/csound.cpp b/src/eepp/audio/csound.cpp index 8daaae28a..6b1c5f0f2 100755 --- a/src/eepp/audio/csound.cpp +++ b/src/eepp/audio/csound.cpp @@ -2,12 +2,20 @@ namespace EE { namespace Audio { -cSound::cSound() : mBuffer(NULL) { +cSound::cSound() : + mBuffer(NULL) +{ + EnsureALInit(); + ALCheck( alGenSources( 1, &mSource ) ); ALCheck( alSourcei( mSource, AL_BUFFER, 0 ) ); } -cSound::cSound( const cSoundBuffer& Buffer, const bool& Loop, const eeFloat& Pitch, const eeFloat& Volume, const Vector3AL& Position ) : mBuffer(&Buffer) { +cSound::cSound( const cSoundBuffer& Buffer, const bool& Loop, const eeFloat& Pitch, const eeFloat& Volume, const Vector3AL& Position ) : + mBuffer(&Buffer) +{ + EnsureALInit(); + ALCheck( alGenSources(1, &mSource) ); ALCheck( alSourcei ( mSource, AL_BUFFER, Buffer.mBuffer ) ); @@ -18,9 +26,10 @@ cSound::cSound( const cSoundBuffer& Buffer, const bool& Loop, const eeFloat& Pit } cSound::cSound(const cSound& Copy) : - cAudioResource(Copy), mBuffer(Copy.mBuffer) { + EnsureALInit(); + ALCheck( alGenSources( 1, &mSource ) ); ALCheck( alSourcei ( mSource, AL_BUFFER, mBuffer ? mBuffer->mBuffer : 0) ); diff --git a/src/eepp/audio/csoundbuffer.cpp b/src/eepp/audio/csoundbuffer.cpp index e6c9a12a1..554288a70 100755 --- a/src/eepp/audio/csoundbuffer.cpp +++ b/src/eepp/audio/csoundbuffer.cpp @@ -16,7 +16,6 @@ cSoundBuffer::cSoundBuffer() : } cSoundBuffer::cSoundBuffer(const cSoundBuffer& Copy) : - cAudioResource(Copy), mBuffer(0), mSamples(Copy.mSamples), mDuration(Copy.mDuration), @@ -60,7 +59,7 @@ bool cSoundBuffer::LoadFromFile(const std::string& Filename) { // Get the sound parameters std::size_t NbSamples = File->GetSamplesCount(); unsigned int ChannelsCount = File->GetChannelsCount(); - unsigned int SampleRate = File->GetSampleRate(); + unsigned int SampleRate = File->GetSampleRate(); // Read the samples from the opened file mSamples.resize( NbSamples ); @@ -105,7 +104,7 @@ bool cSoundBuffer::LoadFromMemory( const char* Data, std::size_t SizeInBytes ) { // Get the sound parameters std::size_t NbSamples = File->GetSamplesCount(); unsigned int ChannelsCount = File->GetChannelsCount(); - unsigned int SampleRate = File->GetSampleRate(); + unsigned int SampleRate = File->GetSampleRate(); // Read the samples from the opened file mSamples.resize( NbSamples ); diff --git a/src/eepp/audio/csoundfileogg.cpp b/src/eepp/audio/csoundfileogg.cpp index 86d2fb922..6aac2fb8d 100755 --- a/src/eepp/audio/csoundfileogg.cpp +++ b/src/eepp/audio/csoundfileogg.cpp @@ -59,7 +59,7 @@ bool cSoundFileOgg::OpenRead( const std::string& Filename, std::size_t& NbSample stb_vorbis_info Infos = stb_vorbis_get_info( mStream ); ChannelsCount = mChannelsCount = Infos.channels; SampleRate = Infos.sample_rate; - NbSamples = static_cast(stb_vorbis_stream_length_in_samples(mStream) * ChannelsCount); + NbSamples = static_cast( stb_vorbis_stream_length_in_samples( mStream ) * ChannelsCount ); return true; } @@ -84,7 +84,7 @@ bool cSoundFileOgg::OpenRead( const char* Data, std::size_t SizeInBytes, std::si stb_vorbis_info Infos = stb_vorbis_get_info( mStream ); ChannelsCount = mChannelsCount = Infos.channels; SampleRate = Infos.sample_rate; - NbSamples = static_cast( stb_vorbis_stream_length_in_samples( mStream ) ); + NbSamples = static_cast( stb_vorbis_stream_length_in_samples( mStream ) * ChannelsCount ); return true; } @@ -92,9 +92,13 @@ bool cSoundFileOgg::OpenRead( const char* Data, std::size_t SizeInBytes, std::si std::size_t cSoundFileOgg::Read( Int16 * Data, std::size_t NbSamples ) { if ( NULL != mStream && Data && NbSamples ) { int Read = stb_vorbis_get_samples_short_interleaved( mStream, mChannelsCount, Data, static_cast( NbSamples ) ); - return static_cast( Read * mChannelsCount ); - } else - return 0; + + std::size_t scount = Read * mChannelsCount; + + return scount; + } + + return 0; } void cSoundFileOgg::Seek( Uint32 timeOffset ) { diff --git a/src/eepp/base/version.cpp b/src/eepp/base/version.cpp index ed0c83653..321f13f53 100644 --- a/src/eepp/base/version.cpp +++ b/src/eepp/base/version.cpp @@ -19,4 +19,8 @@ std::string Version::GetVersionName() { return String::StrFormated( "eepp version %d.%d.%d", ver.major, ver.minor, ver.patch ); } +std::string Version::GetCodename() { + return std::string( EEPP_CODENAME ); +} + } diff --git a/src/eepp/helper/SDL2/src/core/android/SDL_android.cpp b/src/eepp/helper/SDL2/src/core/android/SDL_android.cpp index b1b6490ca..9296e9ed3 100644 --- a/src/eepp/helper/SDL2/src/core/android/SDL_android.cpp +++ b/src/eepp/helper/SDL2/src/core/android/SDL_android.cpp @@ -27,7 +27,6 @@ #include "SDL_system.h" #include "SDL_android.h" -#include extern "C" { #include "../../events/SDL_events_c.h" @@ -103,8 +102,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) Android_JNI_SetupThread(); } - AL_SetJavaVM( vm ); - return JNI_VERSION_1_4; } diff --git a/src/eepp/helper/android/openal-soft/Alc/ALc.c b/src/eepp/helper/android/openal-soft/Alc/ALc.c new file mode 100644 index 000000000..fd5b8894d --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/ALc.c @@ -0,0 +1,3193 @@ +/** + * 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 "alSource.h" +#include "alListener.h" +#include "alThunk.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "bs2b.h" +#include "alu.h" + + +/************************************************ + * Backends + ************************************************/ +#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +static struct 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_COREAUDIO + { "core", alc_ca_init, alc_ca_deinit, alc_ca_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_SNDIO + { "sndio", alc_sndio_init, alc_sndio_deinit, alc_sndio_probe, EmptyFuncs }, +#endif +#ifdef HAVE_MMDEVAPI + { "mmdevapi", alcMMDevApiInit, alcMMDevApiDeinit, alcMMDevApiProbe, 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_OPENSL + { "opensl", alc_opensl_init, alc_opensl_deinit, alc_opensl_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 } +}; +static struct BackendInfo BackendLoopback = { + "loopback", alc_loopback_init, alc_loopback_deinit, alc_loopback_probe, EmptyFuncs +}; +#undef EmptyFuncs + +static struct BackendInfo PlaybackBackend; +static struct BackendInfo CaptureBackend; + +/************************************************ + * Functions, enums, and errors + ************************************************/ +typedef struct ALCfunction { + const ALCchar *funcName; + ALCvoid *address; +} ALCfunction; + +typedef struct ALCenums { + const ALCchar *enumName; + ALCenum value; +} ALCenums; + +#define DECL(x) { #x, (ALCvoid*)(x) } +static const ALCfunction alcFunctions[] = { + DECL(alcCreateContext), + DECL(alcMakeContextCurrent), + DECL(alcProcessContext), + DECL(alcSuspendContext), + DECL(alcDestroyContext), + DECL(alcGetCurrentContext), + DECL(alcGetContextsDevice), + DECL(alcOpenDevice), + DECL(alcCloseDevice), + DECL(alcGetError), + DECL(alcIsExtensionPresent), + DECL(alcGetProcAddress), + DECL(alcGetEnumValue), + DECL(alcGetString), + DECL(alcGetIntegerv), + DECL(alcCaptureOpenDevice), + DECL(alcCaptureCloseDevice), + DECL(alcCaptureStart), + DECL(alcCaptureStop), + DECL(alcCaptureSamples), + + DECL(alcSetThreadContext), + DECL(alcGetThreadContext), + + DECL(alcLoopbackOpenDeviceSOFT), + DECL(alcIsRenderFormatSupportedSOFT), + DECL(alcRenderSamplesSOFT), + + DECL(alEnable), + DECL(alDisable), + DECL(alIsEnabled), + DECL(alGetString), + DECL(alGetBooleanv), + DECL(alGetIntegerv), + DECL(alGetFloatv), + DECL(alGetDoublev), + DECL(alGetBoolean), + DECL(alGetInteger), + DECL(alGetFloat), + DECL(alGetDouble), + DECL(alGetError), + DECL(alIsExtensionPresent), + DECL(alGetProcAddress), + DECL(alGetEnumValue), + DECL(alListenerf), + DECL(alListener3f), + DECL(alListenerfv), + DECL(alListeneri), + DECL(alListener3i), + DECL(alListeneriv), + DECL(alGetListenerf), + DECL(alGetListener3f), + DECL(alGetListenerfv), + DECL(alGetListeneri), + DECL(alGetListener3i), + DECL(alGetListeneriv), + DECL(alGenSources), + DECL(alDeleteSources), + DECL(alIsSource), + DECL(alSourcef), + DECL(alSource3f), + DECL(alSourcefv), + DECL(alSourcei), + DECL(alSource3i), + DECL(alSourceiv), + DECL(alGetSourcef), + DECL(alGetSource3f), + DECL(alGetSourcefv), + DECL(alGetSourcei), + DECL(alGetSource3i), + DECL(alGetSourceiv), + DECL(alSourcePlayv), + DECL(alSourceStopv), + DECL(alSourceRewindv), + DECL(alSourcePausev), + DECL(alSourcePlay), + DECL(alSourceStop), + DECL(alSourceRewind), + DECL(alSourcePause), + DECL(alSourceQueueBuffers), + DECL(alSourceUnqueueBuffers), + DECL(alGenBuffers), + DECL(alDeleteBuffers), + DECL(alIsBuffer), + DECL(alBufferData), + DECL(alBufferf), + DECL(alBuffer3f), + DECL(alBufferfv), + DECL(alBufferi), + DECL(alBuffer3i), + DECL(alBufferiv), + DECL(alGetBufferf), + DECL(alGetBuffer3f), + DECL(alGetBufferfv), + DECL(alGetBufferi), + DECL(alGetBuffer3i), + DECL(alGetBufferiv), + DECL(alDopplerFactor), + DECL(alDopplerVelocity), + DECL(alSpeedOfSound), + DECL(alDistanceModel), + + DECL(alGenFilters), + DECL(alDeleteFilters), + DECL(alIsFilter), + DECL(alFilteri), + DECL(alFilteriv), + DECL(alFilterf), + DECL(alFilterfv), + DECL(alGetFilteri), + DECL(alGetFilteriv), + DECL(alGetFilterf), + DECL(alGetFilterfv), + DECL(alGenEffects), + DECL(alDeleteEffects), + DECL(alIsEffect), + DECL(alEffecti), + DECL(alEffectiv), + DECL(alEffectf), + DECL(alEffectfv), + DECL(alGetEffecti), + DECL(alGetEffectiv), + DECL(alGetEffectf), + DECL(alGetEffectfv), + DECL(alGenAuxiliaryEffectSlots), + DECL(alDeleteAuxiliaryEffectSlots), + DECL(alIsAuxiliaryEffectSlot), + DECL(alAuxiliaryEffectSloti), + DECL(alAuxiliaryEffectSlotiv), + DECL(alAuxiliaryEffectSlotf), + DECL(alAuxiliaryEffectSlotfv), + DECL(alGetAuxiliaryEffectSloti), + DECL(alGetAuxiliaryEffectSlotiv), + DECL(alGetAuxiliaryEffectSlotf), + DECL(alGetAuxiliaryEffectSlotfv), + + DECL(alBufferSubDataSOFT), + + DECL(alBufferSamplesSOFT), + DECL(alBufferSubSamplesSOFT), + DECL(alGetBufferSamplesSOFT), + DECL(alIsBufferFormatSupportedSOFT), + + DECL(alDeferUpdatesSOFT), + DECL(alProcessUpdatesSOFT), + + DECL(alSourcedSOFT), + DECL(alSource3dSOFT), + DECL(alSourcedvSOFT), + DECL(alGetSourcedSOFT), + DECL(alGetSource3dSOFT), + DECL(alGetSourcedvSOFT), + DECL(alSourcei64SOFT), + DECL(alSource3i64SOFT), + DECL(alSourcei64vSOFT), + DECL(alGetSourcei64SOFT), + DECL(alGetSource3i64SOFT), + DECL(alGetSourcei64vSOFT), + + { NULL, NULL } +}; +#undef DECL + +#define DECL(x) { #x, (x) } +static const ALCenums enumeration[] = { + DECL(ALC_INVALID), + DECL(ALC_FALSE), + DECL(ALC_TRUE), + + DECL(ALC_MAJOR_VERSION), + DECL(ALC_MINOR_VERSION), + DECL(ALC_ATTRIBUTES_SIZE), + DECL(ALC_ALL_ATTRIBUTES), + DECL(ALC_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_DEVICE_SPECIFIER), + DECL(ALC_ALL_DEVICES_SPECIFIER), + DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), + DECL(ALC_EXTENSIONS), + DECL(ALC_FREQUENCY), + DECL(ALC_REFRESH), + DECL(ALC_SYNC), + DECL(ALC_MONO_SOURCES), + DECL(ALC_STEREO_SOURCES), + DECL(ALC_CAPTURE_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_SAMPLES), + DECL(ALC_CONNECTED), + + DECL(ALC_EFX_MAJOR_VERSION), + DECL(ALC_EFX_MINOR_VERSION), + DECL(ALC_MAX_AUXILIARY_SENDS), + + DECL(ALC_FORMAT_CHANNELS_SOFT), + DECL(ALC_FORMAT_TYPE_SOFT), + + DECL(ALC_MONO_SOFT), + DECL(ALC_STEREO_SOFT), + DECL(ALC_QUAD_SOFT), + DECL(ALC_5POINT1_SOFT), + DECL(ALC_6POINT1_SOFT), + DECL(ALC_7POINT1_SOFT), + + DECL(ALC_BYTE_SOFT), + DECL(ALC_UNSIGNED_BYTE_SOFT), + DECL(ALC_SHORT_SOFT), + DECL(ALC_UNSIGNED_SHORT_SOFT), + DECL(ALC_INT_SOFT), + DECL(ALC_UNSIGNED_INT_SOFT), + DECL(ALC_FLOAT_SOFT), + + DECL(ALC_NO_ERROR), + DECL(ALC_INVALID_DEVICE), + DECL(ALC_INVALID_CONTEXT), + DECL(ALC_INVALID_ENUM), + DECL(ALC_INVALID_VALUE), + DECL(ALC_OUT_OF_MEMORY), + + + DECL(AL_INVALID), + DECL(AL_NONE), + DECL(AL_FALSE), + DECL(AL_TRUE), + + DECL(AL_SOURCE_RELATIVE), + DECL(AL_CONE_INNER_ANGLE), + DECL(AL_CONE_OUTER_ANGLE), + DECL(AL_PITCH), + DECL(AL_POSITION), + DECL(AL_DIRECTION), + DECL(AL_VELOCITY), + DECL(AL_LOOPING), + DECL(AL_BUFFER), + DECL(AL_GAIN), + DECL(AL_MIN_GAIN), + DECL(AL_MAX_GAIN), + DECL(AL_ORIENTATION), + DECL(AL_REFERENCE_DISTANCE), + DECL(AL_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAIN), + DECL(AL_MAX_DISTANCE), + DECL(AL_SEC_OFFSET), + DECL(AL_SAMPLE_OFFSET), + DECL(AL_SAMPLE_RW_OFFSETS_SOFT), + DECL(AL_BYTE_OFFSET), + DECL(AL_BYTE_RW_OFFSETS_SOFT), + DECL(AL_SOURCE_TYPE), + DECL(AL_STATIC), + DECL(AL_STREAMING), + DECL(AL_UNDETERMINED), + DECL(AL_METERS_PER_UNIT), + DECL(AL_DIRECT_CHANNELS_SOFT), + + DECL(AL_DIRECT_FILTER), + DECL(AL_AUXILIARY_SEND_FILTER), + DECL(AL_AIR_ABSORPTION_FACTOR), + DECL(AL_ROOM_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAINHF), + DECL(AL_DIRECT_FILTER_GAINHF_AUTO), + DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO), + DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO), + + DECL(AL_SOURCE_STATE), + DECL(AL_INITIAL), + DECL(AL_PLAYING), + DECL(AL_PAUSED), + DECL(AL_STOPPED), + + DECL(AL_BUFFERS_QUEUED), + DECL(AL_BUFFERS_PROCESSED), + + DECL(AL_FORMAT_MONO8), + DECL(AL_FORMAT_MONO16), + DECL(AL_FORMAT_MONO_FLOAT32), + DECL(AL_FORMAT_MONO_DOUBLE_EXT), + DECL(AL_FORMAT_STEREO8), + DECL(AL_FORMAT_STEREO16), + DECL(AL_FORMAT_STEREO_FLOAT32), + DECL(AL_FORMAT_STEREO_DOUBLE_EXT), + DECL(AL_FORMAT_MONO_IMA4), + DECL(AL_FORMAT_STEREO_IMA4), + DECL(AL_FORMAT_QUAD8_LOKI), + DECL(AL_FORMAT_QUAD16_LOKI), + DECL(AL_FORMAT_QUAD8), + DECL(AL_FORMAT_QUAD16), + DECL(AL_FORMAT_QUAD32), + DECL(AL_FORMAT_51CHN8), + DECL(AL_FORMAT_51CHN16), + DECL(AL_FORMAT_51CHN32), + DECL(AL_FORMAT_61CHN8), + DECL(AL_FORMAT_61CHN16), + DECL(AL_FORMAT_61CHN32), + DECL(AL_FORMAT_71CHN8), + DECL(AL_FORMAT_71CHN16), + DECL(AL_FORMAT_71CHN32), + DECL(AL_FORMAT_REAR8), + DECL(AL_FORMAT_REAR16), + DECL(AL_FORMAT_REAR32), + DECL(AL_FORMAT_MONO_MULAW), + DECL(AL_FORMAT_MONO_MULAW_EXT), + DECL(AL_FORMAT_STEREO_MULAW), + DECL(AL_FORMAT_STEREO_MULAW_EXT), + DECL(AL_FORMAT_QUAD_MULAW), + DECL(AL_FORMAT_51CHN_MULAW), + DECL(AL_FORMAT_61CHN_MULAW), + DECL(AL_FORMAT_71CHN_MULAW), + DECL(AL_FORMAT_REAR_MULAW), + DECL(AL_FORMAT_MONO_ALAW_EXT), + DECL(AL_FORMAT_STEREO_ALAW_EXT), + + DECL(AL_MONO8_SOFT), + DECL(AL_MONO16_SOFT), + DECL(AL_MONO32F_SOFT), + DECL(AL_STEREO8_SOFT), + DECL(AL_STEREO16_SOFT), + DECL(AL_STEREO32F_SOFT), + DECL(AL_QUAD8_SOFT), + DECL(AL_QUAD16_SOFT), + DECL(AL_QUAD32F_SOFT), + DECL(AL_REAR8_SOFT), + DECL(AL_REAR16_SOFT), + DECL(AL_REAR32F_SOFT), + DECL(AL_5POINT1_8_SOFT), + DECL(AL_5POINT1_16_SOFT), + DECL(AL_5POINT1_32F_SOFT), + DECL(AL_6POINT1_8_SOFT), + DECL(AL_6POINT1_16_SOFT), + DECL(AL_6POINT1_32F_SOFT), + DECL(AL_7POINT1_8_SOFT), + DECL(AL_7POINT1_16_SOFT), + DECL(AL_7POINT1_32F_SOFT), + + DECL(AL_MONO_SOFT), + DECL(AL_STEREO_SOFT), + DECL(AL_QUAD_SOFT), + DECL(AL_REAR_SOFT), + DECL(AL_5POINT1_SOFT), + DECL(AL_6POINT1_SOFT), + DECL(AL_7POINT1_SOFT), + + DECL(AL_BYTE_SOFT), + DECL(AL_UNSIGNED_BYTE_SOFT), + DECL(AL_SHORT_SOFT), + DECL(AL_UNSIGNED_SHORT_SOFT), + DECL(AL_INT_SOFT), + DECL(AL_UNSIGNED_INT_SOFT), + DECL(AL_FLOAT_SOFT), + DECL(AL_DOUBLE_SOFT), + DECL(AL_BYTE3_SOFT), + DECL(AL_UNSIGNED_BYTE3_SOFT), + + DECL(AL_FREQUENCY), + DECL(AL_BITS), + DECL(AL_CHANNELS), + DECL(AL_SIZE), + DECL(AL_INTERNAL_FORMAT_SOFT), + DECL(AL_BYTE_LENGTH_SOFT), + DECL(AL_SAMPLE_LENGTH_SOFT), + DECL(AL_SEC_LENGTH_SOFT), + + DECL(AL_UNUSED), + DECL(AL_PENDING), + DECL(AL_PROCESSED), + + DECL(AL_NO_ERROR), + DECL(AL_INVALID_NAME), + DECL(AL_INVALID_ENUM), + DECL(AL_INVALID_VALUE), + DECL(AL_INVALID_OPERATION), + DECL(AL_OUT_OF_MEMORY), + + DECL(AL_VENDOR), + DECL(AL_VERSION), + DECL(AL_RENDERER), + DECL(AL_EXTENSIONS), + + DECL(AL_DOPPLER_FACTOR), + DECL(AL_DOPPLER_VELOCITY), + DECL(AL_DISTANCE_MODEL), + DECL(AL_SPEED_OF_SOUND), + DECL(AL_SOURCE_DISTANCE_MODEL), + DECL(AL_DEFERRED_UPDATES_SOFT), + + DECL(AL_INVERSE_DISTANCE), + DECL(AL_INVERSE_DISTANCE_CLAMPED), + DECL(AL_LINEAR_DISTANCE), + DECL(AL_LINEAR_DISTANCE_CLAMPED), + DECL(AL_EXPONENT_DISTANCE), + DECL(AL_EXPONENT_DISTANCE_CLAMPED), + + DECL(AL_FILTER_TYPE), + DECL(AL_FILTER_NULL), + DECL(AL_FILTER_LOWPASS), +#if 0 + DECL(AL_FILTER_HIGHPASS), + DECL(AL_FILTER_BANDPASS), +#endif + + DECL(AL_LOWPASS_GAIN), + DECL(AL_LOWPASS_GAINHF), + + DECL(AL_EFFECT_TYPE), + DECL(AL_EFFECT_NULL), + DECL(AL_EFFECT_REVERB), + DECL(AL_EFFECT_EAXREVERB), +#if 0 + DECL(AL_EFFECT_CHORUS), + DECL(AL_EFFECT_DISTORTION), +#endif + DECL(AL_EFFECT_ECHO), +#if 0 + DECL(AL_EFFECT_FLANGER), + DECL(AL_EFFECT_FREQUENCY_SHIFTER), + DECL(AL_EFFECT_VOCAL_MORPHER), + DECL(AL_EFFECT_PITCH_SHIFTER), +#endif + DECL(AL_EFFECT_RING_MODULATOR), +#if 0 + DECL(AL_EFFECT_AUTOWAH), + DECL(AL_EFFECT_COMPRESSOR), + DECL(AL_EFFECT_EQUALIZER), +#endif + DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), + DECL(AL_EFFECT_DEDICATED_DIALOGUE), + + DECL(AL_EAXREVERB_DENSITY), + DECL(AL_EAXREVERB_DIFFUSION), + DECL(AL_EAXREVERB_GAIN), + DECL(AL_EAXREVERB_GAINHF), + DECL(AL_EAXREVERB_GAINLF), + DECL(AL_EAXREVERB_DECAY_TIME), + DECL(AL_EAXREVERB_DECAY_HFRATIO), + DECL(AL_EAXREVERB_DECAY_LFRATIO), + DECL(AL_EAXREVERB_REFLECTIONS_GAIN), + DECL(AL_EAXREVERB_REFLECTIONS_DELAY), + DECL(AL_EAXREVERB_REFLECTIONS_PAN), + DECL(AL_EAXREVERB_LATE_REVERB_GAIN), + DECL(AL_EAXREVERB_LATE_REVERB_DELAY), + DECL(AL_EAXREVERB_LATE_REVERB_PAN), + DECL(AL_EAXREVERB_ECHO_TIME), + DECL(AL_EAXREVERB_ECHO_DEPTH), + DECL(AL_EAXREVERB_MODULATION_TIME), + DECL(AL_EAXREVERB_MODULATION_DEPTH), + DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF), + DECL(AL_EAXREVERB_HFREFERENCE), + DECL(AL_EAXREVERB_LFREFERENCE), + DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR), + DECL(AL_EAXREVERB_DECAY_HFLIMIT), + + DECL(AL_REVERB_DENSITY), + DECL(AL_REVERB_DIFFUSION), + DECL(AL_REVERB_GAIN), + DECL(AL_REVERB_GAINHF), + DECL(AL_REVERB_DECAY_TIME), + DECL(AL_REVERB_DECAY_HFRATIO), + DECL(AL_REVERB_REFLECTIONS_GAIN), + DECL(AL_REVERB_REFLECTIONS_DELAY), + DECL(AL_REVERB_LATE_REVERB_GAIN), + DECL(AL_REVERB_LATE_REVERB_DELAY), + DECL(AL_REVERB_AIR_ABSORPTION_GAINHF), + DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR), + DECL(AL_REVERB_DECAY_HFLIMIT), + + DECL(AL_ECHO_DELAY), + DECL(AL_ECHO_LRDELAY), + DECL(AL_ECHO_DAMPING), + DECL(AL_ECHO_FEEDBACK), + DECL(AL_ECHO_SPREAD), + + DECL(AL_RING_MODULATOR_FREQUENCY), + DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), + DECL(AL_RING_MODULATOR_WAVEFORM), + + DECL(AL_DEDICATED_GAIN), + + { NULL, (ALCenum)0 } +}; +#undef DECL + +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; + + +/************************************************ + * Global variables + ************************************************/ + +/* Enumerated device names */ +static const ALCchar alcDefaultName[] = "OpenAL Soft\0"; +static ALCchar *alcAllDevicesList; +static ALCchar *alcCaptureDeviceList; +/* Sizes only include the first ending null character, not the second */ +static size_t alcAllDevicesListSize; +static size_t alcCaptureDeviceListSize; + +/* Default is always the first in the list */ +static ALCchar *alcDefaultAllDevicesSpecifier; +static ALCchar *alcCaptureDefaultDeviceSpecifier; + +/* Default context extensions */ +static const ALchar alExtList[] = + "AL_EXT_ALAW 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_samples AL_SOFT_buffer_sub_data " + "AL_SOFTX_deferred_updates AL_SOFT_direct_channels AL_SOFT_loop_points " + "AL_SOFT_source_latency"; + +static volatile ALCenum LastNullDeviceError = ALC_NO_ERROR; + +/* Thread-local current context */ +static pthread_key_t LocalContext; +/* Process-wide current context */ +static ALCcontext *volatile GlobalContext = NULL; + +/* Mixing thread piority level */ +ALint RTPrioLevel; + +FILE *LogFile; +#ifdef _DEBUG +enum LogLevel LogLevel = LogWarning; +#else +enum LogLevel LogLevel = LogError; +#endif + +/* Flag to trap ALC device errors */ +static ALCboolean TrapALCError = ALC_FALSE; + +/* One-time configuration init control */ +static pthread_once_t alc_config_once = PTHREAD_ONCE_INIT; + +/* Default effect that applies to sources that don't have an effect on send 0 */ +static ALeffect DefaultEffect; + + +/************************************************ + * ALC information + ************************************************/ +static const ALCchar alcNoDeviceExtList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_thread_local_context ALC_SOFT_loopback"; +static const ALCchar alcExtensionList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX " + "ALC_EXT_thread_local_context ALC_SOFT_loopback"; +static const ALCint alcMajorVersion = 1; +static const ALCint alcMinorVersion = 1; + +static const ALCint alcEFXMajorVersion = 1; +static const ALCint alcEFXMinorVersion = 0; + + +/************************************************ + * Device lists + ************************************************/ +static ALCdevice *volatile DeviceList = NULL; + +static CRITICAL_SECTION ListLock; + +static void LockLists(void) +{ + EnterCriticalSection(&ListLock); +} +static void UnlockLists(void) +{ + LeaveCriticalSection(&ListLock); +} + +/************************************************ + * Library initialization + ************************************************/ +#if defined(_WIN32) +static void alc_init(void); +static void alc_deinit(void); +static void alc_deinit_safe(void); + +UIntMap TlsDestructor; + +#ifndef AL_LIBTYPE_STATIC +BOOL APIENTRY DllMain(HINSTANCE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) +{ + ALsizei i; + + // Perform actions based on the reason for calling. + switch(ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + /* Pin the DLL so we won't get unloaded until the process terminates */ + GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (WCHAR*)hModule, &hModule); + InitUIntMap(&TlsDestructor, ~0); + alc_init(); + break; + + case DLL_THREAD_DETACH: + LockUIntMapRead(&TlsDestructor); + for(i = 0;i < TlsDestructor.size;i++) + { + void *ptr = pthread_getspecific(TlsDestructor.array[i].key); + void (*callback)(void*) = (void(*)(void*))TlsDestructor.array[i].value; + if(ptr && callback) + callback(ptr); + } + UnlockUIntMapRead(&TlsDestructor); + break; + + case DLL_PROCESS_DETACH: + if(!lpReserved) + alc_deinit(); + else + alc_deinit_safe(); + ResetUIntMap(&TlsDestructor); + break; + } + return TRUE; +} +#elif defined(_MSC_VER) +#pragma section(".CRT$XCU",read) +static void alc_constructor(void); +static void alc_destructor(void); +__declspec(allocate(".CRT$XCU")) void (__cdecl* alc_constructor_)(void) = alc_constructor; + +static void alc_constructor(void) +{ + atexit(alc_destructor); + alc_init(); +} + +static void alc_destructor(void) +{ + alc_deinit(); +} +#elif defined(HAVE_GCC_DESTRUCTOR) +static void alc_init(void) __attribute__((constructor)); +static void alc_deinit(void) __attribute__((destructor)); +#else +#error "No static initialization available on this platform!" +#endif + +#elif defined(HAVE_GCC_DESTRUCTOR) + +static void alc_init(void) __attribute__((constructor)); +static void alc_deinit(void) __attribute__((destructor)); + +#else +#error "No global initialization available on this platform!" +#endif + +static void ReleaseThreadCtx(void *ptr); +static void alc_init(void) +{ + const char *str; + + LogFile = stderr; + + str = getenv("__ALSOFT_HALF_ANGLE_CONES"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) + ConeScale *= 0.5f; + + str = getenv("__ALSOFT_REVERSE_Z"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) + ZScale *= -1.0f; + + pthread_key_create(&LocalContext, ReleaseThreadCtx); + InitializeCriticalSection(&ListLock); + ThunkInit(); +} + +static void alc_initconfig(void) +{ + const char *devs, *str; + ALuint capfilter; + float valf; + int i, n; + + str = getenv("ALSOFT_LOGLEVEL"); + if(str) + { + long lvl = strtol(str, NULL, 0); + if(lvl >= NoLog && lvl <= LogRef) + LogLevel = lvl; + } + + str = getenv("ALSOFT_LOGFILE"); + if(str && str[0]) + { + FILE *logfile = fopen(str, "wat"); + if(logfile) LogFile = logfile; + else ERR("Failed to open log file '%s'\n", str); + } + + { + char buf[1024] = ""; + int len = snprintf(buf, sizeof(buf), "%s", BackendList[0].name); + for(i = 1;BackendList[i].name;i++) + len += snprintf(buf+len, sizeof(buf)-len, ", %s", BackendList[i].name); + TRACE("Supported backends: %s\n", buf); + } + ReadALConfig(); + + capfilter = 0; +#ifdef HAVE_SSE + capfilter |= CPU_CAP_SSE; +#endif +#ifdef HAVE_NEON + capfilter |= CPU_CAP_NEON; +#endif + if(ConfigValueStr(NULL, "disable-cpu-exts", &str)) + { + if(strcasecmp(str, "all") == 0) + capfilter = 0; + else + { + size_t len; + const char *next = str; + + i = 0; + do { + str = next; + next = strchr(str, ','); + + while(isspace(str[0])) + str++; + if(!str[0] || str[0] == ',') + continue; + + len = (next ? ((size_t)(next-str)) : strlen(str)); + if(strncasecmp(str, "sse", len) == 0) + capfilter &= ~CPU_CAP_SSE; + else if(strncasecmp(str, "neon", len) == 0) + capfilter &= ~CPU_CAP_NEON; + else + WARN("Invalid CPU extension \"%s\"\n", str); + } while(next++); + } + } + FillCPUCaps(capfilter); + +#ifdef _WIN32 + RTPrioLevel = 1; +#else + RTPrioLevel = 0; +#endif + ConfigValueInt(NULL, "rt-prio", &RTPrioLevel); + + if(ConfigValueStr(NULL, "resampler", &str)) + { + if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) + DefaultResampler = PointResampler; + else if(strcasecmp(str, "linear") == 0) + DefaultResampler = LinearResampler; + else if(strcasecmp(str, "cubic") == 0) + DefaultResampler = CubicResampler; + else + { + char *end; + + n = strtol(str, &end, 0); + if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == CubicResampler)) + DefaultResampler = n; + else + WARN("Invalid resampler: %s\n", str); + } + } + + str = getenv("ALSOFT_TRAP_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) + { + TrapALError = AL_TRUE; + TrapALCError = AL_TRUE; + } + else + { + str = getenv("ALSOFT_TRAP_AL_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) + TrapALError = AL_TRUE; + TrapALError = GetConfigValueBool(NULL, "trap-al-error", TrapALError); + + str = getenv("ALSOFT_TRAP_ALC_ERROR"); + if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) + TrapALCError = ALC_TRUE; + TrapALCError = GetConfigValueBool(NULL, "trap-alc-error", TrapALCError); + } + + if(ConfigValueFloat("reverb", "boost", &valf)) + ReverbBoost *= powf(10.0f, valf / 20.0f); + + EmulateEAXReverb = GetConfigValueBool("reverb", "emulate-eax", AL_FALSE); + + if(((devs=getenv("ALSOFT_DRIVERS")) && devs[0]) || + ConfigValueStr(NULL, "drivers", &devs)) + { + 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 + { + struct 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 && (!PlaybackBackend.name || !CaptureBackend.name);i++) + { + if(!BackendList[i].Init(&BackendList[i].Funcs)) + { + WARN("Failed to initialize backend \"%s\"\n", BackendList[i].name); + continue; + } + + TRACE("Initialized backend \"%s\"\n", BackendList[i].name); + if(BackendList[i].Funcs.OpenPlayback && !PlaybackBackend.name) + { + PlaybackBackend = BackendList[i]; + TRACE("Added \"%s\" for playback\n", PlaybackBackend.name); + } + if(BackendList[i].Funcs.OpenCapture && !CaptureBackend.name) + { + CaptureBackend = BackendList[i]; + TRACE("Added \"%s\" for capture\n", CaptureBackend.name); + } + } + BackendLoopback.Init(&BackendLoopback.Funcs); + + if(ConfigValueStr(NULL, "excludefx", &str)) + { + 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++); + } + + InitEffect(&DefaultEffect); + str = getenv("ALSOFT_DEFAULT_REVERB"); + if((str && str[0]) || ConfigValueStr(NULL, "default-reverb", &str)) + LoadReverbPreset(str, &DefaultEffect); +} +#define DO_INITCONFIG() pthread_once(&alc_config_once, alc_initconfig) + + +/************************************************ + * Library deinitialization + ************************************************/ +static void alc_cleanup(void) +{ + ALCdevice *dev; + + free(alcAllDevicesList); alcAllDevicesList = NULL; + alcAllDevicesListSize = 0; + free(alcCaptureDeviceList); alcCaptureDeviceList = NULL; + alcCaptureDeviceListSize = 0; + + free(alcDefaultAllDevicesSpecifier); + alcDefaultAllDevicesSpecifier = NULL; + free(alcCaptureDefaultDeviceSpecifier); + alcCaptureDefaultDeviceSpecifier = NULL; + + if((dev=ExchangePtr((XchgPtr*)&DeviceList, NULL)) != NULL) + { + ALCuint num = 0; + do { + num++; + } while((dev=dev->next) != NULL); + ERR("%u device%s not closed\n", num, (num>1)?"s":""); + } +} + +static void alc_deinit_safe(void) +{ + alc_cleanup(); + + FreeHrtfs(); + FreeALConfig(); + + ThunkExit(); + DeleteCriticalSection(&ListLock); + pthread_key_delete(LocalContext); + + if(LogFile != stderr) + fclose(LogFile); + LogFile = NULL; +} + +static void alc_deinit(void) +{ + int i; + + alc_cleanup(); + + memset(&PlaybackBackend, 0, sizeof(PlaybackBackend)); + memset(&CaptureBackend, 0, sizeof(CaptureBackend)); + + for(i = 0;BackendList[i].Deinit;i++) + BackendList[i].Deinit(); + BackendLoopback.Deinit(); + + alc_deinit_safe(); +} + + +/************************************************ + * Device enumeration + ************************************************/ +static void ProbeList(ALCchar **list, size_t *listsize, enum DevProbe type) +{ + DO_INITCONFIG(); + + LockLists(); + free(*list); + *list = NULL; + *listsize = 0; + + if(type == ALL_DEVICE_PROBE && PlaybackBackend.Probe) + PlaybackBackend.Probe(type); + else if(type == CAPTURE_DEVICE_PROBE && CaptureBackend.Probe) + CaptureBackend.Probe(type); + UnlockLists(); +} + +static void ProbeAllDevicesList(void) +{ ProbeList(&alcAllDevicesList, &alcAllDevicesListSize, ALL_DEVICE_PROBE); } +static void ProbeCaptureDeviceList(void) +{ ProbeList(&alcCaptureDeviceList, &alcCaptureDeviceListSize, 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) + { + ERR("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(AllDevices) +DECL_APPEND_LIST_FUNC(CaptureDevice) + +#undef DECL_APPEND_LIST_FUNC + + +/************************************************ + * Device format information + ************************************************/ +const ALCchar *DevFmtTypeString(enum DevFmtType type) +{ + switch(type) + { + case DevFmtByte: return "Signed Byte"; + case DevFmtUByte: return "Unsigned Byte"; + case DevFmtShort: return "Signed Short"; + case DevFmtUShort: return "Unsigned Short"; + case DevFmtInt: return "Signed Int"; + case DevFmtUInt: return "Unsigned Int"; + case DevFmtFloat: return "Float"; + } + return "(unknown type)"; +} +const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) +{ + switch(chans) + { + case DevFmtMono: return "Mono"; + case DevFmtStereo: return "Stereo"; + case DevFmtQuad: return "Quadraphonic"; + case DevFmtX51: return "5.1 Surround"; + case DevFmtX51Side: return "5.1 Side"; + case DevFmtX61: return "6.1 Surround"; + case DevFmtX71: return "7.1 Surround"; + } + return "(unknown channels)"; +} + +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 DevFmtInt: return sizeof(ALint); + case DevFmtUInt: return sizeof(ALuint); + 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 DevFmtX51Side: return 6; + case DevFmtX61: return 7; + case DevFmtX71: return 8; + } + return 0; +} + +static ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans, + enum DevFmtType *type) +{ + static const struct { + ALenum format; + enum DevFmtChannels channels; + enum DevFmtType type; + } list[] = { + { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, + { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, + { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat }, + + { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte }, + { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat }, + + { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte }, + { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort }, + { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat }, + + { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte }, + { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort }, + { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat }, + + { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte }, + { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort }, + { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat }, + + { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte }, + { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, + { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, + }; + ALuint i; + + for(i = 0;i < COUNTOF(list);i++) + { + if(list[i].format == format) + { + *chans = list[i].channels; + *type = list[i].type; + return AL_TRUE; + } + } + + return AL_FALSE; +} + +static ALCboolean IsValidALCType(ALCenum type) +{ + switch(type) + { + case ALC_BYTE_SOFT: + case ALC_UNSIGNED_BYTE_SOFT: + case ALC_SHORT_SOFT: + case ALC_UNSIGNED_SHORT_SOFT: + case ALC_INT_SOFT: + case ALC_UNSIGNED_INT_SOFT: + case ALC_FLOAT_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + +static ALCboolean IsValidALCChannels(ALCenum channels) +{ + switch(channels) + { + case ALC_MONO_SOFT: + case ALC_STEREO_SOFT: + case ALC_QUAD_SOFT: + case ALC_5POINT1_SOFT: + case ALC_6POINT1_SOFT: + case ALC_7POINT1_SOFT: + return ALC_TRUE; + } + return ALC_FALSE; +} + + +/************************************************ + * Miscellaneous ALC helpers + ************************************************/ + +void ALCdevice_LockDefault(ALCdevice *device) +{ + EnterCriticalSection(&device->Mutex); +} +void ALCdevice_UnlockDefault(ALCdevice *device) +{ + LeaveCriticalSection(&device->Mutex); +} +ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device) +{ + (void)device; + return 0; +} + +/* SetDefaultWFXChannelOrder + * + * Sets the default channel order used by WaveFormatEx. + */ +void SetDefaultWFXChannelOrder(ALCdevice *device) +{ + ALuint i; + + for(i = 0;i < MaxChannels;i++) + device->ChannelOffsets[i] = INVALID_OFFSET; + + switch(device->FmtChans) + { + case DevFmtMono: device->ChannelOffsets[FrontCenter] = 0; + break; + case DevFmtStereo: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + break; + case DevFmtQuad: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + device->ChannelOffsets[BackLeft] = 2; + device->ChannelOffsets[BackRight] = 3; + break; + case DevFmtX51: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + device->ChannelOffsets[FrontCenter] = 2; + device->ChannelOffsets[LFE] = 3; + device->ChannelOffsets[BackLeft] = 4; + device->ChannelOffsets[BackRight] = 5; + break; + case DevFmtX51Side: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + device->ChannelOffsets[FrontCenter] = 2; + device->ChannelOffsets[LFE] = 3; + device->ChannelOffsets[SideLeft] = 4; + device->ChannelOffsets[SideRight] = 5; + break; + case DevFmtX61: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + device->ChannelOffsets[FrontCenter] = 2; + device->ChannelOffsets[LFE] = 3; + device->ChannelOffsets[BackCenter] = 4; + device->ChannelOffsets[SideLeft] = 5; + device->ChannelOffsets[SideRight] = 6; + break; + case DevFmtX71: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + device->ChannelOffsets[FrontCenter] = 2; + device->ChannelOffsets[LFE] = 3; + device->ChannelOffsets[BackLeft] = 4; + device->ChannelOffsets[BackRight] = 5; + device->ChannelOffsets[SideLeft] = 6; + device->ChannelOffsets[SideRight] = 7; + break; + } +} + +/* SetDefaultChannelOrder + * + * Sets the default channel order used by most non-WaveFormatEx-based APIs. + */ +void SetDefaultChannelOrder(ALCdevice *device) +{ + ALuint i; + + for(i = 0;i < MaxChannels;i++) + device->ChannelOffsets[i] = INVALID_OFFSET; + + switch(device->FmtChans) + { + case DevFmtX51: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + device->ChannelOffsets[BackLeft] = 2; + device->ChannelOffsets[BackRight] = 3; + device->ChannelOffsets[FrontCenter] = 4; + device->ChannelOffsets[LFE] = 5; + return; + case DevFmtX71: device->ChannelOffsets[FrontLeft] = 0; + device->ChannelOffsets[FrontRight] = 1; + device->ChannelOffsets[BackLeft] = 2; + device->ChannelOffsets[BackRight] = 3; + device->ChannelOffsets[FrontCenter] = 4; + device->ChannelOffsets[LFE] = 5; + device->ChannelOffsets[SideLeft] = 6; + device->ChannelOffsets[SideRight] = 7; + return; + + /* Same as WFX order */ + case DevFmtMono: + case DevFmtStereo: + case DevFmtQuad: + case DevFmtX51Side: + case DevFmtX61: + break; + } + SetDefaultWFXChannelOrder(device); +} + + +/* alcSetError + * + * Stores the latest ALC device error + */ +static void alcSetError(ALCdevice *device, ALCenum errorCode) +{ + if(TrapALCError) + { +#ifdef _WIN32 + /* DebugBreak() will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + if(device) + device->LastError = errorCode; + else + LastNullDeviceError = errorCode; +} + + +/* UpdateDeviceParams + * + * Updates device parameters according to the attribute list (caller is + * responsible for holding the list lock). + */ +static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) +{ + ALCcontext *context; + enum DevFmtChannels oldChans; + enum DevFmtType oldType; + ALCuint oldFreq; + FPUCtl oldMode; + ALuint i; + + // Check for attributes + if(device->Type == Loopback) + { + enum { + GotFreq = 1<<0, + GotChans = 1<<1, + GotType = 1<<2, + GotAll = GotFreq|GotChans|GotType + }; + ALCuint freq, numMono, numStereo, numSends; + enum DevFmtChannels schans; + enum DevFmtType stype; + ALCuint attrIdx = 0; + ALCint gotFmt = 0; + + if(!attrList) + { + WARN("Missing attributes for loopback device\n"); + return ALC_INVALID_VALUE; + } + + numMono = device->NumMonoSources; + numStereo = device->NumStereoSources; + numSends = device->NumAuxSends; + schans = device->FmtChans; + stype = device->FmtType; + freq = device->Frequency; + + while(attrList[attrIdx]) + { + if(attrList[attrIdx] == ALC_FORMAT_CHANNELS_SOFT) + { + ALCint val = attrList[attrIdx + 1]; + if(!IsValidALCChannels(val) || !ChannelsFromDevFmt(val)) + return ALC_INVALID_VALUE; + schans = val; + gotFmt |= GotChans; + } + + if(attrList[attrIdx] == ALC_FORMAT_TYPE_SOFT) + { + ALCint val = attrList[attrIdx + 1]; + if(!IsValidALCType(val) || !BytesFromDevFmt(val)) + return ALC_INVALID_VALUE; + stype = val; + gotFmt |= GotType; + } + + if(attrList[attrIdx] == ALC_FREQUENCY) + { + freq = attrList[attrIdx + 1]; + if(freq < MIN_OUTPUT_RATE) + return ALC_INVALID_VALUE; + gotFmt |= GotFreq; + } + + 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) + numSends = attrList[attrIdx + 1]; + + attrIdx += 2; + } + + if(gotFmt != GotAll) + { + WARN("Missing format for loopback device\n"); + return ALC_INVALID_VALUE; + } + + ConfigValueUInt(NULL, "sends", &numSends); + numSends = minu(MAX_SENDS, numSends); + + if((device->Flags&DEVICE_RUNNING)) + ALCdevice_StopPlayback(device); + device->Flags &= ~DEVICE_RUNNING; + + device->Frequency = freq; + device->FmtChans = schans; + device->FmtType = stype; + device->NumMonoSources = numMono; + device->NumStereoSources = numStereo; + device->NumAuxSends = numSends; + } + else if(attrList && attrList[0]) + { + ALCuint freq, numMono, numStereo, numSends; + ALCuint attrIdx = 0; + + /* If a context is already running on the device, stop playback so the + * device attributes can be updated. */ + if((device->Flags&DEVICE_RUNNING)) + ALCdevice_StopPlayback(device); + device->Flags &= ~DEVICE_RUNNING; + + freq = device->Frequency; + numMono = device->NumMonoSources; + numStereo = device->NumStereoSources; + numSends = device->NumAuxSends; + + while(attrList[attrIdx]) + { + if(attrList[attrIdx] == ALC_FREQUENCY) + { + freq = attrList[attrIdx + 1]; + device->Flags |= DEVICE_FREQUENCY_REQUEST; + } + + 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) + numSends = attrList[attrIdx + 1]; + + attrIdx += 2; + } + + ConfigValueUInt(NULL, "frequency", &freq); + freq = maxu(freq, MIN_OUTPUT_RATE); + + ConfigValueUInt(NULL, "sends", &numSends); + numSends = minu(MAX_SENDS, numSends); + + device->UpdateSize = (ALuint64)device->UpdateSize * freq / + device->Frequency; + /* SSE does best with the update size being a multiple of 4 */ + if((CPUCapFlags&CPU_CAP_SSE)) + device->UpdateSize = (device->UpdateSize+3)&~3; + + device->Frequency = freq; + device->NumMonoSources = numMono; + device->NumStereoSources = numStereo; + device->NumAuxSends = numSends; + } + + if((device->Flags&DEVICE_RUNNING)) + return ALC_NO_ERROR; + + oldFreq = device->Frequency; + oldChans = device->FmtChans; + oldType = device->FmtType; + + TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u update size x%d\n", + (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"", + DevFmtChannelsString(device->FmtChans), + (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"", + DevFmtTypeString(device->FmtType), + (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", + device->Frequency, + device->UpdateSize, device->NumUpdates); + + if(ALCdevice_ResetPlayback(device) == ALC_FALSE) + return ALC_INVALID_DEVICE; + + if(device->FmtChans != oldChans && (device->Flags&DEVICE_CHANNELS_REQUEST)) + { + ERR("Failed to set %s, got %s instead\n", DevFmtChannelsString(oldChans), + DevFmtChannelsString(device->FmtChans)); + device->Flags &= ~DEVICE_CHANNELS_REQUEST; + } + if(device->FmtType != oldType && (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + { + ERR("Failed to set %s, got %s instead\n", DevFmtTypeString(oldType), + DevFmtTypeString(device->FmtType)); + device->Flags &= ~DEVICE_SAMPLE_TYPE_REQUEST; + } + if(device->Frequency != oldFreq && (device->Flags&DEVICE_FREQUENCY_REQUEST)) + { + ERR("Failed to set %uhz, got %uhz instead\n", oldFreq, device->Frequency); + device->Flags &= ~DEVICE_FREQUENCY_REQUEST; + } + + TRACE("Post-reset: %s, %s, %uhz, %u update size x%d\n", + DevFmtChannelsString(device->FmtChans), + DevFmtTypeString(device->FmtType), device->Frequency, + device->UpdateSize, device->NumUpdates); + + aluInitPanning(device); + + for(i = 0;i < MaxChannels;i++) + { + device->ClickRemoval[i] = 0.0f; + device->PendingClicks[i] = 0.0f; + } + + device->Hrtf = NULL; + if(device->Type != Loopback && GetConfigValueBool(NULL, "hrtf", AL_FALSE)) + device->Hrtf = GetHrtf(device); + TRACE("HRTF %s\n", device->Hrtf?"enabled":"disabled"); + + if(!device->Hrtf && 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); + TRACE("BS2B level %d\n", device->Bs2bLevel); + } + else + { + free(device->Bs2b); + device->Bs2b = NULL; + TRACE("BS2B disabled\n"); + } + + device->Flags &= ~DEVICE_WIDE_STEREO; + if(device->Type != Loopback && !device->Hrtf && GetConfigValueBool(NULL, "wide-stereo", AL_FALSE)) + device->Flags |= DEVICE_WIDE_STEREO; + + if(!device->Hrtf && (device->UpdateSize&3)) + { + if((CPUCapFlags&CPU_CAP_SSE)) + WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); + } + + SetMixerFPUMode(&oldMode); + ALCdevice_Lock(device); + context = device->ContextList; + while(context) + { + ALsizei pos; + + context->UpdateSources = AL_FALSE; + LockUIntMapRead(&context->EffectSlotMap); + for(pos = 0;pos < context->EffectSlotMap.size;pos++) + { + ALeffectslot *slot = context->EffectSlotMap.array[pos].value; + + if(ALeffectState_DeviceUpdate(slot->EffectState, device) == AL_FALSE) + { + UnlockUIntMapRead(&context->EffectSlotMap); + ALCdevice_Unlock(device); + RestoreFPUMode(&oldMode); + return ALC_INVALID_DEVICE; + } + slot->NeedsUpdate = AL_FALSE; + ALeffectState_Update(slot->EffectState, device, slot); + } + UnlockUIntMapRead(&context->EffectSlotMap); + + LockUIntMapRead(&context->SourceMap); + 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) + DecrementRef(&source->Send[s].Slot->ref); + source->Send[s].Slot = NULL; + source->Send[s].Gain = 1.0f; + source->Send[s].GainHF = 1.0f; + s++; + } + source->NeedsUpdate = AL_FALSE; + ALsource_Update(source, context); + } + UnlockUIntMapRead(&context->SourceMap); + + context = context->next; + } + if(device->DefaultSlot) + { + ALeffectslot *slot = device->DefaultSlot; + + if(ALeffectState_DeviceUpdate(slot->EffectState, device) == AL_FALSE) + { + ALCdevice_Unlock(device); + RestoreFPUMode(&oldMode); + return ALC_INVALID_DEVICE; + } + slot->NeedsUpdate = AL_FALSE; + ALeffectState_Update(slot->EffectState, device, slot); + } + ALCdevice_Unlock(device); + RestoreFPUMode(&oldMode); + + if(ALCdevice_StartPlayback(device) == ALC_FALSE) + return ALC_INVALID_DEVICE; + device->Flags |= DEVICE_RUNNING; + + return ALC_NO_ERROR; +} + +/* FreeDevice + * + * Frees the device structure, and destroys any objects the app failed to + * delete. Called once there's no more references on the device. + */ +static ALCvoid FreeDevice(ALCdevice *device) +{ + TRACE("%p\n", device); + + if(device->Type != Capture) + ALCdevice_ClosePlayback(device); + else + ALCdevice_CloseCapture(device); + + if(device->DefaultSlot) + { + ALeffectState_Destroy(device->DefaultSlot->EffectState); + device->DefaultSlot->EffectState = NULL; + } + + if(device->BufferMap.size > 0) + { + WARN("(%p) Deleting %d Buffer(s)\n", device, device->BufferMap.size); + ReleaseALBuffers(device); + } + ResetUIntMap(&device->BufferMap); + + if(device->EffectMap.size > 0) + { + WARN("(%p) Deleting %d Effect(s)\n", device, device->EffectMap.size); + ReleaseALEffects(device); + } + ResetUIntMap(&device->EffectMap); + + if(device->FilterMap.size > 0) + { + WARN("(%p) Deleting %d Filter(s)\n", device, device->FilterMap.size); + ReleaseALFilters(device); + } + ResetUIntMap(&device->FilterMap); + + free(device->Bs2b); + device->Bs2b = NULL; + + free(device->DeviceName); + device->DeviceName = NULL; + + DeleteCriticalSection(&device->Mutex); + + al_free(device); +} + + +void ALCdevice_IncRef(ALCdevice *device) +{ + RefCount ref; + ref = IncrementRef(&device->ref); + TRACEREF("%p increasing refcount to %u\n", device, ref); +} + +void ALCdevice_DecRef(ALCdevice *device) +{ + RefCount ref; + ref = DecrementRef(&device->ref); + TRACEREF("%p decreasing refcount to %u\n", device, ref); + if(ref == 0) FreeDevice(device); +} + +/* VerifyDevice + * + * Checks if the device handle is valid, and increments its ref count if so. + */ +static ALCdevice *VerifyDevice(ALCdevice *device) +{ + ALCdevice *tmpDevice; + + if(!device) + return NULL; + + LockLists(); + tmpDevice = DeviceList; + while(tmpDevice && tmpDevice != device) + tmpDevice = tmpDevice->next; + + if(tmpDevice) + ALCdevice_IncRef(tmpDevice); + UnlockLists(); + return tmpDevice; +} + + +/* InitContext + * + * Initializes context fields + */ +static ALvoid InitContext(ALCcontext *Context) +{ + ALint i, j; + + //Initialise listener + Context->Listener->Gain = 1.0f; + Context->Listener->MetersPerUnit = 1.0f; + Context->Listener->Position[0] = 0.0f; + Context->Listener->Position[1] = 0.0f; + Context->Listener->Position[2] = 0.0f; + Context->Listener->Velocity[0] = 0.0f; + Context->Listener->Velocity[1] = 0.0f; + Context->Listener->Velocity[2] = 0.0f; + Context->Listener->Forward[0] = 0.0f; + Context->Listener->Forward[1] = 0.0f; + Context->Listener->Forward[2] = -1.0f; + Context->Listener->Up[0] = 0.0f; + Context->Listener->Up[1] = 1.0f; + Context->Listener->Up[2] = 0.0f; + for(i = 0;i < 4;i++) + { + for(j = 0;j < 4;j++) + Context->Listener->Params.Matrix[i][j] = ((i==j) ? 1.0f : 0.0f); + } + for(i = 0;i < 3;i++) + Context->Listener->Params.Velocity[i] = 0.0f; + + //Validate Context + Context->LastError = AL_NO_ERROR; + Context->UpdateSources = AL_FALSE; + Context->ActiveSourceCount = 0; + InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources); + InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); + + //Set globals + Context->DistanceModel = DefaultDistanceModel; + Context->SourceDistanceModel = AL_FALSE; + Context->DopplerFactor = 1.0f; + Context->DopplerVelocity = 1.0f; + Context->SpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + Context->DeferUpdates = AL_FALSE; + + Context->ExtensionList = alExtList; +} + + +/* FreeContext + * + * Cleans up the context, and destroys any remaining objects the app failed to + * delete. Called once there's no more references on the context. + */ +static ALCvoid FreeContext(ALCcontext *context) +{ + TRACE("%p\n", context); + + if(context->SourceMap.size > 0) + { + WARN("(%p) Deleting %d Source(s)\n", context, context->SourceMap.size); + ReleaseALSources(context); + } + ResetUIntMap(&context->SourceMap); + + if(context->EffectSlotMap.size > 0) + { + WARN("(%p) Deleting %d AuxiliaryEffectSlot(s)\n", context, context->EffectSlotMap.size); + ReleaseALAuxiliaryEffectSlots(context); + } + ResetUIntMap(&context->EffectSlotMap); + + context->ActiveSourceCount = 0; + free(context->ActiveSources); + context->ActiveSources = NULL; + context->MaxActiveSources = 0; + + context->ActiveEffectSlotCount = 0; + free(context->ActiveEffectSlots); + context->ActiveEffectSlots = NULL; + context->MaxActiveEffectSlots = 0; + + ALCdevice_DecRef(context->Device); + context->Device = NULL; + + //Invalidate context + memset(context, 0, sizeof(ALCcontext)); + free(context); +} + +/* ReleaseContext + * + * Removes the context reference from the given device and removes it from + * being current on the running thread or globally. + */ +static void ReleaseContext(ALCcontext *context, ALCdevice *device) +{ + ALCcontext *volatile*tmp_ctx; + + if(pthread_getspecific(LocalContext) == context) + { + WARN("%p released while current on thread\n", context); + pthread_setspecific(LocalContext, NULL); + ALCcontext_DecRef(context); + } + + if(CompExchangePtr((XchgPtr*)&GlobalContext, context, NULL)) + ALCcontext_DecRef(context); + + ALCdevice_Lock(device); + tmp_ctx = &device->ContextList; + while(*tmp_ctx) + { + if(CompExchangePtr((XchgPtr*)tmp_ctx, context, context->next)) + break; + tmp_ctx = &(*tmp_ctx)->next; + } + ALCdevice_Unlock(device); + + ALCcontext_DecRef(context); +} + +void ALCcontext_IncRef(ALCcontext *context) +{ + RefCount ref; + ref = IncrementRef(&context->ref); + TRACEREF("%p increasing refcount to %u\n", context, ref); +} + +void ALCcontext_DecRef(ALCcontext *context) +{ + RefCount ref; + ref = DecrementRef(&context->ref); + TRACEREF("%p decreasing refcount to %u\n", context, ref); + if(ref == 0) FreeContext(context); +} + +static void ReleaseThreadCtx(void *ptr) +{ + WARN("%p current for thread being destroyed\n", ptr); + ALCcontext_DecRef(ptr); +} + +/* VerifyContext + * + * Checks that the given context is valid, and increments its reference count. + */ +static ALCcontext *VerifyContext(ALCcontext *context) +{ + ALCdevice *dev; + + LockLists(); + dev = DeviceList; + while(dev) + { + ALCcontext *tmp_ctx = dev->ContextList; + while(tmp_ctx) + { + if(tmp_ctx == context) + { + ALCcontext_IncRef(tmp_ctx); + UnlockLists(); + return tmp_ctx; + } + tmp_ctx = tmp_ctx->next; + } + dev = dev->next; + } + UnlockLists(); + + return NULL; +} + + +/* GetContextRef + * + * Returns the currently active context for this thread, and adds a reference + * without locking it. + */ +ALCcontext *GetContextRef(void) +{ + ALCcontext *context; + + context = pthread_getspecific(LocalContext); + if(context) + ALCcontext_IncRef(context); + else + { + LockLists(); + context = GlobalContext; + if(context) + ALCcontext_IncRef(context); + UnlockLists(); + } + + return context; +} + + +/************************************************ + * Standard ALC functions + ************************************************/ + +/* alcGetError + * + * Return last ALC generated error code for the given device +*/ +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) +{ + ALCenum errorCode; + + if(VerifyDevice(device)) + { + errorCode = ExchangeInt(&device->LastError, ALC_NO_ERROR); + ALCdevice_DecRef(device); + } + else + errorCode = ExchangeInt(&LastNullDeviceError, ALC_NO_ERROR); + + return errorCode; +} + + +/* alcSuspendContext + * + * Not functional + */ +ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *Context) +{ + (void)Context; +} + +/* alcProcessContext + * + * Not functional + */ +ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *Context) +{ + (void)Context; +} + + +/* alcGetString + * + * Returns information about the device, and error strings + */ +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, 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: + value = alcDefaultName; + break; + + case ALC_ALL_DEVICES_SPECIFIER: + if(VerifyDevice(Device)) + { + value = Device->DeviceName; + ALCdevice_DecRef(Device); + } + else + { + ProbeAllDevicesList(); + value = alcAllDevicesList; + } + break; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + if(VerifyDevice(Device)) + { + value = Device->DeviceName; + ALCdevice_DecRef(Device); + } + else + { + ProbeCaptureDeviceList(); + value = alcCaptureDeviceList; + } + break; + + /* Default devices are always first in the list */ + case ALC_DEFAULT_DEVICE_SPECIFIER: + value = alcDefaultName; + break; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + if(!alcAllDevicesList) + ProbeAllDevicesList(); + + Device = VerifyDevice(Device); + + free(alcDefaultAllDevicesSpecifier); + alcDefaultAllDevicesSpecifier = strdup(alcAllDevicesList ? + alcAllDevicesList : ""); + if(!alcDefaultAllDevicesSpecifier) + alcSetError(Device, ALC_OUT_OF_MEMORY); + + value = alcDefaultAllDevicesSpecifier; + if(Device) ALCdevice_DecRef(Device); + break; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + if(!alcCaptureDeviceList) + ProbeCaptureDeviceList(); + + Device = VerifyDevice(Device); + + free(alcCaptureDefaultDeviceSpecifier); + alcCaptureDefaultDeviceSpecifier = strdup(alcCaptureDeviceList ? + alcCaptureDeviceList : ""); + if(!alcCaptureDefaultDeviceSpecifier) + alcSetError(Device, ALC_OUT_OF_MEMORY); + + value = alcCaptureDefaultDeviceSpecifier; + if(Device) ALCdevice_DecRef(Device); + break; + + case ALC_EXTENSIONS: + if(!VerifyDevice(Device)) + value = alcNoDeviceExtList; + else + { + value = alcExtensionList; + ALCdevice_DecRef(Device); + } + break; + + default: + Device = VerifyDevice(Device); + alcSetError(Device, ALC_INVALID_ENUM); + if(Device) ALCdevice_DecRef(Device); + break; + } + + return value; +} + + +/* alcGetIntegerv + * + * Returns information about the device and the version of OpenAL + */ +ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data) +{ + device = VerifyDevice(device); + + if(size == 0 || data == NULL) + { + alcSetError(device, ALC_INVALID_VALUE); + if(device) ALCdevice_DecRef(device); + return; + } + + if(!device) + { + switch(param) + { + case ALC_MAJOR_VERSION: + *data = alcMajorVersion; + break; + case ALC_MINOR_VERSION: + *data = alcMinorVersion; + break; + + case ALC_ATTRIBUTES_SIZE: + case ALC_ALL_ATTRIBUTES: + case ALC_FREQUENCY: + case ALC_REFRESH: + case ALC_SYNC: + case ALC_MONO_SOURCES: + case ALC_STEREO_SOURCES: + case ALC_CAPTURE_SAMPLES: + case ALC_FORMAT_CHANNELS_SOFT: + case ALC_FORMAT_TYPE_SOFT: + alcSetError(NULL, ALC_INVALID_DEVICE); + break; + + default: + alcSetError(NULL, ALC_INVALID_ENUM); + break; + } + } + else if(device->Type == Capture) + { + switch(param) + { + case ALC_CAPTURE_SAMPLES: + ALCdevice_Lock(device); + *data = ALCdevice_AvailableSamples(device); + ALCdevice_Unlock(device); + break; + + case ALC_CONNECTED: + *data = device->Connected; + break; + + default: + alcSetError(device, ALC_INVALID_ENUM); + break; + } + } + else /* render 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_ATTRIBUTES_SIZE: + *data = 13; + break; + + case ALC_ALL_ATTRIBUTES: + if(size < 13) + alcSetError(device, ALC_INVALID_VALUE); + else + { + int i = 0; + + data[i++] = ALC_FREQUENCY; + data[i++] = device->Frequency; + + if(device->Type != Loopback) + { + data[i++] = ALC_REFRESH; + data[i++] = device->Frequency / device->UpdateSize; + + data[i++] = ALC_SYNC; + data[i++] = ALC_FALSE; + } + else + { + data[i++] = ALC_FORMAT_CHANNELS_SOFT; + data[i++] = device->FmtChans; + + data[i++] = ALC_FORMAT_TYPE_SOFT; + data[i++] = device->FmtType; + } + + 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; + } + break; + + case ALC_FREQUENCY: + *data = device->Frequency; + break; + + case ALC_REFRESH: + if(device->Type == Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->Frequency / device->UpdateSize; + break; + + case ALC_SYNC: + if(device->Type == Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = ALC_FALSE; + break; + + case ALC_FORMAT_CHANNELS_SOFT: + if(device->Type != Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->FmtChans; + break; + + case ALC_FORMAT_TYPE_SOFT: + if(device->Type != Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else + *data = device->FmtType; + break; + + case ALC_MONO_SOURCES: + *data = device->NumMonoSources; + break; + + case ALC_STEREO_SOURCES: + *data = device->NumStereoSources; + break; + + case ALC_MAX_AUXILIARY_SENDS: + *data = device->NumAuxSends; + break; + + case ALC_CONNECTED: + *data = device->Connected; + break; + + default: + alcSetError(device, ALC_INVALID_ENUM); + break; + } + } + if(device) + ALCdevice_DecRef(device); +} + + +/* 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; + + device = VerifyDevice(device); + + if(!extName) + alcSetError(device, ALC_INVALID_VALUE); + else + { + size_t len = strlen(extName); + const char *ptr = (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)); + } + } + } + if(device) + ALCdevice_DecRef(device); + return bResult; +} + + +/* alcGetProcAddress + * + * Retrieves the function address for a particular extension function + */ +ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) +{ + ALCvoid *ptr = NULL; + + if(!funcName) + { + device = VerifyDevice(device); + alcSetError(device, ALC_INVALID_VALUE); + if(device) ALCdevice_DecRef(device); + } + else + { + ALsizei i = 0; + while(alcFunctions[i].funcName && strcmp(alcFunctions[i].funcName, funcName) != 0) + i++; + ptr = alcFunctions[i].address; + } + + return ptr; +} + + +/* alcGetEnumValue + * + * Get the value for a particular ALC enumeration name + */ +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) +{ + ALCenum val = 0; + + if(!enumName) + { + device = VerifyDevice(device); + alcSetError(device, ALC_INVALID_VALUE); + if(device) ALCdevice_DecRef(device); + } + else + { + ALsizei i = 0; + while(enumeration[i].enumName && strcmp(enumeration[i].enumName, enumName) != 0) + i++; + val = enumeration[i].value; + } + + return val; +} + + +/* alcCreateContext + * + * Create and attach a context to the given device. + */ +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) +{ + ALCcontext *ALContext; + ALCenum err; + + LockLists(); + if(!(device=VerifyDevice(device)) || device->Type == Capture || !device->Connected) + { + UnlockLists(); + alcSetError(device, ALC_INVALID_DEVICE); + if(device) ALCdevice_DecRef(device); + return NULL; + } + + device->LastError = ALC_NO_ERROR; + + if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) + { + UnlockLists(); + alcSetError(device, err); + if(err == ALC_INVALID_DEVICE) + { + ALCdevice_Lock(device); + aluHandleDisconnect(device); + ALCdevice_Unlock(device); + } + ALCdevice_DecRef(device); + return NULL; + } + + ALContext = calloc(1, sizeof(ALCcontext)+15+sizeof(ALlistener)); + if(ALContext) + { + ALContext->ref = 1; + ALContext->Listener = (ALlistener*)(((ALintptrEXT)(ALContext+1)+15)&~15); + + ALContext->MaxActiveSources = 256; + ALContext->ActiveSources = malloc(sizeof(ALContext->ActiveSources[0]) * + ALContext->MaxActiveSources); + } + if(!ALContext || !ALContext->ActiveSources) + { + if(!device->ContextList) + { + ALCdevice_StopPlayback(device); + device->Flags &= ~DEVICE_RUNNING; + } + UnlockLists(); + + free(ALContext); + ALContext = NULL; + + alcSetError(device, ALC_OUT_OF_MEMORY); + ALCdevice_DecRef(device); + return NULL; + } + + ALContext->Device = device; + ALCdevice_IncRef(device); + InitContext(ALContext); + + do { + ALContext->next = device->ContextList; + } while(!CompExchangePtr((XchgPtr*)&device->ContextList, ALContext->next, ALContext)); + UnlockLists(); + + ALCdevice_DecRef(device); + + TRACE("Created context %p\n", ALContext); + return ALContext; +} + +/* alcDestroyContext + * + * Remove a context from its device + */ +ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) +{ + ALCdevice *Device; + + LockLists(); + /* alcGetContextsDevice sets an error for invalid contexts */ + Device = alcGetContextsDevice(context); + if(Device) + { + ReleaseContext(context, Device); + if(!Device->ContextList) + { + ALCdevice_StopPlayback(Device); + Device->Flags &= ~DEVICE_RUNNING; + } + } + UnlockLists(); +} + + +/* alcGetCurrentContext + * + * Returns the currently active context on the calling thread + */ +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) +{ + ALCcontext *Context; + + Context = pthread_getspecific(LocalContext); + if(!Context) Context = GlobalContext; + + return Context; +} + +/* alcGetThreadContext + * + * Returns the currently active thread-local context + */ +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) +{ + ALCcontext *Context; + Context = pthread_getspecific(LocalContext); + return Context; +} + + +/* alcMakeContextCurrent + * + * Makes the given context the active process-wide context, and removes the + * thread-local context for the calling thread. + */ +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + /* context must be valid or NULL */ + if(context && !(context=VerifyContext(context))) + { + alcSetError(NULL, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } + /* context's reference count is already incremented */ + context = ExchangePtr((XchgPtr*)&GlobalContext, context); + if(context) ALCcontext_DecRef(context); + + if((context=pthread_getspecific(LocalContext)) != NULL) + { + pthread_setspecific(LocalContext, NULL); + ALCcontext_DecRef(context); + } + + return ALC_TRUE; +} + +/* alcSetThreadContext + * + * Makes the given context the active context for the current thread + */ +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) +{ + ALCcontext *old; + + /* context must be valid or NULL */ + if(context && !(context=VerifyContext(context))) + { + alcSetError(NULL, ALC_INVALID_CONTEXT); + return ALC_FALSE; + } + /* context's reference count is already incremented */ + old = pthread_getspecific(LocalContext); + pthread_setspecific(LocalContext, context); + if(old) ALCcontext_DecRef(old); + + return ALC_TRUE; +} + + +/* alcGetContextsDevice + * + * Returns the device that a particular context is attached to + */ +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) +{ + ALCdevice *Device; + + if(!(Context=VerifyContext(Context))) + { + alcSetError(NULL, ALC_INVALID_CONTEXT); + return NULL; + } + Device = Context->Device; + ALCcontext_DecRef(Context); + + return Device; +} + + +/* alcOpenDevice + * + * Opens the named device. + */ +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) +{ + const ALCchar *fmt; + ALCdevice *device; + ALCenum err; + + DO_INITCONFIG(); + + if(!PlaybackBackend.name) + { + alcSetError(NULL, ALC_INVALID_VALUE); + return NULL; + } + + if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) + deviceName = NULL; + + device = al_calloc(16, sizeof(ALCdevice)+15+sizeof(ALeffectslot)); + if(!device) + { + alcSetError(NULL, ALC_OUT_OF_MEMORY); + return NULL; + } + + //Validate device + device->Funcs = &PlaybackBackend.Funcs; + device->ref = 1; + device->Connected = ALC_TRUE; + device->Type = Playback; + InitializeCriticalSection(&device->Mutex); + device->LastError = ALC_NO_ERROR; + + device->Flags = 0; + device->Bs2b = NULL; + device->Bs2bLevel = 0; + device->DeviceName = NULL; + + device->ContextList = NULL; + + device->MaxNoOfSources = 256; + device->AuxiliaryEffectSlotMax = 4; + device->NumAuxSends = MAX_SENDS; + + InitUIntMap(&device->BufferMap, ~0); + InitUIntMap(&device->EffectMap, ~0); + InitUIntMap(&device->FilterMap, ~0); + + //Set output format + device->FmtChans = DevFmtChannelsDefault; + device->FmtType = DevFmtTypeDefault; + device->Frequency = DEFAULT_OUTPUT_RATE; + device->NumUpdates = 4; + device->UpdateSize = 1024; + + if(ConfigValueStr(NULL, "channels", &fmt)) + { + static const struct { + const char name[16]; + enum DevFmtChannels chans; + } chanlist[] = { + { "mono", DevFmtMono }, + { "stereo", DevFmtStereo }, + { "quad", DevFmtQuad }, + { "surround51", DevFmtX51 }, + { "surround61", DevFmtX61 }, + { "surround71", DevFmtX71 }, + }; + size_t i; + + for(i = 0;i < COUNTOF(chanlist);i++) + { + if(strcasecmp(chanlist[i].name, fmt) == 0) + { + device->FmtChans = chanlist[i].chans; + device->Flags |= DEVICE_CHANNELS_REQUEST; + break; + } + } + if(i == COUNTOF(chanlist)) + ERR("Unsupported channels: %s\n", fmt); + } + if(ConfigValueStr(NULL, "sample-type", &fmt)) + { + static const struct { + const char name[16]; + enum DevFmtType type; + } typelist[] = { + { "int8", DevFmtByte }, + { "uint8", DevFmtUByte }, + { "int16", DevFmtShort }, + { "uint16", DevFmtUShort }, + { "int32", DevFmtInt }, + { "uint32", DevFmtUInt }, + { "float32", DevFmtFloat }, + }; + size_t i; + + for(i = 0;i < COUNTOF(typelist);i++) + { + if(strcasecmp(typelist[i].name, fmt) == 0) + { + device->FmtType = typelist[i].type; + device->Flags |= DEVICE_SAMPLE_TYPE_REQUEST; + break; + } + } + if(i == COUNTOF(typelist)) + ERR("Unsupported sample-type: %s\n", fmt); + } +#define DEVICE_FORMAT_REQUEST (DEVICE_CHANNELS_REQUEST|DEVICE_SAMPLE_TYPE_REQUEST) + if((device->Flags&DEVICE_FORMAT_REQUEST) != DEVICE_FORMAT_REQUEST && + ConfigValueStr(NULL, "format", &fmt)) + { + static const struct { + const char name[32]; + enum DevFmtChannels channels; + enum DevFmtType type; + } formats[] = { + { "AL_FORMAT_MONO32", DevFmtMono, DevFmtFloat }, + { "AL_FORMAT_STEREO32", DevFmtStereo, DevFmtFloat }, + { "AL_FORMAT_QUAD32", DevFmtQuad, DevFmtFloat }, + { "AL_FORMAT_51CHN32", DevFmtX51, DevFmtFloat }, + { "AL_FORMAT_61CHN32", DevFmtX61, DevFmtFloat }, + { "AL_FORMAT_71CHN32", DevFmtX71, DevFmtFloat }, + + { "AL_FORMAT_MONO16", DevFmtMono, DevFmtShort }, + { "AL_FORMAT_STEREO16", DevFmtStereo, DevFmtShort }, + { "AL_FORMAT_QUAD16", DevFmtQuad, DevFmtShort }, + { "AL_FORMAT_51CHN16", DevFmtX51, DevFmtShort }, + { "AL_FORMAT_61CHN16", DevFmtX61, DevFmtShort }, + { "AL_FORMAT_71CHN16", DevFmtX71, DevFmtShort }, + + { "AL_FORMAT_MONO8", DevFmtMono, DevFmtByte }, + { "AL_FORMAT_STEREO8", DevFmtStereo, DevFmtByte }, + { "AL_FORMAT_QUAD8", DevFmtQuad, DevFmtByte }, + { "AL_FORMAT_51CHN8", DevFmtX51, DevFmtByte }, + { "AL_FORMAT_61CHN8", DevFmtX61, DevFmtByte }, + { "AL_FORMAT_71CHN8", DevFmtX71, DevFmtByte } + }; + size_t i; + + ERR("Option 'format' is deprecated, please use 'channels' and 'sample-type'\n"); + for(i = 0;i < COUNTOF(formats);i++) + { + if(strcasecmp(fmt, formats[i].name) == 0) + { + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + device->FmtChans = formats[i].channels; + if(!(device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + device->FmtType = formats[i].type; + device->Flags |= DEVICE_FORMAT_REQUEST; + break; + } + } + if(i == COUNTOF(formats)) + ERR("Unsupported format: %s\n", fmt); + } +#undef DEVICE_FORMAT_REQUEST + + if(ConfigValueUInt(NULL, "frequency", &device->Frequency)) + { + device->Flags |= DEVICE_FREQUENCY_REQUEST; + if(device->Frequency < MIN_OUTPUT_RATE) + ERR("%uhz request clamped to %uhz minimum\n", device->Frequency, MIN_OUTPUT_RATE); + device->Frequency = maxu(device->Frequency, MIN_OUTPUT_RATE); + } + + ConfigValueUInt(NULL, "periods", &device->NumUpdates); + device->NumUpdates = clampu(device->NumUpdates, 2, 16); + + ConfigValueUInt(NULL, "period_size", &device->UpdateSize); + device->UpdateSize = clampu(device->UpdateSize, 64, 8192); + if((CPUCapFlags&CPU_CAP_SSE)) + device->UpdateSize = (device->UpdateSize+3)&~3; + + ConfigValueUInt(NULL, "sources", &device->MaxNoOfSources); + if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256; + + ConfigValueUInt(NULL, "slots", &device->AuxiliaryEffectSlotMax); + if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; + + ConfigValueUInt(NULL, "sends", &device->NumAuxSends); + if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; + + ConfigValueInt(NULL, "cf_level", &device->Bs2bLevel); + + device->NumStereoSources = 1; + device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources; + + // Find a playback device to open + if((err=ALCdevice_OpenPlayback(device, deviceName)) != ALC_NO_ERROR) + { + DeleteCriticalSection(&device->Mutex); + al_free(device); + alcSetError(NULL, err); + return NULL; + } + + if(DefaultEffect.type != AL_EFFECT_NULL) + { + device->DefaultSlot = (ALeffectslot*)(((ALintptrEXT)(device+1)+15)&~15); + if(InitEffectSlot(device->DefaultSlot) != AL_NO_ERROR) + { + device->DefaultSlot = NULL; + ERR("Failed to initialize the default effect slot\n"); + } + else if(InitializeEffect(device, device->DefaultSlot, &DefaultEffect) != AL_NO_ERROR) + { + ALeffectState_Destroy(device->DefaultSlot->EffectState); + device->DefaultSlot = NULL; + ERR("Failed to initialize the default effect\n"); + } + } + + do { + device->next = DeviceList; + } while(!CompExchangePtr((XchgPtr*)&DeviceList, device->next, device)); + + TRACE("Created device %p, \"%s\"\n", device, device->DeviceName); + return device; +} + +/* alcCloseDevice + * + * Closes the given device. + */ +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *Device) +{ + ALCdevice *volatile*list; + ALCcontext *ctx; + + LockLists(); + list = &DeviceList; + while(*list && *list != Device) + list = &(*list)->next; + + if(!*list || (*list)->Type == Capture) + { + alcSetError(*list, ALC_INVALID_DEVICE); + UnlockLists(); + return ALC_FALSE; + } + + *list = (*list)->next; + UnlockLists(); + + while((ctx=Device->ContextList) != NULL) + { + WARN("Releasing context %p\n", ctx); + ReleaseContext(ctx, Device); + } + if((Device->Flags&DEVICE_RUNNING)) + ALCdevice_StopPlayback(Device); + Device->Flags &= ~DEVICE_RUNNING; + + ALCdevice_DecRef(Device); + + return ALC_TRUE; +} + + +/************************************************ + * ALC capture functions + ************************************************/ +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) +{ + ALCdevice *device = NULL; + ALCenum err; + + DO_INITCONFIG(); + + if(!CaptureBackend.name) + { + alcSetError(NULL, ALC_INVALID_VALUE); + return NULL; + } + + if(samples <= 0) + { + alcSetError(NULL, ALC_INVALID_VALUE); + return NULL; + } + + if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) + deviceName = NULL; + + device = al_calloc(16, sizeof(ALCdevice)); + if(!device) + { + alcSetError(NULL, ALC_OUT_OF_MEMORY); + return NULL; + } + + //Validate device + device->Funcs = &CaptureBackend.Funcs; + device->ref = 1; + device->Connected = ALC_TRUE; + device->Type = Capture; + InitializeCriticalSection(&device->Mutex); + + InitUIntMap(&device->BufferMap, ~0); + InitUIntMap(&device->EffectMap, ~0); + InitUIntMap(&device->FilterMap, ~0); + + device->DeviceName = NULL; + + device->Flags |= DEVICE_FREQUENCY_REQUEST; + device->Frequency = frequency; + + device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_SAMPLE_TYPE_REQUEST; + if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE) + { + DeleteCriticalSection(&device->Mutex); + al_free(device); + alcSetError(NULL, ALC_INVALID_ENUM); + return NULL; + } + + device->UpdateSize = samples; + device->NumUpdates = 1; + + if((err=ALCdevice_OpenCapture(device, deviceName)) != ALC_NO_ERROR) + { + DeleteCriticalSection(&device->Mutex); + al_free(device); + alcSetError(NULL, err); + return NULL; + } + + do { + device->next = DeviceList; + } while(!CompExchangePtr((XchgPtr*)&DeviceList, device->next, device)); + + TRACE("Created device %p, \"%s\"\n", device, device->DeviceName); + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *Device) +{ + ALCdevice *volatile*list; + + LockLists(); + list = &DeviceList; + while(*list && *list != Device) + list = &(*list)->next; + + if(!*list || (*list)->Type != Capture) + { + alcSetError(*list, ALC_INVALID_DEVICE); + UnlockLists(); + return ALC_FALSE; + } + + *list = (*list)->next; + UnlockLists(); + + ALCdevice_DecRef(Device); + + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) +{ + if(!(device=VerifyDevice(device)) || device->Type != Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + ALCdevice_Lock(device); + if(device->Connected) + { + if(!(device->Flags&DEVICE_RUNNING)) + ALCdevice_StartCapture(device); + device->Flags |= DEVICE_RUNNING; + } + ALCdevice_Unlock(device); + } + + if(device) ALCdevice_DecRef(device); +} + +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) +{ + if(!(device=VerifyDevice(device)) || device->Type != Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + ALCdevice_Lock(device); + if((device->Flags&DEVICE_RUNNING)) + ALCdevice_StopCapture(device); + device->Flags &= ~DEVICE_RUNNING; + ALCdevice_Unlock(device); + } + + if(device) ALCdevice_DecRef(device); +} + +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + if(!(device=VerifyDevice(device)) && device->Type != Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else + { + ALCenum err = ALC_INVALID_VALUE; + + ALCdevice_Lock(device); + if(samples >= 0 && ALCdevice_AvailableSamples(device) >= (ALCuint)samples) + err = ALCdevice_CaptureSamples(device, buffer, samples); + ALCdevice_Unlock(device); + + if(err != ALC_NO_ERROR) + alcSetError(device, err); + } + if(device) ALCdevice_DecRef(device); +} + + +/************************************************ + * ALC loopback functions + ************************************************/ + +/* alcLoopbackOpenDeviceSOFT + * + * Open a loopback device, for manual rendering. + */ +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) +{ + ALCdevice *device; + + DO_INITCONFIG(); + + /* Make sure the device name, if specified, is us. */ + if(deviceName && strcmp(deviceName, alcDefaultName) != 0) + { + alcSetError(NULL, ALC_INVALID_VALUE); + return NULL; + } + + device = al_calloc(16, sizeof(ALCdevice)); + if(!device) + { + alcSetError(NULL, ALC_OUT_OF_MEMORY); + return NULL; + } + + //Validate device + device->Funcs = &BackendLoopback.Funcs; + device->ref = 1; + device->Connected = ALC_TRUE; + device->Type = Loopback; + InitializeCriticalSection(&device->Mutex); + device->LastError = ALC_NO_ERROR; + + device->Flags = 0; + device->Bs2b = NULL; + device->Bs2bLevel = 0; + device->DeviceName = NULL; + + device->ContextList = NULL; + + device->MaxNoOfSources = 256; + device->AuxiliaryEffectSlotMax = 4; + device->NumAuxSends = MAX_SENDS; + + InitUIntMap(&device->BufferMap, ~0); + InitUIntMap(&device->EffectMap, ~0); + InitUIntMap(&device->FilterMap, ~0); + + //Set output format + device->NumUpdates = 0; + device->UpdateSize = 0; + + device->Frequency = DEFAULT_OUTPUT_RATE; + device->FmtChans = DevFmtChannelsDefault; + device->FmtType = DevFmtTypeDefault; + + ConfigValueUInt(NULL, "sources", &device->MaxNoOfSources); + if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256; + + ConfigValueUInt(NULL, "slots", &device->AuxiliaryEffectSlotMax); + if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; + + ConfigValueUInt(NULL, "sends", &device->NumAuxSends); + if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; + + device->NumStereoSources = 1; + device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources; + + // Open the "backend" + ALCdevice_OpenPlayback(device, "Loopback"); + do { + device->next = DeviceList; + } while(!CompExchangePtr((XchgPtr*)&DeviceList, device->next, device)); + + TRACE("Created device %p\n", device); + return device; +} + +/* alcIsRenderFormatSupportedSOFT + * + * Determines if the loopback device supports the given format for rendering. + */ +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) +{ + ALCboolean ret = ALC_FALSE; + + if(!(device=VerifyDevice(device)) || device->Type != Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else if(freq <= 0) + alcSetError(device, ALC_INVALID_VALUE); + else + { + if(IsValidALCType(type) && BytesFromDevFmt(type) > 0 && + IsValidALCChannels(channels) && ChannelsFromDevFmt(channels) > 0 && + freq >= MIN_OUTPUT_RATE) + ret = ALC_TRUE; + } + if(device) ALCdevice_DecRef(device); + + return ret; +} + +/* alcRenderSamplesSOFT + * + * Renders some samples into a buffer, using the format last set by the + * attributes given to alcCreateContext. + */ +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + if(!(device=VerifyDevice(device)) || device->Type != Loopback) + alcSetError(device, ALC_INVALID_DEVICE); + else if(samples < 0 || (samples > 0 && buffer == NULL)) + alcSetError(device, ALC_INVALID_VALUE); + else + aluMixData(device, buffer, samples); + if(device) ALCdevice_DecRef(device); +} diff --git a/src/eepp/helper/android/openal-soft/Alc/ALu.c b/src/eepp/helper/android/openal-soft/Alc/ALu.c new file mode 100644 index 000000000..282053c7d --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/ALu.c @@ -0,0 +1,1204 @@ +/** + * 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 "alBuffer.h" +#include "alListener.h" +#include "alAuxEffectSlot.h" +#include "alu.h" +#include "bs2b.h" + +#include "mixer_defs.h" + + +struct ChanMap { + enum Channel channel; + ALfloat angle; +}; + +/* Cone scalar */ +ALfloat ConeScale = 1.0f; + +/* Localized Z scalar for mono sources */ +ALfloat ZScale = 1.0f; + + +static ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment) +{ + if(increment == FRACTIONONE) + return Resample_copy32_C; + switch(Resampler) + { + case PointResampler: + return Resample_point32_C; + case LinearResampler: + return Resample_lerp32_C; + case CubicResampler: + return Resample_cubic32_C; + case ResamplerMax: + /* Shouldn't happen */ + break; + } + + return Resample_point32_C; +} + + +static DryMixerFunc SelectHrtfMixer(void) +{ +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixDirect_Hrtf_SSE; +#endif +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixDirect_Hrtf_Neon; +#endif + + return MixDirect_Hrtf_C; +} + +static DryMixerFunc SelectDirectMixer(void) +{ +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixDirect_SSE; +#endif + + return MixDirect_C; +} + +static WetMixerFunc SelectSendMixer(void) +{ +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixSend_SSE; +#endif + + return MixSend_C; +} + + +static __inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) +{ + outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; + outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; + outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; +} + +static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2) +{ + return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] + + inVector1[2]*inVector2[2]; +} + +static __inline void aluNormalize(ALfloat *inVector) +{ + ALfloat lengthsqr = aluDotproduct(inVector, inVector); + if(lengthsqr > 0.0f) + { + ALfloat inv_length = 1.0f/sqrtf(lengthsqr); + inVector[0] *= inv_length; + inVector[1] *= inv_length; + inVector[2] *= inv_length; + } +} + +static __inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*RESTRICT matrix)[4]) +{ + ALfloat temp[4] = { + vector[0], vector[1], vector[2], w + }; + + vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0]; + vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1]; + vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2]; +} + + +static ALvoid CalcListenerParams(ALlistener *Listener) +{ + ALfloat N[3], V[3], U[3], P[3]; + + /* AT then UP */ + N[0] = Listener->Forward[0]; + N[1] = Listener->Forward[1]; + N[2] = Listener->Forward[2]; + aluNormalize(N); + V[0] = Listener->Up[0]; + V[1] = Listener->Up[1]; + V[2] = Listener->Up[2]; + aluNormalize(V); + /* Build and normalize right-vector */ + aluCrossproduct(N, V, U); + aluNormalize(U); + + Listener->Params.Matrix[0][0] = U[0]; + Listener->Params.Matrix[0][1] = V[0]; + Listener->Params.Matrix[0][2] = -N[0]; + Listener->Params.Matrix[0][3] = 0.0f; + Listener->Params.Matrix[1][0] = U[1]; + Listener->Params.Matrix[1][1] = V[1]; + Listener->Params.Matrix[1][2] = -N[1]; + Listener->Params.Matrix[1][3] = 0.0f; + Listener->Params.Matrix[2][0] = U[2]; + Listener->Params.Matrix[2][1] = V[2]; + Listener->Params.Matrix[2][2] = -N[2]; + Listener->Params.Matrix[2][3] = 0.0f; + Listener->Params.Matrix[3][0] = 0.0f; + Listener->Params.Matrix[3][1] = 0.0f; + Listener->Params.Matrix[3][2] = 0.0f; + Listener->Params.Matrix[3][3] = 1.0f; + + P[0] = Listener->Position[0]; + P[1] = Listener->Position[1]; + P[2] = Listener->Position[2]; + aluMatrixVector(P, 1.0f, Listener->Params.Matrix); + Listener->Params.Matrix[3][0] = -P[0]; + Listener->Params.Matrix[3][1] = -P[1]; + Listener->Params.Matrix[3][2] = -P[2]; + + Listener->Params.Velocity[0] = Listener->Velocity[0]; + Listener->Params.Velocity[1] = Listener->Velocity[1]; + Listener->Params.Velocity[2] = Listener->Velocity[2]; + aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix); +} + +ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext) +{ + static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } }; + static const struct ChanMap StereoMap[2] = { + { FrontLeft, -30.0f * F_PI/180.0f }, + { FrontRight, 30.0f * F_PI/180.0f } + }; + static const struct ChanMap StereoWideMap[2] = { + { FrontLeft, -90.0f * F_PI/180.0f }, + { FrontRight, 90.0f * F_PI/180.0f } + }; + static const struct ChanMap RearMap[2] = { + { BackLeft, -150.0f * F_PI/180.0f }, + { BackRight, 150.0f * F_PI/180.0f } + }; + static const struct ChanMap QuadMap[4] = { + { FrontLeft, -45.0f * F_PI/180.0f }, + { FrontRight, 45.0f * F_PI/180.0f }, + { BackLeft, -135.0f * F_PI/180.0f }, + { BackRight, 135.0f * F_PI/180.0f } + }; + static const struct ChanMap X51Map[6] = { + { FrontLeft, -30.0f * F_PI/180.0f }, + { FrontRight, 30.0f * F_PI/180.0f }, + { FrontCenter, 0.0f * F_PI/180.0f }, + { LFE, 0.0f }, + { BackLeft, -110.0f * F_PI/180.0f }, + { BackRight, 110.0f * F_PI/180.0f } + }; + static const struct ChanMap X61Map[7] = { + { FrontLeft, -30.0f * F_PI/180.0f }, + { FrontRight, 30.0f * F_PI/180.0f }, + { FrontCenter, 0.0f * F_PI/180.0f }, + { LFE, 0.0f }, + { BackCenter, 180.0f * F_PI/180.0f }, + { SideLeft, -90.0f * F_PI/180.0f }, + { SideRight, 90.0f * F_PI/180.0f } + }; + static const struct ChanMap X71Map[8] = { + { FrontLeft, -30.0f * F_PI/180.0f }, + { FrontRight, 30.0f * F_PI/180.0f }, + { FrontCenter, 0.0f * F_PI/180.0f }, + { LFE, 0.0f }, + { BackLeft, -150.0f * F_PI/180.0f }, + { BackRight, 150.0f * F_PI/180.0f }, + { SideLeft, -90.0f * F_PI/180.0f }, + { SideRight, 90.0f * F_PI/180.0f } + }; + + ALCdevice *Device = ALContext->Device; + ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; + ALbufferlistitem *BufferListItem; + enum FmtChannels Channels; + ALfloat (*SrcMatrix)[MaxChannels]; + ALfloat DryGain, DryGainHF; + ALfloat WetGain[MAX_SENDS]; + ALfloat WetGainHF[MAX_SENDS]; + ALint NumSends, Frequency; + const struct ChanMap *chans = NULL; + enum Resampler Resampler; + ALint num_channels = 0; + ALboolean DirectChannels; + ALfloat hwidth = 0.0f; + ALfloat Pitch; + ALfloat cw; + ALint i, c; + + /* Get device properties */ + NumSends = Device->NumAuxSends; + Frequency = Device->Frequency; + + /* Get listener properties */ + ListenerGain = ALContext->Listener->Gain; + + /* Get source properties */ + SourceVolume = ALSource->Gain; + MinVolume = ALSource->MinGain; + MaxVolume = ALSource->MaxGain; + Pitch = ALSource->Pitch; + Resampler = ALSource->Resampler; + DirectChannels = ALSource->DirectChannels; + + /* Calculate the stepping value */ + Channels = FmtMono; + BufferListItem = ALSource->queue; + while(BufferListItem != NULL) + { + ALbuffer *ALBuffer; + if((ALBuffer=BufferListItem->buffer) != NULL) + { + ALsizei maxstep = BUFFERSIZE; + maxstep -= ResamplerPadding[Resampler] + + ResamplerPrePadding[Resampler] + 1; + maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS); + + Pitch = Pitch * ALBuffer->Frequency / Frequency; + if(Pitch > (ALfloat)maxstep) + ALSource->Params.Step = maxstep<Params.Step = fastf2i(Pitch*FRACTIONONE); + if(ALSource->Params.Step == 0) + ALSource->Params.Step = 1; + } + ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step); + + Channels = ALBuffer->FmtChannels; + break; + } + BufferListItem = BufferListItem->next; + } + if(!DirectChannels && Device->Hrtf) + ALSource->Params.DryMix = SelectHrtfMixer(); + else + ALSource->Params.DryMix = SelectDirectMixer(); + ALSource->Params.WetMix = SelectSendMixer(); + + /* Calculate gains */ + DryGain = clampf(SourceVolume, MinVolume, MaxVolume); + DryGain *= ALSource->DirectGain * ListenerGain; + DryGainHF = ALSource->DirectGainHF; + for(i = 0;i < NumSends;i++) + { + WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); + WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; + WetGainHF[i] = ALSource->Send[i].GainHF; + } + + SrcMatrix = ALSource->Params.Direct.Gains; + for(i = 0;i < MaxChannels;i++) + { + for(c = 0;c < MaxChannels;c++) + SrcMatrix[i][c] = 0.0f; + } + switch(Channels) + { + case FmtMono: + chans = MonoMap; + num_channels = 1; + break; + + case FmtStereo: + if(!(Device->Flags&DEVICE_WIDE_STEREO)) + { + /* HACK: Place the stereo channels at +/-90 degrees when using non- + * HRTF stereo output. This helps reduce the "monoization" caused + * by them panning towards the center. */ + if(Device->FmtChans == DevFmtStereo && !Device->Hrtf) + chans = StereoWideMap; + else + chans = StereoMap; + } + else + { + chans = StereoWideMap; + hwidth = 60.0f * F_PI/180.0f; + } + num_channels = 2; + break; + + case FmtRear: + chans = RearMap; + num_channels = 2; + break; + + case FmtQuad: + chans = QuadMap; + num_channels = 4; + break; + + case FmtX51: + chans = X51Map; + num_channels = 6; + break; + + case FmtX61: + chans = X61Map; + num_channels = 7; + break; + + case FmtX71: + chans = X71Map; + num_channels = 8; + break; + } + + if(DirectChannels != AL_FALSE) + { + for(c = 0;c < num_channels;c++) + { + for(i = 0;i < (ALint)Device->NumChan;i++) + { + enum Channel chan = Device->Speaker2Chan[i]; + if(chan == chans[c].channel) + { + SrcMatrix[c][chan] = DryGain; + break; + } + } + } + } + else if(Device->Hrtf) + { + for(c = 0;c < num_channels;c++) + { + if(chans[c].channel == LFE) + { + /* Skip LFE */ + ALSource->Params.Direct.Hrtf.Params.Delay[c][0] = 0; + ALSource->Params.Direct.Hrtf.Params.Delay[c][1] = 0; + for(i = 0;i < HRIR_LENGTH;i++) + { + ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][0] = 0.0f; + ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][1] = 0.0f; + } + } + else + { + /* Get the static HRIR coefficients and delays for this + * channel. */ + GetLerpedHrtfCoeffs(Device->Hrtf, + 0.0f, chans[c].angle, DryGain, + ALSource->Params.Direct.Hrtf.Params.Coeffs[c], + ALSource->Params.Direct.Hrtf.Params.Delay[c]); + } + } + ALSource->Hrtf.Counter = 0; + ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf); + + ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf; + } + else + { + DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI); + for(c = 0;c < num_channels;c++) + { + /* Special-case LFE */ + if(chans[c].channel == LFE) + { + SrcMatrix[c][chans[c].channel] = DryGain; + continue; + } + ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain, + SrcMatrix[c]); + } + } + + ALSource->Params.Direct.OutBuffer = Device->DryBuffer; + ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval; + ALSource->Params.Direct.PendingClicks = Device->PendingClicks; + for(i = 0;i < NumSends;i++) + { + ALeffectslot *Slot = ALSource->Send[i].Slot; + + if(!Slot && i == 0) + Slot = Device->DefaultSlot; + if(Slot && Slot->effect.type == AL_EFFECT_NULL) + Slot = NULL; + ALSource->Params.Send[i].Slot = Slot; + ALSource->Params.Send[i].Gain = WetGain[i]; + } + + /* Update filter coefficients. Calculations based on the I3DL2 + * spec. */ + cw = cosf(F_PI*2.0f * LOWPASSFREQREF / 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.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw); + for(i = 0;i < NumSends;i++) + { + ALfloat a = lpCoeffCalc(WetGainHF[i], cw); + ALSource->Params.Send[i].iirFilter.coeff = a; + } +} + +ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext) +{ + ALCdevice *Device = ALContext->Device; + ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3]; + ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist; + ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; + ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain; + ALfloat DopplerFactor, SpeedOfSound; + ALfloat AirAbsorptionFactor; + ALfloat RoomAirAbsorption[MAX_SENDS]; + ALbufferlistitem *BufferListItem; + ALfloat Attenuation; + ALfloat RoomAttenuation[MAX_SENDS]; + ALfloat MetersPerUnit; + ALfloat RoomRolloffBase; + ALfloat RoomRolloff[MAX_SENDS]; + ALfloat DecayDistance[MAX_SENDS]; + ALfloat DryGain; + ALfloat DryGainHF; + ALboolean DryGainHFAuto; + ALfloat WetGain[MAX_SENDS]; + ALfloat WetGainHF[MAX_SENDS]; + ALboolean WetGainAuto; + ALboolean WetGainHFAuto; + enum Resampler Resampler; + ALfloat Pitch; + ALuint Frequency; + ALint NumSends; + ALfloat cw; + ALint i, j; + + DryGainHF = 1.0f; + for(i = 0;i < MAX_SENDS;i++) + WetGainHF[i] = 1.0f; + + /* Get context/device properties */ + DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor; + SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity; + NumSends = Device->NumAuxSends; + Frequency = Device->Frequency; + + /* Get listener properties */ + ListenerGain = ALContext->Listener->Gain; + MetersPerUnit = ALContext->Listener->MetersPerUnit; + + /* Get source properties */ + SourceVolume = ALSource->Gain; + MinVolume = ALSource->MinGain; + MaxVolume = ALSource->MaxGain; + Pitch = ALSource->Pitch; + Resampler = ALSource->Resampler; + Position[0] = ALSource->Position[0]; + Position[1] = ALSource->Position[1]; + Position[2] = ALSource->Position[2]; + Direction[0] = ALSource->Orientation[0]; + Direction[1] = ALSource->Orientation[1]; + Direction[2] = ALSource->Orientation[2]; + Velocity[0] = ALSource->Velocity[0]; + Velocity[1] = ALSource->Velocity[1]; + Velocity[2] = ALSource->Velocity[2]; + MinDist = ALSource->RefDistance; + MaxDist = ALSource->MaxDistance; + Rolloff = ALSource->RollOffFactor; + InnerAngle = ALSource->InnerAngle; + OuterAngle = ALSource->OuterAngle; + AirAbsorptionFactor = ALSource->AirAbsorptionFactor; + DryGainHFAuto = ALSource->DryGainHFAuto; + WetGainAuto = ALSource->WetGainAuto; + WetGainHFAuto = ALSource->WetGainHFAuto; + RoomRolloffBase = ALSource->RoomRolloffFactor; + + ALSource->Params.Direct.OutBuffer = Device->DryBuffer; + ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval; + ALSource->Params.Direct.PendingClicks = Device->PendingClicks; + for(i = 0;i < NumSends;i++) + { + ALeffectslot *Slot = ALSource->Send[i].Slot; + + if(!Slot && i == 0) + Slot = Device->DefaultSlot; + if(!Slot || Slot->effect.type == AL_EFFECT_NULL) + { + Slot = NULL; + RoomRolloff[i] = 0.0f; + DecayDistance[i] = 0.0f; + RoomAirAbsorption[i] = 1.0f; + } + else if(Slot->AuxSendAuto) + { + RoomRolloff[i] = RoomRolloffBase; + if(IsReverbEffect(Slot->effect.type)) + { + RoomRolloff[i] += Slot->effect.Reverb.RoomRolloffFactor; + DecayDistance[i] = Slot->effect.Reverb.DecayTime * + SPEEDOFSOUNDMETRESPERSEC; + RoomAirAbsorption[i] = Slot->effect.Reverb.AirAbsorptionGainHF; + } + else + { + DecayDistance[i] = 0.0f; + RoomAirAbsorption[i] = 1.0f; + } + } + 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 */ + RoomRolloff[i] = Rolloff; + DecayDistance[i] = 0.0f; + RoomAirAbsorption[i] = AIRABSORBGAINHF; + } + + ALSource->Params.Send[i].Slot = Slot; + } + + /* Transform source to listener space (convert to head relative) */ + if(ALSource->HeadRelative == AL_FALSE) + { + ALfloat (*RESTRICT Matrix)[4] = ALContext->Listener->Params.Matrix; + /* Transform source vectors */ + aluMatrixVector(Position, 1.0f, Matrix); + aluMatrixVector(Direction, 0.0f, Matrix); + aluMatrixVector(Velocity, 0.0f, Matrix); + } + else + { + const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity; + /* Offset the source velocity to be relative of the listener velocity */ + Velocity[0] += ListenerVel[0]; + Velocity[1] += ListenerVel[1]; + Velocity[2] += ListenerVel[2]; + } + + SourceToListener[0] = -Position[0]; + SourceToListener[1] = -Position[1]; + SourceToListener[2] = -Position[2]; + aluNormalize(SourceToListener); + aluNormalize(Direction); + + /* Calculate distance attenuation */ + Distance = sqrtf(aluDotproduct(Position, Position)); + ClampedDist = Distance; + + Attenuation = 1.0f; + for(i = 0;i < NumSends;i++) + RoomAttenuation[i] = 1.0f; + switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel : + ALContext->DistanceModel) + { + case InverseDistanceClamped: + ClampedDist = clampf(ClampedDist, MinDist, MaxDist); + if(MaxDist < MinDist) + break; + /*fall-through*/ + case InverseDistance: + if(MinDist > 0.0f) + { + if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f) + Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist))); + for(i = 0;i < NumSends;i++) + { + if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f) + RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))); + } + } + break; + + case LinearDistanceClamped: + ClampedDist = clampf(ClampedDist, MinDist, MaxDist); + if(MaxDist < MinDist) + break; + /*fall-through*/ + case LinearDistance: + if(MaxDist != MinDist) + { + Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist)); + Attenuation = maxf(Attenuation, 0.0f); + for(i = 0;i < NumSends;i++) + { + RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist)); + RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f); + } + } + break; + + case ExponentDistanceClamped: + ClampedDist = clampf(ClampedDist, MinDist, MaxDist); + if(MaxDist < MinDist) + break; + /*fall-through*/ + case ExponentDistance: + if(ClampedDist > 0.0f && MinDist > 0.0f) + { + Attenuation = powf(ClampedDist/MinDist, -Rolloff); + for(i = 0;i < NumSends;i++) + RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]); + } + break; + + case DisableDistance: + ClampedDist = MinDist; + break; + } + + /* Source Gain + Attenuation */ + DryGain = SourceVolume * Attenuation; + for(i = 0;i < NumSends;i++) + WetGain[i] = SourceVolume * RoomAttenuation[i]; + + /* Distance-based air absorption */ + if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist) + { + ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit; + DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters); + for(i = 0;i < NumSends;i++) + WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters); + } + + if(WetGainAuto) + { + ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f; + + /* Apply a decay-time transformation to the wet path, based on the + * attenuation of the dry path. + * + * Using the apparent distance, based on the distance attenuation, the + * initial decay of the reverb effect is calculated and applied to the + * wet path. + */ + for(i = 0;i < NumSends;i++) + { + if(DecayDistance[i] > 0.0f) + WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]); + } + } + + /* Calculate directional soundcones */ + Angle = acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale * (360.0f/F_PI); + if(Angle > InnerAngle && Angle <= OuterAngle) + { + ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); + ConeVolume = lerp(1.0f, ALSource->OuterGain, scale); + ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale); + } + else if(Angle > OuterAngle) + { + ConeVolume = ALSource->OuterGain; + ConeHF = ALSource->OuterGainHF; + } + else + { + ConeVolume = 1.0f; + ConeHF = 1.0f; + } + + DryGain *= ConeVolume; + if(WetGainAuto) + { + for(i = 0;i < NumSends;i++) + WetGain[i] *= ConeVolume; + } + if(DryGainHFAuto) + DryGainHF *= ConeHF; + if(WetGainHFAuto) + { + for(i = 0;i < NumSends;i++) + WetGainHF[i] *= ConeHF; + } + + /* Clamp to Min/Max Gain */ + DryGain = clampf(DryGain, MinVolume, MaxVolume); + for(i = 0;i < NumSends;i++) + WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); + + /* Apply gain and frequency filters */ + DryGain *= ALSource->DirectGain * ListenerGain; + DryGainHF *= ALSource->DirectGainHF; + for(i = 0;i < NumSends;i++) + { + WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; + WetGainHF[i] *= ALSource->Send[i].GainHF; + } + + /* Calculate velocity-based doppler effect */ + if(DopplerFactor > 0.0f) + { + const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity; + ALfloat VSS, VLS; + + if(SpeedOfSound < 1.0f) + { + DopplerFactor *= 1.0f/SpeedOfSound; + SpeedOfSound = 1.0f; + } + + VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor; + VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor; + + Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) / + clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f); + } + + BufferListItem = ALSource->queue; + while(BufferListItem != NULL) + { + ALbuffer *ALBuffer; + if((ALBuffer=BufferListItem->buffer) != NULL) + { + /* Calculate fixed-point stepping value, based on the pitch, buffer + * frequency, and output frequency. */ + ALsizei maxstep = BUFFERSIZE; + maxstep -= ResamplerPadding[Resampler] + + ResamplerPrePadding[Resampler] + 1; + maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS); + + Pitch = Pitch * ALBuffer->Frequency / Frequency; + if(Pitch > (ALfloat)maxstep) + ALSource->Params.Step = maxstep<Params.Step = fastf2i(Pitch*FRACTIONONE); + if(ALSource->Params.Step == 0) + ALSource->Params.Step = 1; + } + ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step); + + break; + } + BufferListItem = BufferListItem->next; + } + if(Device->Hrtf) + ALSource->Params.DryMix = SelectHrtfMixer(); + else + ALSource->Params.DryMix = SelectDirectMixer(); + ALSource->Params.WetMix = SelectSendMixer(); + + if(Device->Hrtf) + { + /* Use a binaural HRTF algorithm for stereo headphone playback */ + ALfloat delta, ev = 0.0f, az = 0.0f; + + if(Distance > FLT_EPSILON) + { + ALfloat invlen = 1.0f/Distance; + Position[0] *= invlen; + Position[1] *= invlen; + Position[2] *= invlen; + + /* Calculate elevation and azimuth only when the source is not at + * the listener. This prevents +0 and -0 Z from producing + * inconsistent panning. Also, clamp Y in case FP precision errors + * cause it to land outside of -1..+1. */ + ev = asinf(clampf(Position[1], -1.0f, 1.0f)); + az = atan2f(Position[0], -Position[2]*ZScale); + } + + /* Check to see if the HRIR is already moving. */ + if(ALSource->Hrtf.Moving) + { + /* Calculate the normalized HRTF transition factor (delta). */ + delta = CalcHrtfDelta(ALSource->Params.Direct.Hrtf.Params.Gain, DryGain, + ALSource->Params.Direct.Hrtf.Params.Dir, Position); + /* If the delta is large enough, get the moving HRIR target + * coefficients, target delays, steppping values, and counter. */ + if(delta > 0.001f) + { + ALSource->Hrtf.Counter = GetMovingHrtfCoeffs(Device->Hrtf, + ev, az, DryGain, delta, + ALSource->Hrtf.Counter, + ALSource->Params.Direct.Hrtf.Params.Coeffs[0], + ALSource->Params.Direct.Hrtf.Params.Delay[0], + ALSource->Params.Direct.Hrtf.Params.CoeffStep, + ALSource->Params.Direct.Hrtf.Params.DelayStep); + ALSource->Params.Direct.Hrtf.Params.Gain = DryGain; + ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0]; + ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1]; + ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2]; + } + } + else + { + /* Get the initial (static) HRIR coefficients and delays. */ + GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain, + ALSource->Params.Direct.Hrtf.Params.Coeffs[0], + ALSource->Params.Direct.Hrtf.Params.Delay[0]); + ALSource->Hrtf.Counter = 0; + ALSource->Hrtf.Moving = AL_TRUE; + ALSource->Params.Direct.Hrtf.Params.Gain = DryGain; + ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0]; + ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1]; + ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2]; + } + ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf); + + ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf; + } + else + { + ALfloat (*Matrix)[MaxChannels] = ALSource->Params.Direct.Gains; + ALfloat DirGain = 0.0f; + ALfloat AmbientGain; + + for(i = 0;i < MaxChannels;i++) + { + for(j = 0;j < MaxChannels;j++) + Matrix[i][j] = 0.0f; + } + + /* Normalize the length, and compute panned gains. */ + if(Distance > FLT_EPSILON) + { + ALfloat invlen = 1.0f/Distance; + Position[0] *= invlen; + Position[1] *= invlen; + Position[2] *= invlen; + + DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]); + ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f, + DryGain*DirGain, Matrix[0]); + } + + /* Adjustment for vertical offsets. Not the greatest, but simple + * enough. */ + AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain); + for(i = 0;i < (ALint)Device->NumChan;i++) + { + enum Channel chan = Device->Speaker2Chan[i]; + Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain); + } + } + for(i = 0;i < NumSends;i++) + ALSource->Params.Send[i].Gain = WetGain[i]; + + /* Update filter coefficients. */ + cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency); + + ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw); + for(i = 0;i < NumSends;i++) + { + ALfloat a = lpCoeffCalc(WetGainHF[i], cw); + ALSource->Params.Send[i].iirFilter.coeff = a; + } +} + + +static __inline ALfloat aluF2F(ALfloat val) +{ return val; } +static __inline ALint aluF2I(ALfloat val) +{ + /* Clamp the value between -1 and +1. This handles that without branching. */ + val = val+1.0f - fabsf(val-1.0f); + val = (val-2.0f + fabsf(val+2.0f)) * 0.25f; + /* Convert to a signed integer, between -2147483647 and +2147483647. */ + return fastf2i((ALfloat)(val*2147483647.0)); +} +static __inline ALuint aluF2UI(ALfloat val) +{ return aluF2I(val)+2147483648u; } +static __inline ALshort aluF2S(ALfloat val) +{ return aluF2I(val)>>16; } +static __inline ALushort aluF2US(ALfloat val) +{ return aluF2S(val)+32768; } +static __inline ALbyte aluF2B(ALfloat val) +{ return aluF2I(val)>>24; } +static __inline ALubyte aluF2UB(ALfloat val) +{ return aluF2B(val)+128; } + +#define DECL_TEMPLATE(T, func) \ +static int Write_##T(ALCdevice *device, T *RESTRICT buffer, \ + ALuint SamplesToDo) \ +{ \ + ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \ + ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \ + const ALuint *offsets = device->ChannelOffsets; \ + ALuint i, j; \ + \ + for(j = 0;j < MaxChannels;j++) \ + { \ + T *RESTRICT out; \ + \ + if(offsets[j] == INVALID_OFFSET) \ + continue; \ + \ + out = buffer + offsets[j]; \ + for(i = 0;i < SamplesToDo;i++) \ + out[i*numchans] = func(DryBuffer[j][i]); \ + } \ + return SamplesToDo*numchans*sizeof(T); \ +} + +DECL_TEMPLATE(ALfloat, aluF2F) +DECL_TEMPLATE(ALuint, aluF2UI) +DECL_TEMPLATE(ALint, aluF2I) +DECL_TEMPLATE(ALushort, aluF2US) +DECL_TEMPLATE(ALshort, aluF2S) +DECL_TEMPLATE(ALubyte, aluF2UB) +DECL_TEMPLATE(ALbyte, aluF2B) + +#undef DECL_TEMPLATE + + +ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) +{ + ALuint SamplesToDo; + ALeffectslot **slot, **slot_end; + ALsource **src, **src_end; + ALCcontext *ctx; + FPUCtl oldMode; + ALuint i, c; + + SetMixerFPUMode(&oldMode); + + while(size > 0) + { + SamplesToDo = minu(size, BUFFERSIZE); + for(c = 0;c < MaxChannels;c++) + memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); + + ALCdevice_Lock(device); + ctx = device->ContextList; + while(ctx) + { + ALenum DeferUpdates = ctx->DeferUpdates; + ALenum UpdateSources = AL_FALSE; + + if(!DeferUpdates) + UpdateSources = ExchangeInt(&ctx->UpdateSources, AL_FALSE); + + if(UpdateSources) + CalcListenerParams(ctx->Listener); + + /* source processing */ + src = ctx->ActiveSources; + src_end = src + ctx->ActiveSourceCount; + while(src != src_end) + { + if((*src)->state != AL_PLAYING) + { + --(ctx->ActiveSourceCount); + *src = *(--src_end); + continue; + } + + if(!DeferUpdates && (ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) || + UpdateSources)) + ALsource_Update(*src, ctx); + + MixSource(*src, device, SamplesToDo); + src++; + } + + /* effect slot processing */ + slot = ctx->ActiveEffectSlots; + slot_end = slot + ctx->ActiveEffectSlotCount; + while(slot != slot_end) + { + ALfloat offset = (*slot)->ClickRemoval[0]; + if(offset < (1.0f/32768.0f)) + offset = 0.0f; + else for(i = 0;i < SamplesToDo;i++) + { + (*slot)->WetBuffer[0][i] += offset; + offset -= offset * (1.0f/256.0f); + } + (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0]; + (*slot)->PendingClicks[0] = 0.0f; + + if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE)) + ALeffectState_Update((*slot)->EffectState, device, *slot); + + ALeffectState_Process((*slot)->EffectState, SamplesToDo, + (*slot)->WetBuffer[0], device->DryBuffer); + + for(i = 0;i < SamplesToDo;i++) + (*slot)->WetBuffer[0][i] = 0.0f; + + slot++; + } + + ctx = ctx->next; + } + + slot = &device->DefaultSlot; + if(*slot != NULL) + { + ALfloat offset = (*slot)->ClickRemoval[0]; + if(offset < (1.0f/32768.0f)) + offset = 0.0f; + else for(i = 0;i < SamplesToDo;i++) + { + (*slot)->WetBuffer[0][i] += offset; + offset -= offset * (1.0f/256.0f); + } + (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0]; + (*slot)->PendingClicks[0] = 0.0f; + + if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE)) + ALeffectState_Update((*slot)->EffectState, device, *slot); + + ALeffectState_Process((*slot)->EffectState, SamplesToDo, + (*slot)->WetBuffer[0], device->DryBuffer); + + for(i = 0;i < SamplesToDo;i++) + (*slot)->WetBuffer[0][i] = 0.0f; + } + ALCdevice_Unlock(device); + + /* Click-removal. Could do better; this only really handles immediate + * changes between updates where a predictive sample could be + * generated. Delays caused by effects and HRTF aren't caught. */ + if(device->FmtChans == DevFmtMono) + { + ALfloat offset = device->ClickRemoval[FrontCenter]; + if(offset < (1.0f/32768.0f)) + offset = 0.0f; + else for(i = 0;i < SamplesToDo;i++) + { + device->DryBuffer[FrontCenter][i] += offset; + offset -= offset * (1.0f/256.0f); + } + device->ClickRemoval[FrontCenter] = offset + device->PendingClicks[FrontCenter]; + device->PendingClicks[FrontCenter] = 0.0f; + } + else if(device->FmtChans == DevFmtStereo) + { + /* Assumes the first two channels are FrontLeft and FrontRight */ + for(c = 0;c < 2;c++) + { + ALfloat offset = device->ClickRemoval[c]; + if(offset < (1.0f/32768.0f)) + offset = 0.0f; + else for(i = 0;i < SamplesToDo;i++) + { + device->DryBuffer[c][i] += offset; + offset -= offset * (1.0f/256.0f); + } + device->ClickRemoval[c] = offset + device->PendingClicks[c]; + device->PendingClicks[c] = 0.0f; + } + if(device->Bs2b) + { + float samples[2]; + for(i = 0;i < SamplesToDo;i++) + { + samples[0] = device->DryBuffer[FrontLeft][i]; + samples[1] = device->DryBuffer[FrontRight][i]; + bs2b_cross_feed(device->Bs2b, samples); + device->DryBuffer[FrontLeft][i] = samples[0]; + device->DryBuffer[FrontRight][i] = samples[1]; + } + } + } + else + { + for(c = 0;c < MaxChannels;c++) + { + ALfloat offset = device->ClickRemoval[c]; + if(offset < (1.0f/32768.0f)) + offset = 0.0f; + else for(i = 0;i < SamplesToDo;i++) + { + device->DryBuffer[c][i] += offset; + offset -= offset * (1.0f/256.0f); + } + device->ClickRemoval[c] = offset + device->PendingClicks[c]; + device->PendingClicks[c] = 0.0f; + } + } + + if(buffer) + { + int bytes = 0; + switch(device->FmtType) + { + case DevFmtByte: + bytes = Write_ALbyte(device, buffer, SamplesToDo); + break; + case DevFmtUByte: + bytes = Write_ALubyte(device, buffer, SamplesToDo); + break; + case DevFmtShort: + bytes = Write_ALshort(device, buffer, SamplesToDo); + break; + case DevFmtUShort: + bytes = Write_ALushort(device, buffer, SamplesToDo); + break; + case DevFmtInt: + bytes = Write_ALint(device, buffer, SamplesToDo); + break; + case DevFmtUInt: + bytes = Write_ALuint(device, buffer, SamplesToDo); + break; + case DevFmtFloat: + bytes = Write_ALfloat(device, buffer, SamplesToDo); + break; + } + + buffer = (ALubyte*)buffer + bytes; + } + + size -= SamplesToDo; + } + + RestoreFPUMode(&oldMode); +} + + +ALvoid aluHandleDisconnect(ALCdevice *device) +{ + ALCcontext *Context; + + device->Connected = ALC_FALSE; + + Context = device->ContextList; + while(Context) + { + ALsource **src, **src_end; + + src = Context->ActiveSources; + src_end = src + Context->ActiveSourceCount; + while(src != src_end) + { + if((*src)->state == AL_PLAYING) + { + (*src)->state = AL_STOPPED; + (*src)->BuffersPlayed = (*src)->BuffersInQueue; + (*src)->position = 0; + (*src)->position_fraction = 0; + } + src++; + } + Context->ActiveSourceCount = 0; + + Context = Context->next; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/alcConfig.c b/src/eepp/helper/android/openal-soft/Alc/alcConfig.c new file mode 100644 index 000000000..49a02b233 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/alcConfig.c @@ -0,0 +1,363 @@ +/** + * 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 __MINGW32__ +#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; + unsigned int entryCount; +} ConfigBlock; + +static ConfigBlock *cfgBlocks; +static unsigned int cfgCount; + +static char buffer[1024]; + +static void LoadConfigFromFile(FILE *f) +{ + ConfigBlock *curBlock = cfgBlocks; + ConfigEntry *ent; + + while(fgets(buffer, sizeof(buffer), f)) + { + int 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; + unsigned int i; + + i = 1; + while(buffer[i] && buffer[i] != ']') + i++; + + if(!buffer[i]) + { + ERR("config parse error: bad line \"%s\"\n", buffer); + continue; + } + buffer[i] = 0; + + do { + i++; + if(buffer[i] && !isspace(buffer[i])) + { + if(buffer[i] != '#') + WARN("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; + TRACE("found block '%s'\n", nextBlock->name); + break; + } + } + + if(!nextBlock) + { + nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock)); + if(!nextBlock) + { + ERR("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; + + TRACE("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) + { + ERR("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] != '=') + { + ERR("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((unsigned int)(ent-curBlock->entries) < curBlock->entryCount) + { + if(strcasecmp(ent->key, buffer) == 0) + break; + ent++; + } + + if((unsigned int)(ent-curBlock->entries) >= curBlock->entryCount) + { + /* Allocate a new option entry */ + ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry)); + if(!ent) + { + ERR("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(i >= 0 && isspace(buffer[i])); + buffer[++i] = 0; + + free(ent->value); + ent->value = strdup(buffer); + + TRACE("found '%s' = '%s'\n", ent->key, ent->value); + } +} + +void ReadALConfig(void) +{ + const char *str; + 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((str=getenv("HOME")) != NULL && *str) + { + snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str); + f = fopen(buffer, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } +#endif + if((str=getenv("ALSOFT_CONF")) != NULL && *str) + { + f = fopen(str, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } +} + +void FreeALConfig(void) +{ + unsigned int i; + + for(i = 0;i < cfgCount;i++) + { + unsigned int 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) +{ + unsigned int 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) + { + TRACE("Found %s:%s = \"%s\"\n", blockName, keyName, + cfgBlocks[i].entries[j].value); + if(cfgBlocks[i].entries[j].value[0]) + return cfgBlocks[i].entries[j].value; + return def; + } + } + } + + TRACE("Key %s:%s not found\n", blockName, keyName); + return def; +} + +int ConfigValueExists(const char *blockName, const char *keyName) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + return !!val[0]; +} + +int ConfigValueStr(const char *blockName, const char *keyName, const char **ret) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = val; + return 1; +} + +int ConfigValueInt(const char *blockName, const char *keyName, int *ret) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = strtol(val, NULL, 0); + return 1; +} + +int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = strtoul(val, NULL, 0); + return 1; +} + +int ConfigValueFloat(const char *blockName, const char *keyName, float *ret) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + if(!val[0]) return 0; + +#ifdef HAVE_STRTOF + *ret = strtof(val, NULL); +#else + *ret = (float)strtod(val, NULL); +#endif + return 1; +} + +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/src/eepp/helper/android/openal-soft/Alc/alcDedicated.c b/src/eepp/helper/android/openal-soft/Alc/alcDedicated.c new file mode 100644 index 000000000..1d2cbc420 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/alcDedicated.c @@ -0,0 +1,100 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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 "alFilter.h" +#include "alAuxEffectSlot.h" +#include "alError.h" +#include "alu.h" + + +typedef struct ALdedicatedState { + // Must be first in all effects! + ALeffectState state; + + ALfloat gains[MaxChannels]; +} ALdedicatedState; + + +static ALvoid DedicatedDestroy(ALeffectState *effect) +{ + ALdedicatedState *state = (ALdedicatedState*)effect; + free(state); +} + +static ALboolean DedicatedDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + (void)effect; + (void)Device; + return AL_TRUE; +} + +static ALvoid DedicatedUpdate(ALeffectState *effect, ALCdevice *device, const ALeffectslot *Slot) +{ + ALdedicatedState *state = (ALdedicatedState*)effect; + ALfloat Gain; + ALsizei s; + + Gain = Slot->Gain * Slot->effect.Dedicated.Gain; + for(s = 0;s < MaxChannels;s++) + state->gains[s] = 0.0f; + + if(Slot->effect.type == AL_EFFECT_DEDICATED_DIALOGUE) + ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains); + else if(Slot->effect.type == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + state->gains[LFE] = Gain; +} + +static ALvoid DedicatedProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + ALdedicatedState *state = (ALdedicatedState*)effect; + const ALfloat *gains = state->gains; + ALuint i, c; + + for(c = 0;c < MaxChannels;c++) + { + for(i = 0;i < SamplesToDo;i++) + SamplesOut[c][i] = SamplesIn[i] * gains[c]; + } +} + +ALeffectState *DedicatedCreate(void) +{ + ALdedicatedState *state; + ALsizei s; + + state = malloc(sizeof(*state)); + if(!state) + return NULL; + + state->state.Destroy = DedicatedDestroy; + state->state.DeviceUpdate = DedicatedDeviceUpdate; + state->state.Update = DedicatedUpdate; + state->state.Process = DedicatedProcess; + + for(s = 0;s < MaxChannels;s++) + state->gains[s] = 0.0f; + + return &state->state; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/alcEcho.c b/src/eepp/helper/android/openal-soft/Alc/alcEcho.c new file mode 100644 index 000000000..9ca91747a --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/alcEcho.c @@ -0,0 +1,184 @@ +/** + * 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; + + ALfloat *SampleBuffer; + ALuint BufferLength; + + // The echo is two tap. The delay is the number of samples from before the + // current offset + struct { + ALuint delay; + } Tap[2]; + ALuint Offset; + /* The panning gains for the two taps */ + ALfloat Gain[2][MaxChannels]; + + ALfloat FeedGain; + + FILTER iirFilter; + ALfloat history[2]; +} ALechoState; + +static ALvoid EchoDestroy(ALeffectState *effect) +{ + ALechoState *state = (ALechoState*)effect; + if(state) + { + free(state->SampleBuffer); + state->SampleBuffer = NULL; + free(state); + } +} + +static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALechoState *state = (ALechoState*)effect; + ALuint maxlen, i; + + // Use the next power of 2 for the buffer length, so the tap offsets can be + // wrapped using a mask instead of a modulo + maxlen = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1; + maxlen += fastf2u(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1; + maxlen = NextPowerOf2(maxlen); + + if(maxlen != state->BufferLength) + { + void *temp; + + temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat)); + if(!temp) + return AL_FALSE; + state->SampleBuffer = temp; + state->BufferLength = maxlen; + } + for(i = 0;i < state->BufferLength;i++) + state->SampleBuffer[i] = 0.0f; + + return AL_TRUE; +} + +static ALvoid EchoUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALechoState *state = (ALechoState*)effect; + ALuint frequency = Device->Frequency; + ALfloat lrpan, cw, g, gain; + ALfloat dirGain; + ALuint i; + + state->Tap[0].delay = fastf2u(Slot->effect.Echo.Delay * frequency) + 1; + state->Tap[1].delay = fastf2u(Slot->effect.Echo.LRDelay * frequency); + state->Tap[1].delay += state->Tap[0].delay; + + lrpan = Slot->effect.Echo.Spread; + + state->FeedGain = Slot->effect.Echo.Feedback; + + cw = cosf(F_PI*2.0f * LOWPASSFREQREF / frequency); + g = 1.0f - Slot->effect.Echo.Damping; + state->iirFilter.coeff = lpCoeffCalc(g, cw); + + gain = Slot->Gain; + for(i = 0;i < MaxChannels;i++) + { + state->Gain[0][i] = 0.0f; + state->Gain[1][i] = 0.0f; + } + + dirGain = fabsf(lrpan); + + /* First tap panning */ + ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]); + + /* Second tap panning */ + ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]); +} + +static ALvoid EchoProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + 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; + ALfloat smp; + ALuint i, k; + + for(i = 0;i < SamplesToDo;i++,offset++) + { + /* First tap */ + smp = state->SampleBuffer[(offset-tap1) & mask]; + for(k = 0;k < MaxChannels;k++) + SamplesOut[k][i] += smp * state->Gain[0][k]; + + /* Second tap */ + smp = state->SampleBuffer[(offset-tap2) & mask]; + for(k = 0;k < MaxChannels;k++) + SamplesOut[k][i] += smp * state->Gain[1][k]; + + // Apply damping and feedback gain to the second tap, and mix in the + // new sample + smp = lpFilter2P(&state->iirFilter, 0, smp+SamplesIn[i]); + state->SampleBuffer[offset&mask] = smp * state->FeedGain; + } + 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->iirFilter.coeff = 0.0f; + state->iirFilter.history[0] = 0.0f; + state->iirFilter.history[1] = 0.0f; + + return &state->state; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/alcModulator.c b/src/eepp/helper/android/openal-soft/Alc/alcModulator.c new file mode 100644 index 000000000..de0621511 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/alcModulator.c @@ -0,0 +1,204 @@ +/** + * 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; + + ALfloat Gain[MaxChannels]; + + FILTER iirFilter; + ALfloat history[1]; +} ALmodulatorState; + +#define WAVEFORM_FRACBITS 16 +#define WAVEFORM_FRACONE (1<>(WAVEFORM_FRACBITS-1))&1)*2.0f - 1.0f; +} + + +static __inline ALfloat hpFilter1P(FILTER *iir, ALuint offset, ALfloat input) +{ + ALfloat *history = &iir->history[offset]; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + history[0] = output; + + return input - output; +} + + +#define DECL_TEMPLATE(func) \ +static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ + const ALfloat *RESTRICT SamplesIn, \ + ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) \ +{ \ + const ALuint step = state->step; \ + ALuint index = state->index; \ + ALfloat samp; \ + ALuint i, k; \ + \ + for(i = 0;i < SamplesToDo;i++) \ + { \ + samp = SamplesIn[i]; \ + \ + index += step; \ + index &= WAVEFORM_FRACMASK; \ + samp *= func(index); \ + \ + samp = hpFilter1P(&state->iirFilter, 0, samp); \ + \ + for(k = 0;k < MaxChannels;k++) \ + SamplesOut[k][i] += state->Gain[k] * samp; \ + } \ + state->index = index; \ +} + +DECL_TEMPLATE(Sin) +DECL_TEMPLATE(Saw) +DECL_TEMPLATE(Square) + +#undef DECL_TEMPLATE + + +static ALvoid ModulatorDestroy(ALeffectState *effect) +{ + ALmodulatorState *state = (ALmodulatorState*)effect; + free(state); +} + +static ALboolean ModulatorDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + return AL_TRUE; + (void)effect; + (void)Device; +} + +static ALvoid ModulatorUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALmodulatorState *state = (ALmodulatorState*)effect; + ALfloat gain, cw, a = 0.0f; + ALuint index; + + if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) + state->Waveform = SINUSOID; + else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH) + state->Waveform = SAWTOOTH; + else if(Slot->effect.Modulator.Waveform == AL_RING_MODULATOR_SQUARE) + state->Waveform = SQUARE; + + state->step = fastf2u(Slot->effect.Modulator.Frequency*WAVEFORM_FRACONE / + Device->Frequency); + if(state->step == 0) state->step = 1; + + cw = cosf(F_PI*2.0f * Slot->effect.Modulator.HighPassCutoff / + Device->Frequency); + a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); + state->iirFilter.coeff = a; + + gain = sqrtf(1.0f/Device->NumChan); + gain *= Slot->Gain; + for(index = 0;index < MaxChannels;index++) + state->Gain[index] = 0.0f; + for(index = 0;index < Device->NumChan;index++) + { + enum Channel chan = Device->Speaker2Chan[index]; + state->Gain[chan] = gain; + } +} + +static ALvoid ModulatorProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + ALmodulatorState *state = (ALmodulatorState*)effect; + + switch(state->Waveform) + { + case SINUSOID: + ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut); + break; + + case SAWTOOTH: + ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut); + break; + + case SQUARE: + ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut); + break; + } +} + +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 = 0.0f; + state->iirFilter.history[0] = 0.0f; + + return &state->state; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/alcReverb.c b/src/eepp/helper/android/openal-soft/Alc/alcReverb.c new file mode 100644 index 000000000..b7dcdab91 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/alcReverb.c @@ -0,0 +1,1283 @@ +/** + * 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 "alMain.h" +#include "alu.h" +#include "alAuxEffectSlot.h" +#include "alEffect.h" +#include "alFilter.h" +#include "alError.h" + +typedef struct DelayLine +{ + // The delay lines use sample lengths that are powers of 2 to allow the + // use of bit-masking instead of a modulus for wrapping. + ALuint Mask; + ALfloat *Line; +} DelayLine; + +typedef struct ALverbState { + // Must be first in all effects! + ALeffectState state; + + // All delay lines are allocated as a single buffer to reduce memory + // fragmentation and management code. + ALfloat *SampleBuffer; + ALuint TotalSamples; + + // Master effect low-pass filter (2 chained 1-pole filters). + FILTER LpFilter; + ALfloat LpHistory[2]; + + struct { + // Modulator delay line. + DelayLine Delay; + + // The vibrato time is tracked with an index over a modulus-wrapped + // range (in samples). + ALuint Index; + ALuint Range; + + // The depth of frequency change (also in samples) and its filter. + ALfloat Depth; + ALfloat Coeff; + ALfloat Filter; + } Mod; + + // Initial effect delay. + DelayLine Delay; + // The tap points for the initial delay. First tap goes to early + // reflections, the last to late reverb. + ALuint DelayTap[2]; + + struct { + // Output gain for early reflections. + ALfloat Gain; + + // Early reflections are done with 4 delay lines. + ALfloat Coeff[4]; + DelayLine Delay[4]; + ALuint Offset[4]; + + // The gain for each output channel based on 3D panning (only for the + // EAX path). + ALfloat PanGain[MaxChannels]; + } Early; + + // Decorrelator delay line. + DelayLine Decorrelator; + // There are actually 4 decorrelator taps, but the first occurs at the + // initial sample. + ALuint DecoTap[3]; + + struct { + // Output gain for late reverb. + ALfloat Gain; + + // Attenuation to compensate for the modal density and decay rate of + // the late lines. + ALfloat DensityGain; + + // The feed-back and feed-forward all-pass coefficient. + ALfloat ApFeedCoeff; + + // Mixing matrix coefficient. + ALfloat MixCoeff; + + // Late reverb has 4 parallel all-pass filters. + ALfloat ApCoeff[4]; + DelayLine ApDelay[4]; + ALuint ApOffset[4]; + + // In addition to 4 cyclical delay lines. + ALfloat Coeff[4]; + DelayLine Delay[4]; + ALuint Offset[4]; + + // The cyclical delay lines are 1-pole low-pass filtered. + ALfloat LpCoeff[4]; + ALfloat LpSample[4]; + + // The gain for each output channel based on 3D panning (only for the + // EAX path). + ALfloat PanGain[MaxChannels]; + } Late; + + struct { + // Attenuation to compensate for the modal density and decay rate of + // the echo line. + ALfloat DensityGain; + + // Echo delay and all-pass lines. + DelayLine Delay; + DelayLine ApDelay; + + ALfloat Coeff; + ALfloat ApFeedCoeff; + ALfloat ApCoeff; + + ALuint Offset; + ALuint ApOffset; + + // The echo line is 1-pole low-pass filtered. + ALfloat LpCoeff; + ALfloat LpSample; + + // Echo mixing coefficients. + ALfloat MixCoeff[2]; + } Echo; + + // The current read offset for all delay lines. + ALuint Offset; + + // The gain for each output channel (non-EAX path only; aliased from + // Late.PanGain) + ALfloat *Gain; + + /* Temporary storage used when processing, before deinterlacing. */ + ALfloat ReverbSamples[BUFFERSIZE][4]; + ALfloat EarlySamples[BUFFERSIZE][4]; +} ALverbState; + +/* This is a user config option for modifying the overall output of the reverb + * effect. + */ +ALfloat ReverbBoost = 1.0f; + +/* Specifies whether to use a standard reverb effect in place of EAX reverb */ +ALboolean EmulateEAXReverb = AL_FALSE; + +/* This coefficient is used to define the maximum frequency range controlled + * by the modulation depth. The current value of 0.1 will allow it to swing + * from 0.9x to 1.1x. This value must be below 1. At 1 it will cause the + * sampler to stall on the downswing, and above 1 it will cause it to sample + * backwards. + */ +static const ALfloat MODULATION_DEPTH_COEFF = 0.1f; + +/* A filter is used to avoid the terrible distortion caused by changing + * modulation time and/or depth. To be consistent across different sample + * rates, the coefficient must be raised to a constant divided by the sample + * rate: coeff^(constant / rate). + */ +static const ALfloat MODULATION_FILTER_COEFF = 0.048f; +static const ALfloat MODULATION_FILTER_CONST = 100000.0f; + +// When diffusion is above 0, an all-pass filter is used to take the edge off +// the echo effect. It uses the following line length (in seconds). +static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f; + +// Input into the late reverb is decorrelated between four channels. Their +// timings are dependent on a fraction and multiplier. See the +// UpdateDecorrelator() routine for the calculations involved. +static const ALfloat DECO_FRACTION = 0.15f; +static const ALfloat DECO_MULTIPLIER = 2.0f; + +// All delay line lengths are specified in seconds. + +// The lengths of the early delay lines. +static const ALfloat EARLY_LINE_LENGTH[4] = +{ + 0.0015f, 0.0045f, 0.0135f, 0.0405f +}; + +// The lengths of the late all-pass delay lines. +static const ALfloat ALLPASS_LINE_LENGTH[4] = +{ + 0.0151f, 0.0167f, 0.0183f, 0.0200f, +}; + +// The lengths of the late cyclical delay lines. +static const ALfloat LATE_LINE_LENGTH[4] = +{ + 0.0211f, 0.0311f, 0.0461f, 0.0680f +}; + +// The late cyclical delay lines have a variable length dependent on the +// effect's density parameter (inverted for some reason) and this multiplier. +static const ALfloat LATE_LINE_MULTIPLIER = 4.0f; + + +// Basic delay line input/output routines. +static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset) +{ + return Delay->Line[offset&Delay->Mask]; +} + +static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) +{ + Delay->Line[offset&Delay->Mask] = in; +} + +// Attenuated delay line output routine. +static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff) +{ + return coeff * Delay->Line[offset&Delay->Mask]; +} + +// Basic attenuated all-pass input/output routine. +static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff) +{ + ALfloat out, feed; + + out = DelayLineOut(Delay, outOffset); + feed = feedCoeff * in; + DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in); + + // The time-based attenuation is only applied to the delay output to + // keep it from affecting the feed-back path (which is already controlled + // by the all-pass feed coefficient). + return (coeff * out) - feed; +} + +// Given an input sample, this function produces modulation for the late +// reverb. +static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in) +{ + ALfloat sinus, frac; + ALuint offset; + ALfloat out0, out1; + + // Calculate the sinus rythm (dependent on modulation time and the + // sampling rate). The center of the sinus is moved to reduce the delay + // of the effect when the time or depth are low. + sinus = 1.0f - cosf(F_PI*2.0f * State->Mod.Index / State->Mod.Range); + + // The depth determines the range over which to read the input samples + // from, so it must be filtered to reduce the distortion caused by even + // small parameter changes. + State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, + State->Mod.Coeff); + + // Calculate the read offset and fraction between it and the next sample. + frac = (1.0f + (State->Mod.Filter * sinus)); + offset = fastf2u(frac); + frac -= offset; + + // Get the two samples crossed by the offset, and feed the delay line + // with the next input sample. + out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset); + out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1); + DelayLineIn(&State->Mod.Delay, State->Offset, in); + + // Step the modulation index forward, keeping it bound to its range. + State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; + + // The output is obtained by linearly interpolating the two samples that + // were acquired above. + return lerp(out0, out1, frac); +} + +// Delay line output routine for early reflections. +static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index) +{ + return AttenuatedDelayLineOut(&State->Early.Delay[index], + State->Offset - State->Early.Offset[index], + State->Early.Coeff[index]); +} + +// Given an input sample, this function produces four-channel output for the +// early reflections. +static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *RESTRICT out) +{ + ALfloat d[4], v, f[4]; + + // Obtain the decayed results of each early delay line. + d[0] = EarlyDelayLineOut(State, 0); + d[1] = EarlyDelayLineOut(State, 1); + d[2] = EarlyDelayLineOut(State, 2); + d[3] = EarlyDelayLineOut(State, 3); + + /* The following uses a lossless scattering junction from waveguide + * theory. It actually amounts to a householder mixing matrix, which + * will produce a maximally diffuse response, and means this can probably + * be considered a simple feed-back delay network (FDN). + * N + * --- + * \ + * v = 2/N / d_i + * --- + * i=1 + */ + v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; + // The junction is loaded with the input here. + v += in; + + // Calculate the feed values for the delay lines. + f[0] = v - d[0]; + f[1] = v - d[1]; + f[2] = v - d[2]; + f[3] = v - d[3]; + + // Re-feed the delay lines. + DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]); + DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]); + DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]); + DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]); + + // Output the results of the junction for all four channels. + out[0] = State->Early.Gain * f[0]; + out[1] = State->Early.Gain * f[1]; + out[2] = State->Early.Gain * f[2]; + out[3] = State->Early.Gain * f[3]; +} + +// All-pass input/output routine for late reverb. +static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in) +{ + return AllpassInOut(&State->Late.ApDelay[index], + State->Offset - State->Late.ApOffset[index], + State->Offset, in, State->Late.ApFeedCoeff, + State->Late.ApCoeff[index]); +} + +// Delay line output routine for late reverb. +static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index) +{ + return AttenuatedDelayLineOut(&State->Late.Delay[index], + State->Offset - State->Late.Offset[index], + State->Late.Coeff[index]); +} + +// Low-pass filter input/output routine for late reverb. +static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in) +{ + in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]); + State->Late.LpSample[index] = in; + return in; +} + +// Given four decorrelated input samples, this function produces four-channel +// output for the late reverb. +static __inline ALvoid LateReverb(ALverbState *State, const ALfloat *RESTRICT in, ALfloat *RESTRICT out) +{ + ALfloat d[4], f[4]; + + // Obtain the decayed results of the cyclical delay lines, and add the + // corresponding input channels. Then pass the results through the + // low-pass filters. + + // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back + // to 0. + d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2)); + d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0)); + d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3)); + d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1)); + + // To help increase diffusion, run each line through an all-pass filter. + // When there is no diffusion, the shortest all-pass filter will feed the + // shortest delay line. + d[0] = LateAllPassInOut(State, 0, d[0]); + d[1] = LateAllPassInOut(State, 1, d[1]); + d[2] = LateAllPassInOut(State, 2, d[2]); + d[3] = LateAllPassInOut(State, 3, d[3]); + + /* Late reverb is done with a modified feed-back delay network (FDN) + * topology. Four input lines are each fed through their own all-pass + * filter and then into the mixing matrix. The four outputs of the + * mixing matrix are then cycled back to the inputs. Each output feeds + * a different input to form a circlular feed cycle. + * + * The mixing matrix used is a 4D skew-symmetric rotation matrix derived + * using a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y + * with differing signs, and d is the coefficient x. The matrix is thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * To reduce the number of multiplies, the x coefficient is applied with + * the cyclical delay line coefficients. Thus only the y coefficient is + * applied when mixing, and is modified to be: y / x. + */ + f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); + f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); + f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); + f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); + + // Output the results of the matrix for all four channels, attenuated by + // the late reverb gain (which is attenuated by the 'x' mix coefficient). + out[0] = State->Late.Gain * f[0]; + out[1] = State->Late.Gain * f[1]; + out[2] = State->Late.Gain * f[2]; + out[3] = State->Late.Gain * f[3]; + + // Re-feed the cyclical delay lines. + DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]); + DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]); + DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]); + DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]); +} + +// Given an input sample, this function mixes echo into the four-channel late +// reverb. +static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *RESTRICT late) +{ + ALfloat out, feed; + + // Get the latest attenuated echo sample for output. + feed = AttenuatedDelayLineOut(&State->Echo.Delay, + State->Offset - State->Echo.Offset, + State->Echo.Coeff); + + // Mix the output into the late reverb channels. + out = State->Echo.MixCoeff[0] * feed; + late[0] = (State->Echo.MixCoeff[1] * late[0]) + out; + late[1] = (State->Echo.MixCoeff[1] * late[1]) + out; + late[2] = (State->Echo.MixCoeff[1] * late[2]) + out; + late[3] = (State->Echo.MixCoeff[1] * late[3]) + out; + + // Mix the energy-attenuated input with the output and pass it through + // the echo low-pass filter. + feed += State->Echo.DensityGain * in; + feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff); + State->Echo.LpSample = feed; + + // Then the echo all-pass filter. + feed = AllpassInOut(&State->Echo.ApDelay, + State->Offset - State->Echo.ApOffset, + State->Offset, feed, State->Echo.ApFeedCoeff, + State->Echo.ApCoeff); + + // Feed the delay with the mixed and filtered sample. + DelayLineIn(&State->Echo.Delay, State->Offset, feed); +} + +// Perform the non-EAX reverb pass on a given input sample, resulting in +// four-channel output. +static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *RESTRICT out) +{ + ALfloat feed, late[4], 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, out); + + // Feed the decorrelator from the energy-attenuated output of the second + // delay tap. + in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]); + feed = in * State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, State->Offset, feed); + + // Calculate the late reverb from the decorrelator taps. + taps[0] = feed; + taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]); + taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]); + taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]); + LateReverb(State, taps, late); + + // Mix early reflections and late reverb. + out[0] += late[0]; + out[1] += late[1]; + out[2] += late[2]; + out[3] += late[3]; + + // Step all delays forward one sample. + State->Offset++; +} + +// Perform the EAX reverb pass on a given input sample, resulting in four- +// channel output. +static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *RESTRICT early, ALfloat *RESTRICT late) +{ + ALfloat feed, taps[4]; + + // Low-pass filter the incoming sample. + in = lpFilter2P(&State->LpFilter, 0, in); + + // Perform any modulation on the input. + in = EAXModulation(State, in); + + // Feed the initial delay line. + DelayLineIn(&State->Delay, State->Offset, in); + + // Calculate the early reflection from the first delay tap. + in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]); + EarlyReflection(State, in, early); + + // Feed the decorrelator from the energy-attenuated output of the second + // delay tap. + in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]); + feed = in * State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, State->Offset, feed); + + // Calculate the late reverb from the decorrelator taps. + taps[0] = feed; + taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]); + taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]); + taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]); + LateReverb(State, taps, late); + + // Calculate and mix in any echo. + EAXEcho(State, in, late); + + // Step all delays forward one sample. + State->Offset++; +} + +// This processes the reverb state, given the input samples and an output +// buffer. +static ALvoid VerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + ALverbState *State = (ALverbState*)effect; + ALfloat (*RESTRICT out)[4] = State->ReverbSamples; + ALuint index, c; + + /* Process reverb for these samples. */ + for(index = 0;index < SamplesToDo;index++) + VerbPass(State, SamplesIn[index], out[index]); + + for(c = 0;c < MaxChannels;c++) + { + ALfloat gain = State->Gain[c]; + if(gain > 0.00001f) + { + for(index = 0;index < SamplesToDo;index++) + SamplesOut[c][index] += gain * out[index][c&3]; + } + } +} + +// This processes the EAX reverb state, given the input samples and an output +// buffer. +static ALvoid EAXVerbProcess(ALeffectState *effect, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + ALverbState *State = (ALverbState*)effect; + ALfloat (*RESTRICT early)[4] = State->EarlySamples; + ALfloat (*RESTRICT late)[4] = State->ReverbSamples; + ALuint index, c; + + /* Process reverb for these samples. */ + for(index = 0;index < SamplesToDo;index++) + EAXVerbPass(State, SamplesIn[index], early[index], late[index]); + + for(c = 0;c < MaxChannels;c++) + { + ALfloat earlyGain = State->Early.PanGain[c]; + ALfloat lateGain = State->Late.PanGain[c]; + + if(earlyGain > 0.00001f) + { + for(index = 0;index < SamplesToDo;index++) + SamplesOut[c][index] += earlyGain*early[index][c&3]; + } + if(lateGain > 0.00001f) + { + for(index = 0;index < SamplesToDo;index++) + SamplesOut[c][index] += lateGain*late[index][c&3]; + } + } +} + + +// Given the allocated sample buffer, this function updates each delay line +// offset. +static __inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay) +{ + Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line]; +} + +// Calculate the length of a delay line and store its mask and offset. +static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay) +{ + ALuint samples; + + // All line lengths are powers of 2, calculated from their lengths, with + // an additional sample in case of rounding errors. + samples = NextPowerOf2(fastf2u(length * frequency) + 1); + // All lines share a single sample buffer. + Delay->Mask = samples - 1; + Delay->Line = (ALfloat*)offset; + // Return the sample count for accumulation. + return samples; +} + +/* Calculates the delay line metrics and allocates the shared sample buffer + * for all lines given the sample rate (frequency). If an allocation failure + * occurs, it returns AL_FALSE. + */ +static ALboolean AllocLines(ALuint frequency, ALverbState *State) +{ + ALuint totalSamples, index; + ALfloat length; + ALfloat *newBuffer = NULL; + + // All delay line lengths are calculated to accomodate the full range of + // lengths given their respective paramters. + totalSamples = 0; + + /* The modulator's line length is calculated from the maximum modulation + * time and depth coefficient, and halfed for the low-to-high frequency + * swing. An additional sample is added to keep it stable when there is no + * modulation. + */ + length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f) + + (1.0f / frequency); + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Mod.Delay); + + // The initial delay is the sum of the reflections and late reverb + // delays. + length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + + AL_EAXREVERB_MAX_LATE_REVERB_DELAY; + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Delay); + + // The early reflection lines. + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, + frequency, &State->Early.Delay[index]); + + // The decorrelator line is calculated from the lowest reverb density (a + // parameter value of 1). + length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * + LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Decorrelator); + + // The late all-pass lines. + for(index = 0;index < 4;index++) + totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, + frequency, &State->Late.ApDelay[index]); + + // The late delay lines are calculated from the lowest reverb density. + for(index = 0;index < 4;index++) + { + length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER); + totalSamples += CalcLineLength(length, totalSamples, frequency, + &State->Late.Delay[index]); + } + + // The echo all-pass and delay lines. + totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, + frequency, &State->Echo.ApDelay); + totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, + frequency, &State->Echo.Delay); + + if(totalSamples != State->TotalSamples) + { + TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); + newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples); + if(newBuffer == NULL) + return AL_FALSE; + State->SampleBuffer = newBuffer; + State->TotalSamples = totalSamples; + } + + // Update all delays to reflect the new sample buffer. + RealizeLineOffset(State->SampleBuffer, &State->Delay); + RealizeLineOffset(State->SampleBuffer, &State->Decorrelator); + for(index = 0;index < 4;index++) + { + RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]); + RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); + } + RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay); + RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay); + RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay); + + // Clear the sample buffer. + for(index = 0;index < State->TotalSamples;index++) + State->SampleBuffer[index] = 0.0f; + + return AL_TRUE; +} + +// 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 ReverbDeviceUpdate(ALeffectState *effect, ALCdevice *Device) +{ + ALverbState *State = (ALverbState*)effect; + ALuint frequency = Device->Frequency, index; + + // Allocate the delay lines. + if(!AllocLines(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 = powf(MODULATION_FILTER_COEFF, + MODULATION_FILTER_CONST / frequency); + + // The early reflection and late all-pass filter line lengths are static, + // so their offsets only need to be calculated once. + for(index = 0;index < 4;index++) + { + State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * + frequency); + State->Late.ApOffset[index] = fastf2u(ALLPASS_LINE_LENGTH[index] * + frequency); + } + + // The echo all-pass filter line length is static, so its offset only + // needs to be calculated once. + State->Echo.ApOffset = fastf2u(ECHO_ALLPASS_LENGTH * frequency); + + return AL_TRUE; +} + +// Calculate a decay coefficient given the length of each cycle and the time +// until the decay reaches -60 dB. +static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime) +{ + return powf(0.001f/*-60 dB*/, length/decayTime); +} + +// Calculate a decay length from a coefficient and the time until the decay +// reaches -60 dB. +static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime) +{ + return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/; +} + +// Calculate the high frequency parameter for the I3DL2 coefficient +// calculation. +static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency) +{ + return cosf(F_PI*2.0f * hfRef / frequency); +} + +// Calculate an attenuation to be applied to the input of any echo models to +// compensate for modal density and decay time. +static __inline ALfloat CalcDensityGain(ALfloat a) +{ + /* The energy of a signal can be obtained by finding the area under the + * squared signal. This takes the form of Sum(x_n^2), where x is the + * amplitude for the sample n. + * + * Decaying feedback matches exponential decay of the form Sum(a^n), + * where a is the attenuation coefficient, and n is the sample. The area + * under this decay curve can be calculated as: 1 / (1 - a). + * + * Modifying the above equation to find the squared area under the curve + * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be + * calculated by inverting the square root of this approximation, + * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). + */ + return sqrtf(1.0f - (a * a)); +} + +// Calculate the mixing matrix coefficients given a diffusion factor. +static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y) +{ + ALfloat n, t; + + // The matrix is of order 4, so n is sqrt (4 - 1). + n = sqrtf(3.0f); + t = diffusion * atanf(n); + + // Calculate the first mixing matrix coefficient. + *x = cosf(t); + // Calculate the second mixing matrix coefficient. + *y = sinf(t) / n; +} + +// Calculate the limited HF ratio for use with the late reverb low-pass +// filters. +static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime) +{ + ALfloat limitRatio; + + /* Find the attenuation due to air absorption in dB (converting delay + * time to meters using the speed of sound). Then reversing the decay + * equation, solve for HF ratio. The delay length is cancelled out of + * the equation, so it can be calculated once for all lines. + */ + limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * + SPEEDOFSOUNDMETRESPERSEC); + /* Using the limit calculated above, apply the upper bound to the HF + * ratio. Also need to limit the result to a minimum of 0.1, just like the + * HF ratio parameter. */ + return clampf(limitRatio, 0.1f, hfRatio); +} + +// Calculate the coefficient for a HF (and eventually LF) decay damping +// filter. +static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw) +{ + ALfloat coeff, g; + + // Eventually this should boost the high frequencies when the ratio + // exceeds 1. + coeff = 0.0f; + if (hfRatio < 1.0f) + { + // Calculate the low-pass coefficient by dividing the HF decay + // coefficient by the full decay coefficient. + g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff; + + // Damping is done with a 1-pole filter, so g needs to be squared. + g *= g; + coeff = lpCoeffCalc(g, cw); + + // Very low decay times will produce minimal output, so apply an + // upper bound to the coefficient. + coeff = minf(coeff, 0.98f); + } + return coeff; +} + +// Update the EAX modulation index, range, and depth. Keep in mind that this +// kind of vibrato is additive and not multiplicative as one may expect. The +// downswing will sound stronger than the upswing. +static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State) +{ + ALuint range; + + /* 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). + */ + range = maxu(fastf2u(modTime*frequency), 1); + State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range / + State->Mod.Range); + State->Mod.Range = range; + + /* The modulation depth effects the amount of frequency change over the + * range of the sinus. It needs to be scaled by the modulation time so + * that a given depth produces a consistent change in frequency over all + * ranges of time. Since the depth is applied to a sinus value, it needs + * to be halfed once for the sinus range and again for the sinus swing + * in time (half of it is spent decreasing the frequency, half is spent + * increasing it). + */ + State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f / + 2.0f * frequency; +} + +// Update the offsets for the initial effect delay line. +static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State) +{ + // Calculate the initial delay taps. + State->DelayTap[0] = fastf2u(earlyDelay * frequency); + State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); +} + +// Update the early reflections gain and line coefficients. +static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State) +{ + ALuint index; + + // Calculate the early reflections gain (from the master effect gain, and + // reflections gain parameters) with a constant attenuation of 0.5. + State->Early.Gain = 0.5f * reverbGain * earlyGain; + + // Calculate the gain (coefficient) for each early delay line using the + // late delay time. This expands the early reflections to the start of + // the late reverb. + for(index = 0;index < 4;index++) + State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index], + lateDelay); +} + +// Update the offsets for the decorrelator line. +static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State) +{ + ALuint index; + ALfloat length; + + /* The late reverb inputs are decorrelated to smooth the reverb tail and + * reduce harsh echos. The first tap occurs immediately, while the + * remaining taps are delayed by multiples of a fraction of the smallest + * cyclical delay time. + * + * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay + */ + for(index = 0;index < 3;index++) + { + length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * + LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); + State->DecoTap[index] = fastf2u(length * frequency); + } +} + +// Update the late reverb gains, line lengths, and line coefficients. +static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State) +{ + ALfloat length; + ALuint index; + + /* Calculate the late reverb gain (from the master effect gain, and late + * reverb gain parameters). Since the output is tapped prior to the + * application of the next delay line coefficients, this gain needs to be + * attenuated by the 'x' mixing matrix coefficient as well. + */ + State->Late.Gain = reverbGain * lateGain * xMix; + + /* To compensate for changes in modal density and decay time of the late + * reverb signal, the input is attenuated based on the maximal energy of + * the outgoing signal. This approximation is used to keep the apparent + * energy of the signal equal for all ranges of density and decay time. + * + * The average length of the cyclcical delay lines is used to calculate + * the attenuation coefficient. + */ + length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + + LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; + length *= 1.0f + (density * LATE_LINE_MULTIPLIER); + State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length, + decayTime)); + + // Calculate the all-pass feed-back and feed-forward coefficient. + State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); + + for(index = 0;index < 4;index++) + { + // Calculate the gain (coefficient) for each all-pass line. + State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index], + decayTime); + + // Calculate the length (in seconds) of each cyclical delay line. + length = LATE_LINE_LENGTH[index] * (1.0f + (density * + LATE_LINE_MULTIPLIER)); + + // Calculate the delay offset for each cyclical delay line. + State->Late.Offset[index] = fastf2u(length * frequency); + + // Calculate the gain (coefficient) for each cyclical line. + State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); + + // Calculate the damping coefficient for each low-pass filter. + State->Late.LpCoeff[index] = + CalcDampingCoeff(hfRatio, length, decayTime, + State->Late.Coeff[index], cw); + + // Attenuate the cyclical line coefficients by the mixing coefficient + // (x). + State->Late.Coeff[index] *= xMix; + } +} + +// Update the echo gain, line offset, line coefficients, and mixing +// coefficients. +static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State) +{ + // Update the offset and coefficient for the echo delay line. + State->Echo.Offset = fastf2u(echoTime * frequency); + + // Calculate the decay coefficient for the echo line. + State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime); + + // Calculate the energy-based attenuation coefficient for the echo delay + // line. + State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff); + + // Calculate the echo all-pass feed coefficient. + State->Echo.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); + + // Calculate the echo all-pass attenuation coefficient. + State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime); + + // Calculate the damping coefficient for each low-pass filter. + State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, + State->Echo.Coeff, cw); + + /* Calculate the echo mixing coefficients. The first is applied to the + * echo itself. The second is used to attenuate the late reverb when + * echo depth is high and diffusion is low, so the echo is slightly + * stronger than the decorrelated echos in the reverb tail. + */ + State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth; + State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion)); +} + +// Update the early and late 3D panning gains. +static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALverbState *State) +{ + ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1], + ReflectionsPan[2] }; + ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1], + LateReverbPan[2] }; + ALfloat ambientGain; + ALfloat dirGain; + ALfloat length; + ALuint index; + + Gain *= ReverbBoost; + + /* Attenuate reverb according to its coverage (dirGain=0 will give + * Gain*ambientGain, and dirGain=1 will give Gain). */ + ambientGain = minf(sqrtf(2.0f/Device->NumChan), 1.0f); + + length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2]; + if(length > 1.0f) + { + length = 1.0f / sqrtf(length); + earlyPan[0] *= length; + earlyPan[1] *= length; + earlyPan[2] *= length; + } + length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2]; + if(length > 1.0f) + { + length = 1.0f / sqrtf(length); + latePan[0] *= length; + latePan[1] *= length; + latePan[2] *= length; + } + + dirGain = sqrtf(earlyPan[0]*earlyPan[0] + earlyPan[2]*earlyPan[2]); + for(index = 0;index < MaxChannels;index++) + State->Early.PanGain[index] = 0.0f; + ComputeAngleGains(Device, atan2f(earlyPan[0], earlyPan[2]), (1.0f-dirGain)*F_PI, + lerp(ambientGain, 1.0f, dirGain) * Gain, State->Early.PanGain); + + dirGain = sqrtf(latePan[0]*latePan[0] + latePan[2]*latePan[2]); + for(index = 0;index < MaxChannels;index++) + State->Late.PanGain[index] = 0.0f; + ComputeAngleGains(Device, atan2f(latePan[0], latePan[2]), (1.0f-dirGain)*F_PI, + lerp(ambientGain, 1.0f, dirGain) * Gain, State->Late.PanGain); +} + +// This updates the EAX reverb state. This is called any time the EAX reverb +// effect is loaded into a slot. +static ALvoid ReverbUpdate(ALeffectState *effect, ALCdevice *Device, const ALeffectslot *Slot) +{ + ALverbState *State = (ALverbState*)effect; + ALuint frequency = Device->Frequency; + ALboolean isEAX = AL_FALSE; + ALfloat cw, x, y, hfRatio; + + if(Slot->effect.type == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) + { + State->state.Process = EAXVerbProcess; + isEAX = AL_TRUE; + } + else if(Slot->effect.type == AL_EFFECT_REVERB || EmulateEAXReverb) + { + State->state.Process = VerbProcess; + isEAX = AL_FALSE; + } + + // Calculate the master low-pass filter (from the master effect HF gain). + if(isEAX) cw = CalcI3DL2HFreq(Slot->effect.Reverb.HFReference, frequency); + else cw = CalcI3DL2HFreq(LOWPASSFREQREF, frequency); + // This is done with 2 chained 1-pole filters, so no need to square g. + State->LpFilter.coeff = lpCoeffCalc(Slot->effect.Reverb.GainHF, cw); + + if(isEAX) + { + // Update the modulator line. + UpdateModulator(Slot->effect.Reverb.ModulationTime, + Slot->effect.Reverb.ModulationDepth, + frequency, State); + } + + // Update the initial effect delay. + UpdateDelayLine(Slot->effect.Reverb.ReflectionsDelay, + Slot->effect.Reverb.LateReverbDelay, + frequency, State); + + // Update the early lines. + UpdateEarlyLines(Slot->effect.Reverb.Gain, + Slot->effect.Reverb.ReflectionsGain, + Slot->effect.Reverb.LateReverbDelay, State); + + // Update the decorrelator. + UpdateDecorrelator(Slot->effect.Reverb.Density, frequency, State); + + // Get the mixing matrix coefficients (x and y). + CalcMatrixCoeffs(Slot->effect.Reverb.Diffusion, &x, &y); + // Then divide x into y to simplify the matrix calculation. + State->Late.MixCoeff = y / x; + + // If the HF limit parameter is flagged, calculate an appropriate limit + // based on the air absorption parameter. + hfRatio = Slot->effect.Reverb.DecayHFRatio; + if(Slot->effect.Reverb.DecayHFLimit && + Slot->effect.Reverb.AirAbsorptionGainHF < 1.0f) + hfRatio = CalcLimitedHfRatio(hfRatio, + Slot->effect.Reverb.AirAbsorptionGainHF, + Slot->effect.Reverb.DecayTime); + + // Update the late lines. + UpdateLateLines(Slot->effect.Reverb.Gain, Slot->effect.Reverb.LateReverbGain, + x, Slot->effect.Reverb.Density, Slot->effect.Reverb.DecayTime, + Slot->effect.Reverb.Diffusion, hfRatio, cw, frequency, State); + + if(isEAX) + { + // Update the echo line. + UpdateEchoLine(Slot->effect.Reverb.Gain, Slot->effect.Reverb.LateReverbGain, + Slot->effect.Reverb.EchoTime, Slot->effect.Reverb.DecayTime, + Slot->effect.Reverb.Diffusion, Slot->effect.Reverb.EchoDepth, + hfRatio, cw, frequency, State); + + // Update early and late 3D panning. + Update3DPanning(Device, Slot->effect.Reverb.ReflectionsPan, + Slot->effect.Reverb.LateReverbPan, Slot->Gain, State); + } + else + { + ALfloat gain = Slot->Gain; + ALuint index; + + /* Update channel gains */ + gain *= sqrtf(2.0f/Device->NumChan) * ReverbBoost; + for(index = 0;index < MaxChannels;index++) + State->Gain[index] = 0.0f; + for(index = 0;index < Device->NumChan;index++) + { + enum Channel chan = Device->Speaker2Chan[index]; + State->Gain[chan] = gain; + } + } +} + +// 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 ReverbDestroy(ALeffectState *effect) +{ + ALverbState *State = (ALverbState*)effect; + if(State) + { + free(State->SampleBuffer); + State->SampleBuffer = NULL; + free(State); + } +} + +// 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 *ReverbCreate(void) +{ + ALverbState *State = NULL; + ALuint index; + + State = malloc(sizeof(ALverbState)); + if(!State) + return NULL; + + State->state.Destroy = ReverbDestroy; + State->state.DeviceUpdate = ReverbDeviceUpdate; + State->state.Update = ReverbUpdate; + State->state.Process = VerbProcess; + + State->TotalSamples = 0; + State->SampleBuffer = NULL; + + State->LpFilter.coeff = 0.0f; + State->LpFilter.history[0] = 0.0f; + State->LpFilter.history[1] = 0.0f; + + State->Mod.Delay.Mask = 0; + State->Mod.Delay.Line = NULL; + State->Mod.Index = 0; + State->Mod.Range = 1; + State->Mod.Depth = 0.0f; + State->Mod.Coeff = 0.0f; + State->Mod.Filter = 0.0f; + + State->Delay.Mask = 0; + State->Delay.Line = NULL; + State->DelayTap[0] = 0; + State->DelayTap[1] = 0; + + State->Early.Gain = 0.0f; + for(index = 0;index < 4;index++) + { + State->Early.Coeff[index] = 0.0f; + State->Early.Delay[index].Mask = 0; + State->Early.Delay[index].Line = NULL; + State->Early.Offset[index] = 0; + } + + State->Decorrelator.Mask = 0; + State->Decorrelator.Line = NULL; + State->DecoTap[0] = 0; + State->DecoTap[1] = 0; + State->DecoTap[2] = 0; + + State->Late.Gain = 0.0f; + State->Late.DensityGain = 0.0f; + State->Late.ApFeedCoeff = 0.0f; + State->Late.MixCoeff = 0.0f; + for(index = 0;index < 4;index++) + { + State->Late.ApCoeff[index] = 0.0f; + State->Late.ApDelay[index].Mask = 0; + State->Late.ApDelay[index].Line = NULL; + State->Late.ApOffset[index] = 0; + + State->Late.Coeff[index] = 0.0f; + State->Late.Delay[index].Mask = 0; + State->Late.Delay[index].Line = NULL; + State->Late.Offset[index] = 0; + + State->Late.LpCoeff[index] = 0.0f; + State->Late.LpSample[index] = 0.0f; + } + + for(index = 0;index < MaxChannels;index++) + { + State->Early.PanGain[index] = 0.0f; + State->Late.PanGain[index] = 0.0f; + } + + State->Echo.DensityGain = 0.0f; + State->Echo.Delay.Mask = 0; + State->Echo.Delay.Line = NULL; + State->Echo.ApDelay.Mask = 0; + State->Echo.ApDelay.Line = NULL; + State->Echo.Coeff = 0.0f; + State->Echo.ApFeedCoeff = 0.0f; + State->Echo.ApCoeff = 0.0f; + State->Echo.Offset = 0; + State->Echo.ApOffset = 0; + State->Echo.LpCoeff = 0.0f; + State->Echo.LpSample = 0.0f; + State->Echo.MixCoeff[0] = 0.0f; + State->Echo.MixCoeff[1] = 0.0f; + + State->Offset = 0; + + State->Gain = State->Late.PanGain; + + return &State->state; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/alcRing.c b/src/eepp/helper/android/openal-soft/Alc/alcRing.c new file mode 100644 index 000000000..2d9d50694 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/alcRing.c @@ -0,0 +1,127 @@ +/** + * 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) + ((length+1) * frame_size)); + if(ring) + { + ring->mem = (ALubyte*)(ring+1); + + ring->frame_size = frame_size; + ring->length = length+1; + ring->read_pos = 0; + ring->write_pos = 0; + + InitializeCriticalSection(&ring->cs); + } + return ring; +} + +void DestroyRingBuffer(RingBuffer *ring) +{ + if(ring) + { + DeleteCriticalSection(&ring->cs); + free(ring); + } +} + +ALsizei RingBufferSize(RingBuffer *ring) +{ + ALsizei s; + + EnterCriticalSection(&ring->cs); + s = (ring->write_pos-ring->read_pos+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-1+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/src/eepp/helper/android/openal-soft/Alc/alcThread.c b/src/eepp/helper/android/openal-soft/Alc/alcThread.c new file mode 100644 index 000000000..c2f38031e --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/alcThread.c @@ -0,0 +1,144 @@ +/** + * 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" + +#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */ + +#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, THREAD_STACK_SIZE, 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) +{ + pthread_attr_t attr; + ThreadInfo *inf = malloc(sizeof(ThreadInfo)); + if(!inf) return NULL; + + if(pthread_attr_init(&attr) != 0) + { + free(inf); + return NULL; + } + if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE) != 0) + { + pthread_attr_destroy(&attr); + free(inf); + return NULL; + } + + inf->func = func; + inf->ptr = ptr; + if(pthread_create(&inf->thread, &attr, StarterFunc, inf) != 0) + { + pthread_attr_destroy(&attr); + free(inf); + return NULL; + } + pthread_attr_destroy(&attr); + + 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/src/eepp/helper/android/openal-soft/Alc/backends/alsa.c b/src/eepp/helper/android/openal-soft/Alc/backends/alsa.c new file mode 100644 index 000000000..5ff6307f1 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/alsa.c @@ -0,0 +1,1371 @@ +/** + * 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 "alu.h" + +#include + + +static const ALCchar alsaDevice[] = "ALSA Default"; + + +#ifdef HAVE_DYNLOAD +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_current); +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_time_min); +MAKE_FUNC(snd_pcm_hw_params_get_buffer_time_max); +MAKE_FUNC(snd_pcm_hw_params_get_period_time_min); +MAKE_FUNC(snd_pcm_hw_params_get_period_time_max); +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_test_format); +MAKE_FUNC(snd_pcm_hw_params_test_channels); +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_set_stop_threshold); +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_reset); +MAKE_FUNC(snd_pcm_wait); +MAKE_FUNC(snd_pcm_delay); +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_drop); +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_ctl_card_info_get_id); +MAKE_FUNC(snd_card_next); +MAKE_FUNC(snd_config_update_free_global); +#undef MAKE_FUNC + +#define snd_strerror psnd_strerror +#define snd_pcm_open psnd_pcm_open +#define snd_pcm_close psnd_pcm_close +#define snd_pcm_nonblock psnd_pcm_nonblock +#define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes +#define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames +#define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc +#define snd_pcm_hw_params_free psnd_pcm_hw_params_free +#define snd_pcm_hw_params_any psnd_pcm_hw_params_any +#define snd_pcm_hw_params_current psnd_pcm_hw_params_current +#define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access +#define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format +#define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels +#define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near +#define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near +#define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate +#define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample +#define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near +#define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near +#define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near +#define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near +#define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min +#define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min +#define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max +#define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min +#define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max +#define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size +#define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size +#define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access +#define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods +#define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format +#define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels +#define snd_pcm_hw_params psnd_pcm_hw_params +#define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc +#define snd_pcm_sw_params_current psnd_pcm_sw_params_current +#define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min +#define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold +#define snd_pcm_sw_params psnd_pcm_sw_params +#define snd_pcm_sw_params_free psnd_pcm_sw_params_free +#define snd_pcm_prepare psnd_pcm_prepare +#define snd_pcm_start psnd_pcm_start +#define snd_pcm_resume psnd_pcm_resume +#define snd_pcm_reset psnd_pcm_reset +#define snd_pcm_wait psnd_pcm_wait +#define snd_pcm_delay psnd_pcm_delay +#define snd_pcm_state psnd_pcm_state +#define snd_pcm_avail_update psnd_pcm_avail_update +#define snd_pcm_areas_silence psnd_pcm_areas_silence +#define snd_pcm_mmap_begin psnd_pcm_mmap_begin +#define snd_pcm_mmap_commit psnd_pcm_mmap_commit +#define snd_pcm_readi psnd_pcm_readi +#define snd_pcm_writei psnd_pcm_writei +#define snd_pcm_drain psnd_pcm_drain +#define snd_pcm_drop psnd_pcm_drop +#define snd_pcm_recover psnd_pcm_recover +#define snd_pcm_info_malloc psnd_pcm_info_malloc +#define snd_pcm_info_free psnd_pcm_info_free +#define snd_pcm_info_set_device psnd_pcm_info_set_device +#define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice +#define snd_pcm_info_set_stream psnd_pcm_info_set_stream +#define snd_pcm_info_get_name psnd_pcm_info_get_name +#define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device +#define snd_ctl_pcm_info psnd_ctl_pcm_info +#define snd_ctl_open psnd_ctl_open +#define snd_ctl_close psnd_ctl_close +#define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc +#define snd_ctl_card_info_free psnd_ctl_card_info_free +#define snd_ctl_card_info psnd_ctl_card_info +#define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name +#define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id +#define snd_card_next psnd_card_next +#define snd_config_update_free_global psnd_config_update_free_global +#endif + + +static ALCboolean alsa_load(void) +{ +#ifdef HAVE_DYNLOAD + if(!alsa_handle) + { + alsa_handle = LoadLib("libasound.so.2"); + if(!alsa_handle) + return ALC_FALSE; + +#define LOAD_FUNC(f) do { \ + p##f = GetSymbol(alsa_handle, #f); \ + if(p##f == NULL) { \ + CloseLib(alsa_handle); \ + alsa_handle = NULL; \ + return ALC_FALSE; \ + } \ +} while(0) + 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_current); + 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_time_min); + LOAD_FUNC(snd_pcm_hw_params_get_buffer_time_max); + LOAD_FUNC(snd_pcm_hw_params_get_period_time_min); + LOAD_FUNC(snd_pcm_hw_params_get_period_time_max); + 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_test_format); + LOAD_FUNC(snd_pcm_hw_params_test_channels); + 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_set_stop_threshold); + 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_reset); + LOAD_FUNC(snd_pcm_wait); + LOAD_FUNC(snd_pcm_delay); + 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_drop); + 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_ctl_card_info_get_id); + LOAD_FUNC(snd_card_next); + LOAD_FUNC(snd_config_update_free_global); +#undef LOAD_FUNC + } +#endif + return ALC_TRUE; +} + + +typedef struct { + snd_pcm_t *pcmHandle; + + ALvoid *buffer; + ALsizei size; + + ALboolean doCapture; + RingBuffer *ring; + + snd_pcm_sframes_t last_avail; + + volatile int killNow; + ALvoid *thread; +} alsa_data; + +typedef struct { + ALCchar *name; + char *device; +} DevMap; + +static DevMap *allDevNameMap; +static ALuint numDevNames; +static DevMap *allCaptureDevNameMap; +static ALuint numCaptureDevNames; + + +static const char *prefix_name(snd_pcm_stream_t stream) +{ + assert(stream == SND_PCM_STREAM_PLAYBACK || stream == SND_PCM_STREAM_CAPTURE); + return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix"; +} + +static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count) +{ + const char *main_prefix = "plughw:"; + snd_ctl_t *handle; + int card, err, dev, idx; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + DevMap *DevList; + + snd_ctl_card_info_malloc(&info); + snd_pcm_info_malloc(&pcminfo); + + DevList = malloc(sizeof(DevMap) * 1); + DevList[0].name = strdup(alsaDevice); + DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? + "device" : "capture", "default")); + idx = 1; + + card = -1; + if((err=snd_card_next(&card)) < 0) + ERR("Failed to find a card: %s\n", snd_strerror(err)); + ConfigValueStr("alsa", prefix_name(stream), &main_prefix); + while(card >= 0) + { + const char *card_prefix = main_prefix; + const char *cardname, *cardid; + char name[256]; + + snprintf(name, sizeof(name), "hw:%d", card); + if((err = snd_ctl_open(&handle, name, 0)) < 0) + { + ERR("control open (hw:%d): %s\n", card, snd_strerror(err)); + goto next_card; + } + if((err = snd_ctl_card_info(handle, info)) < 0) + { + ERR("control hardware info (hw:%d): %s\n", card, snd_strerror(err)); + snd_ctl_close(handle); + goto next_card; + } + + cardname = snd_ctl_card_info_get_name(info); + cardid = snd_ctl_card_info_get_id(info); + + snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid); + ConfigValueStr("alsa", name, &card_prefix); + + dev = -1; + while(1) + { + const char *devname; + void *temp; + + if(snd_ctl_pcm_next_device(handle, &dev) < 0) + ERR("snd_ctl_pcm_next_device failed\n"); + if(dev < 0) + break; + + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, stream); + if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) { + if(err != -ENOENT) + ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err)); + continue; + } + + temp = realloc(DevList, sizeof(DevMap) * (idx+1)); + if(temp) + { + const char *device_prefix = card_prefix; + char device[128]; + + DevList = temp; + devname = snd_pcm_info_get_name(pcminfo); + + snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev); + ConfigValueStr("alsa", name, &device_prefix); + + snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", + cardname, devname, cardid, dev); + snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d", + device_prefix, cardid, dev); + + TRACE("Got device \"%s\", \"%s\"\n", name, device); + DevList[idx].name = strdup(name); + DevList[idx].device = strdup(device); + idx++; + } + } + snd_ctl_close(handle); + next_card: + if(snd_card_next(&card) < 0) { + ERR("snd_card_next failed\n"); + break; + } + } + + snd_pcm_info_free(pcminfo); + snd_ctl_card_info_free(info); + + *count = idx; + return DevList; +} + + +static int verify_state(snd_pcm_t *handle) +{ + snd_pcm_state_t state = snd_pcm_state(handle); + int err; + + switch(state) + { + case SND_PCM_STATE_OPEN: + case SND_PCM_STATE_SETUP: + case SND_PCM_STATE_PREPARED: + case SND_PCM_STATE_RUNNING: + case SND_PCM_STATE_DRAINING: + case SND_PCM_STATE_PAUSED: + /* All Okay */ + break; + + case SND_PCM_STATE_XRUN: + if((err=snd_pcm_recover(handle, -EPIPE, 1)) < 0) + return err; + break; + case SND_PCM_STATE_SUSPENDED: + if((err=snd_pcm_recover(handle, -ESTRPIPE, 1)) < 0) + return err; + break; + case SND_PCM_STATE_DISCONNECTED: + return -ENODEV; + } + + return state; +} + + +static ALuint ALSAProc(ALvoid *ptr) +{ + ALCdevice *Device = (ALCdevice*)ptr; + alsa_data *data = (alsa_data*)Device->ExtraData; + const snd_pcm_channel_area_t *areas = NULL; + snd_pcm_uframes_t update_size, num_updates; + snd_pcm_sframes_t avail, commitres; + snd_pcm_uframes_t offset, frames; + char *WritePtr; + int err; + + SetRTPriority(); + + update_size = Device->UpdateSize; + num_updates = Device->NumUpdates; + while(!data->killNow) + { + int state = verify_state(data->pcmHandle); + if(state < 0) + { + ERR("Invalid state detected: %s\n", snd_strerror(state)); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + break; + } + + avail = snd_pcm_avail_update(data->pcmHandle); + if(avail < 0) + { + ERR("available update failed: %s\n", snd_strerror(avail)); + continue; + } + + if((snd_pcm_uframes_t)avail > update_size*(num_updates+1)) + { + WARN("available samples exceeds the buffer size\n"); + snd_pcm_reset(data->pcmHandle); + continue; + } + + // make sure there's frames to process + if((snd_pcm_uframes_t)avail < update_size) + { + if(state != SND_PCM_STATE_RUNNING) + { + err = snd_pcm_start(data->pcmHandle); + if(err < 0) + { + ERR("start failed: %s\n", snd_strerror(err)); + continue; + } + } + if(snd_pcm_wait(data->pcmHandle, 1000) == 0) + ERR("Wait timeout... buffer size too low?\n"); + continue; + } + avail -= avail%update_size; + + // it is possible that contiguous areas are smaller, thus we use a loop + ALCdevice_Lock(Device); + while(avail > 0) + { + frames = avail; + + err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames); + if(err < 0) + { + ERR("mmap begin error: %s\n", snd_strerror(err)); + break; + } + + WritePtr = (char*)areas->addr + (offset * areas->step / 8); + aluMixData(Device, WritePtr, frames); + + commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames); + if(commitres < 0 || (commitres-frames) != 0) + { + ERR("mmap commit error: %s\n", + snd_strerror(commitres >= 0 ? -EPIPE : commitres)); + break; + } + + avail -= frames; + } + ALCdevice_Unlock(Device); + } + + return 0; +} + +static ALuint ALSANoMMapProc(ALvoid *ptr) +{ + ALCdevice *Device = (ALCdevice*)ptr; + alsa_data *data = (alsa_data*)Device->ExtraData; + snd_pcm_uframes_t update_size, num_updates; + snd_pcm_sframes_t avail; + char *WritePtr; + int err; + + SetRTPriority(); + + update_size = Device->UpdateSize; + num_updates = Device->NumUpdates; + while(!data->killNow) + { + int state = verify_state(data->pcmHandle); + if(state < 0) + { + ERR("Invalid state detected: %s\n", snd_strerror(state)); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + break; + } + + avail = snd_pcm_avail_update(data->pcmHandle); + if(avail < 0) + { + ERR("available update failed: %s\n", snd_strerror(avail)); + continue; + } + + if((snd_pcm_uframes_t)avail > update_size*num_updates) + { + WARN("available samples exceeds the buffer size\n"); + snd_pcm_reset(data->pcmHandle); + continue; + } + + if((snd_pcm_uframes_t)avail < update_size) + { + if(state != SND_PCM_STATE_RUNNING) + { + err = snd_pcm_start(data->pcmHandle); + if(err < 0) + { + ERR("start failed: %s\n", snd_strerror(err)); + continue; + } + } + if(snd_pcm_wait(data->pcmHandle, 1000) == 0) + ERR("Wait timeout... buffer size too low?\n"); + continue; + } + + ALCdevice_Lock(Device); + WritePtr = data->buffer; + avail = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); + aluMixData(Device, WritePtr, avail); + + while(avail > 0) + { + int ret = snd_pcm_writei(data->pcmHandle, WritePtr, avail); + switch (ret) + { + case -EAGAIN: + continue; + case -ESTRPIPE: + case -EPIPE: + case -EINTR: + ret = snd_pcm_recover(data->pcmHandle, ret, 1); + if(ret < 0) + avail = 0; + break; + default: + if (ret >= 0) + { + WritePtr += snd_pcm_frames_to_bytes(data->pcmHandle, ret); + avail -= ret; + } + break; + } + if (ret < 0) + { + ret = snd_pcm_prepare(data->pcmHandle); + if(ret < 0) + break; + } + } + ALCdevice_Unlock(Device); + } + + return 0; +} + +static ALCenum alsa_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + const char *driver = NULL; + alsa_data *data; + int err; + + if(deviceName) + { + size_t idx; + + if(!allDevNameMap) + allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames); + + for(idx = 0;idx < numDevNames;idx++) + { + if(strcmp(deviceName, allDevNameMap[idx].name) == 0) + { + driver = allDevNameMap[idx].device; + break; + } + } + if(idx == numDevNames) + return ALC_INVALID_VALUE; + } + else + { + deviceName = alsaDevice; + driver = GetConfigValue("alsa", "device", "default"); + } + + data = (alsa_data*)calloc(1, sizeof(alsa_data)); + + err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + if(err < 0) + { + free(data); + ERR("Could not open playback device '%s': %s\n", driver, snd_strerror(err)); + return ALC_OUT_OF_MEMORY; + } + + /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ + snd_config_update_free_global(); + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_NO_ERROR; +} + +static void alsa_close_playback(ALCdevice *device) +{ + alsa_data *data = (alsa_data*)device->ExtraData; + + snd_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 *hp = NULL; + snd_pcm_access_t access; + snd_pcm_format_t format; + unsigned int periods; + unsigned int rate; + const char *funcerr; + int allowmmap; + int err; + + 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 DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + 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; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp)); + /* set interleaved access */ + if(!allowmmap || snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) + { + /* No mmap */ + CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + } + /* test and set format (implicitly sets sample bits) */ + if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) < 0) + { + static const struct { + snd_pcm_format_t format; + enum DevFmtType fmttype; + } formatlist[] = { + { SND_PCM_FORMAT_FLOAT, DevFmtFloat }, + { SND_PCM_FORMAT_S32, DevFmtInt }, + { SND_PCM_FORMAT_U32, DevFmtUInt }, + { SND_PCM_FORMAT_S16, DevFmtShort }, + { SND_PCM_FORMAT_U16, DevFmtUShort }, + { SND_PCM_FORMAT_S8, DevFmtByte }, + { SND_PCM_FORMAT_U8, DevFmtUByte }, + }; + size_t k; + + for(k = 0;k < COUNTOF(formatlist);k++) + { + format = formatlist[k].format; + if(snd_pcm_hw_params_test_format(data->pcmHandle, hp, format) >= 0) + { + device->FmtType = formatlist[k].fmttype; + break; + } + } + } + CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format)); + /* test and set channels (implicitly sets frame bits) */ + if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0) + { + static const enum DevFmtChannels channellist[] = { + DevFmtStereo, + DevFmtQuad, + DevFmtX51, + DevFmtX71, + DevFmtMono, + }; + size_t k; + + for(k = 0;k < COUNTOF(channellist);k++) + { + if(snd_pcm_hw_params_test_channels(data->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0) + { + device->FmtChans = channellist[k]; + break; + } + } + } + CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); + /* set rate (implicitly constrains period/buffer parameters) */ + if(snd_pcm_hw_params_set_rate_resample(data->pcmHandle, hp, 0) < 0) + ERR("Failed to disable ALSA resampler\n"); + CHECK(snd_pcm_hw_params_set_rate_near(data->pcmHandle, hp, &rate, NULL)); + /* set buffer time (implicitly constrains period/buffer parameters) */ + if(snd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, hp, &bufferLen, NULL) < 0) + ERR("snd_pcm_hw_params_set_buffer_time_near failed: %s\n", snd_strerror(err)); + /* set period time (implicitly sets buffer size/bytes/time and period size/bytes) */ + if(snd_pcm_hw_params_set_period_time_near(data->pcmHandle, hp, &periodLen, NULL) < 0) + ERR("snd_pcm_hw_params_set_period_time_near failed: %s\n", snd_strerror(err)); + /* install and prepare hardware configuration */ + CHECK(snd_pcm_hw_params(data->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); + CHECK(snd_pcm_hw_params_get_periods(hp, &periods, NULL)); + + snd_pcm_hw_params_free(hp); + hp = NULL; + snd_pcm_sw_params_malloc(&sp); + + CHECK(snd_pcm_sw_params_current(data->pcmHandle, sp)); + CHECK(snd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)); + CHECK(snd_pcm_sw_params_set_stop_threshold(data->pcmHandle, sp, periodSizeInFrames*periods)); + CHECK(snd_pcm_sw_params(data->pcmHandle, sp)); +#undef CHECK + snd_pcm_sw_params_free(sp); + sp = NULL; + + device->NumUpdates = periods; + device->UpdateSize = periodSizeInFrames; + device->Frequency = rate; + + SetDefaultChannelOrder(device); + + return ALC_TRUE; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + if(sp) snd_pcm_sw_params_free(sp); + return ALC_FALSE; +} + +static ALCboolean alsa_start_playback(ALCdevice *device) +{ + alsa_data *data = (alsa_data*)device->ExtraData; + snd_pcm_hw_params_t *hp = NULL; + snd_pcm_access_t access; + const char *funcerr; + int err; + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_access(hp, &access)); +#undef CHECK + snd_pcm_hw_params_free(hp); + hp = NULL; + + data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize); + if(access == SND_PCM_ACCESS_RW_INTERLEAVED) + { + data->buffer = malloc(data->size); + if(!data->buffer) + { + ERR("buffer malloc failed\n"); + return ALC_FALSE; + } + data->thread = StartThread(ALSANoMMapProc, device); + } + else + { + err = snd_pcm_prepare(data->pcmHandle); + if(err < 0) + { + ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err)); + return ALC_FALSE; + } + data->thread = StartThread(ALSAProc, device); + } + if(data->thread == NULL) + { + ERR("Could not create playback thread\n"); + free(data->buffer); + data->buffer = NULL; + return ALC_FALSE; + } + + return ALC_TRUE; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + return ALC_FALSE; +} + +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 ALCenum alsa_open_capture(ALCdevice *Device, const ALCchar *deviceName) +{ + const char *driver = NULL; + snd_pcm_hw_params_t *hp; + snd_pcm_uframes_t bufferSizeInFrames; + snd_pcm_uframes_t periodSizeInFrames; + ALboolean needring = AL_FALSE; + snd_pcm_format_t format; + const char *funcerr; + alsa_data *data; + int err; + + if(deviceName) + { + size_t idx; + + if(!allCaptureDevNameMap) + allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); + + for(idx = 0;idx < numCaptureDevNames;idx++) + { + if(strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0) + { + driver = allCaptureDevNameMap[idx].device; + break; + } + } + if(idx == numCaptureDevNames) + return ALC_INVALID_VALUE; + } + else + { + deviceName = alsaDevice; + driver = GetConfigValue("alsa", "capture", "default"); + } + + data = (alsa_data*)calloc(1, sizeof(alsa_data)); + + err = snd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); + if(err < 0) + { + ERR("Could not open capture device '%s': %s\n", driver, snd_strerror(err)); + free(data); + return ALC_INVALID_VALUE; + } + + /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */ + snd_config_update_free_global(); + + 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 DevFmtInt: + format = SND_PCM_FORMAT_S32; + break; + case DevFmtUInt: + format = SND_PCM_FORMAT_U32; + break; + case DevFmtFloat: + format = SND_PCM_FORMAT_FLOAT; + break; + } + + funcerr = NULL; + bufferSizeInFrames = maxu(Device->UpdateSize*Device->NumUpdates, + 100*Device->Frequency/1000); + periodSizeInFrames = minu(bufferSizeInFrames, 25*Device->Frequency/1000); + + snd_pcm_hw_params_malloc(&hp); +#define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error + CHECK(snd_pcm_hw_params_any(data->pcmHandle, hp)); + /* set interleaved access */ + CHECK(snd_pcm_hw_params_set_access(data->pcmHandle, hp, SND_PCM_ACCESS_RW_INTERLEAVED)); + /* set format (implicitly sets sample bits) */ + CHECK(snd_pcm_hw_params_set_format(data->pcmHandle, hp, format)); + /* set channels (implicitly sets frame bits) */ + CHECK(snd_pcm_hw_params_set_channels(data->pcmHandle, hp, ChannelsFromDevFmt(Device->FmtChans))); + /* set rate (implicitly constrains period/buffer parameters) */ + CHECK(snd_pcm_hw_params_set_rate(data->pcmHandle, hp, Device->Frequency, 0)); + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + if(snd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, hp, &bufferSizeInFrames) < 0) + { + TRACE("Buffer too large, using intermediate ring buffer\n"); + needring = AL_TRUE; + CHECK(snd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, hp, &bufferSizeInFrames)); + } + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + CHECK(snd_pcm_hw_params_set_period_size_near(data->pcmHandle, hp, &periodSizeInFrames, NULL)); + /* install and prepare hardware configuration */ + CHECK(snd_pcm_hw_params(data->pcmHandle, hp)); + /* retrieve configuration info */ + CHECK(snd_pcm_hw_params_get_period_size(hp, &periodSizeInFrames, NULL)); +#undef CHECK + snd_pcm_hw_params_free(hp); + hp = NULL; + + if(needring) + { + data->ring = CreateRingBuffer(FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType), + Device->UpdateSize*Device->NumUpdates); + if(!data->ring) + { + ERR("ring buffer create failed\n"); + goto error2; + } + + data->size = snd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames); + data->buffer = malloc(data->size); + if(!data->buffer) + { + ERR("buffer malloc failed\n"); + goto error2; + } + } + + Device->DeviceName = strdup(deviceName); + + Device->ExtraData = data; + return ALC_NO_ERROR; + +error: + ERR("%s failed: %s\n", funcerr, snd_strerror(err)); + if(hp) snd_pcm_hw_params_free(hp); + +error2: + free(data->buffer); + DestroyRingBuffer(data->ring); + snd_pcm_close(data->pcmHandle); + free(data); + + Device->ExtraData = NULL; + return ALC_INVALID_VALUE; +} + +static void alsa_close_capture(ALCdevice *Device) +{ + alsa_data *data = (alsa_data*)Device->ExtraData; + + snd_pcm_close(data->pcmHandle); + DestroyRingBuffer(data->ring); + + free(data->buffer); + free(data); + Device->ExtraData = NULL; +} + +static void alsa_start_capture(ALCdevice *Device) +{ + alsa_data *data = (alsa_data*)Device->ExtraData; + int err; + + err = snd_pcm_start(data->pcmHandle); + if(err < 0) + { + ERR("start failed: %s\n", snd_strerror(err)); + aluHandleDisconnect(Device); + } + else + data->doCapture = AL_TRUE; +} + +static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) +{ + alsa_data *data = (alsa_data*)Device->ExtraData; + + if(data->ring) + { + ReadRingBuffer(data->ring, Buffer, Samples); + return ALC_NO_ERROR; + } + + data->last_avail -= Samples; + while(Device->Connected && Samples > 0) + { + snd_pcm_sframes_t amt = 0; + + if(data->size > 0) + { + /* First get any data stored from the last stop */ + amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); + if((snd_pcm_uframes_t)amt > Samples) amt = Samples; + + amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt); + memmove(Buffer, data->buffer, amt); + + if(data->size > amt) + { + memmove(data->buffer, data->buffer+amt, data->size - amt); + data->size -= amt; + } + else + { + free(data->buffer); + data->buffer = NULL; + data->size = 0; + } + amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt); + } + else if(data->doCapture) + amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples); + if(amt < 0) + { + ERR("read error: %s\n", snd_strerror(amt)); + + if(amt == -EAGAIN) + continue; + if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) + { + amt = snd_pcm_start(data->pcmHandle); + if(amt >= 0) + amt = snd_pcm_avail_update(data->pcmHandle); + } + if(amt < 0) + { + ERR("restore error: %s\n", snd_strerror(amt)); + aluHandleDisconnect(Device); + break; + } + /* If the amount available is less than what's asked, we lost it + * during recovery. So just give silence instead. */ + if((snd_pcm_uframes_t)amt < Samples) + break; + continue; + } + + Buffer = (ALbyte*)Buffer + amt; + Samples -= amt; + } + if(Samples > 0) + memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0), + snd_pcm_frames_to_bytes(data->pcmHandle, Samples)); + + return ALC_NO_ERROR; +} + +static ALCuint alsa_available_samples(ALCdevice *Device) +{ + alsa_data *data = (alsa_data*)Device->ExtraData; + snd_pcm_sframes_t avail = 0; + + if(Device->Connected && data->doCapture) + avail = snd_pcm_avail_update(data->pcmHandle); + if(avail < 0) + { + ERR("avail update failed: %s\n", snd_strerror(avail)); + + if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0) + { + if(data->doCapture) + avail = snd_pcm_start(data->pcmHandle); + if(avail >= 0) + avail = snd_pcm_avail_update(data->pcmHandle); + } + if(avail < 0) + { + ERR("restore error: %s\n", snd_strerror(avail)); + aluHandleDisconnect(Device); + } + } + + if(!data->ring) + { + if(avail < 0) avail = 0; + avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size); + if(avail > data->last_avail) data->last_avail = avail; + return data->last_avail; + } + + while(avail > 0) + { + snd_pcm_sframes_t amt; + + amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size); + if(avail < amt) amt = avail; + + amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt); + if(amt < 0) + { + ERR("read error: %s\n", snd_strerror(amt)); + + if(amt == -EAGAIN) + continue; + if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0) + { + if(data->doCapture) + amt = snd_pcm_start(data->pcmHandle); + if(amt >= 0) + amt = snd_pcm_avail_update(data->pcmHandle); + } + if(amt < 0) + { + ERR("restore error: %s\n", snd_strerror(amt)); + aluHandleDisconnect(Device); + break; + } + avail = amt; + continue; + } + + WriteRingBuffer(data->ring, data->buffer, amt); + avail -= amt; + } + + return RingBufferSize(data->ring); +} + +static void alsa_stop_capture(ALCdevice *Device) +{ + alsa_data *data = (alsa_data*)Device->ExtraData; + ALCuint avail; + int err; + + /* OpenAL requires access to unread audio after stopping, but ALSA's + * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's + * available now so it'll be available later after the drop. */ + avail = alsa_available_samples(Device); + if(!data->ring && avail > 0) + { + /* The ring buffer implicitly captures when checking availability. + * Direct access needs to explicitly capture it into temp storage. */ + ALsizei size; + void *ptr; + + size = snd_pcm_frames_to_bytes(data->pcmHandle, avail); + ptr = realloc(data->buffer, size); + if(ptr) + { + data->buffer = ptr; + alsa_capture_samples(Device, data->buffer, avail); + data->size = size; + } + } + err = snd_pcm_drop(data->pcmHandle); + if(err < 0) + ERR("drop failed: %s\n", snd_strerror(err)); + data->doCapture = AL_FALSE; +} + + +static ALint64 alsa_get_latency(ALCdevice *device) +{ + alsa_data *data = (alsa_data*)device->ExtraData; + snd_pcm_sframes_t delay = 0; + int err; + + if((err=snd_pcm_delay(data->pcmHandle, &delay)) < 0) + { + ERR("Failed to get pcm delay: %s\n", snd_strerror(err)); + return 0; + } + return maxi64((ALint64)delay*1000000000/device->Frequency, 0); +} + + +static const BackendFuncs alsa_funcs = { + alsa_open_playback, + alsa_close_playback, + alsa_reset_playback, + alsa_start_playback, + alsa_stop_playback, + alsa_open_capture, + alsa_close_capture, + alsa_start_capture, + alsa_stop_capture, + alsa_capture_samples, + alsa_available_samples, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + alsa_get_latency +}; + +ALCboolean alc_alsa_init(BackendFuncs *func_list) +{ + if(!alsa_load()) + return ALC_FALSE; + *func_list = alsa_funcs; + return ALC_TRUE; +} + +void alc_alsa_deinit(void) +{ + ALuint i; + + for(i = 0;i < numDevNames;++i) + { + free(allDevNameMap[i].name); + free(allDevNameMap[i].device); + } + free(allDevNameMap); + allDevNameMap = NULL; + numDevNames = 0; + + for(i = 0;i < numCaptureDevNames;++i) + { + free(allCaptureDevNameMap[i].name); + free(allCaptureDevNameMap[i].device); + } + free(allCaptureDevNameMap); + allCaptureDevNameMap = NULL; + numCaptureDevNames = 0; + +#ifdef HAVE_DYNLOAD + if(alsa_handle) + CloseLib(alsa_handle); + alsa_handle = NULL; +#endif +} + +void alc_alsa_probe(enum DevProbe type) +{ + ALuint i; + + switch(type) + { + case ALL_DEVICE_PROBE: + for(i = 0;i < numDevNames;++i) + { + free(allDevNameMap[i].name); + free(allDevNameMap[i].device); + } + + free(allDevNameMap); + allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames); + + for(i = 0;i < numDevNames;++i) + AppendAllDevicesList(allDevNameMap[i].name); + break; + + case CAPTURE_DEVICE_PROBE: + for(i = 0;i < numCaptureDevNames;++i) + { + free(allCaptureDevNameMap[i].name); + free(allCaptureDevNameMap[i].device); + } + + free(allCaptureDevNameMap); + allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames); + + for(i = 0;i < numCaptureDevNames;++i) + AppendCaptureDeviceList(allCaptureDevNameMap[i].name); + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/coreaudio.c b/src/eepp/helper/android/openal-soft/Alc/backends/coreaudio.c new file mode 100644 index 000000000..150f37ac2 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/coreaudio.c @@ -0,0 +1,706 @@ +/** + * 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 "alu.h" + +#include +#include +#include +#include + + +typedef struct { + AudioUnit audioUnit; + + ALuint frameSize; + ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate + AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD + + AudioConverterRef audioConverter; // Sample rate converter if needed + AudioBufferList *bufferList; // Buffer for data coming from the input device + ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling + + RingBuffer *ring; +} ca_data; + +static const ALCchar ca_device[] = "CoreAudio Default"; + + +static void destroy_buffer_list(AudioBufferList* list) +{ + if(list) + { + UInt32 i; + for(i = 0;i < list->mNumberBuffers;i++) + free(list->mBuffers[i].mData); + free(list); + } +} + +static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize) +{ + AudioBufferList *list; + + list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer)); + if(list) + { + list->mNumberBuffers = 1; + + list->mBuffers[0].mNumberChannels = channelCount; + list->mBuffers[0].mDataByteSize = byteSize; + list->mBuffers[0].mData = malloc(byteSize); + if(list->mBuffers[0].mData == NULL) + { + free(list); + list = NULL; + } + } + return list; +} + +static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) +{ + ALCdevice *device = (ALCdevice*)inRefCon; + ca_data *data = (ca_data*)device->ExtraData; + + aluMixData(device, ioData->mBuffers[0].mData, + ioData->mBuffers[0].mDataByteSize / data->frameSize); + + return noErr; +} + +static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, + AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData) +{ + ALCdevice *device = (ALCdevice*)inUserData; + ca_data *data = (ca_data*)device->ExtraData; + + // Read from the ring buffer and store temporarily in a large buffer + ReadRingBuffer(data->ring, data->resampleBuffer, (ALsizei)(*ioNumberDataPackets)); + + // Set the input data + ioData->mNumberBuffers = 1; + ioData->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame; + ioData->mBuffers[0].mData = data->resampleBuffer; + ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * data->format.mBytesPerFrame; + + return noErr; +} + +static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList *ioData) +{ + ALCdevice *device = (ALCdevice*)inRefCon; + ca_data *data = (ca_data*)device->ExtraData; + AudioUnitRenderActionFlags flags = 0; + OSStatus err; + + // fill the bufferList with data from the input device + err = AudioUnitRender(data->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, data->bufferList); + if(err != noErr) + { + ERR("AudioUnitRender error: %d\n", err); + return err; + } + + WriteRingBuffer(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames); + + return noErr; +} + +static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + ComponentDescription desc; + Component comp; + ca_data *data; + OSStatus err; + + if(!deviceName) + deviceName = ca_device; + else if(strcmp(deviceName, ca_device) != 0) + return ALC_INVALID_VALUE; + + /* open the default output unit */ + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + comp = FindNextComponent(NULL, &desc); + if(comp == NULL) + { + ERR("FindNextComponent failed\n"); + return ALC_INVALID_VALUE; + } + + data = calloc(1, sizeof(*data)); + + err = OpenAComponent(comp, &data->audioUnit); + if(err != noErr) + { + ERR("OpenAComponent failed\n"); + free(data); + return ALC_INVALID_VALUE; + } + + /* init and start the default audio unit... */ + err = AudioUnitInitialize(data->audioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + CloseComponent(data->audioUnit); + free(data); + return ALC_INVALID_VALUE; + } + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_NO_ERROR; +} + +static void ca_close_playback(ALCdevice *device) +{ + ca_data *data = (ca_data*)device->ExtraData; + + AudioUnitUninitialize(data->audioUnit); + CloseComponent(data->audioUnit); + + free(data); + device->ExtraData = NULL; +} + +static ALCboolean ca_reset_playback(ALCdevice *device) +{ + ca_data *data = (ca_data*)device->ExtraData; + AudioStreamBasicDescription streamFormat; + AURenderCallbackStruct input; + OSStatus err; + UInt32 size; + + err = AudioUnitUninitialize(data->audioUnit); + if(err != noErr) + ERR("-- AudioUnitUninitialize failed.\n"); + + /* retrieve default output unit's properties (output side) */ + size = sizeof(AudioStreamBasicDescription); + err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size); + if(err != noErr || size != sizeof(AudioStreamBasicDescription)) + { + ERR("AudioUnitGetProperty failed\n"); + return ALC_FALSE; + } + +#if 0 + TRACE("Output streamFormat of default output unit -\n"); + TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket); + TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame); + TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel); + TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket); + TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame); + TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate); +#endif + + /* set default output unit's input side to match output side */ + err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + if(device->Frequency != streamFormat.mSampleRate) + { + device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * + streamFormat.mSampleRate / + device->Frequency); + device->Frequency = streamFormat.mSampleRate; + } + + /* FIXME: How to tell what channels are what in the output device, and how + * to specify what we're giving? eg, 6.0 vs 5.1 */ + switch(streamFormat.mChannelsPerFrame) + { + case 1: + device->FmtChans = DevFmtMono; + break; + case 2: + device->FmtChans = DevFmtStereo; + break; + case 4: + device->FmtChans = DevFmtQuad; + break; + case 6: + device->FmtChans = DevFmtX51; + break; + case 7: + device->FmtChans = DevFmtX61; + break; + case 8: + device->FmtChans = DevFmtX71; + break; + default: + ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame); + device->FmtChans = DevFmtStereo; + streamFormat.mChannelsPerFrame = 2; + break; + } + SetDefaultWFXChannelOrder(device); + + /* use channel count and sample rate from the default output unit's current + * parameters, but reset everything else */ + streamFormat.mFramesPerPacket = 1; + streamFormat.mFormatFlags = 0; + switch(device->FmtType) + { + case DevFmtUByte: + device->FmtType = DevFmtByte; + /* fall-through */ + case DevFmtByte: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 8; + break; + case DevFmtUShort: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 16; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger; + streamFormat.mBitsPerChannel = 32; + break; + case DevFmtFloat: + streamFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat; + streamFormat.mBitsPerChannel = 32; + break; + } + streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame * + streamFormat.mBitsPerChannel / 8; + streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame; + streamFormat.mFormatID = kAudioFormatLinearPCM; + streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian | + kLinearPCMFormatFlagIsPacked; + + err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + /* setup callback */ + data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + input.inputProc = ca_callback; + input.inputProcRefCon = device; + + err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + return ALC_FALSE; + } + + /* init the default audio unit... */ + err = AudioUnitInitialize(data->audioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static ALCboolean ca_start_playback(ALCdevice *device) +{ + ca_data *data = (ca_data*)device->ExtraData; + OSStatus err; + + err = AudioOutputUnitStart(data->audioUnit); + if(err != noErr) + { + ERR("AudioOutputUnitStart failed\n"); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void ca_stop_playback(ALCdevice *device) +{ + ca_data *data = (ca_data*)device->ExtraData; + OSStatus err; + + err = AudioOutputUnitStop(data->audioUnit); + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + +static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) +{ + AudioStreamBasicDescription requestedFormat; // The application requested format + AudioStreamBasicDescription hardwareFormat; // The hardware format + AudioStreamBasicDescription outputFormat; // The AudioUnit output format + AURenderCallbackStruct input; + ComponentDescription desc; + AudioDeviceID inputDevice; + UInt32 outputFrameCount; + UInt32 propertySize; + UInt32 enableIO; + Component comp; + ca_data *data; + OSStatus err; + + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_HALOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + // Search for component with given description + comp = FindNextComponent(NULL, &desc); + if(comp == NULL) + { + ERR("FindNextComponent failed\n"); + return ALC_INVALID_VALUE; + } + + data = calloc(1, sizeof(*data)); + device->ExtraData = data; + + // Open the component + err = OpenAComponent(comp, &data->audioUnit); + if(err != noErr) + { + ERR("OpenAComponent failed\n"); + goto error; + } + + // Turn off AudioUnit output + enableIO = 0; + err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // Turn on AudioUnit input + enableIO = 1; + err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // Get the default input device + propertySize = sizeof(AudioDeviceID); + err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice); + if(err != noErr) + { + ERR("AudioHardwareGetProperty failed\n"); + goto error; + } + + if(inputDevice == kAudioDeviceUnknown) + { + ERR("No input device found\n"); + goto error; + } + + // Track the input device + err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // set capture callback + input.inputProc = ca_capture_callback; + input.inputProcRefCon = device; + + err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // Initialize the device + err = AudioUnitInitialize(data->audioUnit); + if(err != noErr) + { + ERR("AudioUnitInitialize failed\n"); + goto error; + } + + // Get the hardware format + propertySize = sizeof(AudioStreamBasicDescription); + err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize); + if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription)) + { + ERR("AudioUnitGetProperty failed\n"); + goto error; + } + + // Set up the requested format description + switch(device->FmtType) + { + case DevFmtUByte: + requestedFormat.mBitsPerChannel = 8; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtShort: + requestedFormat.mBitsPerChannel = 16; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtInt: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked; + break; + case DevFmtFloat: + requestedFormat.mBitsPerChannel = 32; + requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + goto error; + } + + switch(device->FmtChans) + { + case DevFmtMono: + requestedFormat.mChannelsPerFrame = 1; + break; + case DevFmtStereo: + requestedFormat.mChannelsPerFrame = 2; + break; + + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Side: + case DevFmtX61: + case DevFmtX71: + ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); + goto error; + } + + requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8; + requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame; + requestedFormat.mSampleRate = device->Frequency; + requestedFormat.mFormatID = kAudioFormatLinearPCM; + requestedFormat.mReserved = 0; + requestedFormat.mFramesPerPacket = 1; + + // save requested format description for later use + data->format = requestedFormat; + data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + + // Use intermediate format for sample rate conversion (outputFormat) + // Set sample rate to the same as hardware for resampling later + outputFormat = requestedFormat; + outputFormat.mSampleRate = hardwareFormat.mSampleRate; + + // Determine sample rate ratio for resampling + data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency; + + // The output format should be the requested format, but using the hardware sample rate + // This is because the AudioUnit will automatically scale other properties, except for sample rate + err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed\n"); + goto error; + } + + // Set the AudioUnit output format frame count + outputFrameCount = device->UpdateSize * data->sampleRateRatio; + err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount)); + if(err != noErr) + { + ERR("AudioUnitSetProperty failed: %d\n", err); + goto error; + } + + // Set up sample converter + err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter); + if(err != noErr) + { + ERR("AudioConverterNew failed: %d\n", err); + goto error; + } + + // Create a buffer for use in the resample callback + data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio); + + // Allocate buffer for the AudioUnit output + data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio); + if(data->bufferList == NULL) + goto error; + + data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates); + if(data->ring == NULL) + goto error; + + return ALC_NO_ERROR; + +error: + DestroyRingBuffer(data->ring); + free(data->resampleBuffer); + destroy_buffer_list(data->bufferList); + + if(data->audioConverter) + AudioConverterDispose(data->audioConverter); + if(data->audioUnit) + CloseComponent(data->audioUnit); + + free(data); + device->ExtraData = NULL; + + return ALC_INVALID_VALUE; +} + +static void ca_close_capture(ALCdevice *device) +{ + ca_data *data = (ca_data*)device->ExtraData; + + DestroyRingBuffer(data->ring); + free(data->resampleBuffer); + destroy_buffer_list(data->bufferList); + + AudioConverterDispose(data->audioConverter); + CloseComponent(data->audioUnit); + + free(data); + device->ExtraData = NULL; +} + +static void ca_start_capture(ALCdevice *device) +{ + ca_data *data = (ca_data*)device->ExtraData; + OSStatus err = AudioOutputUnitStart(data->audioUnit); + if(err != noErr) + ERR("AudioOutputUnitStart failed\n"); +} + +static void ca_stop_capture(ALCdevice *device) +{ + ca_data *data = (ca_data*)device->ExtraData; + OSStatus err = AudioOutputUnitStop(data->audioUnit); + if(err != noErr) + ERR("AudioOutputUnitStop failed\n"); +} + +static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) +{ + ca_data *data = (ca_data*)device->ExtraData; + AudioBufferList *list; + UInt32 frameCount; + OSStatus err; + + // If no samples are requested, just return + if(samples == 0) + return ALC_NO_ERROR; + + // Allocate a temporary AudioBufferList to use as the return resamples data + list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer)); + + // Point the resampling buffer to the capture buffer + list->mNumberBuffers = 1; + list->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame; + list->mBuffers[0].mDataByteSize = samples * data->frameSize; + list->mBuffers[0].mData = buffer; + + // Resample into another AudioBufferList + frameCount = samples; + err = AudioConverterFillComplexBuffer(data->audioConverter, ca_capture_conversion_callback, + device, &frameCount, list, NULL); + if(err != noErr) + { + ERR("AudioConverterFillComplexBuffer error: %d\n", err); + return ALC_INVALID_VALUE; + } + return ALC_NO_ERROR; +} + +static ALCuint ca_available_samples(ALCdevice *device) +{ + ca_data *data = device->ExtraData; + return RingBufferSize(data->ring) / data->sampleRateRatio; +} + + +static const BackendFuncs ca_funcs = { + ca_open_playback, + ca_close_playback, + ca_reset_playback, + ca_start_playback, + ca_stop_playback, + ca_open_capture, + ca_close_capture, + ca_start_capture, + ca_stop_capture, + ca_capture_samples, + ca_available_samples, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_ca_init(BackendFuncs *func_list) +{ + *func_list = ca_funcs; + return ALC_TRUE; +} + +void alc_ca_deinit(void) +{ +} + +void alc_ca_probe(enum DevProbe type) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + AppendAllDevicesList(ca_device); + break; + case CAPTURE_DEVICE_PROBE: + AppendCaptureDeviceList(ca_device); + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/dsound.c b/src/eepp/helper/android/openal-soft/Alc/backends/dsound.c new file mode 100644 index 000000000..c6f666e1c --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/dsound.c @@ -0,0 +1,1035 @@ +/** + * 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 +#ifndef _WAVEFORMATEXTENSIBLE_ +#include +#include +#endif + +#include "alMain.h" +#include "alu.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, IDirectSound **ppDS, IUnknown *pUnkOuter); +static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext); +static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter); +static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext); + +#define DirectSoundCreate pDirectSoundCreate +#define DirectSoundEnumerateA pDirectSoundEnumerateA +#define DirectSoundCaptureCreate pDirectSoundCaptureCreate +#define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA + + +typedef struct { + // DirectSound Playback Device + IDirectSound *DS; + IDirectSoundBuffer *PrimaryBuffer; + IDirectSoundBuffer *Buffer; + IDirectSoundNotify *Notifies; + HANDLE NotifyEvent; + + volatile int killNow; + ALvoid *thread; +} DSoundPlaybackData; + +typedef struct { + // DirectSound Capture Device + IDirectSoundCapture *DSC; + IDirectSoundCaptureBuffer *DSCbuffer; + DWORD BufferBytes; + DWORD Cursor; + RingBuffer *Ring; +} DSoundCaptureData; + + +typedef struct { + ALCchar *name; + GUID guid; +} DevMap; + +static DevMap *PlaybackDeviceList; +static ALuint NumPlaybackDevices; +static DevMap *CaptureDeviceList; +static ALuint NumCaptureDevices; + +#define MAX_UPDATES 128 + +static ALCboolean DSoundLoad(void) +{ + if(!ds_handle) + { + ds_handle = LoadLib("dsound.dll"); + if(ds_handle == NULL) + { + ERR("Failed to load dsound.dll\n"); + return ALC_FALSE; + } + +#define LOAD_FUNC(f) do { \ + p##f = GetSymbol(ds_handle, #f); \ + if(p##f == NULL) { \ + CloseLib(ds_handle); \ + ds_handle = NULL; \ + return ALC_FALSE; \ + } \ +} while(0) + LOAD_FUNC(DirectSoundCreate); + LOAD_FUNC(DirectSoundEnumerateA); + LOAD_FUNC(DirectSoundCaptureCreate); + LOAD_FUNC(DirectSoundCaptureEnumerateA); +#undef LOAD_FUNC + } + return ALC_TRUE; +} + + +static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data) +{ + LPOLESTR guidstr = NULL; + char str[1024]; + HRESULT hr; + void *temp; + int count; + ALuint i; + + (void)data; + (void)drvname; + + if(!guid) + return TRUE; + + count = 0; + do { + if(count == 0) + snprintf(str, sizeof(str), "%s", desc); + else + snprintf(str, sizeof(str), "%s #%d", desc, count+1); + count++; + + for(i = 0;i < NumPlaybackDevices;i++) + { + if(strcmp(str, PlaybackDeviceList[i].name) == 0) + break; + } + } while(i != NumPlaybackDevices); + + hr = StringFromCLSID(guid, &guidstr); + if(SUCCEEDED(hr)) + { + TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr); + CoTaskMemFree(guidstr); + } + + temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1)); + if(temp) + { + PlaybackDeviceList = temp; + PlaybackDeviceList[NumPlaybackDevices].name = strdup(str); + PlaybackDeviceList[NumPlaybackDevices].guid = *guid; + NumPlaybackDevices++; + } + + return TRUE; +} + + +static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data) +{ + LPOLESTR guidstr = NULL; + char str[1024]; + HRESULT hr; + void *temp; + int count; + ALuint i; + + (void)data; + (void)drvname; + + if(!guid) + return TRUE; + + count = 0; + do { + if(count == 0) + snprintf(str, sizeof(str), "%s", desc); + else + snprintf(str, sizeof(str), "%s #%d", desc, count+1); + count++; + + for(i = 0;i < NumCaptureDevices;i++) + { + if(strcmp(str, CaptureDeviceList[i].name) == 0) + break; + } + } while(i != NumCaptureDevices); + + hr = StringFromCLSID(guid, &guidstr); + if(SUCCEEDED(hr)) + { + TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr); + CoTaskMemFree(guidstr); + } + + temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1)); + if(temp) + { + CaptureDeviceList = temp; + CaptureDeviceList[NumCaptureDevices].name = strdup(str); + CaptureDeviceList[NumCaptureDevices].guid = *guid; + NumCaptureDevices++; + } + + return TRUE; +} + + +static ALuint DSoundPlaybackProc(ALvoid *ptr) +{ + ALCdevice *Device = (ALCdevice*)ptr; + DSoundPlaybackData *data = (DSoundPlaybackData*)Device->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(data->Buffer, &DSBCaps); + if(FAILED(err)) + { + ERR("Failed to get buffer caps: 0x%lx\n", err); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + return 1; + } + + FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + FragSize = Device->UpdateSize * FrameSize; + + IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &LastCursor, NULL); + while(!data->killNow) + { + // Get current play cursor + IDirectSoundBuffer_GetCurrentPosition(data->Buffer, &PlayCursor, NULL); + avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; + + if(avail < FragSize) + { + if(!Playing) + { + err = IDirectSoundBuffer_Play(data->Buffer, 0, 0, DSBPLAY_LOOPING); + if(FAILED(err)) + { + ERR("Failed to play buffer: 0x%lx\n", err); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + return 1; + } + Playing = TRUE; + } + + avail = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE); + if(avail != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); + continue; + } + avail -= avail%FragSize; + + // Lock output buffer + WriteCnt1 = 0; + WriteCnt2 = 0; + err = IDirectSoundBuffer_Lock(data->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); + + // If the buffer is lost, restore it and lock + if(err == DSERR_BUFFERLOST) + { + WARN("Buffer lost, restoring...\n"); + err = IDirectSoundBuffer_Restore(data->Buffer); + if(SUCCEEDED(err)) + { + Playing = FALSE; + LastCursor = 0; + err = IDirectSoundBuffer_Lock(data->Buffer, 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(Device, WritePtr1, WriteCnt1/FrameSize); + aluMixData(Device, WritePtr2, WriteCnt2/FrameSize); + + // Unlock output buffer only when successfully locked + IDirectSoundBuffer_Unlock(data->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); + } + else + { + ERR("Buffer lock error: %#lx\n", err); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + return 1; + } + + // Update old write cursor location + LastCursor += WriteCnt1+WriteCnt2; + LastCursor %= DSBCaps.dwBufferBytes; + } + + return 0; +} + +static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) +{ + DSoundPlaybackData *data = NULL; + LPGUID guid = NULL; + HRESULT hr; + + if(!PlaybackDeviceList) + { + hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL); + if(FAILED(hr)) + ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); + } + + if(!deviceName && NumPlaybackDevices > 0) + { + deviceName = PlaybackDeviceList[0].name; + guid = &PlaybackDeviceList[0].guid; + } + else + { + ALuint i; + + for(i = 0;i < NumPlaybackDevices;i++) + { + if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0) + { + guid = &PlaybackDeviceList[i].guid; + break; + } + } + if(i == NumPlaybackDevices) + return ALC_INVALID_VALUE; + } + + //Initialise requested device + data = calloc(1, sizeof(DSoundPlaybackData)); + if(!data) + return ALC_OUT_OF_MEMORY; + + hr = DS_OK; + data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(data->NotifyEvent == NULL) + hr = E_FAIL; + + //DirectSound Init code + if(SUCCEEDED(hr)) + hr = DirectSoundCreate(guid, &data->DS, NULL); + if(SUCCEEDED(hr)) + hr = IDirectSound_SetCooperativeLevel(data->DS, GetForegroundWindow(), DSSCL_PRIORITY); + if(FAILED(hr)) + { + if(data->DS) + IDirectSound_Release(data->DS); + if(data->NotifyEvent) + CloseHandle(data->NotifyEvent); + free(data); + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_NO_ERROR; +} + +static void DSoundClosePlayback(ALCdevice *device) +{ + DSoundPlaybackData *data = device->ExtraData; + + if(data->Notifies) + IDirectSoundNotify_Release(data->Notifies); + data->Notifies = NULL; + if(data->Buffer) + IDirectSoundBuffer_Release(data->Buffer); + data->Buffer = NULL; + if(data->PrimaryBuffer != NULL) + IDirectSoundBuffer_Release(data->PrimaryBuffer); + data->PrimaryBuffer = NULL; + + IDirectSound_Release(data->DS); + CloseHandle(data->NotifyEvent); + free(data); + device->ExtraData = NULL; +} + +static ALCboolean DSoundResetPlayback(ALCdevice *device) +{ + DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData; + DSBUFFERDESC DSBDescription; + WAVEFORMATEXTENSIBLE OutputType; + DWORD speakers; + HRESULT hr; + + memset(&OutputType, 0, sizeof(OutputType)); + + if(data->Notifies) + IDirectSoundNotify_Release(data->Notifies); + data->Notifies = NULL; + if(data->Buffer) + IDirectSoundBuffer_Release(data->Buffer); + data->Buffer = NULL; + if(data->PrimaryBuffer != NULL) + IDirectSoundBuffer_Release(data->PrimaryBuffer); + data->PrimaryBuffer = NULL; + + switch(device->FmtType) + { + case DevFmtByte: + device->FmtType = DevFmtUByte; + break; + case DevFmtFloat: + if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) + break; + /* fall-through */ + case DevFmtUShort: + device->FmtType = DevFmtShort; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + break; + } + + hr = IDirectSound_GetSpeakerConfig(data->DS, &speakers); + if(SUCCEEDED(hr)) + { + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + { + speakers = DSSPEAKER_CONFIG(speakers); + if(speakers == DSSPEAKER_MONO) + device->FmtChans = DevFmtMono; + else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) + device->FmtChans = DevFmtStereo; + else if(speakers == DSSPEAKER_QUAD) + device->FmtChans = DevFmtQuad; + else if(speakers == DSSPEAKER_5POINT1) + device->FmtChans = DevFmtX51; + else if(speakers == DSSPEAKER_7POINT1) + device->FmtChans = DevFmtX71; + else + ERR("Unknown system speaker config: 0x%lx\n", speakers); + } + + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtStereo: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51Side: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX61: + OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_CENTER | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case 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; + break; + } + +retry_open: + hr = S_OK; + 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 || device->FmtType == DevFmtFloat) + { + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + if(device->FmtType == DevFmtFloat) + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + if(data->PrimaryBuffer) + IDirectSoundBuffer_Release(data->PrimaryBuffer); + data->PrimaryBuffer = NULL; + } + else + { + if(SUCCEEDED(hr) && !data->PrimaryBuffer) + { + memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); + DSBDescription.dwSize=sizeof(DSBUFFERDESC); + DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; + hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->PrimaryBuffer, NULL); + } + if(SUCCEEDED(hr)) + hr = IDirectSoundBuffer_SetFormat(data->PrimaryBuffer,&OutputType.Format); + } + + if(SUCCEEDED(hr)) + { + if(device->NumUpdates > MAX_UPDATES) + { + device->UpdateSize = (device->UpdateSize*device->NumUpdates + + MAX_UPDATES-1) / MAX_UPDATES; + device->NumUpdates = MAX_UPDATES; + } + + memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); + DSBDescription.dwSize=sizeof(DSBUFFERDESC); + DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS; + DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates * + OutputType.Format.nBlockAlign; + DSBDescription.lpwfxFormat=&OutputType.Format; + hr = IDirectSound_CreateSoundBuffer(data->DS, &DSBDescription, &data->Buffer, NULL); + if(FAILED(hr) && device->FmtType == DevFmtFloat) + { + device->FmtType = DevFmtShort; + goto retry_open; + } + } + + if(SUCCEEDED(hr)) + { + hr = IDirectSoundBuffer_QueryInterface(data->Buffer, &IID_IDirectSoundNotify, (LPVOID *)&data->Notifies); + if(SUCCEEDED(hr)) + { + DSBPOSITIONNOTIFY notifies[MAX_UPDATES]; + ALuint i; + + for(i = 0;i < device->NumUpdates;++i) + { + notifies[i].dwOffset = i * device->UpdateSize * + OutputType.Format.nBlockAlign; + notifies[i].hEventNotify = data->NotifyEvent; + } + if(IDirectSoundNotify_SetNotificationPositions(data->Notifies, device->NumUpdates, notifies) != DS_OK) + hr = E_FAIL; + } + } + + if(FAILED(hr)) + { + if(data->Notifies != NULL) + IDirectSoundNotify_Release(data->Notifies); + data->Notifies = NULL; + if(data->Buffer != NULL) + IDirectSoundBuffer_Release(data->Buffer); + data->Buffer = NULL; + if(data->PrimaryBuffer != NULL) + IDirectSoundBuffer_Release(data->PrimaryBuffer); + data->PrimaryBuffer = NULL; + return ALC_FALSE; + } + + ResetEvent(data->NotifyEvent); + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean DSoundStartPlayback(ALCdevice *device) +{ + DSoundPlaybackData *data = (DSoundPlaybackData*)device->ExtraData; + + data->thread = StartThread(DSoundPlaybackProc, device); + if(data->thread == NULL) + return ALC_FALSE; + + return ALC_TRUE; +} + +static void DSoundStopPlayback(ALCdevice *device) +{ + DSoundPlaybackData *data = device->ExtraData; + + if(!data->thread) + return; + + data->killNow = 1; + StopThread(data->thread); + data->thread = NULL; + + data->killNow = 0; + IDirectSoundBuffer_Stop(data->Buffer); +} + + +static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName) +{ + DSoundCaptureData *data = NULL; + WAVEFORMATEXTENSIBLE InputType; + DSCBUFFERDESC DSCBDescription; + LPGUID guid = NULL; + HRESULT hr, hrcom; + ALuint samples; + + if(!CaptureDeviceList) + { + /* Initialize COM to prevent name truncation */ + hrcom = CoInitialize(NULL); + hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL); + if(FAILED(hr)) + ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); + if(SUCCEEDED(hrcom)) + CoUninitialize(); + } + + if(!deviceName && NumCaptureDevices > 0) + { + deviceName = CaptureDeviceList[0].name; + guid = &CaptureDeviceList[0].guid; + } + else + { + ALuint i; + + for(i = 0;i < NumCaptureDevices;i++) + { + if(strcmp(deviceName, CaptureDeviceList[i].name) == 0) + { + guid = &CaptureDeviceList[i].guid; + break; + } + } + if(i == NumCaptureDevices) + return ALC_INVALID_VALUE; + } + + switch(device->FmtType) + { + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_ENUM; + + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + } + + //Initialise requested device + data = calloc(1, sizeof(DSoundCaptureData)); + if(!data) + return ALC_OUT_OF_MEMORY; + + hr = DS_OK; + + //DirectSoundCapture Init code + if(SUCCEEDED(hr)) + hr = DirectSoundCaptureCreate(guid, &data->DSC, NULL); + if(SUCCEEDED(hr)) + { + memset(&InputType, 0, sizeof(InputType)); + + switch(device->FmtChans) + { + case DevFmtMono: + InputType.dwChannelMask = SPEAKER_FRONT_CENTER; + break; + case DevFmtStereo: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT; + break; + case DevFmtQuad: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; + break; + case DevFmtX51Side: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX61: + InputType.dwChannelMask = SPEAKER_FRONT_LEFT | + SPEAKER_FRONT_RIGHT | + SPEAKER_FRONT_CENTER | + SPEAKER_LOW_FREQUENCY | + SPEAKER_BACK_CENTER | + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; + break; + case DevFmtX71: + InputType.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; + break; + } + + InputType.Format.wFormatTag = WAVE_FORMAT_PCM; + InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans); + InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8; + InputType.Format.nSamplesPerSec = device->Frequency; + InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign; + InputType.Format.cbSize = 0; + + if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) + { + InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample; + if(device->FmtType == DevFmtFloat) + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + + samples = device->UpdateSize * device->NumUpdates; + samples = maxu(samples, 100 * device->Frequency / 1000); + + memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC)); + DSCBDescription.dwSize = sizeof(DSCBUFFERDESC); + DSCBDescription.dwFlags = 0; + DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign; + DSCBDescription.lpwfxFormat = &InputType.Format; + + hr = IDirectSoundCapture_CreateCaptureBuffer(data->DSC, &DSCBDescription, &data->DSCbuffer, NULL); + } + if(SUCCEEDED(hr)) + { + data->Ring = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates); + if(data->Ring == NULL) + hr = DSERR_OUTOFMEMORY; + } + + if(FAILED(hr)) + { + ERR("Device init failed: 0x%08lx\n", hr); + + DestroyRingBuffer(data->Ring); + data->Ring = NULL; + if(data->DSCbuffer != NULL) + IDirectSoundCaptureBuffer_Release(data->DSCbuffer); + data->DSCbuffer = NULL; + if(data->DSC) + IDirectSoundCapture_Release(data->DSC); + data->DSC = NULL; + + free(data); + return ALC_INVALID_VALUE; + } + + data->BufferBytes = DSCBDescription.dwBufferBytes; + SetDefaultWFXChannelOrder(device); + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + + return ALC_NO_ERROR; +} + +static void DSoundCloseCapture(ALCdevice *device) +{ + DSoundCaptureData *data = device->ExtraData; + + DestroyRingBuffer(data->Ring); + data->Ring = NULL; + + if(data->DSCbuffer != NULL) + { + IDirectSoundCaptureBuffer_Stop(data->DSCbuffer); + IDirectSoundCaptureBuffer_Release(data->DSCbuffer); + data->DSCbuffer = NULL; + } + + IDirectSoundCapture_Release(data->DSC); + data->DSC = NULL; + + free(data); + device->ExtraData = NULL; +} + +static void DSoundStartCapture(ALCdevice *device) +{ + DSoundCaptureData *data = device->ExtraData; + HRESULT hr; + + hr = IDirectSoundCaptureBuffer_Start(data->DSCbuffer, DSCBSTART_LOOPING); + if(FAILED(hr)) + { + ERR("start failed: 0x%08lx\n", hr); + aluHandleDisconnect(device); + } +} + +static void DSoundStopCapture(ALCdevice *device) +{ + DSoundCaptureData *data = device->ExtraData; + HRESULT hr; + + hr = IDirectSoundCaptureBuffer_Stop(data->DSCbuffer); + if(FAILED(hr)) + { + ERR("stop failed: 0x%08lx\n", hr); + aluHandleDisconnect(device); + } +} + +static ALCenum DSoundCaptureSamples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples) +{ + DSoundCaptureData *data = Device->ExtraData; + ReadRingBuffer(data->Ring, pBuffer, lSamples); + return ALC_NO_ERROR; +} + +static ALCuint DSoundAvailableSamples(ALCdevice *Device) +{ + DSoundCaptureData *data = Device->ExtraData; + DWORD ReadCursor, LastCursor, BufferBytes, NumBytes; + VOID *ReadPtr1, *ReadPtr2; + DWORD ReadCnt1, ReadCnt2; + DWORD FrameSize; + HRESULT hr; + + if(!Device->Connected) + goto done; + + FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + BufferBytes = data->BufferBytes; + LastCursor = data->Cursor; + + hr = IDirectSoundCaptureBuffer_GetCurrentPosition(data->DSCbuffer, NULL, &ReadCursor); + if(SUCCEEDED(hr)) + { + NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes; + if(NumBytes == 0) + goto done; + hr = IDirectSoundCaptureBuffer_Lock(data->DSCbuffer, LastCursor, NumBytes, + &ReadPtr1, &ReadCnt1, + &ReadPtr2, &ReadCnt2, 0); + } + if(SUCCEEDED(hr)) + { + WriteRingBuffer(data->Ring, ReadPtr1, ReadCnt1/FrameSize); + if(ReadPtr2 != NULL) + WriteRingBuffer(data->Ring, ReadPtr2, ReadCnt2/FrameSize); + hr = IDirectSoundCaptureBuffer_Unlock(data->DSCbuffer, + ReadPtr1, ReadCnt1, + ReadPtr2, ReadCnt2); + data->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; + } + + if(FAILED(hr)) + { + ERR("update failed: 0x%08lx\n", hr); + aluHandleDisconnect(Device); + } + +done: + return RingBufferSize(data->Ring); +} + + +static const BackendFuncs DSoundFuncs = { + DSoundOpenPlayback, + DSoundClosePlayback, + DSoundResetPlayback, + DSoundStartPlayback, + DSoundStopPlayback, + DSoundOpenCapture, + DSoundCloseCapture, + DSoundStartCapture, + DSoundStopCapture, + DSoundCaptureSamples, + DSoundAvailableSamples, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + + +ALCboolean alcDSoundInit(BackendFuncs *FuncList) +{ + if(!DSoundLoad()) + return ALC_FALSE; + *FuncList = DSoundFuncs; + return ALC_TRUE; +} + +void alcDSoundDeinit(void) +{ + ALuint i; + + for(i = 0;i < NumPlaybackDevices;++i) + free(PlaybackDeviceList[i].name); + free(PlaybackDeviceList); + PlaybackDeviceList = NULL; + NumPlaybackDevices = 0; + + for(i = 0;i < NumCaptureDevices;++i) + free(CaptureDeviceList[i].name); + free(CaptureDeviceList); + CaptureDeviceList = NULL; + NumCaptureDevices = 0; + + if(ds_handle) + CloseLib(ds_handle); + ds_handle = NULL; +} + +void alcDSoundProbe(enum DevProbe type) +{ + HRESULT hr, hrcom; + ALuint i; + + switch(type) + { + case ALL_DEVICE_PROBE: + for(i = 0;i < NumPlaybackDevices;++i) + free(PlaybackDeviceList[i].name); + free(PlaybackDeviceList); + PlaybackDeviceList = NULL; + NumPlaybackDevices = 0; + + hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL); + if(FAILED(hr)) + ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr); + else + { + for(i = 0;i < NumPlaybackDevices;i++) + AppendAllDevicesList(PlaybackDeviceList[i].name); + } + break; + + case CAPTURE_DEVICE_PROBE: + for(i = 0;i < NumCaptureDevices;++i) + free(CaptureDeviceList[i].name); + free(CaptureDeviceList); + CaptureDeviceList = NULL; + NumCaptureDevices = 0; + + /* Initialize COM to prevent name truncation */ + hrcom = CoInitialize(NULL); + hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL); + if(FAILED(hr)) + ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr); + else + { + for(i = 0;i < NumCaptureDevices;i++) + AppendCaptureDeviceList(CaptureDeviceList[i].name); + } + if(SUCCEEDED(hrcom)) + CoUninitialize(); + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/loopback.c b/src/eepp/helper/android/openal-soft/Alc/backends/loopback.c new file mode 100644 index 000000000..e1bdd3c12 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/loopback.c @@ -0,0 +1,88 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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 "alu.h" + + +static ALCenum loopback_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + device->DeviceName = strdup(deviceName); + return ALC_NO_ERROR; +} + +static void loopback_close_playback(ALCdevice *device) +{ + (void)device; +} + +static ALCboolean loopback_reset_playback(ALCdevice *device) +{ + SetDefaultWFXChannelOrder(device); + return ALC_TRUE; +} + +static ALCboolean loopback_start_playback(ALCdevice *device) +{ + return ALC_TRUE; + (void)device; +} + +static void loopback_stop_playback(ALCdevice *device) +{ + (void)device; +} + + +static const BackendFuncs loopback_funcs = { + loopback_open_playback, + loopback_close_playback, + loopback_reset_playback, + loopback_start_playback, + loopback_stop_playback, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_loopback_init(BackendFuncs *func_list) +{ + *func_list = loopback_funcs; + return ALC_TRUE; +} + +void alc_loopback_deinit(void) +{ +} + +void alc_loopback_probe(enum DevProbe type) +{ + (void)type; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/mmdevapi.c b/src/eepp/helper/android/openal-soft/Alc/backends/mmdevapi.c new file mode 100644 index 000000000..9c934095d --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/mmdevapi.c @@ -0,0 +1,1039 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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 COBJMACROS +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _WAVEFORMATEXTENSIBLE_ +#include +#include +#endif + +#include "alMain.h" +#include "alu.h" + + +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); + +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); + +#define MONO SPEAKER_FRONT_CENTER +#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) +#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) +#define X5DOT1SIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) + + +typedef struct { + WCHAR *devid; + + IMMDevice *mmdev; + IAudioClient *client; + IAudioRenderClient *render; + HANDLE NotifyEvent; + + HANDLE MsgEvent; + + volatile UINT32 Padding; + + volatile int killNow; + ALvoid *thread; +} MMDevApiData; + + +typedef struct { + ALCchar *name; + WCHAR *devid; +} DevMap; + +static DevMap *PlaybackDeviceList; +static ALuint NumPlaybackDevices; +static DevMap *CaptureDeviceList; +static ALuint NumCaptureDevices; + + +static HANDLE ThreadHdl; +static DWORD ThreadID; + +typedef struct { + HANDLE FinishedEvt; + HRESULT result; +} ThreadRequest; + +#define WM_USER_OpenDevice (WM_USER+0) +#define WM_USER_ResetDevice (WM_USER+1) +#define WM_USER_StartDevice (WM_USER+2) +#define WM_USER_StopDevice (WM_USER+3) +#define WM_USER_CloseDevice (WM_USER+4) +#define WM_USER_Enumerate (WM_USER+5) + +static HRESULT WaitForResponse(ThreadRequest *req) +{ + if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0) + return req->result; + ERR("Message response error: %lu\n", GetLastError()); + return E_FAIL; +} + + +static ALCchar *get_device_name(IMMDevice *device) +{ + ALCchar *name = NULL; + IPropertyStore *ps; + PROPVARIANT pvname; + HRESULT hr; + int len; + + hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return calloc(1, 1); + } + + PropVariantInit(&pvname); + + hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname); + if(FAILED(hr)) + { + WARN("GetValue failed: 0x%08lx\n", hr); + name = calloc(1, 1); + } + else + { + if((len=WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, NULL, 0, NULL, NULL)) > 0) + { + name = calloc(1, len); + WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, name, len, NULL, NULL); + } + } + + PropVariantClear(&pvname); + IPropertyStore_Release(ps); + + return name; +} + +static void add_device(IMMDevice *device, DevMap *devmap) +{ + LPWSTR devid; + HRESULT hr; + + hr = IMMDevice_GetId(device, &devid); + if(SUCCEEDED(hr)) + { + devmap->devid = strdupW(devid); + devmap->name = get_device_name(device); + TRACE("Got device \"%s\", \"%ls\"\n", devmap->name, devmap->devid); + CoTaskMemFree(devid); + } +} + +static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALuint *numdevs) +{ + IMMDeviceCollection *coll; + IMMDevice *defdev = NULL; + DevMap *devlist = NULL; + HRESULT hr; + UINT count; + UINT idx; + UINT i; + + hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll); + if(FAILED(hr)) + { + ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr); + return NULL; + } + + idx = count = 0; + hr = IMMDeviceCollection_GetCount(coll, &count); + if(SUCCEEDED(hr) && count > 0) + { + devlist = calloc(count, sizeof(*devlist)); + if(!devlist) + { + IMMDeviceCollection_Release(coll); + return NULL; + } + + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir, + eMultimedia, &defdev); + } + if(SUCCEEDED(hr) && defdev != NULL) + add_device(defdev, &devlist[idx++]); + + for(i = 0;i < count && idx < count;++i) + { + IMMDevice *device; + + if(FAILED(IMMDeviceCollection_Item(coll, i, &device))) + continue; + + if(device != defdev) + add_device(device, &devlist[idx++]); + + IMMDevice_Release(device); + } + + if(defdev) IMMDevice_Release(defdev); + IMMDeviceCollection_Release(coll); + + *numdevs = idx; + return devlist; +} + + +static ALuint MMDevApiProc(ALvoid *ptr) +{ + ALCdevice *device = ptr; + MMDevApiData *data = device->ExtraData; + UINT32 buffer_len, written; + ALuint update_size, len; + BYTE *buffer; + HRESULT hr; + + hr = CoInitialize(NULL); + if(FAILED(hr)) + { + ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); + ALCdevice_Lock(device); + aluHandleDisconnect(device); + ALCdevice_Unlock(device); + return 0; + } + + SetRTPriority(); + + update_size = device->UpdateSize; + buffer_len = update_size * device->NumUpdates; + while(!data->killNow) + { + hr = IAudioClient_GetCurrentPadding(data->client, &written); + if(FAILED(hr)) + { + ERR("Failed to get padding: 0x%08lx\n", hr); + ALCdevice_Lock(device); + aluHandleDisconnect(device); + ALCdevice_Unlock(device); + break; + } + data->Padding = written; + + len = buffer_len - written; + if(len < update_size) + { + DWORD res; + res = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE); + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + continue; + } + len -= len%update_size; + + hr = IAudioRenderClient_GetBuffer(data->render, len, &buffer); + if(SUCCEEDED(hr)) + { + ALCdevice_Lock(device); + aluMixData(device, buffer, len); + data->Padding = written + len; + ALCdevice_Unlock(device); + hr = IAudioRenderClient_ReleaseBuffer(data->render, len, 0); + } + if(FAILED(hr)) + { + ERR("Failed to buffer data: 0x%08lx\n", hr); + ALCdevice_Lock(device); + aluHandleDisconnect(device); + ALCdevice_Unlock(device); + break; + } + } + data->Padding = 0; + + CoUninitialize(); + return 0; +} + + +static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in) +{ + memset(out, 0, sizeof(*out)); + if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + *out = *(const WAVEFORMATEXTENSIBLE*)in; + else if(in->wFormatTag == WAVE_FORMAT_PCM) + { + out->Format = *in; + out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + out->Format.cbSize = sizeof(*out) - sizeof(*in); + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + out->Format = *in; + out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + out->Format.cbSize = sizeof(*out) - sizeof(*in); + if(out->Format.nChannels == 1) + out->dwChannelMask = MONO; + else if(out->Format.nChannels == 2) + out->dwChannelMask = STEREO; + else + ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels); + out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + } + else + { + ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag); + return ALC_FALSE; + } + return ALC_TRUE; +} + +static HRESULT DoReset(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + WAVEFORMATEXTENSIBLE OutputType; + WAVEFORMATEX *wfx = NULL; + REFERENCE_TIME min_per, buf_time; + UINT32 buffer_len, min_len; + HRESULT hr; + + hr = IAudioClient_GetMixFormat(data->client, &wfx); + if(FAILED(hr)) + { + ERR("Failed to get mix format: 0x%08lx\n", hr); + return hr; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = NULL; + + buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 + + device->Frequency-1) / device->Frequency; + + if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) + device->Frequency = OutputType.Format.nSamplesPerSec; + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + { + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + device->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + device->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + device->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + device->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE) + device->FmtChans = DevFmtX51Side; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + device->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1) + device->FmtChans = DevFmtX71; + else + ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + } + + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Side: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1SIDE; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + } + switch(device->FmtType) + { + case DevFmtByte: + device->FmtType = DevFmtUByte; + /* fall-through */ + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.Samples.wValidBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUShort: + device->FmtType = DevFmtShort; + /* fall-through */ + case DevFmtShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.Samples.wValidBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtUInt: + device->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + } + OutputType.Format.nSamplesPerSec = device->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + + hr = IAudioClient_IsFormatSupported(data->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + hr = IAudioClient_GetMixFormat(data->client, &wfx); + } + if(FAILED(hr)) + { + ERR("Failed to find a supported format: 0x%08lx\n", hr); + return hr; + } + + if(wfx != NULL) + { + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = NULL; + + device->Frequency = OutputType.Format.nSamplesPerSec; + if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) + device->FmtChans = DevFmtMono; + else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO) + device->FmtChans = DevFmtStereo; + else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD) + device->FmtChans = DevFmtQuad; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) + device->FmtChans = DevFmtX51; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE) + device->FmtChans = DevFmtX51Side; + else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) + device->FmtChans = DevFmtX61; + else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1) + device->FmtChans = DevFmtX71; + else + { + ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); + device->FmtChans = DevFmtStereo; + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + } + + if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) + { + if(OutputType.Format.wBitsPerSample == 8) + device->FmtType = DevFmtUByte; + else if(OutputType.Format.wBitsPerSample == 16) + device->FmtType = DevFmtShort; + else if(OutputType.Format.wBitsPerSample == 32) + device->FmtType = DevFmtInt; + else + { + device->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + } + } + else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + device->FmtType = DevFmtFloat; + OutputType.Format.wBitsPerSample = 32; + } + else + { + ERR("Unhandled format sub-type\n"); + device->FmtType = DevFmtShort; + OutputType.Format.wBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } + OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; + } + + SetDefaultWFXChannelOrder(device); + + hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, NULL); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + hr = IAudioClient_GetDevicePeriod(data->client, &min_per, NULL); + if(SUCCEEDED(hr)) + { + min_len = (UINT32)((min_per*device->Frequency + 10000000-1) / 10000000); + /* Find the nearest multiple of the period size to the update size */ + if(min_len < device->UpdateSize) + min_len *= (device->UpdateSize + min_len/2)/min_len; + hr = IAudioClient_GetBufferSize(data->client, &buffer_len); + } + if(FAILED(hr)) + { + ERR("Failed to get audio buffer info: 0x%08lx\n", hr); + return hr; + } + + device->UpdateSize = min_len; + device->NumUpdates = buffer_len / device->UpdateSize; + if(device->NumUpdates <= 1) + { + ERR("Audio client returned buffer_len < period*2; expect break up\n"); + device->NumUpdates = 2; + device->UpdateSize = buffer_len / device->NumUpdates; + } + + return hr; +} + + +static DWORD CALLBACK MMDevApiMsgProc(void *ptr) +{ + ThreadRequest *req = ptr; + IMMDeviceEnumerator *Enumerator; + ALuint deviceCount = 0; + MMDevApiData *data; + ALCdevice *device; + HRESULT hr, cohr; + MSG msg; + + TRACE("Starting message thread\n"); + + cohr = CoInitialize(NULL); + if(FAILED(cohr)) + { + WARN("Failed to initialize COM: 0x%08lx\n", cohr); + req->result = cohr; + SetEvent(req->FinishedEvt); + return 0; + } + + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(FAILED(hr)) + { + WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr); + CoUninitialize(); + req->result = hr; + SetEvent(req->FinishedEvt); + return 0; + } + Enumerator = ptr; + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + + CoUninitialize(); + + req->result = S_OK; + SetEvent(req->FinishedEvt); + + TRACE("Starting message loop\n"); + while(GetMessage(&msg, NULL, 0, 0)) + { + TRACE("Got message %u\n", msg.message); + switch(msg.message) + { + case WM_USER_OpenDevice: + req = (ThreadRequest*)msg.wParam; + device = (ALCdevice*)msg.lParam; + data = device->ExtraData; + + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitialize(NULL); + if(SUCCEEDED(hr)) + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + Enumerator = ptr; + if(!data->devid) + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev); + else + hr = IMMDeviceEnumerator_GetDevice(Enumerator, data->devid, &data->mmdev); + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + } + if(SUCCEEDED(hr)) + hr = IMMDevice_Activate(data->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + if(SUCCEEDED(hr)) + { + data->client = ptr; + device->DeviceName = get_device_name(data->mmdev); + } + + if(FAILED(hr)) + { + if(data->mmdev) + IMMDevice_Release(data->mmdev); + data->mmdev = NULL; + if(--deviceCount == 0 && SUCCEEDED(cohr)) + CoUninitialize(); + } + + req->result = hr; + SetEvent(req->FinishedEvt); + continue; + + case WM_USER_ResetDevice: + req = (ThreadRequest*)msg.wParam; + device = (ALCdevice*)msg.lParam; + + req->result = DoReset(device); + SetEvent(req->FinishedEvt); + continue; + + case WM_USER_StartDevice: + req = (ThreadRequest*)msg.wParam; + device = (ALCdevice*)msg.lParam; + data = device->ExtraData; + + ResetEvent(data->NotifyEvent); + hr = IAudioClient_SetEventHandle(data->client, data->NotifyEvent); + if(FAILED(hr)) + ERR("Failed to set event handle: 0x%08lx\n", hr); + else + { + hr = IAudioClient_Start(data->client); + if(FAILED(hr)) + ERR("Failed to start audio client: 0x%08lx\n", hr); + } + + if(SUCCEEDED(hr)) + hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr); + if(SUCCEEDED(hr)) + { + data->render = ptr; + data->thread = StartThread(MMDevApiProc, device); + if(!data->thread) + { + if(data->render) + IAudioRenderClient_Release(data->render); + data->render = NULL; + IAudioClient_Stop(data->client); + ERR("Failed to start thread\n"); + hr = E_FAIL; + } + } + + req->result = hr; + SetEvent(req->FinishedEvt); + continue; + + case WM_USER_StopDevice: + req = (ThreadRequest*)msg.wParam; + device = (ALCdevice*)msg.lParam; + data = device->ExtraData; + + if(data->thread) + { + data->killNow = 1; + StopThread(data->thread); + data->thread = NULL; + + data->killNow = 0; + + IAudioRenderClient_Release(data->render); + data->render = NULL; + IAudioClient_Stop(data->client); + } + + req->result = S_OK; + SetEvent(req->FinishedEvt); + continue; + + case WM_USER_CloseDevice: + req = (ThreadRequest*)msg.wParam; + device = (ALCdevice*)msg.lParam; + data = device->ExtraData; + + IAudioClient_Release(data->client); + data->client = NULL; + + IMMDevice_Release(data->mmdev); + data->mmdev = NULL; + + if(--deviceCount == 0) + CoUninitialize(); + + req->result = S_OK; + SetEvent(req->FinishedEvt); + continue; + + case WM_USER_Enumerate: + req = (ThreadRequest*)msg.wParam; + + hr = cohr = S_OK; + if(++deviceCount == 1) + hr = cohr = CoInitialize(NULL); + if(SUCCEEDED(hr)) + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + EDataFlow flowdir; + DevMap **devlist; + ALuint *numdevs; + ALuint i; + + Enumerator = ptr; + if(msg.lParam == CAPTURE_DEVICE_PROBE) + { + flowdir = eCapture; + devlist = &CaptureDeviceList; + numdevs = &NumCaptureDevices; + } + else + { + flowdir = eRender; + devlist = &PlaybackDeviceList; + numdevs = &NumPlaybackDevices; + } + + for(i = 0;i < *numdevs;i++) + { + free((*devlist)[i].name); + free((*devlist)[i].devid); + } + free(*devlist); + *devlist = NULL; + *numdevs = 0; + + *devlist = ProbeDevices(Enumerator, flowdir, numdevs); + + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + } + + if(--deviceCount == 0 && SUCCEEDED(cohr)) + CoUninitialize(); + + req->result = S_OK; + SetEvent(req->FinishedEvt); + continue; + + default: + ERR("Unexpected message: %u\n", msg.message); + continue; + } + } + TRACE("Message loop finished\n"); + + return 0; +} + + +static BOOL MMDevApiLoad(void) +{ + static HRESULT InitResult; + if(!ThreadHdl) + { + ThreadRequest req; + InitResult = E_FAIL; + + req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL); + if(req.FinishedEvt == NULL) + ERR("Failed to create event: %lu\n", GetLastError()); + else + { + ThreadHdl = CreateThread(NULL, 0, MMDevApiMsgProc, &req, 0, &ThreadID); + if(ThreadHdl != NULL) + InitResult = WaitForResponse(&req); + CloseHandle(req.FinishedEvt); + } + } + return SUCCEEDED(InitResult); +} + + +static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName) +{ + MMDevApiData *data = NULL; + HRESULT hr; + + //Initialise requested device + data = calloc(1, sizeof(MMDevApiData)); + if(!data) + return ALC_OUT_OF_MEMORY; + device->ExtraData = data; + + hr = S_OK; + data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + data->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(data->NotifyEvent == NULL || data->MsgEvent == NULL) + hr = E_FAIL; + + if(SUCCEEDED(hr)) + { + if(deviceName) + { + ALuint i; + + if(!PlaybackDeviceList) + { + ThreadRequest req = { data->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE)) + (void)WaitForResponse(&req); + } + + hr = E_FAIL; + for(i = 0;i < NumPlaybackDevices;i++) + { + if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0) + { + data->devid = strdupW(PlaybackDeviceList[i].devid); + hr = S_OK; + break; + } + } + } + } + + if(SUCCEEDED(hr)) + { + ThreadRequest req = { data->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)device)) + hr = WaitForResponse(&req); + } + + if(FAILED(hr)) + { + if(data->NotifyEvent != NULL) + CloseHandle(data->NotifyEvent); + data->NotifyEvent = NULL; + if(data->MsgEvent != NULL) + CloseHandle(data->MsgEvent); + data->MsgEvent = NULL; + + free(data); + device->ExtraData = NULL; + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + + return ALC_NO_ERROR; +} + +static void MMDevApiClosePlayback(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + ThreadRequest req = { data->MsgEvent, 0 }; + + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)device)) + (void)WaitForResponse(&req); + + CloseHandle(data->MsgEvent); + data->MsgEvent = NULL; + + CloseHandle(data->NotifyEvent); + data->NotifyEvent = NULL; + + free(data->devid); + data->devid = NULL; + + free(data); + device->ExtraData = NULL; +} + +static ALCboolean MMDevApiResetPlayback(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + ThreadRequest req = { data->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)device)) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static ALCboolean MMDevApiStartPlayback(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + ThreadRequest req = { data->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)device)) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static void MMDevApiStopPlayback(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + ThreadRequest req = { data->MsgEvent, 0 }; + + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)device)) + (void)WaitForResponse(&req); +} + + +static ALint64 MMDevApiGetLatency(ALCdevice *device) +{ + MMDevApiData *data = device->ExtraData; + + return (ALint64)data->Padding * 1000000000 / device->Frequency; +} + + +static const BackendFuncs MMDevApiFuncs = { + MMDevApiOpenPlayback, + MMDevApiClosePlayback, + MMDevApiResetPlayback, + MMDevApiStartPlayback, + MMDevApiStopPlayback, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + MMDevApiGetLatency +}; + + +ALCboolean alcMMDevApiInit(BackendFuncs *FuncList) +{ + if(!MMDevApiLoad()) + return ALC_FALSE; + *FuncList = MMDevApiFuncs; + return ALC_TRUE; +} + +void alcMMDevApiDeinit(void) +{ + ALuint i; + + for(i = 0;i < NumPlaybackDevices;i++) + { + free(PlaybackDeviceList[i].name); + free(PlaybackDeviceList[i].devid); + } + free(PlaybackDeviceList); + PlaybackDeviceList = NULL; + NumPlaybackDevices = 0; + + for(i = 0;i < NumCaptureDevices;i++) + { + free(CaptureDeviceList[i].name); + free(CaptureDeviceList[i].devid); + } + free(CaptureDeviceList); + CaptureDeviceList = NULL; + NumCaptureDevices = 0; + + if(ThreadHdl) + { + TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID); + PostThreadMessage(ThreadID, WM_QUIT, 0, 0); + CloseHandle(ThreadHdl); + ThreadHdl = NULL; + } +} + +void alcMMDevApiProbe(enum DevProbe type) +{ + ThreadRequest req = { NULL, 0 }; + HRESULT hr = E_FAIL; + + switch(type) + { + case ALL_DEVICE_PROBE: + req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL); + if(req.FinishedEvt == NULL) + ERR("Failed to create event: %lu\n", GetLastError()); + else if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type)) + hr = WaitForResponse(&req); + if(SUCCEEDED(hr)) + { + ALuint i; + for(i = 0;i < NumPlaybackDevices;i++) + { + if(PlaybackDeviceList[i].name) + AppendAllDevicesList(PlaybackDeviceList[i].name); + } + } + break; + + case CAPTURE_DEVICE_PROBE: + break; + } + if(req.FinishedEvt != NULL) + CloseHandle(req.FinishedEvt); + req.FinishedEvt = NULL; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/null.c b/src/eepp/helper/android/openal-soft/Alc/backends/null.c new file mode 100644 index 000000000..93b38063a --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/null.c @@ -0,0 +1,172 @@ +/** + * 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 +#ifdef HAVE_WINDOWS_H +#include +#endif + +#include "alMain.h" +#include "alu.h" + + +typedef struct { + volatile int killNow; + ALvoid *thread; +} null_data; + + +static const ALCchar nullDevice[] = "No Output"; + +static ALuint NullProc(ALvoid *ptr) +{ + ALCdevice *Device = (ALCdevice*)ptr; + null_data *data = (null_data*)Device->ExtraData; + ALuint now, start; + ALuint64 avail, done; + const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 / + Device->Frequency / 2; + + done = 0; + start = timeGetTime(); + while(!data->killNow && Device->Connected) + { + now = timeGetTime(); + + avail = (ALuint64)(now-start) * Device->Frequency / 1000; + if(avail < done) + { + /* Timer wrapped (50 days???). Add the remainder of the cycle to + * the available count and reset the number of samples done */ + avail += ((ALuint64)1<<32)*Device->Frequency/1000 - done; + done = 0; + } + if(avail-done < Device->UpdateSize) + { + Sleep(restTime); + continue; + } + + while(avail-done >= Device->UpdateSize) + { + aluMixData(Device, NULL, Device->UpdateSize); + done += Device->UpdateSize; + } + } + + return 0; +} + +static ALCenum null_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + null_data *data; + + if(!deviceName) + deviceName = nullDevice; + else if(strcmp(deviceName, nullDevice) != 0) + return ALC_INVALID_VALUE; + + data = (null_data*)calloc(1, sizeof(*data)); + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_NO_ERROR; +} + +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) +{ + SetDefaultWFXChannelOrder(device); + return ALC_TRUE; +} + +static ALCboolean null_start_playback(ALCdevice *device) +{ + null_data *data = (null_data*)device->ExtraData; + + data->thread = StartThread(NullProc, device); + if(data->thread == 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; +} + + +static const BackendFuncs null_funcs = { + null_open_playback, + null_close_playback, + null_reset_playback, + null_start_playback, + null_stop_playback, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_null_init(BackendFuncs *func_list) +{ + *func_list = null_funcs; + return ALC_TRUE; +} + +void alc_null_deinit(void) +{ +} + +void alc_null_probe(enum DevProbe type) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + AppendAllDevicesList(nullDevice); + break; + case CAPTURE_DEVICE_PROBE: + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/opensl.c b/src/eepp/helper/android/openal-soft/Alc/backends/opensl.c new file mode 100644 index 000000000..1a1040293 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/opensl.c @@ -0,0 +1,449 @@ +/* + * 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 "config.h" + +#include + +#include "alMain.h" +#include "alu.h" + + +#include +#if 1 +#include +#else +extern SLAPIENTRY const SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + +struct SLAndroidSimpleBufferQueueItf_; +typedef const struct SLAndroidSimpleBufferQueueItf_ * const * SLAndroidSimpleBufferQueueItf; + +typedef void (*slAndroidSimpleBufferQueueCallback)(SLAndroidSimpleBufferQueueItf caller, void *pContext); + +typedef struct SLAndroidSimpleBufferQueueState_ { + SLuint32 count; + SLuint32 index; +} SLAndroidSimpleBufferQueueState; + + +struct SLAndroidSimpleBufferQueueItf_ { + SLresult (*Enqueue) ( + SLAndroidSimpleBufferQueueItf self, + const void *pBuffer, + SLuint32 size + ); + SLresult (*Clear) ( + SLAndroidSimpleBufferQueueItf self + ); + SLresult (*GetState) ( + SLAndroidSimpleBufferQueueItf self, + SLAndroidSimpleBufferQueueState *pState + ); + SLresult (*RegisterCallback) ( + SLAndroidSimpleBufferQueueItf self, + slAndroidSimpleBufferQueueCallback callback, + void* pContext + ); +}; + +#define SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE ((SLuint32) 0x800007BD) + +typedef struct SLDataLocator_AndroidSimpleBufferQueue { + SLuint32 locatorType; + SLuint32 numBuffers; +} SLDataLocator_AndroidSimpleBufferQueue; + +#endif + +/* Helper macros */ +#define SLObjectItf_Realize(a,b) ((*(a))->Realize((a),(b))) +#define SLObjectItf_GetInterface(a,b,c) ((*(a))->GetInterface((a),(b),(c))) +#define SLObjectItf_Destroy(a) ((*(a))->Destroy((a))) + +#define SLEngineItf_CreateOutputMix(a,b,c,d,e) ((*(a))->CreateOutputMix((a),(b),(c),(d),(e))) +#define SLEngineItf_CreateAudioPlayer(a,b,c,d,e,f,g) ((*(a))->CreateAudioPlayer((a),(b),(c),(d),(e),(f),(g))) + +#define SLPlayItf_SetPlayState(a,b) ((*(a))->SetPlayState((a),(b))) + + +typedef struct { + /* engine interfaces */ + SLObjectItf engineObject; + SLEngineItf engine; + + /* output mix interfaces */ + SLObjectItf outputMix; + + /* buffer queue player interfaces */ + SLObjectItf bufferQueueObject; + + void *buffer; + ALuint bufferSize; + + ALuint frameSize; +} osl_data; + + +static const ALCchar opensl_device[] = "OpenSL"; + + +static SLuint32 GetChannelMask(enum DevFmtChannels chans) +{ + switch(chans) + { + case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; + case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; + case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; + case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; + case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_CENTER| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + } + return 0; +} + +static const char *res_str(SLresult result) +{ + switch(result) + { + case SL_RESULT_SUCCESS: return "Success"; + case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; + case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; + case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; + case SL_RESULT_RESOURCE_ERROR: return "Resource error"; + case SL_RESULT_RESOURCE_LOST: return "Resource lost"; + case SL_RESULT_IO_ERROR: return "I/O error"; + case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; + case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; + case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; + case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; + case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; + case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; + case SL_RESULT_INTERNAL_ERROR: return "Internal error"; + case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; + case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; + case SL_RESULT_CONTROL_LOST: return "Control lost"; +#ifdef SL_RESULT_READONLY + case SL_RESULT_READONLY: return "ReadOnly"; +#endif +#ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED + case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; +#endif +#ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE + case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; +#endif + } + return "Unknown error code"; +} + +#define PRINTERR(x, s) do { \ + if((x) != SL_RESULT_SUCCESS) \ + ERR("%s: %s\n", (s), res_str((x))); \ +} while(0) + +/* this callback handler is called every time a buffer finishes playing */ +static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context) +{ + ALCdevice *Device = context; + osl_data *data = Device->ExtraData; + SLresult result; + + aluMixData(Device, data->buffer, data->bufferSize/data->frameSize); + + result = (*bq)->Enqueue(bq, data->buffer, data->bufferSize); + PRINTERR(result, "bq->Enqueue"); +} + + +static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName) +{ + osl_data *data = NULL; + SLresult result; + + if(!deviceName) + deviceName = opensl_device; + else if(strcmp(deviceName, opensl_device) != 0) + return ALC_INVALID_VALUE; + + data = calloc(1, sizeof(*data)); + if(!data) + return ALC_OUT_OF_MEMORY; + + // create engine + result = slCreateEngine(&data->engineObject, 0, NULL, 0, NULL, NULL); + PRINTERR(result, "slCreateEngine"); + if(SL_RESULT_SUCCESS == result) + { + result = SLObjectItf_Realize(data->engineObject, SL_BOOLEAN_FALSE); + PRINTERR(result, "engine->Realize"); + } + if(SL_RESULT_SUCCESS == result) + { + result = SLObjectItf_GetInterface(data->engineObject, SL_IID_ENGINE, &data->engine); + PRINTERR(result, "engine->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + result = SLEngineItf_CreateOutputMix(data->engine, &data->outputMix, 0, NULL, NULL); + PRINTERR(result, "engine->CreateOutputMix"); + } + if(SL_RESULT_SUCCESS == result) + { + result = SLObjectItf_Realize(data->outputMix, SL_BOOLEAN_FALSE); + PRINTERR(result, "outputMix->Realize"); + } + + if(SL_RESULT_SUCCESS != result) + { + if(data->outputMix != NULL) + SLObjectItf_Destroy(data->outputMix); + data->outputMix = NULL; + + if(data->engineObject != NULL) + SLObjectItf_Destroy(data->engineObject); + data->engineObject = NULL; + data->engine = NULL; + + free(data); + return ALC_INVALID_VALUE; + } + + Device->DeviceName = strdup(deviceName); + Device->ExtraData = data; + + return ALC_NO_ERROR; +} + + +static void opensl_close_playback(ALCdevice *Device) +{ + osl_data *data = Device->ExtraData; + + if(data->bufferQueueObject != NULL) + SLObjectItf_Destroy(data->bufferQueueObject); + data->bufferQueueObject = NULL; + + SLObjectItf_Destroy(data->outputMix); + data->outputMix = NULL; + + SLObjectItf_Destroy(data->engineObject); + data->engineObject = NULL; + data->engine = NULL; + + free(data); + Device->ExtraData = NULL; +} + +static ALCboolean opensl_reset_playback(ALCdevice *Device) +{ + osl_data *data = Device->ExtraData; + SLDataLocator_AndroidSimpleBufferQueue loc_bufq; + SLDataLocator_OutputMix loc_outmix; + SLDataFormat_PCM format_pcm; + SLDataSource audioSrc; + SLDataSink audioSnk; + SLInterfaceID id; + SLboolean req; + SLresult result; + + + Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency; + Device->UpdateSize = Device->UpdateSize * Device->NumUpdates / 2; + Device->NumUpdates = 2; + + Device->Frequency = 44100; + Device->FmtChans = DevFmtStereo; + Device->FmtType = DevFmtShort; + + SetDefaultWFXChannelOrder(Device); + + + id = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; + req = SL_BOOLEAN_TRUE; + + loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; + loc_bufq.numBuffers = Device->NumUpdates; + + format_pcm.formatType = SL_DATAFORMAT_PCM; + format_pcm.numChannels = ChannelsFromDevFmt(Device->FmtChans); + format_pcm.samplesPerSec = Device->Frequency * 1000; + format_pcm.bitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; + format_pcm.containerSize = format_pcm.bitsPerSample; + format_pcm.channelMask = GetChannelMask(Device->FmtChans); + format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : + SL_BYTEORDER_BIGENDIAN; + + audioSrc.pLocator = &loc_bufq; + audioSrc.pFormat = &format_pcm; + + loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; + loc_outmix.outputMix = data->outputMix; + audioSnk.pLocator = &loc_outmix; + audioSnk.pFormat = NULL; + + + if(data->bufferQueueObject != NULL) + SLObjectItf_Destroy(data->bufferQueueObject); + data->bufferQueueObject = NULL; + + result = SLEngineItf_CreateAudioPlayer(data->engine, &data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req); + PRINTERR(result, "engine->CreateAudioPlayer"); + if(SL_RESULT_SUCCESS == result) + { + result = SLObjectItf_Realize(data->bufferQueueObject, SL_BOOLEAN_FALSE); + PRINTERR(result, "bufferQueue->Realize"); + } + + if(SL_RESULT_SUCCESS != result) + { + if(data->bufferQueueObject != NULL) + SLObjectItf_Destroy(data->bufferQueueObject); + data->bufferQueueObject = NULL; + + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static ALCboolean opensl_start_playback(ALCdevice *Device) +{ + osl_data *data = Device->ExtraData; + SLAndroidSimpleBufferQueueItf bufferQueue; + SLPlayItf player; + SLresult result; + ALuint i; + + result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue); + PRINTERR(result, "bufferQueue->GetInterface"); + if(SL_RESULT_SUCCESS == result) + { + result = (*bufferQueue)->RegisterCallback(bufferQueue, opensl_callback, Device); + PRINTERR(result, "bufferQueue->RegisterCallback"); + } + if(SL_RESULT_SUCCESS == result) + { + data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + data->bufferSize = Device->UpdateSize * data->frameSize; + data->buffer = calloc(1, data->bufferSize); + if(!data->buffer) + { + result = SL_RESULT_MEMORY_FAILURE; + PRINTERR(result, "calloc"); + } + } + /* enqueue the first buffer to kick off the callbacks */ + for(i = 0;i < Device->NumUpdates;i++) + { + if(SL_RESULT_SUCCESS == result) + { + result = (*bufferQueue)->Enqueue(bufferQueue, data->buffer, data->bufferSize); + PRINTERR(result, "bufferQueue->Enqueue"); + } + } + if(SL_RESULT_SUCCESS == result) + { + result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_PLAY, &player); + PRINTERR(result, "bufferQueue->GetInterface"); + } + if(SL_RESULT_SUCCESS == result) + { + result = SLPlayItf_SetPlayState(player, SL_PLAYSTATE_PLAYING); + PRINTERR(result, "player->SetPlayState"); + } + + if(SL_RESULT_SUCCESS != result) + { + if(data->bufferQueueObject != NULL) + SLObjectItf_Destroy(data->bufferQueueObject); + data->bufferQueueObject = NULL; + + free(data->buffer); + data->buffer = NULL; + data->bufferSize = 0; + + return ALC_FALSE; + } + + return ALC_TRUE; +} + + +static void opensl_stop_playback(ALCdevice *Device) +{ + osl_data *data = Device->ExtraData; + + free(data->buffer); + data->buffer = NULL; + data->bufferSize = 0; +} + + +static const BackendFuncs opensl_funcs = { + opensl_open_playback, + opensl_close_playback, + opensl_reset_playback, + opensl_start_playback, + opensl_stop_playback, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + + +ALCboolean alc_opensl_init(BackendFuncs *func_list) +{ + *func_list = opensl_funcs; + return ALC_TRUE; +} + +void alc_opensl_deinit(void) +{ +} + +void alc_opensl_probe(enum DevProbe type) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + AppendAllDevicesList(opensl_device); + break; + case CAPTURE_DEVICE_PROBE: + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/oss.c b/src/eepp/helper/android/openal-soft/Alc/backends/oss.c new file mode 100644 index 000000000..0ed49517b --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/oss.c @@ -0,0 +1,537 @@ +/** + * 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 "alu.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"; + +static const char *oss_driver = "/dev/dsp"; +static const char *oss_capture = "/dev/dsp"; + +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 *Device = (ALCdevice*)ptr; + oss_data *data = (oss_data*)Device->ExtraData; + ALint frameSize; + ssize_t wrote; + + SetRTPriority(); + + frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + + while(!data->killNow && Device->Connected) + { + ALint len = data->data_size; + ALubyte *WritePtr = data->mix_data; + + aluMixData(Device, WritePtr, len/frameSize); + while(len > 0 && !data->killNow) + { + wrote = write(data->fd, WritePtr, len); + if(wrote < 0) + { + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + { + ERR("write failed: %s\n", strerror(errno)); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + break; + } + + Sleep(1); + continue; + } + + len -= wrote; + WritePtr += wrote; + } + } + + return 0; +} + +static ALuint OSSCaptureProc(ALvoid *ptr) +{ + ALCdevice *Device = (ALCdevice*)ptr; + oss_data *data = (oss_data*)Device->ExtraData; + int frameSize; + int amt; + + SetRTPriority(); + + frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + + while(!data->killNow) + { + amt = read(data->fd, data->mix_data, data->data_size); + if(amt < 0) + { + ERR("read failed: %s\n", strerror(errno)); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + break; + } + if(amt == 0) + { + Sleep(1); + continue; + } + if(data->doCapture) + WriteRingBuffer(data->ring, data->mix_data, amt/frameSize); + } + + return 0; +} + +static ALCenum oss_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + oss_data *data; + + if(!deviceName) + deviceName = oss_device; + else if(strcmp(deviceName, oss_device) != 0) + return ALC_INVALID_VALUE; + + data = (oss_data*)calloc(1, sizeof(oss_data)); + data->killNow = 0; + + data->fd = open(oss_driver, O_WRONLY); + if(data->fd == -1) + { + free(data); + ERR("Could not open %s: %s\n", oss_driver, strerror(errno)); + return ALC_INVALID_VALUE; + } + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_NO_ERROR; +} + +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 DevFmtInt: + case DevFmtUInt: + 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: + ERR("%s failed: %s\n", err, strerror(errno)); + return ALC_FALSE; + } +#undef CHECKERR + + if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) + { + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(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))) + { + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); + return ALC_FALSE; + } + + device->Frequency = ossSpeed; + device->UpdateSize = info.fragsize / frameSize; + device->NumUpdates = info.fragments + 1; + + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean oss_start_playback(ALCdevice *device) +{ + oss_data *data = (oss_data*)device->ExtraData; + + data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + data->mix_data = calloc(1, data->data_size); + + 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) + ERR("Error resetting device: %s\n", strerror(errno)); + + free(data->mix_data); + data->mix_data = NULL; +} + + +static ALCenum oss_open_capture(ALCdevice *device, const ALCchar *deviceName) +{ + int numFragmentsLogSize; + int log2FragmentSize; + unsigned int periods; + audio_buf_info info; + ALuint frameSize; + int numChannels; + oss_data *data; + int ossFormat; + int ossSpeed; + char *err; + + if(!deviceName) + deviceName = oss_device; + else if(strcmp(deviceName, oss_device) != 0) + return ALC_INVALID_VALUE; + + data = (oss_data*)calloc(1, sizeof(oss_data)); + data->killNow = 0; + + data->fd = open(oss_capture, O_RDONLY); + if(data->fd == -1) + { + free(data); + ERR("Could not open %s: %s\n", oss_capture, strerror(errno)); + return ALC_INVALID_VALUE; + } + + 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 DevFmtInt: + case DevFmtUInt: + case DevFmtFloat: + free(data); + ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return ALC_INVALID_VALUE; + } + + 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: + ERR("%s failed: %s\n", err, strerror(errno)); + close(data->fd); + free(data); + return ALC_INVALID_VALUE; + } +#undef CHECKERR + + if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels) + { + ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels); + close(data->fd); + free(data); + return ALC_INVALID_VALUE; + } + + if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) || + (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) || + (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort))) + { + ERR("Failed to set %s samples, got OSS format %#x\n", DevFmtTypeString(device->FmtType), ossFormat); + close(data->fd); + free(data); + return ALC_INVALID_VALUE; + } + + data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates); + if(!data->ring) + { + ERR("Ring buffer create failed\n"); + close(data->fd); + free(data); + return ALC_OUT_OF_MEMORY; + } + + 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_OUT_OF_MEMORY; + } + + device->DeviceName = strdup(deviceName); + return ALC_NO_ERROR; +} + +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 *Device) +{ + oss_data *data = (oss_data*)Device->ExtraData; + data->doCapture = 1; +} + +static void oss_stop_capture(ALCdevice *Device) +{ + oss_data *data = (oss_data*)Device->ExtraData; + data->doCapture = 0; +} + +static ALCenum oss_capture_samples(ALCdevice *Device, ALCvoid *pBuffer, ALCuint lSamples) +{ + oss_data *data = (oss_data*)Device->ExtraData; + ReadRingBuffer(data->ring, pBuffer, lSamples); + return ALC_NO_ERROR; +} + +static ALCuint oss_available_samples(ALCdevice *Device) +{ + oss_data *data = (oss_data*)Device->ExtraData; + return RingBufferSize(data->ring); +} + + +static const BackendFuncs oss_funcs = { + oss_open_playback, + oss_close_playback, + oss_reset_playback, + oss_start_playback, + oss_stop_playback, + oss_open_capture, + oss_close_capture, + oss_start_capture, + oss_stop_capture, + oss_capture_samples, + oss_available_samples, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_oss_init(BackendFuncs *func_list) +{ + ConfigValueStr("oss", "device", &oss_driver); + ConfigValueStr("oss", "capture", &oss_capture); + + *func_list = oss_funcs; + return ALC_TRUE; +} + +void alc_oss_deinit(void) +{ +} + +void alc_oss_probe(enum DevProbe type) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(oss_driver, &buf) == 0) +#endif + AppendAllDevicesList(oss_device); + } + break; + + case CAPTURE_DEVICE_PROBE: + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(oss_capture, &buf) == 0) +#endif + AppendCaptureDeviceList(oss_device); + } + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/portaudio.c b/src/eepp/helper/android/openal-soft/Alc/backends/portaudio.c new file mode 100644 index 000000000..2f5766390 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/portaudio.c @@ -0,0 +1,472 @@ +/** + * 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 "alu.h" + +#include + + +static const ALCchar pa_device[] = "PortAudio Default"; + + +#ifdef HAVE_DYNLOAD +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 + +#define Pa_Initialize pPa_Initialize +#define Pa_Terminate pPa_Terminate +#define Pa_GetErrorText pPa_GetErrorText +#define Pa_StartStream pPa_StartStream +#define Pa_StopStream pPa_StopStream +#define Pa_OpenStream pPa_OpenStream +#define Pa_CloseStream pPa_CloseStream +#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice +#define Pa_GetStreamInfo pPa_GetStreamInfo +#endif + +static ALCboolean pa_load(void) +{ + PaError err; + +#ifdef HAVE_DYNLOAD + if(!pa_handle) + { +#ifdef _WIN32 +# define PALIB "portaudio.dll" +#elif defined(__APPLE__) && defined(__MACH__) +# define PALIB "libportaudio.2.dylib" +#elif defined(__OpenBSD__) +# define PALIB "libportaudio.so" +#else +# define PALIB "libportaudio.so.2" +#endif + + pa_handle = LoadLib(PALIB); + if(!pa_handle) + return ALC_FALSE; + +#define LOAD_FUNC(f) do { \ + p##f = GetSymbol(pa_handle, #f); \ + if(p##f == NULL) \ + { \ + CloseLib(pa_handle); \ + pa_handle = NULL; \ + return ALC_FALSE; \ + } \ +} while(0) + 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=Pa_Initialize()) != paNoError) + { + ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); + CloseLib(pa_handle); + pa_handle = NULL; + return ALC_FALSE; + } + } +#else + if((err=Pa_Initialize()) != paNoError) + { + ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); + return ALC_FALSE; + } +#endif + return ALC_TRUE; +} + + +typedef struct { + PaStream *stream; + PaStreamParameters params; + 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 ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + pa_data *data; + PaError err; + + if(!deviceName) + deviceName = pa_device; + else if(strcmp(deviceName, pa_device) != 0) + return ALC_INVALID_VALUE; + + data = (pa_data*)calloc(1, sizeof(pa_data)); + data->update_size = device->UpdateSize; + + data->params.device = -1; + if(!ConfigValueInt("port", "device", &data->params.device) || + data->params.device < 0) + data->params.device = Pa_GetDefaultOutputDevice(); + data->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / + (float)device->Frequency; + data->params.hostApiSpecificStreamInfo = NULL; + + data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); + + switch(device->FmtType) + { + case DevFmtByte: + data->params.sampleFormat = paInt8; + break; + case DevFmtUByte: + data->params.sampleFormat = paUInt8; + break; + case DevFmtUShort: + /* fall-through */ + case DevFmtShort: + data->params.sampleFormat = paInt16; + break; + case DevFmtUInt: + /* fall-through */ + case DevFmtInt: + data->params.sampleFormat = paInt32; + break; + case DevFmtFloat: + data->params.sampleFormat = paFloat32; + break; + } + +retry_open: + err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency, + device->UpdateSize, paNoFlag, pa_callback, device); + if(err != paNoError) + { + if(data->params.sampleFormat == paFloat32) + { + data->params.sampleFormat = paInt16; + goto retry_open; + } + ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); + free(data); + return ALC_INVALID_VALUE; + } + + device->ExtraData = data; + device->DeviceName = strdup(deviceName); + + return ALC_NO_ERROR; +} + +static void pa_close_playback(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + PaError err; + + err = Pa_CloseStream(data->stream); + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + + free(data); + device->ExtraData = NULL; +} + +static ALCboolean pa_reset_playback(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + const PaStreamInfo *streamInfo; + + streamInfo = Pa_GetStreamInfo(data->stream); + device->Frequency = streamInfo->sampleRate; + device->UpdateSize = data->update_size; + + if(data->params.sampleFormat == paInt8) + device->FmtType = DevFmtByte; + else if(data->params.sampleFormat == paUInt8) + device->FmtType = DevFmtUByte; + else if(data->params.sampleFormat == paInt16) + device->FmtType = DevFmtShort; + else if(data->params.sampleFormat == paInt32) + device->FmtType = DevFmtInt; + else if(data->params.sampleFormat == paFloat32) + device->FmtType = DevFmtFloat; + else + { + ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat); + return ALC_FALSE; + } + + if(data->params.channelCount == 2) + device->FmtChans = DevFmtStereo; + else if(data->params.channelCount == 1) + device->FmtChans = DevFmtMono; + else + { + ERR("Unexpected channel count: %u\n", data->params.channelCount); + return ALC_FALSE; + } + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean pa_start_playback(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + PaError err; + + err = Pa_StartStream(data->stream); + if(err != paNoError) + { + ERR("Pa_StartStream() returned an error: %s\n", Pa_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 = Pa_StopStream(data->stream); + if(err != paNoError) + ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); +} + + +static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName) +{ + ALuint frame_size; + pa_data *data; + PaError err; + + if(!deviceName) + deviceName = pa_device; + else if(strcmp(deviceName, pa_device) != 0) + return ALC_INVALID_VALUE; + + data = (pa_data*)calloc(1, sizeof(pa_data)); + if(data == NULL) + return ALC_OUT_OF_MEMORY; + + frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates); + if(data->ring == NULL) + goto error; + + data->params.device = -1; + if(!ConfigValueInt("port", "capture", &data->params.device) || + data->params.device < 0) + data->params.device = Pa_GetDefaultOutputDevice(); + data->params.suggestedLatency = 0.0f; + data->params.hostApiSpecificStreamInfo = NULL; + + switch(device->FmtType) + { + case DevFmtByte: + data->params.sampleFormat = paInt8; + break; + case DevFmtUByte: + data->params.sampleFormat = paUInt8; + break; + case DevFmtShort: + data->params.sampleFormat = paInt16; + break; + case DevFmtInt: + data->params.sampleFormat = paInt32; + break; + case DevFmtFloat: + data->params.sampleFormat = paFloat32; + break; + case DevFmtUInt: + case DevFmtUShort: + ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); + goto error; + } + data->params.channelCount = ChannelsFromDevFmt(device->FmtChans); + + err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency, + paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device); + if(err != paNoError) + { + ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); + goto error; + } + + device->DeviceName = strdup(deviceName); + + device->ExtraData = data; + return ALC_NO_ERROR; + +error: + DestroyRingBuffer(data->ring); + free(data); + return ALC_INVALID_VALUE; +} + +static void pa_close_capture(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + PaError err; + + err = Pa_CloseStream(data->stream); + if(err != paNoError) + ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + + free(data); + device->ExtraData = NULL; +} + +static void pa_start_capture(ALCdevice *device) +{ + pa_data *data = device->ExtraData; + PaError err; + + err = Pa_StartStream(data->stream); + if(err != paNoError) + ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); +} + +static void pa_stop_capture(ALCdevice *device) +{ + pa_data *data = (pa_data*)device->ExtraData; + PaError err; + + err = Pa_StopStream(data->stream); + if(err != paNoError) + ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); +} + +static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) +{ + pa_data *data = device->ExtraData; + ReadRingBuffer(data->ring, buffer, samples); + return ALC_NO_ERROR; +} + +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_start_playback, + pa_stop_playback, + pa_open_capture, + pa_close_capture, + pa_start_capture, + pa_stop_capture, + pa_capture_samples, + pa_available_samples, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_pa_init(BackendFuncs *func_list) +{ + if(!pa_load()) + return ALC_FALSE; + *func_list = pa_funcs; + return ALC_TRUE; +} + +void alc_pa_deinit(void) +{ +#ifdef HAVE_DYNLOAD + if(pa_handle) + { + Pa_Terminate(); + CloseLib(pa_handle); + pa_handle = NULL; + } +#else + Pa_Terminate(); +#endif +} + +void alc_pa_probe(enum DevProbe type) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + AppendAllDevicesList(pa_device); + break; + case CAPTURE_DEVICE_PROBE: + AppendCaptureDeviceList(pa_device); + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/pulseaudio.c b/src/eepp/helper/android/openal-soft/Alc/backends/pulseaudio.c new file mode 100644 index 000000000..af44e3def --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/pulseaudio.c @@ -0,0 +1,1554 @@ +/** + * 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 + +#include "alMain.h" +#include "alu.h" + +#include + +#if PA_API_VERSION == 12 + +#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 + +#ifdef HAVE_DYNLOAD +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_frame_size); +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_is_corked); +MAKE_FUNC(pa_stream_cork); +MAKE_FUNC(pa_stream_is_suspended); +MAKE_FUNC(pa_stream_get_device_name); +MAKE_FUNC(pa_stream_get_latency); +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_with_proplist); +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_by_name); +MAKE_FUNC(pa_context_get_source_info_list); +MAKE_FUNC(pa_operation_get_state); +MAKE_FUNC(pa_operation_unref); +MAKE_FUNC(pa_proplist_new); +MAKE_FUNC(pa_proplist_free); +MAKE_FUNC(pa_proplist_set); +#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 + +#define pa_context_unref ppa_context_unref +#define pa_sample_spec_valid ppa_sample_spec_valid +#define pa_frame_size ppa_frame_size +#define pa_stream_drop ppa_stream_drop +#define pa_strerror ppa_strerror +#define pa_context_get_state ppa_context_get_state +#define pa_stream_get_state ppa_stream_get_state +#define pa_threaded_mainloop_signal ppa_threaded_mainloop_signal +#define pa_stream_peek ppa_stream_peek +#define pa_threaded_mainloop_wait ppa_threaded_mainloop_wait +#define pa_threaded_mainloop_unlock ppa_threaded_mainloop_unlock +#define pa_threaded_mainloop_in_thread ppa_threaded_mainloop_in_thread +#define pa_context_new ppa_context_new +#define pa_threaded_mainloop_stop ppa_threaded_mainloop_stop +#define pa_context_disconnect ppa_context_disconnect +#define pa_threaded_mainloop_start ppa_threaded_mainloop_start +#define pa_threaded_mainloop_get_api ppa_threaded_mainloop_get_api +#define pa_context_set_state_callback ppa_context_set_state_callback +#define pa_stream_write ppa_stream_write +#define pa_xfree ppa_xfree +#define pa_stream_connect_record ppa_stream_connect_record +#define pa_stream_connect_playback ppa_stream_connect_playback +#define pa_stream_readable_size ppa_stream_readable_size +#define pa_stream_writable_size ppa_stream_writable_size +#define pa_stream_is_corked ppa_stream_is_corked +#define pa_stream_cork ppa_stream_cork +#define pa_stream_is_suspended ppa_stream_is_suspended +#define pa_stream_get_device_name ppa_stream_get_device_name +#define pa_stream_get_latency ppa_stream_get_latency +#define pa_path_get_filename ppa_path_get_filename +#define pa_get_binary_name ppa_get_binary_name +#define pa_threaded_mainloop_free ppa_threaded_mainloop_free +#define pa_context_errno ppa_context_errno +#define pa_xmalloc ppa_xmalloc +#define pa_stream_unref ppa_stream_unref +#define pa_threaded_mainloop_accept ppa_threaded_mainloop_accept +#define pa_stream_set_write_callback ppa_stream_set_write_callback +#define pa_threaded_mainloop_new ppa_threaded_mainloop_new +#define pa_context_connect ppa_context_connect +#define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr +#define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr +#define pa_stream_get_sample_spec ppa_stream_get_sample_spec +#define pa_stream_get_time ppa_stream_get_time +#define pa_stream_set_read_callback ppa_stream_set_read_callback +#define pa_stream_set_state_callback ppa_stream_set_state_callback +#define pa_stream_set_moved_callback ppa_stream_set_moved_callback +#define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback +#define pa_stream_new_with_proplist ppa_stream_new_with_proplist +#define pa_stream_disconnect ppa_stream_disconnect +#define pa_threaded_mainloop_lock ppa_threaded_mainloop_lock +#define pa_channel_map_init_auto ppa_channel_map_init_auto +#define pa_channel_map_parse ppa_channel_map_parse +#define pa_channel_map_snprint ppa_channel_map_snprint +#define pa_channel_map_equal ppa_channel_map_equal +#define pa_context_get_server_info ppa_context_get_server_info +#define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name +#define pa_context_get_sink_info_list ppa_context_get_sink_info_list +#define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name +#define pa_context_get_source_info_list ppa_context_get_source_info_list +#define pa_operation_get_state ppa_operation_get_state +#define pa_operation_unref ppa_operation_unref +#define pa_proplist_new ppa_proplist_new +#define pa_proplist_free ppa_proplist_free +#define pa_proplist_set ppa_proplist_set +#if PA_CHECK_VERSION(0,9,15) +#define pa_channel_map_superset ppa_channel_map_superset +#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback +#endif +#if PA_CHECK_VERSION(0,9,16) +#define pa_stream_begin_write ppa_stream_begin_write +#endif + +#endif + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +typedef struct { + char *device_name; + + const void *cap_store; + size_t cap_len; + size_t cap_remain; + + ALCuint last_readable; + + 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 DevMap *allDevNameMap; +static ALuint numDevNames; +static DevMap *allCaptureDevNameMap; +static ALuint numCaptureDevNames; +static pa_context_flags_t pulse_ctx_flags; +static pa_proplist *prop_filter; + + +static ALCboolean pulse_load(void) +{ + ALCboolean ret = ALC_TRUE; +#ifdef HAVE_DYNLOAD + if(!pa_handle) + { +#ifdef _WIN32 +#define PALIB "libpulse-0.dll" +#elif defined(__APPLE__) && defined(__MACH__) +#define PALIB "libpulse.0.dylib" +#else +#define PALIB "libpulse.so.0" +#endif + pa_handle = LoadLib(PALIB); + if(!pa_handle) + return ALC_FALSE; + +#define LOAD_FUNC(x) do { \ + p##x = GetSymbol(pa_handle, #x); \ + if(!(p##x)) { \ + ret = ALC_FALSE; \ + } \ +} while(0) + LOAD_FUNC(pa_context_unref); + LOAD_FUNC(pa_sample_spec_valid); + LOAD_FUNC(pa_stream_drop); + LOAD_FUNC(pa_frame_size); + 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_is_corked); + LOAD_FUNC(pa_stream_cork); + LOAD_FUNC(pa_stream_is_suspended); + LOAD_FUNC(pa_stream_get_device_name); + LOAD_FUNC(pa_stream_get_latency); + 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_with_proplist); + 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_by_name); + LOAD_FUNC(pa_context_get_source_info_list); + LOAD_FUNC(pa_operation_get_state); + LOAD_FUNC(pa_operation_unref); + LOAD_FUNC(pa_proplist_new); + LOAD_FUNC(pa_proplist_free); + LOAD_FUNC(pa_proplist_set); +#undef LOAD_FUNC +#define LOAD_OPTIONAL_FUNC(x) do { \ + p##x = GetSymbol(pa_handle, #x); \ +} while(0) +#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 + + if(ret == ALC_FALSE) + { + CloseLib(pa_handle); + pa_handle = NULL; + } + } +#endif /* HAVE_DYNLOAD */ + return ret; +} + +/* PulseAudio Event Callbacks */ +static void context_state_callback(pa_context *context, void *pdata) +{ + pa_threaded_mainloop *loop = pdata; + pa_context_state_t state; + + state = pa_context_get_state(context); + if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state)) + pa_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 = pa_stream_get_state(stream); + if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state)) + pa_threaded_mainloop_signal(loop, 0); +} + +static void stream_buffer_attr_callback(pa_stream *stream, void *pdata) +{ + ALCdevice *device = pdata; + pulse_data *data = device->ExtraData; + + data->attr = *pa_stream_get_buffer_attr(stream); + TRACE("minreq=%d, tlength=%d, prebuf=%d\n", data->attr.minreq, data->attr.tlength, data->attr.prebuf); +} + +static void context_state_callback2(pa_context *context, void *pdata) +{ + ALCdevice *Device = pdata; + pulse_data *data = Device->ExtraData; + + if(pa_context_get_state(context) == PA_CONTEXT_FAILED) + { + ERR("Received context failure!\n"); + aluHandleDisconnect(Device); + } + pa_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(pa_stream_get_state(stream) == PA_STREAM_FAILED) + { + ERR("Received stream failure!\n"); + aluHandleDisconnect(Device); + } + pa_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; + + pa_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,front-center,lfe,side-left,side-right", + DevFmtX51Side }, + { "front-left,front-right,rear-left,rear-right", DevFmtQuad }, + { "front-left,front-right", DevFmtStereo }, + { "mono", DevFmtMono }, + { NULL, 0 } + }; + int i; + (void)context; + + if(eol) + { + pa_threaded_mainloop_signal(data->loop, 0); + return; + } + + for(i = 0;chanmaps[i].str;i++) + { + pa_channel_map map; + if(!pa_channel_map_parse(&map, chanmaps[i].str)) + continue; + + if(pa_channel_map_equal(&info->channel_map, &map) +#if PA_CHECK_VERSION(0,9,15) + || (pa_channel_map_superset && + pa_channel_map_superset(&info->channel_map, &map)) +#endif + ) + { + device->FmtChans = chanmaps[i].chans; + return; + } + } + + pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); + ERR("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; + void *temp; + ALuint i; + + (void)context; + + if(eol) + { + pa_threaded_mainloop_signal(loop, 0); + return; + } + + for(i = 0;i < numDevNames;i++) + { + if(strcmp(info->name, allDevNameMap[i].device_name) == 0) + return; + } + + TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name); + + temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap)); + if(temp) + { + allDevNameMap = temp; + allDevNameMap[numDevNames].name = strdup(info->description); + 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; + void *temp; + ALuint i; + + (void)context; + + if(eol) + { + pa_threaded_mainloop_signal(loop, 0); + return; + } + + for(i = 0;i < numCaptureDevNames;i++) + { + if(strcmp(info->name, allCaptureDevNameMap[i].device_name) == 0) + return; + } + + TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name); + + temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap)); + if(temp) + { + allCaptureDevNameMap = temp; + allCaptureDevNameMap[numCaptureDevNames].name = strdup(info->description); + allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name); + numCaptureDevNames++; + } +} + +static void sink_name_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) +{ + ALCdevice *device = pdata; + pulse_data *data = device->ExtraData; + (void)context; + + if(eol) + { + pa_threaded_mainloop_signal(data->loop, 0); + return; + } + + free(device->DeviceName); + device->DeviceName = strdup(info->description); +} + +static void source_name_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata) +{ + ALCdevice *device = pdata; + pulse_data *data = device->ExtraData; + (void)context; + + if(eol) + { + pa_threaded_mainloop_signal(data->loop, 0); + return; + } + + free(device->DeviceName); + device->DeviceName = strdup(info->description); +} + + +static void stream_moved_callback(pa_stream *stream, void *pdata) +{ + ALCdevice *device = pdata; + pulse_data *data = device->ExtraData; + (void)stream; + + free(data->device_name); + data->device_name = strdup(pa_stream_get_device_name(data->stream)); + + TRACE("Stream moved to %s\n", data->device_name); +} + + +static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) +{ + const char *name = "OpenAL Soft"; + char path_name[PATH_MAX]; + pa_context_state_t state; + pa_context *context; + int err; + + if(pa_get_binary_name(path_name, sizeof(path_name))) + name = pa_path_get_filename(path_name); + + context = pa_context_new(pa_threaded_mainloop_get_api(loop), name); + if(!context) + { + ERR("pa_context_new() failed\n"); + return NULL; + } + + pa_context_set_state_callback(context, context_state_callback, loop); + + if((err=pa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0) + { + while((state=pa_context_get_state(context)) != PA_CONTEXT_READY) + { + if(!PA_CONTEXT_IS_GOOD(state)) + { + err = pa_context_errno(context); + if(err > 0) err = -err; + break; + } + + pa_threaded_mainloop_wait(loop); + } + } + pa_context_set_state_callback(context, NULL, NULL); + + if(err < 0) + { + if(!silent) + ERR("Context did not connect: %s\n", pa_strerror(err)); + pa_context_unref(context); + return NULL; + } + + return context; +} + +static pa_stream *connect_playback_stream(const char *device_name, + pa_threaded_mainloop *loop, pa_context *context, + pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap) +{ + pa_stream_state_t state; + pa_stream *stream; + + stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter); + if(!stream) + { + ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); + return NULL; + } + + pa_stream_set_state_callback(stream, stream_state_callback, loop); + + if(pa_stream_connect_playback(stream, device_name, attr, flags, NULL, NULL) < 0) + { + ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return NULL; + } + + while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) + { + if(!PA_STREAM_IS_GOOD(state)) + { + ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return NULL; + } + + pa_threaded_mainloop_wait(loop); + } + pa_stream_set_state_callback(stream, NULL, NULL); + + return stream; +} + +static pa_stream *connect_record_stream(const char *device_name, + pa_threaded_mainloop *loop, pa_context *context, + pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, + pa_channel_map *chanmap) +{ + pa_stream_state_t state; + pa_stream *stream; + + stream = pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter); + if(!stream) + { + ERR("pa_stream_new_with_proplist() failed: %s\n", pa_strerror(pa_context_errno(context))); + return NULL; + } + + pa_stream_set_state_callback(stream, stream_state_callback, loop); + + if(pa_stream_connect_record(stream, device_name, attr, flags) < 0) + { + ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return NULL; + } + + while((state=pa_stream_get_state(stream)) != PA_STREAM_READY) + { + if(!PA_STREAM_IS_GOOD(state)) + { + ERR("Stream did not get ready: %s\n", pa_strerror(pa_context_errno(context))); + pa_stream_unref(stream); + return NULL; + } + + pa_threaded_mainloop_wait(loop); + } + pa_stream_set_state_callback(stream, NULL, NULL); + + return stream; +} + + +static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop) +{ + if(op) + { + while(pa_operation_get_state(op) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(loop); + pa_operation_unref(op); + } +} + + +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=pa_threaded_mainloop_new()) && + pa_threaded_mainloop_start(loop) >= 0) + { + pa_context *context; + + pa_threaded_mainloop_lock(loop); + context = connect_context(loop, AL_FALSE); + if(context) + { + pa_operation *o; + + if(capture == AL_FALSE) + { + pa_stream_flags_t flags; + pa_sample_spec spec; + pa_stream *stream; + + flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; + + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; + + stream = connect_playback_stream(NULL, loop, context, flags, + NULL, &spec, NULL); + if(stream) + { + o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), sink_device_callback, loop); + wait_for_operation(o, loop); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = NULL; + } + + o = pa_context_get_sink_info_list(context, sink_device_callback, loop); + } + else + { + pa_stream_flags_t flags; + pa_sample_spec spec; + pa_stream *stream; + + flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; + + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 1; + + stream = connect_record_stream(NULL, loop, context, flags, + NULL, &spec, NULL); + if(stream) + { + o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), source_device_callback, loop); + wait_for_operation(o, loop); + + pa_stream_disconnect(stream); + pa_stream_unref(stream); + stream = NULL; + } + + o = pa_context_get_source_info_list(context, source_device_callback, loop); + } + wait_for_operation(o, loop); + + pa_context_disconnect(context); + pa_context_unref(context); + } + pa_threaded_mainloop_unlock(loop); + pa_threaded_mainloop_stop(loop); + } + if(loop) + pa_threaded_mainloop_free(loop); +} + + +static ALuint PulseProc(ALvoid *param) +{ + ALCdevice *Device = param; + pulse_data *data = Device->ExtraData; + ALuint buffer_size; + ALint update_size; + size_t frame_size; + ssize_t len; + + SetRTPriority(); + + pa_threaded_mainloop_lock(data->loop); + frame_size = pa_frame_size(&data->spec); + update_size = Device->UpdateSize * frame_size; + + /* Sanitize buffer metrics, in case we actually have less than what we + * asked for. */ + buffer_size = minu(update_size*Device->NumUpdates, data->attr.tlength); + update_size = minu(update_size, buffer_size/2); + do { + len = pa_stream_writable_size(data->stream) - data->attr.tlength + + buffer_size; + if(len < update_size) + { + if(pa_stream_is_corked(data->stream) == 1) + { + pa_operation *o; + o = pa_stream_cork(data->stream, 0, NULL, NULL); + if(o) pa_operation_unref(o); + } + pa_threaded_mainloop_unlock(data->loop); + Sleep(1); + pa_threaded_mainloop_lock(data->loop); + continue; + } + len -= len%update_size; + + while(len > 0) + { + size_t newlen = len; + void *buf; + pa_free_cb_t free_func = NULL; + +#if PA_CHECK_VERSION(0,9,16) + if(!pa_stream_begin_write || + pa_stream_begin_write(data->stream, &buf, &newlen) < 0) +#endif + { + buf = pa_xmalloc(newlen); + free_func = pa_xfree; + } + + aluMixData(Device, buf, newlen/frame_size); + + pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE); + len -= newlen; + } + } while(!data->killNow && Device->Connected); + pa_threaded_mainloop_unlock(data->loop); + + return 0; +} + + +static ALCboolean pulse_open(ALCdevice *device) +{ + pulse_data *data = pa_xmalloc(sizeof(pulse_data)); + memset(data, 0, sizeof(*data)); + + if(!(data->loop = pa_threaded_mainloop_new())) + { + ERR("pa_threaded_mainloop_new() failed!\n"); + goto out; + } + if(pa_threaded_mainloop_start(data->loop) < 0) + { + ERR("pa_threaded_mainloop_start() failed\n"); + goto out; + } + + pa_threaded_mainloop_lock(data->loop); + device->ExtraData = data; + + data->context = connect_context(data->loop, AL_FALSE); + if(!data->context) + { + pa_threaded_mainloop_unlock(data->loop); + goto out; + } + pa_context_set_state_callback(data->context, context_state_callback2, device); + + pa_threaded_mainloop_unlock(data->loop); + return ALC_TRUE; + +out: + if(data->loop) + { + pa_threaded_mainloop_stop(data->loop); + pa_threaded_mainloop_free(data->loop); + } + + device->ExtraData = NULL; + pa_xfree(data); + return ALC_FALSE; +} + +static void pulse_close(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + + pa_threaded_mainloop_lock(data->loop); + + if(data->stream) + { + pa_stream_set_moved_callback(data->stream, NULL, NULL); +#if PA_CHECK_VERSION(0,9,15) + if(pa_stream_set_buffer_attr_callback) + pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL); +#endif + pa_stream_disconnect(data->stream); + pa_stream_unref(data->stream); + } + + pa_context_disconnect(data->context); + pa_context_unref(data->context); + + pa_threaded_mainloop_unlock(data->loop); + + pa_threaded_mainloop_stop(data->loop); + pa_threaded_mainloop_free(data->loop); + + free(data->device_name); + + device->ExtraData = NULL; + pa_xfree(data); +} + +/* OpenAL */ +static ALCenum pulse_open_playback(ALCdevice *device, const ALCchar *device_name) +{ + const char *pulse_name = NULL; + pa_stream_flags_t flags; + pa_sample_spec spec; + pulse_data *data; + pa_operation *o; + + if(device_name) + { + ALuint i; + + if(!allDevNameMap) + probe_devices(AL_FALSE); + + 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_INVALID_VALUE; + } + + if(pulse_open(device) == ALC_FALSE) + return ALC_INVALID_VALUE; + + data = device->ExtraData; + pa_threaded_mainloop_lock(data->loop); + + flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | + PA_STREAM_FIX_CHANNELS; + if(!GetConfigValueBool("pulse", "allow-moves", 0)) + flags |= PA_STREAM_DONT_MOVE; + + spec.format = PA_SAMPLE_S16NE; + spec.rate = 44100; + spec.channels = 2; + + data->stream = connect_playback_stream(pulse_name, data->loop, data->context, + flags, NULL, &spec, NULL); + if(!data->stream) + { + pa_threaded_mainloop_unlock(data->loop); + pulse_close(device); + return ALC_INVALID_VALUE; + } + + data->device_name = strdup(pa_stream_get_device_name(data->stream)); + o = pa_context_get_sink_info_by_name(data->context, data->device_name, + sink_name_callback, device); + wait_for_operation(o, data->loop); + + pa_stream_set_moved_callback(data->stream, stream_moved_callback, device); + + pa_threaded_mainloop_unlock(data->loop); + + return ALC_NO_ERROR; +} + +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; + ALuint len; + + pa_threaded_mainloop_lock(data->loop); + + if(data->stream) + { + pa_stream_set_moved_callback(data->stream, NULL, NULL); +#if PA_CHECK_VERSION(0,9,15) + if(pa_stream_set_buffer_attr_callback) + pa_stream_set_buffer_attr_callback(data->stream, NULL, NULL); +#endif + pa_stream_disconnect(data->stream); + pa_stream_unref(data->stream); + data->stream = NULL; + } + + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + { + pa_operation *o; + o = pa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device); + wait_for_operation(o, data->loop); + } + if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) + flags |= PA_STREAM_FIX_RATE; + + flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; + flags |= PA_STREAM_ADJUST_LATENCY; + flags |= PA_STREAM_START_CORKED; + if(!GetConfigValueBool("pulse", "allow-moves", 0)) + flags |= PA_STREAM_DONT_MOVE; + + 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 DevFmtUInt: + device->FmtType = DevFmtInt; + /* fall-through */ + case DevFmtInt: + data->spec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + data->spec.format = PA_SAMPLE_FLOAT32NE; + break; + } + data->spec.rate = device->Frequency; + data->spec.channels = ChannelsFromDevFmt(device->FmtChans); + + if(pa_sample_spec_valid(&data->spec) == 0) + { + ERR("Invalid sample format\n"); + pa_threaded_mainloop_unlock(data->loop); + return ALC_FALSE; + } + + if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX)) + { + ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels); + pa_threaded_mainloop_unlock(data->loop); + return ALC_FALSE; + } + SetDefaultWFXChannelOrder(device); + + data->attr.fragsize = -1; + data->attr.prebuf = 0; + data->attr.minreq = device->UpdateSize * pa_frame_size(&data->spec); + data->attr.tlength = data->attr.minreq * maxu(device->NumUpdates, 2); + data->attr.maxlength = -1; + + data->stream = connect_playback_stream(data->device_name, data->loop, + data->context, flags, &data->attr, + &data->spec, &chanmap); + if(!data->stream) + { + pa_threaded_mainloop_unlock(data->loop); + return ALC_FALSE; + } + pa_stream_set_state_callback(data->stream, stream_state_callback2, device); + + data->spec = *(pa_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. */ + device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency * + data->spec.rate + 0.5); + data->attr.minreq = device->UpdateSize * pa_frame_size(&data->spec); + data->attr.tlength = data->attr.minreq * clampu(device->NumUpdates, 2, 16); + data->attr.maxlength = -1; + data->attr.prebuf = 0; + + o = pa_stream_set_buffer_attr(data->stream, &data->attr, + stream_success_callback, device); + wait_for_operation(o, data->loop); + + device->Frequency = data->spec.rate; + } + + pa_stream_set_moved_callback(data->stream, stream_moved_callback, device); +#if PA_CHECK_VERSION(0,9,15) + if(pa_stream_set_buffer_attr_callback) + pa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device); +#endif + stream_buffer_attr_callback(data->stream, device); + + len = data->attr.minreq / pa_frame_size(&data->spec); + if((CPUCapFlags&CPU_CAP_SSE)) + len = (len+3)&~3; + device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5); + device->NumUpdates = clampu(device->NumUpdates, 2, 16); + device->UpdateSize = len; + + pa_threaded_mainloop_unlock(data->loop); + return ALC_TRUE; +} + +static ALCboolean pulse_start_playback(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + + data->thread = StartThread(PulseProc, device); + if(!data->thread) + return ALC_FALSE; + + return ALC_TRUE; +} + +static void pulse_stop_playback(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + pa_operation *o; + + if(!data->stream) + return; + + data->killNow = AL_TRUE; + if(data->thread) + { + StopThread(data->thread); + data->thread = NULL; + } + data->killNow = AL_FALSE; + + pa_threaded_mainloop_lock(data->loop); + + o = pa_stream_cork(data->stream, 1, stream_success_callback, device); + wait_for_operation(o, data->loop); + + pa_threaded_mainloop_unlock(data->loop); +} + + +static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name) +{ + const char *pulse_name = NULL; + pa_stream_flags_t flags = 0; + pa_channel_map chanmap; + pulse_data *data; + pa_operation *o; + ALuint samples; + + if(device_name) + { + ALuint i; + + if(!allCaptureDevNameMap) + probe_devices(AL_TRUE); + + 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_INVALID_VALUE; + } + + if(pulse_open(device) == ALC_FALSE) + return ALC_INVALID_VALUE; + + data = device->ExtraData; + pa_threaded_mainloop_lock(data->loop); + + 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 DevFmtInt: + data->spec.format = PA_SAMPLE_S32NE; + break; + case DevFmtFloat: + data->spec.format = PA_SAMPLE_FLOAT32NE; + break; + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + pa_threaded_mainloop_unlock(data->loop); + goto fail; + } + + if(pa_sample_spec_valid(&data->spec) == 0) + { + ERR("Invalid sample format\n"); + pa_threaded_mainloop_unlock(data->loop); + goto fail; + } + + if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX)) + { + ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels); + pa_threaded_mainloop_unlock(data->loop); + goto fail; + } + + samples = device->UpdateSize * device->NumUpdates; + samples = maxu(samples, 100 * device->Frequency / 1000); + + data->attr.minreq = -1; + data->attr.prebuf = -1; + data->attr.maxlength = samples * pa_frame_size(&data->spec); + data->attr.tlength = -1; + data->attr.fragsize = minu(samples, 50*device->Frequency/1000) * + pa_frame_size(&data->spec); + + flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY; + if(!GetConfigValueBool("pulse", "allow-moves", 0)) + flags |= PA_STREAM_DONT_MOVE; + + data->stream = connect_record_stream(pulse_name, data->loop, data->context, + flags, &data->attr, &data->spec, + &chanmap); + if(!data->stream) + { + pa_threaded_mainloop_unlock(data->loop); + goto fail; + } + pa_stream_set_state_callback(data->stream, stream_state_callback2, device); + + data->device_name = strdup(pa_stream_get_device_name(data->stream)); + o = pa_context_get_source_info_by_name(data->context, data->device_name, + source_name_callback, device); + wait_for_operation(o, data->loop); + + pa_stream_set_moved_callback(data->stream, stream_moved_callback, device); + + pa_threaded_mainloop_unlock(data->loop); + return ALC_NO_ERROR; + +fail: + pulse_close(device); + return ALC_INVALID_VALUE; +} + +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; + + o = pa_stream_cork(data->stream, 0, stream_success_callback, device); + wait_for_operation(o, data->loop); +} + +static void pulse_stop_capture(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + pa_operation *o; + + o = pa_stream_cork(data->stream, 1, stream_success_callback, device); + wait_for_operation(o, data->loop); +} + +static ALCenum pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) +{ + pulse_data *data = device->ExtraData; + ALCuint todo = samples * pa_frame_size(&data->spec); + + /* Capture is done in fragment-sized chunks, so we loop until we get all + * that's available */ + data->last_readable -= todo; + while(todo > 0) + { + size_t rem = todo; + + if(data->cap_len == 0) + { + pa_stream_state_t state; + + state = pa_stream_get_state(data->stream); + if(!PA_STREAM_IS_GOOD(state)) + { + aluHandleDisconnect(device); + break; + } + if(pa_stream_peek(data->stream, &data->cap_store, &data->cap_len) < 0) + { + ERR("pa_stream_peek() failed: %s\n", + pa_strerror(pa_context_errno(data->context))); + aluHandleDisconnect(device); + break; + } + data->cap_remain = data->cap_len; + } + if(rem > data->cap_remain) + rem = data->cap_remain; + + memcpy(buffer, data->cap_store, rem); + + buffer = (ALbyte*)buffer + rem; + todo -= rem; + + data->cap_store = (ALbyte*)data->cap_store + rem; + data->cap_remain -= rem; + if(data->cap_remain == 0) + { + pa_stream_drop(data->stream); + data->cap_len = 0; + } + } + if(todo > 0) + memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); + + return ALC_NO_ERROR; +} + +static ALCuint pulse_available_samples(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + size_t readable = data->cap_remain; + + if(device->Connected) + { + ssize_t got = pa_stream_readable_size(data->stream); + if(got < 0) + { + ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got)); + aluHandleDisconnect(device); + } + else if((size_t)got > data->cap_len) + readable += got - data->cap_len; + } + + if(data->last_readable < readable) + data->last_readable = readable; + return data->last_readable / pa_frame_size(&data->spec); +} + + +static void pulse_lock(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + pa_threaded_mainloop_lock(data->loop); +} + +static void pulse_unlock(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + pa_threaded_mainloop_unlock(data->loop); +} + + +static ALint64 pulse_get_latency(ALCdevice *device) +{ + pulse_data *data = device->ExtraData; + pa_usec_t latency = 0; + int neg; + + if(pa_stream_get_latency(data->stream, &latency, &neg) == 0) + { + if(neg) + latency = 0; + return (ALint64)minu64(latency, MAKEU64(0x7fffffff,0xffffffff)/1000) * 1000; + } + ERR("Failed to get stream latency!\n"); + return 0; +} + + +static const BackendFuncs pulse_funcs = { + pulse_open_playback, + pulse_close_playback, + pulse_reset_playback, + pulse_start_playback, + pulse_stop_playback, + pulse_open_capture, + pulse_close_capture, + pulse_start_capture, + pulse_stop_capture, + pulse_capture_samples, + pulse_available_samples, + pulse_lock, + pulse_unlock, + pulse_get_latency +}; + +ALCboolean alc_pulse_init(BackendFuncs *func_list) +{ + ALCboolean ret = ALC_FALSE; + + if(pulse_load()) + { + pa_threaded_mainloop *loop; + + pulse_ctx_flags = 0; + if(!GetConfigValueBool("pulse", "spawn-server", 1)) + pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; + + if((loop=pa_threaded_mainloop_new()) && + pa_threaded_mainloop_start(loop) >= 0) + { + pa_context *context; + + pa_threaded_mainloop_lock(loop); + context = connect_context(loop, AL_TRUE); + if(context) + { + *func_list = pulse_funcs; + ret = ALC_TRUE; + + /* Some libraries (Phonon, Qt) set some pulseaudio properties + * through environment variables, which causes all streams in + * the process to inherit them. This attempts to filter those + * properties out by setting them to 0-length data. */ + prop_filter = pa_proplist_new(); + pa_proplist_set(prop_filter, PA_PROP_MEDIA_ROLE, NULL, 0); + pa_proplist_set(prop_filter, "phonon.streamid", NULL, 0); + + pa_context_disconnect(context); + pa_context_unref(context); + } + pa_threaded_mainloop_unlock(loop); + pa_threaded_mainloop_stop(loop); + } + if(loop) + pa_threaded_mainloop_free(loop); + } + + return ret; +} + +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(prop_filter) + pa_proplist_free(prop_filter); + prop_filter = NULL; + + /* PulseAudio doesn't like being CloseLib'd sometimes */ +} + +void alc_pulse_probe(enum DevProbe type) +{ + ALuint i; + + switch(type) + { + case ALL_DEVICE_PROBE: + 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++) + AppendAllDevicesList(allDevNameMap[i].name); + break; + + case CAPTURE_DEVICE_PROBE: + 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); + break; + } +} + +#else + +#warning "Unsupported API version, backend will be unavailable!" + +ALCboolean alc_pulse_init(BackendFuncs *func_list) +{ return ALC_FALSE; (void)func_list; } + +void alc_pulse_deinit(void) +{ } + +void alc_pulse_probe(enum DevProbe type) +{ (void)type; } + +#endif diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/sndio.c b/src/eepp/helper/android/openal-soft/Alc/backends/sndio.c new file mode 100644 index 000000000..2be887469 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/sndio.c @@ -0,0 +1,296 @@ +/** + * 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 "alu.h" + +#include + + +static const ALCchar sndio_device[] = "SndIO Default"; + + +static ALCboolean sndio_load(void) +{ + return ALC_TRUE; +} + + +typedef struct { + struct sio_hdl *sndHandle; + + ALvoid *mix_data; + ALsizei data_size; + + volatile int killNow; + ALvoid *thread; +} sndio_data; + + +static ALuint sndio_proc(ALvoid *ptr) +{ + ALCdevice *device = ptr; + sndio_data *data = device->ExtraData; + ALsizei frameSize; + size_t wrote; + + SetRTPriority(); + + frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + + while(!data->killNow && device->Connected) + { + ALsizei len = data->data_size; + ALubyte *WritePtr = data->mix_data; + + aluMixData(device, WritePtr, len/frameSize); + while(len > 0 && !data->killNow) + { + wrote = sio_write(data->sndHandle, WritePtr, len); + if(wrote == 0) + { + ERR("sio_write failed\n"); + ALCdevice_Lock(device); + aluHandleDisconnect(device); + ALCdevice_Unlock(device); + break; + } + + len -= wrote; + WritePtr += wrote; + } + } + + return 0; +} + + + +static ALCenum sndio_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + sndio_data *data; + + if(!deviceName) + deviceName = sndio_device; + else if(strcmp(deviceName, sndio_device) != 0) + return ALC_INVALID_VALUE; + + data = calloc(1, sizeof(*data)); + data->killNow = 0; + + data->sndHandle = sio_open(NULL, SIO_PLAY, 0); + if(data->sndHandle == NULL) + { + free(data); + ERR("Could not open device\n"); + return ALC_INVALID_VALUE; + } + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + + return ALC_NO_ERROR; +} + +static void sndio_close_playback(ALCdevice *device) +{ + sndio_data *data = device->ExtraData; + + sio_close(data->sndHandle); + free(data); + device->ExtraData = NULL; +} + +static ALCboolean sndio_reset_playback(ALCdevice *device) +{ + sndio_data *data = device->ExtraData; + struct sio_par par; + + sio_initpar(&par); + + par.rate = device->Frequency; + par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); + + switch(device->FmtType) + { + case DevFmtByte: + par.bits = 8; + par.sig = 1; + break; + case DevFmtUByte: + par.bits = 8; + par.sig = 0; + break; + case DevFmtFloat: + case DevFmtShort: + par.bits = 16; + par.sig = 1; + break; + case DevFmtUShort: + par.bits = 16; + par.sig = 0; + break; + case DevFmtInt: + par.bits = 32; + par.sig = 1; + break; + case DevFmtUInt: + par.bits = 32; + par.sig = 0; + break; + } + par.le = SIO_LE_NATIVE; + + par.round = device->UpdateSize; + par.appbufsz = device->UpdateSize * (device->NumUpdates-1); + if(!par.appbufsz) par.appbufsz = device->UpdateSize; + + if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par)) + { + ERR("Failed to set device parameters\n"); + return ALC_FALSE; + } + + if(par.bits != par.bps*8) + { + ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); + return ALC_FALSE; + } + + device->Frequency = par.rate; + device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); + + if(par.bits == 8 && par.sig == 1) + device->FmtType = DevFmtByte; + else if(par.bits == 8 && par.sig == 0) + device->FmtType = DevFmtUByte; + else if(par.bits == 16 && par.sig == 1) + device->FmtType = DevFmtShort; + else if(par.bits == 16 && par.sig == 0) + device->FmtType = DevFmtUShort; + else if(par.bits == 32 && par.sig == 1) + device->FmtType = DevFmtInt; + else if(par.bits == 32 && par.sig == 0) + device->FmtType = DevFmtUInt; + else + { + ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); + return ALC_FALSE; + } + + device->UpdateSize = par.round; + device->NumUpdates = (par.bufsz/par.round) + 1; + + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean sndio_start_playback(ALCdevice *device) +{ + sndio_data *data = device->ExtraData; + + if(!sio_start(data->sndHandle)) + { + ERR("Error starting playback\n"); + return ALC_FALSE; + } + + data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + data->mix_data = calloc(1, data->data_size); + + data->thread = StartThread(sndio_proc, device); + if(data->thread == NULL) + { + sio_stop(data->sndHandle); + free(data->mix_data); + data->mix_data = NULL; + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void sndio_stop_playback(ALCdevice *device) +{ + sndio_data *data = device->ExtraData; + + if(!data->thread) + return; + + data->killNow = 1; + StopThread(data->thread); + data->thread = NULL; + + data->killNow = 0; + if(!sio_stop(data->sndHandle)) + ERR("Error stopping device\n"); + + free(data->mix_data); + data->mix_data = NULL; +} + + +static const BackendFuncs sndio_funcs = { + sndio_open_playback, + sndio_close_playback, + sndio_reset_playback, + sndio_start_playback, + sndio_stop_playback, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_sndio_init(BackendFuncs *func_list) +{ + if(!sndio_load()) + return ALC_FALSE; + *func_list = sndio_funcs; + return ALC_TRUE; +} + +void alc_sndio_deinit(void) +{ +} + +void alc_sndio_probe(enum DevProbe type) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + AppendAllDevicesList(sndio_device); + break; + case CAPTURE_DEVICE_PROBE: + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/solaris.c b/src/eepp/helper/android/openal-soft/Alc/backends/solaris.c new file mode 100644 index 000000000..1c781387d --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/solaris.c @@ -0,0 +1,287 @@ +/** + * 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 "alu.h" + +#include + + +static const ALCchar solaris_device[] = "Solaris Default"; + +static const char *solaris_driver = "/dev/audio"; + +typedef struct { + int fd; + volatile int killNow; + ALvoid *thread; + + ALubyte *mix_data; + int data_size; +} solaris_data; + + +static ALuint SolarisProc(ALvoid *ptr) +{ + ALCdevice *Device = (ALCdevice*)ptr; + solaris_data *data = (solaris_data*)Device->ExtraData; + ALint frameSize; + int wrote; + + SetRTPriority(); + + frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + + while(!data->killNow && Device->Connected) + { + ALint len = data->data_size; + ALubyte *WritePtr = data->mix_data; + + aluMixData(Device, WritePtr, len/frameSize); + while(len > 0 && !data->killNow) + { + wrote = write(data->fd, WritePtr, len); + if(wrote < 0) + { + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + { + ERR("write failed: %s\n", strerror(errno)); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + break; + } + + Sleep(1); + continue; + } + + len -= wrote; + WritePtr += wrote; + } + } + + return 0; +} + + +static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + solaris_data *data; + + if(!deviceName) + deviceName = solaris_device; + else if(strcmp(deviceName, solaris_device) != 0) + return ALC_INVALID_VALUE; + + data = (solaris_data*)calloc(1, sizeof(solaris_data)); + data->killNow = 0; + + data->fd = open(solaris_driver, O_WRONLY); + if(data->fd == -1) + { + free(data); + ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); + return ALC_INVALID_VALUE; + } + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_NO_ERROR; +} + +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 DevFmtInt: + case DevFmtUInt: + 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) + { + ERR("ioctl failed: %s\n", strerror(errno)); + return ALC_FALSE; + } + + if(ChannelsFromDevFmt(device->FmtChans) != info.play.channels) + { + ERR("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_LINEAR8 && device->FmtType == DevFmtUByte) || + (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) || + (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) || + (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt))) + { + ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(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; + + SetDefaultChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean solaris_start_playback(ALCdevice *device) +{ + solaris_data *data = (solaris_data*)device->ExtraData; + + data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + data->mix_data = calloc(1, data->data_size); + + 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) + ERR("Error draining device: %s\n", strerror(errno)); + + free(data->mix_data); + data->mix_data = NULL; +} + + +static const BackendFuncs solaris_funcs = { + solaris_open_playback, + solaris_close_playback, + solaris_reset_playback, + solaris_start_playback, + solaris_stop_playback, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_solaris_init(BackendFuncs *func_list) +{ + ConfigValueStr("solaris", "device", &solaris_driver); + + *func_list = solaris_funcs; + return ALC_TRUE; +} + +void alc_solaris_deinit(void) +{ +} + +void alc_solaris_probe(enum DevProbe type) +{ + switch(type) + { + case ALL_DEVICE_PROBE: + { +#ifdef HAVE_STAT + struct stat buf; + if(stat(solaris_driver, &buf) == 0) +#endif + AppendAllDevicesList(solaris_device); + } + break; + + case CAPTURE_DEVICE_PROBE: + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/wave.c b/src/eepp/helper/android/openal-soft/Alc/backends/wave.c new file mode 100644 index 000000000..be528c9a0 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/wave.c @@ -0,0 +1,370 @@ +/** + * 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_WINDOWS_H +#include +#endif + +#include "alMain.h" +#include "alu.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 *Device = (ALCdevice*)ptr; + wave_data *data = (wave_data*)Device->ExtraData; + ALuint frameSize; + ALuint now, start; + ALuint64 avail, done; + size_t fs; + const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 / + Device->Frequency / 2; + + frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + + done = 0; + start = timeGetTime(); + while(!data->killNow && Device->Connected) + { + now = timeGetTime(); + + avail = (ALuint64)(now-start) * Device->Frequency / 1000; + if(avail < done) + { + /* Timer wrapped (50 days???). Add the remainder of the cycle to + * the available count and reset the number of samples done */ + avail += ((ALuint64)1<<32)*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; + + if(!IS_LITTLE_ENDIAN) + { + ALuint bytesize = BytesFromDevFmt(Device->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, Device->UpdateSize, + data->f); + fs = fs; + } + if(ferror(data->f)) + { + ERR("Error writing to file\n"); + ALCdevice_Lock(Device); + aluHandleDisconnect(Device); + ALCdevice_Unlock(Device); + break; + } + } + } + + return 0; +} + +static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + wave_data *data; + const char *fname; + + fname = GetConfigValue("wave", "file", ""); + if(!fname[0]) + return ALC_INVALID_VALUE; + + if(!deviceName) + deviceName = waveDevice; + else if(strcmp(deviceName, waveDevice) != 0) + return ALC_INVALID_VALUE; + + data = (wave_data*)calloc(1, sizeof(wave_data)); + + data->f = fopen(fname, "wb"); + if(!data->f) + { + free(data); + ERR("Could not open file '%s': %s\n", fname, strerror(errno)); + return ALC_INVALID_VALUE; + } + + device->DeviceName = strdup(deviceName); + device->ExtraData = data; + return ALC_NO_ERROR; +} + +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 DevFmtUInt: + device->FmtType = DevFmtInt; + break; + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + 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); + val = val; + + fprintf(data->f, "data"); + fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close + + if(ferror(data->f)) + { + ERR("Error writing header: %s\n", strerror(errno)); + return ALC_FALSE; + } + data->DataStart = ftell(data->f); + + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean wave_start_playback(ALCdevice *device) +{ + wave_data *data = (wave_data*)device->ExtraData; + + data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + data->buffer = malloc(data->size); + if(!data->buffer) + { + ERR("Buffer malloc failed\n"); + return ALC_FALSE; + } + + 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 const BackendFuncs wave_funcs = { + wave_open_playback, + wave_close_playback, + wave_reset_playback, + wave_start_playback, + wave_stop_playback, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alc_wave_init(BackendFuncs *func_list) +{ + *func_list = wave_funcs; + return ALC_TRUE; +} + +void alc_wave_deinit(void) +{ +} + +void alc_wave_probe(enum DevProbe type) +{ + if(!ConfigValueExists("wave", "file")) + return; + + switch(type) + { + case ALL_DEVICE_PROBE: + AppendAllDevicesList(waveDevice); + break; + case CAPTURE_DEVICE_PROBE: + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/backends/winmm.c b/src/eepp/helper/android/openal-soft/Alc/backends/winmm.c new file mode 100644 index 000000000..4786d9b40 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/backends/winmm.c @@ -0,0 +1,774 @@ +/** + * 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 "alu.h" + +#ifndef WAVE_FORMAT_IEEE_FLOAT +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#endif + + +typedef struct { + // MMSYSTEM Device + volatile ALboolean killNow; + HANDLE WaveThreadEvent; + HANDLE WaveThread; + DWORD WaveThreadID; + volatile LONG WaveBuffersCommitted; + WAVEHDR WaveBuffer[4]; + + union { + HWAVEIN In; + HWAVEOUT Out; + } WaveHandle; + + WAVEFORMATEX Format; + + RingBuffer *Ring; +} WinMMData; + + +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", WaveCaps.szPname); + else + snprintf(name, sizeof(name), "%s #%d", 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", WaveInCaps.szPname); + else + snprintf(name, sizeof(name), "%s #%d", 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 device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) +{ + ALCdevice *Device = (ALCdevice*)instance; + WinMMData *data = Device->ExtraData; + + (void)device; + (void)param2; + + if(msg != WOM_DONE) + return; + + InterlockedDecrement(&data->WaveBuffersCommitted); + PostThreadMessage(data->WaveThreadID, msg, 0, param1); +} + +/* + PlaybackThreadProc + + Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its + audio data. +*/ +static DWORD WINAPI PlaybackThreadProc(LPVOID param) +{ + ALCdevice *Device = (ALCdevice*)param; + WinMMData *data = Device->ExtraData; + LPWAVEHDR WaveHdr; + ALuint FrameSize; + MSG msg; + + FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + + SetRTPriority(); + + while(GetMessage(&msg, NULL, 0, 0)) + { + if(msg.message != WOM_DONE) + continue; + + if(data->killNow) + { + if(data->WaveBuffersCommitted == 0) + break; + continue; + } + + WaveHdr = ((LPWAVEHDR)msg.lParam); + aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength/FrameSize); + + // Send buffer back to play more data + waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR)); + InterlockedIncrement(&data->WaveBuffersCommitted); + } + + // Signal Wave Thread completed event + if(data->WaveThreadEvent) + SetEvent(data->WaveThreadEvent); + + 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 device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) +{ + ALCdevice *Device = (ALCdevice*)instance; + WinMMData *data = Device->ExtraData; + + (void)device; + (void)param2; + + if(msg != WIM_DATA) + return; + + InterlockedDecrement(&data->WaveBuffersCommitted); + PostThreadMessage(data->WaveThreadID, msg, 0, param1); +} + +/* + CaptureThreadProc + + Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new + audio data. +*/ +static DWORD WINAPI CaptureThreadProc(LPVOID param) +{ + ALCdevice *Device = (ALCdevice*)param; + WinMMData *data = Device->ExtraData; + LPWAVEHDR WaveHdr; + ALuint FrameSize; + MSG msg; + + FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); + + while(GetMessage(&msg, NULL, 0, 0)) + { + if(msg.message != WIM_DATA) + continue; + /* Don't wait for other buffers to finish before quitting. We're + * closing so we don't need them. */ + if(data->killNow) + break; + + WaveHdr = ((LPWAVEHDR)msg.lParam); + WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData, WaveHdr->dwBytesRecorded/FrameSize); + + // Send buffer back to capture more data + waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR)); + InterlockedIncrement(&data->WaveBuffersCommitted); + } + + // Signal Wave Thread completed event + if(data->WaveThreadEvent) + SetEvent(data->WaveThreadEvent); + + ExitThread(0); + return 0; +} + + +static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName) +{ + WinMMData *data = NULL; + UINT DeviceID = 0; + MMRESULT res; + ALuint i = 0; + + if(!PlaybackDeviceList) + ProbePlaybackDevices(); + + // Find the Device ID matching the deviceName if valid + for(i = 0;i < NumPlaybackDevices;i++) + { + if(PlaybackDeviceList[i] && + (!deviceName || strcmp(deviceName, PlaybackDeviceList[i]) == 0)) + { + DeviceID = i; + break; + } + } + if(i == NumPlaybackDevices) + return ALC_INVALID_VALUE; + + data = calloc(1, sizeof(*data)); + if(!data) + return ALC_OUT_OF_MEMORY; + Device->ExtraData = data; + +retry_open: + memset(&data->Format, 0, sizeof(WAVEFORMATEX)); + if(Device->FmtType == DevFmtFloat) + { + data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + data->Format.wBitsPerSample = 32; + } + else + { + data->Format.wFormatTag = WAVE_FORMAT_PCM; + if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte) + data->Format.wBitsPerSample = 8; + else + data->Format.wBitsPerSample = 16; + } + data->Format.nChannels = ((Device->FmtChans == DevFmtMono) ? 1 : 2); + data->Format.nBlockAlign = data->Format.wBitsPerSample * + data->Format.nChannels / 8; + data->Format.nSamplesPerSec = Device->Frequency; + data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * + data->Format.nBlockAlign; + data->Format.cbSize = 0; + + if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + { + if(Device->FmtType == DevFmtFloat) + { + Device->FmtType = DevFmtShort; + goto retry_open; + } + ERR("waveOutOpen failed: %u\n", res); + goto failure; + } + + data->WaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(data->WaveThreadEvent == NULL) + { + ERR("CreateEvent failed: %lu\n", GetLastError()); + goto failure; + } + + Device->DeviceName = strdup(PlaybackDeviceList[DeviceID]); + return ALC_NO_ERROR; + +failure: + if(data->WaveThreadEvent) + CloseHandle(data->WaveThreadEvent); + + if(data->WaveHandle.Out) + waveOutClose(data->WaveHandle.Out); + + free(data); + Device->ExtraData = NULL; + return ALC_INVALID_VALUE; +} + +static void WinMMClosePlayback(ALCdevice *device) +{ + WinMMData *data = (WinMMData*)device->ExtraData; + + // Close the Wave device + CloseHandle(data->WaveThreadEvent); + data->WaveThreadEvent = 0; + + waveOutClose(data->WaveHandle.Out); + data->WaveHandle.Out = 0; + + free(data); + device->ExtraData = NULL; +} + +static ALCboolean WinMMResetPlayback(ALCdevice *device) +{ + WinMMData *data = (WinMMData*)device->ExtraData; + + device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * + data->Format.nSamplesPerSec / + device->Frequency); + device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; + device->NumUpdates = 4; + device->Frequency = data->Format.nSamplesPerSec; + + if(data->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + { + if(data->Format.wBitsPerSample == 32) + device->FmtType = DevFmtFloat; + else + { + ERR("Unhandled IEEE float sample depth: %d\n", data->Format.wBitsPerSample); + return ALC_FALSE; + } + } + else if(data->Format.wFormatTag == WAVE_FORMAT_PCM) + { + if(data->Format.wBitsPerSample == 16) + device->FmtType = DevFmtShort; + else if(data->Format.wBitsPerSample == 8) + device->FmtType = DevFmtUByte; + else + { + ERR("Unhandled PCM sample depth: %d\n", data->Format.wBitsPerSample); + return ALC_FALSE; + } + } + else + { + ERR("Unhandled format tag: 0x%04x\n", data->Format.wFormatTag); + return ALC_FALSE; + } + + if(data->Format.nChannels == 2) + device->FmtChans = DevFmtStereo; + else if(data->Format.nChannels == 1) + device->FmtChans = DevFmtMono; + else + { + ERR("Unhandled channel count: %d\n", data->Format.nChannels); + return ALC_FALSE; + } + SetDefaultWFXChannelOrder(device); + + return ALC_TRUE; +} + +static ALCboolean WinMMStartPlayback(ALCdevice *device) +{ + WinMMData *data = (WinMMData*)device->ExtraData; + ALbyte *BufferData; + ALint BufferSize; + ALuint i; + + data->WaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &data->WaveThreadID); + if(data->WaveThread == NULL) + return ALC_FALSE; + + data->WaveBuffersCommitted = 0; + + // Create 4 Buffers + BufferSize = device->UpdateSize*device->NumUpdates / 4; + BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + + BufferData = calloc(4, BufferSize); + for(i = 0;i < 4;i++) + { + memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); + data->WaveBuffer[i].dwBufferLength = BufferSize; + data->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData : + (data->WaveBuffer[i-1].lpData + + data->WaveBuffer[i-1].dwBufferLength)); + waveOutPrepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); + waveOutWrite(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); + InterlockedIncrement(&data->WaveBuffersCommitted); + } + + return ALC_TRUE; +} + +static void WinMMStopPlayback(ALCdevice *device) +{ + WinMMData *data = (WinMMData*)device->ExtraData; + void *buffer = NULL; + int i; + + if(data->WaveThread == NULL) + return; + + // Set flag to stop processing headers + data->killNow = AL_TRUE; + + // Wait for signal that Wave Thread has been destroyed + WaitForSingleObjectEx(data->WaveThreadEvent, 5000, FALSE); + + CloseHandle(data->WaveThread); + data->WaveThread = 0; + + data->killNow = AL_FALSE; + + // Release the wave buffers + for(i = 0;i < 4;i++) + { + waveOutUnprepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = data->WaveBuffer[i].lpData; + data->WaveBuffer[i].lpData = NULL; + } + free(buffer); +} + + +static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) +{ + ALbyte *BufferData = NULL; + DWORD CapturedDataSize; + WinMMData *data = NULL; + UINT DeviceID = 0; + ALint BufferSize; + MMRESULT res; + ALuint i; + + if(!CaptureDeviceList) + ProbeCaptureDevices(); + + // Find the Device ID matching the deviceName if valid + for(i = 0;i < NumCaptureDevices;i++) + { + if(CaptureDeviceList[i] && + (!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0)) + { + DeviceID = i; + break; + } + } + if(i == NumCaptureDevices) + return ALC_INVALID_VALUE; + + switch(Device->FmtChans) + { + case DevFmtMono: + case DevFmtStereo: + break; + + case DevFmtQuad: + case DevFmtX51: + case DevFmtX51Side: + case DevFmtX61: + case DevFmtX71: + return ALC_INVALID_ENUM; + } + + switch(Device->FmtType) + { + case DevFmtUByte: + case DevFmtShort: + case DevFmtInt: + case DevFmtFloat: + break; + + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + return ALC_INVALID_ENUM; + } + + data = calloc(1, sizeof(*data)); + if(!data) + return ALC_OUT_OF_MEMORY; + Device->ExtraData = data; + + memset(&data->Format, 0, sizeof(WAVEFORMATEX)); + data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ? + WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); + data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans); + data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; + data->Format.nBlockAlign = data->Format.wBitsPerSample * + data->Format.nChannels / 8; + data->Format.nSamplesPerSec = Device->Frequency; + data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * + data->Format.nBlockAlign; + data->Format.cbSize = 0; + + if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + { + ERR("waveInOpen failed: %u\n", res); + goto failure; + } + + data->WaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(data->WaveThreadEvent == NULL) + { + ERR("CreateEvent failed: %lu\n", GetLastError()); + goto failure; + } + + // Allocate circular memory buffer for the captured audio + CapturedDataSize = Device->UpdateSize*Device->NumUpdates; + + // Make sure circular buffer is at least 100ms in size + if(CapturedDataSize < (data->Format.nSamplesPerSec / 10)) + CapturedDataSize = data->Format.nSamplesPerSec / 10; + + data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize); + if(!data->Ring) + goto failure; + + data->WaveBuffersCommitted = 0; + + // Create 4 Buffers of 50ms each + BufferSize = data->Format.nAvgBytesPerSec / 20; + BufferSize -= (BufferSize % data->Format.nBlockAlign); + + BufferData = calloc(4, BufferSize); + if(!BufferData) + goto failure; + + for(i = 0;i < 4;i++) + { + memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); + data->WaveBuffer[i].dwBufferLength = BufferSize; + data->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData : + (data->WaveBuffer[i-1].lpData + + data->WaveBuffer[i-1].dwBufferLength)); + data->WaveBuffer[i].dwFlags = 0; + data->WaveBuffer[i].dwLoops = 0; + waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); + InterlockedIncrement(&data->WaveBuffersCommitted); + } + + data->WaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)Device, 0, &data->WaveThreadID); + if (data->WaveThread == NULL) + goto failure; + + Device->DeviceName = strdup(CaptureDeviceList[DeviceID]); + return ALC_NO_ERROR; + +failure: + if(data->WaveThread) + CloseHandle(data->WaveThread); + + if(BufferData) + { + for(i = 0;i < 4;i++) + waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); + free(BufferData); + } + + if(data->Ring) + DestroyRingBuffer(data->Ring); + + if(data->WaveThreadEvent) + CloseHandle(data->WaveThreadEvent); + + if(data->WaveHandle.In) + waveInClose(data->WaveHandle.In); + + free(data); + Device->ExtraData = NULL; + return ALC_INVALID_VALUE; +} + +static void WinMMCloseCapture(ALCdevice *Device) +{ + WinMMData *data = (WinMMData*)Device->ExtraData; + void *buffer = NULL; + int i; + + /* Tell the processing thread to quit and wait for it to do so. */ + data->killNow = AL_TRUE; + PostThreadMessage(data->WaveThreadID, WM_QUIT, 0, 0); + + WaitForSingleObjectEx(data->WaveThreadEvent, 5000, FALSE); + + /* Make sure capture is stopped and all pending buffers are flushed. */ + waveInReset(data->WaveHandle.In); + + CloseHandle(data->WaveThread); + data->WaveThread = 0; + + // Release the wave buffers + for(i = 0;i < 4;i++) + { + waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = data->WaveBuffer[i].lpData; + data->WaveBuffer[i].lpData = NULL; + } + free(buffer); + + DestroyRingBuffer(data->Ring); + data->Ring = NULL; + + // Close the Wave device + CloseHandle(data->WaveThreadEvent); + data->WaveThreadEvent = 0; + + waveInClose(data->WaveHandle.In); + data->WaveHandle.In = 0; + + free(data); + Device->ExtraData = NULL; +} + +static void WinMMStartCapture(ALCdevice *Device) +{ + WinMMData *data = (WinMMData*)Device->ExtraData; + waveInStart(data->WaveHandle.In); +} + +static void WinMMStopCapture(ALCdevice *Device) +{ + WinMMData *data = (WinMMData*)Device->ExtraData; + waveInStop(data->WaveHandle.In); +} + +static ALCenum WinMMCaptureSamples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) +{ + WinMMData *data = (WinMMData*)Device->ExtraData; + ReadRingBuffer(data->Ring, Buffer, Samples); + return ALC_NO_ERROR; +} + +static ALCuint WinMMAvailableSamples(ALCdevice *Device) +{ + WinMMData *data = (WinMMData*)Device->ExtraData; + return RingBufferSize(data->Ring); +} + + +static const BackendFuncs WinMMFuncs = { + WinMMOpenPlayback, + WinMMClosePlayback, + WinMMResetPlayback, + WinMMStartPlayback, + WinMMStopPlayback, + WinMMOpenCapture, + WinMMCloseCapture, + WinMMStartCapture, + WinMMStopCapture, + WinMMCaptureSamples, + WinMMAvailableSamples, + ALCdevice_LockDefault, + ALCdevice_UnlockDefault, + ALCdevice_GetLatencyDefault +}; + +ALCboolean alcWinMMInit(BackendFuncs *FuncList) +{ + *FuncList = WinMMFuncs; + return ALC_TRUE; +} + +void alcWinMMDeinit() +{ + ALuint i; + + for(i = 0;i < NumPlaybackDevices;i++) + free(PlaybackDeviceList[i]); + free(PlaybackDeviceList); + PlaybackDeviceList = NULL; + + NumPlaybackDevices = 0; + + + for(i = 0;i < NumCaptureDevices;i++) + free(CaptureDeviceList[i]); + free(CaptureDeviceList); + CaptureDeviceList = NULL; + + NumCaptureDevices = 0; +} + +void alcWinMMProbe(enum DevProbe type) +{ + ALuint i; + + switch(type) + { + case ALL_DEVICE_PROBE: + ProbePlaybackDevices(); + for(i = 0;i < NumPlaybackDevices;i++) + { + if(PlaybackDeviceList[i]) + AppendAllDevicesList(PlaybackDeviceList[i]); + } + break; + + case CAPTURE_DEVICE_PROBE: + ProbeCaptureDevices(); + for(i = 0;i < NumCaptureDevices;i++) + { + if(CaptureDeviceList[i]) + AppendCaptureDeviceList(CaptureDeviceList[i]); + } + break; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/bs2b.c b/src/eepp/helper/android/openal-soft/Alc/bs2b.c new file mode 100644 index 000000000..0319f948d --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/bs2b.c @@ -0,0 +1,185 @@ +/*- + * 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 + +#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.0f / (float)(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) +{ + memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample)); +} /* bs2b_clear */ + +void bs2b_cross_feed(struct bs2b *bs2b, float *sample) +{ + /* Lowpass filter */ + bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]); + bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]); + + /* Highboost filter */ + bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]); + bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]); + bs2b->last_sample.asis[0] = sample[0]; + bs2b->last_sample.asis[1] = sample[1]; + + /* Crossfeed */ + sample[0] = (float)(bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1]); + sample[1] = (float)(bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0]); + + /* Bass boost cause allpass attenuation */ + sample[0] *= bs2b->gain; + sample[1] *= bs2b->gain; + + /* Clipping of overloaded samples */ +#if 0 + if (sample[0] > 1.0) + sample[0] = 1.0; + if (sample[0] < -1.0) + sample[0] = -1.0; + if (sample[1] > 1.0) + sample[1] = 1.0; + if (sample[1] < -1.0) + sample[1] = -1.0; +#endif +} /* bs2b_cross_feed */ diff --git a/src/eepp/helper/android/openal-soft/Alc/helpers.c b/src/eepp/helper/android/openal-soft/Alc/helpers.c new file mode 100644 index 000000000..6358f0449 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/helpers.c @@ -0,0 +1,674 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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 +#ifdef HAVE_MALLOC_H +#include +#endif + +#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) +#define INITGUID +#include +#ifdef HAVE_GUIDDEF_H +#include +#else +#include +#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); + +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); + +DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); +DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); +DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); +DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); + +#ifdef HAVE_MMDEVAPI +#include +DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +#endif +#endif +#ifdef HAVE_DLFCN_H +#include +#endif +#ifdef HAVE_CPUID_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_IEEEFP_H +#include +#endif + +#include "alMain.h" + +ALuint CPUCapFlags = 0; + + +void FillCPUCaps(ALuint capfilter) +{ + ALuint caps = 0; + +/* FIXME: We really should get this for all available CPUs in case different + * CPUs have different caps (is that possible on one machine?). */ +#if defined(HAVE_CPUID_H) && (defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64)) + union { + unsigned int regs[4]; + char str[sizeof(unsigned int[4])]; + } cpuinf[3]; + + if(!__get_cpuid(0, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) + ERR("Failed to get CPUID\n"); + else + { + unsigned int maxfunc = cpuinf[0].regs[0]; + unsigned int maxextfunc = 0; + + if(__get_cpuid(0x80000000, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) + maxextfunc = cpuinf[0].regs[0]; + TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); + + TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); + if(maxextfunc >= 0x80000004 && + __get_cpuid(0x80000002, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]) && + __get_cpuid(0x80000003, &cpuinf[1].regs[0], &cpuinf[1].regs[1], &cpuinf[1].regs[2], &cpuinf[1].regs[3]) && + __get_cpuid(0x80000004, &cpuinf[2].regs[0], &cpuinf[2].regs[1], &cpuinf[2].regs[2], &cpuinf[2].regs[3])) + TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); + + if(maxfunc >= 1 && + __get_cpuid(1, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) + { +#ifdef bit_SSE + if((cpuinf[0].regs[3]&bit_SSE)) + caps |= CPU_CAP_SSE; +#endif + } + } +#elif defined(HAVE_WINDOWS_H) + HMODULE k32 = GetModuleHandleA("kernel32.dll"); + BOOL (WINAPI*IsProcessorFeaturePresent)(DWORD ProcessorFeature); + IsProcessorFeaturePresent = (BOOL(WINAPI*)(DWORD))GetProcAddress(k32, "IsProcessorFeaturePresent"); + if(!IsProcessorFeaturePresent) + ERR("IsProcessorFeaturePresent not available; CPU caps not detected\n"); + else + { + if(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) + caps |= CPU_CAP_SSE; + } +#endif +#ifdef HAVE_NEON + /* Assume Neon support if compiled with it */ + caps |= CPU_CAP_NEON; +#endif + + TRACE("Got caps:%s%s%s\n", ((caps&CPU_CAP_SSE)?((capfilter&CPU_CAP_SSE)?" SSE":" (SSE)"):""), + ((caps&CPU_CAP_NEON)?((capfilter&CPU_CAP_NEON)?" Neon":" (Neon)"):""), + ((!caps)?" -none-":"")); + CPUCapFlags = caps & capfilter; +} + + +void *al_malloc(size_t alignment, size_t size) +{ +#if defined(HAVE_ALIGNED_ALLOC) + size = (size+(alignment-1))&~(alignment-1); + return aligned_alloc(alignment, size); +#elif defined(HAVE_POSIX_MEMALIGN) + void *ret; + if(posix_memalign(&ret, alignment, size) == 0) + return ret; + return NULL; +#elif defined(HAVE__ALIGNED_MALLOC) + return _aligned_malloc(size, alignment); +#else + char *ret = malloc(size+alignment); + if(ret != NULL) + { + *(ret++) = 0x00; + while(((ALintptrEXT)ret&(alignment-1)) != 0) + *(ret++) = 0x55; + } + return ret; +#endif +} + +void *al_calloc(size_t alignment, size_t size) +{ + void *ret = al_malloc(alignment, size); + if(ret) memset(ret, 0, size); + return ret; +} + +void al_free(void *ptr) +{ +#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) + free(ptr); +#elif defined(HAVE__ALIGNED_MALLOC) + _aligned_free(ptr); +#else + if(ptr != NULL) + { + char *finder = ptr; + do { + --finder; + } while(*finder == 0x55); + free(finder); + } +#endif +} + + +#if (defined(HAVE___CONTROL87_2) || defined(HAVE__CONTROLFP)) && (defined(__x86_64__) || defined(_M_X64)) +/* Win64 doesn't allow us to set the precision control. */ +#undef _MCW_PC +#define _MCW_PC 0 +#endif + +void SetMixerFPUMode(FPUCtl *ctl) +{ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + unsigned short fpuState; + __asm__ __volatile__("fnstcw %0" : "=m" (*&fpuState)); + ctl->state = fpuState; + fpuState &= ~0x300; /* clear precision to single */ + fpuState |= 0xC00; /* set round-to-zero */ + __asm__ __volatile__("fldcw %0" : : "m" (*&fpuState)); +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + { + int sseState; + __asm__ __volatile__("stmxcsr %0" : "=m" (*&sseState)); + ctl->sse_state = sseState; + sseState |= 0x0C00; /* set round-to-zero */ + sseState |= 0x8000; /* set flush-to-zero */ + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); + } +#endif +#elif defined(HAVE___CONTROL87_2) + int mode; + __control87_2(0, 0, &ctl->state, NULL); + __control87_2(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC, &mode, NULL); +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + { + __control87_2(0, 0, NULL, &ctl->sse_state); + __control87_2(_RC_CHOP|_DN_FLUSH, _MCW_RC|_MCW_DN, NULL, &mode); + } +#endif +#elif defined(HAVE__CONTROLFP) + ctl->state = _controlfp(0, 0); + (void)_controlfp(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC); +#elif defined(HAVE_FESETROUND) + ctl->state = fegetround(); +#ifdef FE_TOWARDZERO + fesetround(FE_TOWARDZERO); +#endif +#endif +} + +void RestoreFPUMode(const FPUCtl *ctl) +{ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + unsigned short fpuState = ctl->state; + __asm__ __volatile__("fldcw %0" : : "m" (*&fpuState)); +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); +#endif +#elif defined(HAVE___CONTROL87_2) + int mode; + __control87_2(ctl->state, _MCW_RC|_MCW_PC, &mode, NULL); +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + __control87_2(ctl->sse_state, _MCW_RC|_MCW_DN, NULL, &mode); +#endif +#elif defined(HAVE__CONTROLFP) + _controlfp(ctl->state, _MCW_RC|_MCW_PC); +#elif defined(HAVE_FESETROUND) + fesetround(ctl->state); +#endif +} + + +#ifdef _WIN32 +void pthread_once(pthread_once_t *once, void (*callback)(void)) +{ + LONG ret; + while((ret=InterlockedExchange(once, 1)) == 1) + sched_yield(); + if(ret == 0) + callback(); + InterlockedExchange(once, 2); +} + + +int pthread_key_create(pthread_key_t *key, void (*callback)(void*)) +{ + *key = TlsAlloc(); + if(callback) + InsertUIntMapEntry(&TlsDestructor, *key, callback); + return 0; +} + +int pthread_key_delete(pthread_key_t key) +{ + InsertUIntMapEntry(&TlsDestructor, key, NULL); + TlsFree(key); + return 0; +} + +void *pthread_getspecific(pthread_key_t key) +{ return TlsGetValue(key); } + +int pthread_setspecific(pthread_key_t key, void *val) +{ + TlsSetValue(key, val); + return 0; +} + + +void *LoadLib(const char *name) +{ return LoadLibraryA(name); } +void CloseLib(void *handle) +{ FreeLibrary((HANDLE)handle); } +void *GetSymbol(void *handle, const char *name) +{ + void *ret; + + ret = (void*)GetProcAddress((HANDLE)handle, name); + if(ret == NULL) + ERR("Failed to load %s\n", name); + return ret; +} + +WCHAR *strdupW(const WCHAR *str) +{ + const WCHAR *n; + WCHAR *ret; + size_t len; + + n = str; + while(*n) n++; + len = n - str; + + ret = calloc(sizeof(WCHAR), len+1); + if(ret != NULL) + memcpy(ret, str, sizeof(WCHAR)*len); + return ret; +} + +#else + +#include +#ifdef HAVE_PTHREAD_NP_H +#include +#endif +#include + +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); +} +void DeleteCriticalSection(CRITICAL_SECTION *cs) +{ + int ret; + ret = pthread_mutex_destroy(cs); + assert(ret == 0); +} +void EnterCriticalSection(CRITICAL_SECTION *cs) +{ + int ret; + ret = pthread_mutex_lock(cs); + assert(ret == 0); +} +void LeaveCriticalSection(CRITICAL_SECTION *cs) +{ + int ret; + ret = pthread_mutex_unlock(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. */ +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 +} + +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; +} + +#ifdef HAVE_DLFCN_H + +void *LoadLib(const char *name) +{ + const char *err; + void *handle; + + dlerror(); + handle = dlopen(name, RTLD_NOW); + if((err=dlerror()) != NULL) + handle = NULL; + return handle; +} +void CloseLib(void *handle) +{ dlclose(handle); } +void *GetSymbol(void *handle, const char *name) +{ + const char *err; + void *sym; + + dlerror(); + sym = dlsym(handle, name); + if((err=dlerror()) != NULL) + { + WARN("Failed to load %s: %s\n", name, err); + sym = NULL; + } + return sym; +} + +#endif +#endif + + +void al_print(const char *type, const char *func, const char *fmt, ...) +{ + char str[256]; + int i; + + i = snprintf(str, sizeof(str), "AL lib: %s %s: ", type, func); + if(i > 0 && (unsigned int)i < sizeof(str)) + { + 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 = AL_FALSE; + +#ifdef _WIN32 + if(RTPrioLevel > 0) + failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); +#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) + if(RTPrioLevel > 0) + { + struct sched_param param; + /* 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 + /* Real-time priority not available */ + failed = (RTPrioLevel>0); +#endif + if(failed) + ERR("Failed to set priority level for thread\n"); +} + + +static void Lock(volatile ALenum *l) +{ + while(ExchangeInt(l, AL_TRUE) == AL_TRUE) + sched_yield(); +} + +static void Unlock(volatile ALenum *l) +{ + ExchangeInt(l, AL_FALSE); +} + +void RWLockInit(RWLock *lock) +{ + lock->read_count = 0; + lock->write_count = 0; + lock->read_lock = AL_FALSE; + lock->read_entry_lock = AL_FALSE; + lock->write_lock = AL_FALSE; +} + +void ReadLock(RWLock *lock) +{ + Lock(&lock->read_entry_lock); + Lock(&lock->read_lock); + if(IncrementRef(&lock->read_count) == 1) + Lock(&lock->write_lock); + Unlock(&lock->read_lock); + Unlock(&lock->read_entry_lock); +} + +void ReadUnlock(RWLock *lock) +{ + if(DecrementRef(&lock->read_count) == 0) + Unlock(&lock->write_lock); +} + +void WriteLock(RWLock *lock) +{ + if(IncrementRef(&lock->write_count) == 1) + Lock(&lock->read_lock); + Lock(&lock->write_lock); +} + +void WriteUnlock(RWLock *lock) +{ + Unlock(&lock->write_lock); + if(DecrementRef(&lock->write_count) == 0) + Unlock(&lock->read_lock); +} + + +void InitUIntMap(UIntMap *map, ALsizei limit) +{ + map->array = NULL; + map->size = 0; + map->maxsize = 0; + map->limit = limit; + RWLockInit(&map->lock); +} + +void ResetUIntMap(UIntMap *map) +{ + WriteLock(&map->lock); + free(map->array); + map->array = NULL; + map->size = 0; + map->maxsize = 0; + WriteUnlock(&map->lock); +} + +ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) +{ + ALsizei pos = 0; + + WriteLock(&map->lock); + 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->limit) + { + WriteUnlock(&map->lock); + return AL_OUT_OF_MEMORY; + } + + if(map->size == map->maxsize) + { + ALvoid *temp = NULL; + ALsizei newsize; + + newsize = (map->maxsize ? (map->maxsize<<1) : 4); + if(newsize >= map->maxsize) + temp = realloc(map->array, newsize*sizeof(map->array[0])); + if(!temp) + { + WriteUnlock(&map->lock); + return AL_OUT_OF_MEMORY; + } + map->array = temp; + map->maxsize = newsize; + } + + if(pos < map->size) + memmove(&map->array[pos+1], &map->array[pos], + (map->size-pos)*sizeof(map->array[0])); + map->size++; + } + map->array[pos].key = key; + map->array[pos].value = value; + WriteUnlock(&map->lock); + + return AL_NO_ERROR; +} + +ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) +{ + ALvoid *ptr = NULL; + WriteLock(&map->lock); + 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) + { + ptr = map->array[low].value; + if(low < map->size-1) + memmove(&map->array[low], &map->array[low+1], + (map->size-1-low)*sizeof(map->array[0])); + map->size--; + } + } + WriteUnlock(&map->lock); + return ptr; +} + +ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) +{ + ALvoid *ptr = NULL; + ReadLock(&map->lock); + 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) + ptr = map->array[low].value; + } + ReadUnlock(&map->lock); + return ptr; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/hrtf.c b/src/eepp/helper/android/openal-soft/Alc/hrtf.c new file mode 100644 index 000000000..11922cc77 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/hrtf.c @@ -0,0 +1,804 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2011 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 "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alSource.h" +#include "alu.h" + + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + + +/* Current data set limits defined by the makehrtf utility. */ +#define MIN_IR_SIZE (8) +#define MAX_IR_SIZE (128) +#define MOD_IR_SIZE (8) + +#define MIN_EV_COUNT (5) +#define MAX_EV_COUNT (128) + +#define MIN_AZ_COUNT (1) +#define MAX_AZ_COUNT (128) + +struct Hrtf { + ALuint sampleRate; + ALuint irSize; + ALubyte evCount; + + const ALubyte *azCount; + const ALushort *evOffset; + const ALshort *coeffs; + const ALubyte *delays; + + struct Hrtf *next; +}; + +static const ALchar magicMarker00[8] = "MinPHR00"; +static const ALchar magicMarker01[8] = "MinPHR01"; + +/* Define the default HRTF: + * ALubyte defaultAzCount [DefaultHrtf.evCount] + * ALushort defaultEvOffset [DefaultHrtf.evCount] + * ALshort defaultCoeffs [DefaultHrtf.irCount * defaultHrtf.irSize] + * ALubyte defaultDelays [DefaultHrtf.irCount] + * + * struct Hrtf DefaultHrtf + */ +#include "hrtf_tables.inc" + +static struct Hrtf *LoadedHrtfs = NULL; + +/* Calculate the elevation indices given the polar elevation in radians. + * This will return two indices between 0 and (Hrtf->evCount - 1) and an + * interpolation factor between 0.0 and 1.0. + */ +static void CalcEvIndices(const struct Hrtf *Hrtf, ALfloat ev, ALuint *evidx, ALfloat *evmu) +{ + ev = (F_PI_2 + ev) * (Hrtf->evCount-1) / F_PI; + evidx[0] = fastf2u(ev); + evidx[1] = minu(evidx[0] + 1, Hrtf->evCount-1); + *evmu = ev - evidx[0]; +} + +/* Calculate the azimuth indices given the polar azimuth in radians. This + * will return two indices between 0 and (Hrtf->azCount[ei] - 1) and an + * interpolation factor between 0.0 and 1.0. + */ +static void CalcAzIndices(const struct Hrtf *Hrtf, ALuint evidx, ALfloat az, ALuint *azidx, ALfloat *azmu) +{ + az = (F_PI*2.0f + az) * Hrtf->azCount[evidx] / (F_PI*2.0f); + azidx[0] = fastf2u(az) % Hrtf->azCount[evidx]; + azidx[1] = (azidx[0] + 1) % Hrtf->azCount[evidx]; + *azmu = az - floorf(az); +} + +/* Calculates the normalized HRTF transition factor (delta) from the changes + * in gain and listener to source angle between updates. The result is a + * normalized delta factor that can be used to calculate moving HRIR stepping + * values. + */ +ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]) +{ + ALfloat gainChange, angleChange, change; + + // Calculate the normalized dB gain change. + newGain = maxf(newGain, 0.0001f); + oldGain = maxf(oldGain, 0.0001f); + gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f)); + + // Calculate the normalized listener to source angle change when there is + // enough gain to notice it. + angleChange = 0.0f; + if(gainChange > 0.0001f || newGain > 0.0001f) + { + // No angle change when the directions are equal or degenerate (when + // both have zero length). + if(newdir[0]-olddir[0] || newdir[1]-olddir[1] || newdir[2]-olddir[2]) + angleChange = acosf(olddir[0]*newdir[0] + + olddir[1]*newdir[1] + + olddir[2]*newdir[2]) / F_PI; + + } + + // Use the largest of the two changes for the delta factor, and apply a + // significance shaping function to it. + change = maxf(angleChange * 25.0f, gainChange) * 2.0f; + return minf(change, 1.0f); +} + +/* Calculates static HRIR coefficients and delays for the given polar + * elevation and azimuth in radians. Linear interpolation is used to + * increase the apparent resolution of the HRIR data set. The coefficients + * are also normalized and attenuated by the specified gain. + */ +void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) +{ + ALuint evidx[2], azidx[2]; + ALuint lidx[4], ridx[4]; + ALfloat mu[3], blend[4]; + ALuint i; + + // Claculate elevation indices and interpolation factor. + CalcEvIndices(Hrtf, elevation, evidx, &mu[2]); + + // Calculate azimuth indices and interpolation factor for the first + // elevation. + CalcAzIndices(Hrtf, evidx[0], azimuth, azidx, &mu[0]); + + // Calculate the first set of linear HRIR indices for left and right + // channels. + lidx[0] = Hrtf->evOffset[evidx[0]] + azidx[0]; + lidx[1] = Hrtf->evOffset[evidx[0]] + azidx[1]; + ridx[0] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[0]) % Hrtf->azCount[evidx[0]]); + ridx[1] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[1]) % Hrtf->azCount[evidx[0]]); + + // Calculate azimuth indices and interpolation factor for the second + // elevation. + CalcAzIndices(Hrtf, evidx[1], azimuth, azidx, &mu[1]); + + // Calculate the second set of linear HRIR indices for left and right + // channels. + lidx[2] = Hrtf->evOffset[evidx[1]] + azidx[0]; + lidx[3] = Hrtf->evOffset[evidx[1]] + azidx[1]; + ridx[2] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[0]) % Hrtf->azCount[evidx[1]]); + ridx[3] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[1]) % Hrtf->azCount[evidx[1]]); + + /* Calculate 4 blending weights for 2D bilinear interpolation. */ + blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); + blend[1] = ( mu[0]) * (1.0f-mu[2]); + blend[2] = (1.0f-mu[1]) * ( mu[2]); + blend[3] = ( mu[1]) * ( mu[2]); + + /* Calculate the HRIR delays using linear interpolation. */ + delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + + Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] + + 0.5f) << HRTFDELAY_BITS; + delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + + Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] + + 0.5f) << HRTFDELAY_BITS; + + /* Calculate the sample offsets for the HRIR indices. */ + lidx[0] *= Hrtf->irSize; + lidx[1] *= Hrtf->irSize; + lidx[2] *= Hrtf->irSize; + lidx[3] *= Hrtf->irSize; + ridx[0] *= Hrtf->irSize; + ridx[1] *= Hrtf->irSize; + ridx[2] *= Hrtf->irSize; + ridx[3] *= Hrtf->irSize; + + /* Calculate the normalized and attenuated HRIR coefficients using linear + * interpolation when there is enough gain to warrant it. Zero the + * coefficients if gain is too low. + */ + if(gain > 0.0001f) + { + gain *= 1.0f/32767.0f; + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] = (Hrtf->coeffs[lidx[0]+i]*blend[0] + + Hrtf->coeffs[lidx[1]+i]*blend[1] + + Hrtf->coeffs[lidx[2]+i]*blend[2] + + Hrtf->coeffs[lidx[3]+i]*blend[3]) * gain; + coeffs[i][1] = (Hrtf->coeffs[ridx[0]+i]*blend[0] + + Hrtf->coeffs[ridx[1]+i]*blend[1] + + Hrtf->coeffs[ridx[2]+i]*blend[2] + + Hrtf->coeffs[ridx[3]+i]*blend[3]) * gain; + } + } + else + { + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] = 0.0f; + coeffs[i][1] = 0.0f; + } + } +} + +/* Calculates the moving HRIR target coefficients, target delays, and + * stepping values for the given polar elevation and azimuth in radians. + * Linear interpolation is used to increase the apparent resolution of the + * HRIR data set. The coefficients are also normalized and attenuated by the + * specified gain. Stepping resolution and count is determined using the + * given delta factor between 0.0 and 1.0. + */ +ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep) +{ + ALuint evidx[2], azidx[2]; + ALuint lidx[4], ridx[4]; + ALfloat mu[3], blend[4]; + ALfloat left, right; + ALfloat step; + ALuint i; + + // Claculate elevation indices and interpolation factor. + CalcEvIndices(Hrtf, elevation, evidx, &mu[2]); + + // Calculate azimuth indices and interpolation factor for the first + // elevation. + CalcAzIndices(Hrtf, evidx[0], azimuth, azidx, &mu[0]); + + // Calculate the first set of linear HRIR indices for left and right + // channels. + lidx[0] = Hrtf->evOffset[evidx[0]] + azidx[0]; + lidx[1] = Hrtf->evOffset[evidx[0]] + azidx[1]; + ridx[0] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[0]) % Hrtf->azCount[evidx[0]]); + ridx[1] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[1]) % Hrtf->azCount[evidx[0]]); + + // Calculate azimuth indices and interpolation factor for the second + // elevation. + CalcAzIndices(Hrtf, evidx[1], azimuth, azidx, &mu[1]); + + // Calculate the second set of linear HRIR indices for left and right + // channels. + lidx[2] = Hrtf->evOffset[evidx[1]] + azidx[0]; + lidx[3] = Hrtf->evOffset[evidx[1]] + azidx[1]; + ridx[2] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[0]) % Hrtf->azCount[evidx[1]]); + ridx[3] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[1]) % Hrtf->azCount[evidx[1]]); + + // Calculate the stepping parameters. + delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f); + step = 1.0f / delta; + + /* Calculate 4 blending weights for 2D bilinear interpolation. */ + blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); + blend[1] = ( mu[0]) * (1.0f-mu[2]); + blend[2] = (1.0f-mu[1]) * ( mu[2]); + blend[3] = ( mu[1]) * ( mu[2]); + + /* Calculate the HRIR delays using linear interpolation. Then calculate + * the delay stepping values using the target and previous running + * delays. + */ + left = (ALfloat)(delays[0] - (delayStep[0] * counter)); + right = (ALfloat)(delays[1] - (delayStep[1] * counter)); + + delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + + Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] + + 0.5f) << HRTFDELAY_BITS; + delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + + Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] + + 0.5f) << HRTFDELAY_BITS; + + delayStep[0] = fastf2i(step * (delays[0] - left)); + delayStep[1] = fastf2i(step * (delays[1] - right)); + + /* Calculate the sample offsets for the HRIR indices. */ + lidx[0] *= Hrtf->irSize; + lidx[1] *= Hrtf->irSize; + lidx[2] *= Hrtf->irSize; + lidx[3] *= Hrtf->irSize; + ridx[0] *= Hrtf->irSize; + ridx[1] *= Hrtf->irSize; + ridx[2] *= Hrtf->irSize; + ridx[3] *= Hrtf->irSize; + + /* Calculate the normalized and attenuated target HRIR coefficients using + * linear interpolation when there is enough gain to warrant it. Zero + * the target coefficients if gain is too low. Then calculate the + * coefficient stepping values using the target and previous running + * coefficients. + */ + if(gain > 0.0001f) + { + gain *= 1.0f/32767.0f; + for(i = 0;i < HRIR_LENGTH;i++) + { + left = coeffs[i][0] - (coeffStep[i][0] * counter); + right = coeffs[i][1] - (coeffStep[i][1] * counter); + + coeffs[i][0] = (Hrtf->coeffs[lidx[0]+i]*blend[0] + + Hrtf->coeffs[lidx[1]+i]*blend[1] + + Hrtf->coeffs[lidx[2]+i]*blend[2] + + Hrtf->coeffs[lidx[3]+i]*blend[3]) * gain; + coeffs[i][1] = (Hrtf->coeffs[ridx[0]+i]*blend[0] + + Hrtf->coeffs[ridx[1]+i]*blend[1] + + Hrtf->coeffs[ridx[2]+i]*blend[2] + + Hrtf->coeffs[ridx[3]+i]*blend[3]) * gain; + + coeffStep[i][0] = step * (coeffs[i][0] - left); + coeffStep[i][1] = step * (coeffs[i][1] - right); + } + } + else + { + for(i = 0;i < HRIR_LENGTH;i++) + { + left = coeffs[i][0] - (coeffStep[i][0] * counter); + right = coeffs[i][1] - (coeffStep[i][1] * counter); + + coeffs[i][0] = 0.0f; + coeffs[i][1] = 0.0f; + + coeffStep[i][0] = step * -left; + coeffStep[i][1] = step * -right; + } + } + + /* The stepping count is the number of samples necessary for the HRIR to + * complete its transition. The mixer will only apply stepping for this + * many samples. + */ + return fastf2u(delta); +} + + +static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate) +{ + const ALubyte maxDelay = SRC_HISTORY_LENGTH-1; + struct Hrtf *Hrtf = NULL; + ALboolean failed = AL_FALSE; + ALuint rate = 0, irCount = 0; + ALushort irSize = 0; + ALubyte evCount = 0; + ALubyte *azCount = NULL; + ALushort *evOffset = NULL; + ALshort *coeffs = NULL; + ALubyte *delays = NULL; + ALuint i, j; + + rate = fgetc(f); + rate |= fgetc(f)<<8; + rate |= fgetc(f)<<16; + rate |= fgetc(f)<<24; + + irCount = fgetc(f); + irCount |= fgetc(f)<<8; + + irSize = fgetc(f); + irSize |= fgetc(f)<<8; + + evCount = fgetc(f); + + if(rate != deviceRate) + { + ERR("HRIR rate does not match device rate: rate=%d (%d)\n", + rate, deviceRate); + failed = AL_TRUE; + } + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + + if(failed) + return NULL; + + azCount = malloc(sizeof(azCount[0])*evCount); + evOffset = malloc(sizeof(evOffset[0])*evCount); + if(azCount == NULL || evOffset == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + + if(!failed) + { + evOffset[0] = fgetc(f); + evOffset[0] |= fgetc(f)<<8; + for(i = 1;i < evCount;i++) + { + evOffset[i] = fgetc(f); + evOffset[i] |= fgetc(f)<<8; + if(evOffset[i] <= evOffset[i-1]) + { + ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", + i, evOffset[i], evOffset[i-1]); + failed = AL_TRUE; + } + + azCount[i-1] = evOffset[i] - evOffset[i-1]; + if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + if(irCount <= evOffset[i-1]) + { + ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n", + i-1, evOffset[i-1], irCount); + failed = AL_TRUE; + } + + azCount[i-1] = irCount - evOffset[i-1]; + if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + + if(!failed) + { + coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); + delays = malloc(sizeof(delays[0])*irCount); + if(coeffs == NULL || delays == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + for(i = 0;i < irCount*irSize;i+=irSize) + { + for(j = 0;j < irSize;j++) + { + ALshort coeff; + coeff = fgetc(f); + coeff |= fgetc(f)<<8; + coeffs[i+j] = coeff; + } + } + for(i = 0;i < irCount;i++) + { + delays[i] = fgetc(f); + if(delays[i] > maxDelay) + { + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); + failed = AL_TRUE; + } + } + + if(feof(f)) + { + ERR("Premature end of data\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + Hrtf = malloc(sizeof(struct Hrtf)); + if(Hrtf == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + Hrtf->sampleRate = rate; + Hrtf->irSize = irSize; + Hrtf->evCount = evCount; + Hrtf->azCount = azCount; + Hrtf->evOffset = evOffset; + Hrtf->coeffs = coeffs; + Hrtf->delays = delays; + Hrtf->next = NULL; + return Hrtf; + } + + free(azCount); + free(evOffset); + free(coeffs); + free(delays); + return NULL; +} + + +static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate) +{ + const ALubyte maxDelay = SRC_HISTORY_LENGTH-1; + struct Hrtf *Hrtf = NULL; + ALboolean failed = AL_FALSE; + ALuint rate = 0, irCount = 0; + ALubyte irSize = 0, evCount = 0; + ALubyte *azCount = NULL; + ALushort *evOffset = NULL; + ALshort *coeffs = NULL; + ALubyte *delays = NULL; + ALuint i, j; + + rate = fgetc(f); + rate |= fgetc(f)<<8; + rate |= fgetc(f)<<16; + rate |= fgetc(f)<<24; + + irSize = fgetc(f); + + evCount = fgetc(f); + + if(rate != deviceRate) + { + ERR("HRIR rate does not match device rate: rate=%d (%d)\n", + rate, deviceRate); + failed = AL_TRUE; + } + if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) + { + ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", + irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); + failed = AL_TRUE; + } + if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) + { + ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", + evCount, MIN_EV_COUNT, MAX_EV_COUNT); + failed = AL_TRUE; + } + + if(failed) + return NULL; + + azCount = malloc(sizeof(azCount[0])*evCount); + evOffset = malloc(sizeof(evOffset[0])*evCount); + if(azCount == NULL || evOffset == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + + if(!failed) + { + for(i = 0;i < evCount;i++) + { + azCount[i] = fgetc(f); + if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) + { + ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", + i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); + failed = AL_TRUE; + } + } + } + + if(!failed) + { + evOffset[0] = 0; + irCount = azCount[0]; + for(i = 1;i < evCount;i++) + { + evOffset[i] = evOffset[i-1] + azCount[i-1]; + irCount += azCount[i]; + } + + coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); + delays = malloc(sizeof(delays[0])*irCount); + if(coeffs == NULL || delays == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + for(i = 0;i < irCount*irSize;i+=irSize) + { + for(j = 0;j < irSize;j++) + { + ALshort coeff; + coeff = fgetc(f); + coeff |= fgetc(f)<<8; + coeffs[i+j] = coeff; + } + } + for(i = 0;i < irCount;i++) + { + delays[i] = fgetc(f); + if(delays[i] > maxDelay) + { + ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); + failed = AL_TRUE; + } + } + + if(feof(f)) + { + ERR("Premature end of data\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + Hrtf = malloc(sizeof(struct Hrtf)); + if(Hrtf == NULL) + { + ERR("Out of memory.\n"); + failed = AL_TRUE; + } + } + + if(!failed) + { + Hrtf->sampleRate = rate; + Hrtf->irSize = irSize; + Hrtf->evCount = evCount; + Hrtf->azCount = azCount; + Hrtf->evOffset = evOffset; + Hrtf->coeffs = coeffs; + Hrtf->delays = delays; + Hrtf->next = NULL; + return Hrtf; + } + + free(azCount); + free(evOffset); + free(coeffs); + free(delays); + return NULL; +} + + +static struct Hrtf *LoadHrtf(ALuint deviceRate) +{ + const char *fnamelist = NULL; + + if(!ConfigValueStr(NULL, "hrtf_tables", &fnamelist)) + return NULL; + while(*fnamelist != '\0') + { + struct Hrtf *Hrtf = NULL; + char fname[PATH_MAX]; + ALchar magic[8]; + ALuint i; + FILE *f; + + while(isspace(*fnamelist) || *fnamelist == ',') + fnamelist++; + i = 0; + while(*fnamelist != '\0' && *fnamelist != ',') + { + const char *next = strpbrk(fnamelist, "%,"); + while(fnamelist != next && *fnamelist && i < sizeof(fname)) + fname[i++] = *(fnamelist++); + + if(!next || *next == ',') + break; + + /* *next == '%' */ + next++; + if(*next == 'r') + { + int wrote = snprintf(&fname[i], sizeof(fname)-i, "%u", deviceRate); + i += minu(wrote, sizeof(fname)-i); + next++; + } + else if(*next == '%') + { + if(i < sizeof(fname)) + fname[i++] = '%'; + next++; + } + else + ERR("Invalid marker '%%%c'\n", *next); + fnamelist = next; + } + i = minu(i, sizeof(fname)-1); + fname[i] = '\0'; + while(i > 0 && isspace(fname[i-1])) + i--; + fname[i] = '\0'; + + if(fname[0] == '\0') + continue; + + TRACE("Loading %s...\n", fname); + f = fopen(fname, "rb"); + if(f == NULL) + { + ERR("Could not open %s\n", fname); + continue; + } + + if(fread(magic, 1, sizeof(magic), f) != sizeof(magic)) + ERR("Failed to read header from %s\n", fname); + else + { + if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + Hrtf = LoadHrtf00(f, deviceRate); + } + else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) + { + TRACE("Detected data set format v1\n"); + Hrtf = LoadHrtf01(f, deviceRate); + } + else + ERR("Invalid header in %s: \"%.8s\"\n", fname, magic); + } + + fclose(f); + f = NULL; + + if(Hrtf) + { + Hrtf->next = LoadedHrtfs; + LoadedHrtfs = Hrtf; + TRACE("Loaded HRTF support for format: %s %uhz\n", + DevFmtChannelsString(DevFmtStereo), Hrtf->sampleRate); + return Hrtf; + } + + ERR("Failed to load %s\n", fname); + } + + return NULL; +} + +const struct Hrtf *GetHrtf(ALCdevice *device) +{ + if(device->FmtChans == DevFmtStereo) + { + struct Hrtf *Hrtf = LoadedHrtfs; + while(Hrtf != NULL) + { + if(device->Frequency == Hrtf->sampleRate) + return Hrtf; + Hrtf = Hrtf->next; + } + + Hrtf = LoadHrtf(device->Frequency); + if(Hrtf != NULL) + return Hrtf; + + if(device->Frequency == DefaultHrtf.sampleRate) + return &DefaultHrtf; + } + ERR("Incompatible format: %s %uhz\n", + DevFmtChannelsString(device->FmtChans), device->Frequency); + return NULL; +} + +void FreeHrtfs(void) +{ + struct Hrtf *Hrtf = NULL; + + while((Hrtf=LoadedHrtfs) != NULL) + { + LoadedHrtfs = Hrtf->next; + free((void*)Hrtf->azCount); + free((void*)Hrtf->evOffset); + free((void*)Hrtf->coeffs); + free((void*)Hrtf->delays); + free(Hrtf); + } +} + +ALuint GetHrtfIrSize (const struct Hrtf *Hrtf) +{ + return Hrtf->irSize; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/hrtf_tables.inc b/src/eepp/helper/android/openal-soft/Alc/hrtf_tables.inc new file mode 100644 index 000000000..9c6af6a1b --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/hrtf_tables.inc @@ -0,0 +1,848 @@ +/* Elevation metrics */ +static const ALubyte defaultAzCount[19] = { 1, 12, 24, 36, 45, 56, 60, 72, 72, 72, 72, 72, 60, 56, 45, 36, 24, 12, 1, }; +static const ALushort defaultEvOffset[19] = { 0, 1, 13, 37, 73, 118, 174, 234, 306, 378, 450, 522, 594, 654, 710, 755, 791, 815, 827, }; + +/* HRIR Coefficients */ +static const ALshort defaultCoeffs[26496] = +{ + +6117, +8354, +3531, +2903, +1118, +342, +874, -822, -2447, -1309, +579, -133, -617, -1093, -998, -416, -244, -202, -84, -134, -375, -200, -416, -331, -408, -614, -489, -332, -207, -97, -7, -145, + +6958, +8678, +3013, +3274, +1145, +25, +847, -771, -2501, -1666, +534, +86, -597, -917, -967, -916, -367, -80, -198, -215, -475, -312, -442, -372, -399, -554, -517, -249, -103, -75, -5, -176, + +6349, +8083, +2935, +2854, +1109, +344, +851, -891, -2351, -1252, +506, -191, -559, -861, -745, -485, -327, -77, -17, -172, -405, -189, -402, -350, -459, -599, -449, -315, -184, -77, +13, -134, + +5910, +7494, +2698, +2625, +992, +373, +884, -825, -2197, -962, +698, -127, -425, -759, -697, -286, -213, -171, -64, -127, -336, -131, -355, -271, -368, -553, -428, -299, -179, -74, +4, -137, + +5808, +7380, +2660, +2585, +1001, +453, +998, -698, -2078, -854, +773, -100, -470, -857, -730, -241, -185, -179, -63, -114, -325, -112, -322, -220, -300, -507, -404, -297, -216, -122, -35, -168, + +5957, +7591, +2687, +2503, +871, +340, +913, -821, -2282, -1053, +775, -16, -459, -904, -784, -240, -114, -100, -12, -59, -285, -105, -334, -253, -340, -532, -400, -251, -127, -17, +33, -156, + +6515, +8209, +2752, +2639, +892, +326, +895, -1074, -2683, -1313, +854, -53, -682, -1135, -939, -316, -155, -153, -32, -64, -346, -124, -339, -249, -345, -543, -400, -232, -129, -39, +38, -120, + +6887, +8888, +3060, +2770, +926, +146, +833, -1245, -2800, -1317, +584, -231, -619, -1119, -983, -413, -244, -71, -9, -143, -405, -183, -399, -307, -420, -595, -439, -302, -153, -55, +34, -129, + +7340, +9090, +2964, +3130, +1162, +115, +612, -1577, -2702, -692, +458, -1019, -864, -943, -587, -190, -434, -226, +41, -162, -398, -144, -463, -353, -533, -708, -464, -374, -270, -103, +2, -187, + +8348, +9865, +2233, +2503, +594, +154, +1277, -1477, -3002, -433, +1280, -991, -1387, -1385, -643, +20, -514, -498, -16, -150, -545, -145, -486, -329, -539, -846, -509, -326, -250, -110, +9, -211, + +8668, +10241, +2446, +2335, +160, +133, +1408, -1244, -3403, -895, +1742, -269, -1341, -2123, -1100, +207, -94, -571, -238, -198, -607, -211, -581, -326, -492, -792, -539, -293, -202, -119, -28, -265, + +8261, +10052, +3261, +2775, +344, +65, +1000, -1138, -3661, -1615, +1337, +126, -290, -1970, -1899, -55, +143, -202, -175, -248, -492, -207, -591, -284, -495, -901, -578, -409, -197, -51, +38, -151, + +7749, +9628, +3084, +3049, +870, +16, +727, -1159, -2880, -1819, +969, +83, -717, -1031, -1759, -1055, -39, -9, -26, -31, -379, -324, -646, -479, -344, -651, -608, -341, -196, -48, +22, -160, + +7872, +8889, +2424, +3846, +1113, -405, +870, -636, -2562, -2175, +535, +438, -627, -691, -988, -1594, -378, +123, -383, -287, -574, -435, -436, -421, -370, -475, -575, -138, +9, -79, -10, -210, + +7007, +8290, +2692, +3507, +1037, -125, +838, -876, -2265, -1597, +225, -49, -510, -580, -573, -987, -677, +32, +42, -236, -535, -281, -374, -349, -433, -522, -408, -257, -182, -133, +15, -132, + +6475, +7694, +2419, +2913, +1152, +342, +794, -920, -2186, -1265, +352, -196, -457, -569, -494, -665, -413, +113, +33, -239, -428, -173, -379, -384, -517, -559, -408, -308, -159, -59, +31, -118, + +5981, +7105, +2165, +2692, +1134, +347, +767, -876, -2030, -957, +421, -294, -318, -441, -466, -416, -281, -39, -27, -194, -378, -156, -345, -274, -384, -498, -440, -344, -158, -51, +21, -134, + +5468, +6465, +2050, +2460, +952, +446, +858, -776, -1849, -646, +711, -106, -171, -377, -412, -225, -208, -139, -49, -122, -280, -59, -288, -217, -330, -482, -372, -276, -153, -54, +11, -123, + +5247, +6086, +1760, +2189, +842, +506, +1054, -433, -1470, -298, +965, +30, -189, -498, -477, -163, -126, -106, -24, -94, -283, -72, -247, -143, -266, -434, -302, -196, -110, -68, -52, -213, + +5232, +6232, +1996, +2383, +983, +625, +1098, -519, -1614, -432, +848, -66, -286, -585, -461, -110, -157, -165, -46, -92, -261, -20, -217, -109, -190, -394, -333, -281, -239, -151, -66, -182, + +5323, +6297, +1900, +2226, +867, +582, +1114, -514, -1700, -507, +886, -53, -362, -695, -545, -42, +42, -2, +24, -89, -290, -90, -302, -188, -238, -341, -202, -173, -185, -163, -115, -218, + +5574, +6674, +1997, +2183, +707, +407, +936, -776, -2047, -829, +914, +130, -285, -696, -573, -93, +9, -5, +50, +20, -186, -16, -247, -182, -271, -441, -315, -175, -47, +63, +58, -176, + +6045, +7217, +2109, +2333, +722, +394, +912, -1008, -2484, -1201, +940, +97, -533, -929, -717, -112, +69, +18, +107, +96, -204, -31, -262, -175, -230, -397, -254, -106, -72, -21, +17, -112, + +6856, +7935, +1962, +2469, +717, +365, +900, -1353, -2894, -1309, +1170, +26, -784, -1168, -861, -220, -61, -113, +16, +18, -323, -43, -253, -171, -282, -468, -311, -130, -56, +10, +78, -94, + +7514, +8789, +1982, +2483, +712, +262, +907, -1695, -3191, -1325, +1153, -23, -806, -1333, -975, -279, -115, -59, -35, -42, -373, -130, -392, -273, -384, -542, -334, -150, -38, +4, +93, -104, + +7708, +9393, +2471, +2673, +752, -59, +807, -1726, -3115, -1282, +555, -307, -586, -1146, -966, -429, -241, +103, +48, -175, -435, -160, -372, -287, -438, -565, -385, -281, -93, -15, +72, -115, + +7961, +9595, +2700, +3173, +1089, -199, +393, -2045, -2982, -748, +119, -1067, -577, -787, -541, -413, -602, -36, +144, -149, -336, -111, -417, -324, -553, -659, -425, -410, -226, -58, +56, -137, + +8750, +9725, +2189, +3527, +1193, -202, +307, -2424, -2793, +130, +87, -2091, -927, -659, -104, -33, -745, -205, +211, -231, -414, -73, -531, -374, -686, -789, -410, -438, -340, -94, +17, -238, + +9887, +10729, +1149, +2712, +812, -159, +1171, -2374, -3238, +573, +900, -2331, -1559, -881, +10, +282, -825, -483, +230, -178, -567, -74, -569, -393, -734, -962, -410, -384, -393, -161, +71, -197, + +11064, +11221, +279, +2282, +77, +57, +1829, -2384, -3518, +811, +1905, -2262, -2145, -1529, -99, +470, -985, -810, +158, -183, -755, -35, -580, -314, -703, -1105, -476, -311, -308, -116, +33, -294, + +11675, +11698, +209, +1859, -553, +242, +2236, -2105, -4055, +456, +2775, -1639, -2377, -2493, -525, +885, -700, -1033, -74, -269, -767, -30, -730, -335, -644, -1070, -436, -206, -262, -87, -13, -377, + +11801, +11992, +657, +1830, -875, +135, +2141, -1883, -4508, -144, +3105, -728, -2249, -3247, -939, +1040, -70, -1098, -336, -229, -882, -166, -780, -279, -597, -994, -559, -229, -208, -150, -49, -410, + +11441, +12041, +1632, +2283, -957, -39, +1816, -1840, -4880, -918, +2879, +121, -1146, -3647, -1711, +1051, +438, -745, -603, -262, -776, -209, -700, -151, -609, -1078, -625, -402, -194, -201, -9, -262, + +10865, +11676, +2584, +2613, -586, -83, +1224, -1524, -5125, -1724, +2382, +303, +58, -3199, -2831, +663, +561, -315, -300, -369, -601, -190, -808, -177, -617, -1246, -617, -484, -161, +7, +81, -166, + +10191, +11218, +2753, +3225, -135, -314, +1139, -1492, -4741, -2381, +2120, +202, +83, -1978, -3635, -327, +757, +52, -23, -340, -548, -69, -879, -641, -441, -1126, -641, -329, -170, +77, +67, -175, + +9689, +10846, +2307, +3298, +545, -344, +602, -1494, -3324, -2412, +1584, +308, -905, -920, -2772, -1685, +423, +196, -11, +88, -409, -493, -902, -608, -212, -710, -760, -321, -179, +12, +47, -183, + +8953, +9908, +2218, +3607, +920, -373, +599, -1197, -2905, -2314, +1261, +665, -1096, -819, -1580, -2014, -168, +187, -326, -97, -344, -334, -636, -572, -272, -489, -771, -288, -106, -59, +97, -199, + +8864, +8963, +1784, +4657, +969, -956, +982, -415, -2657, -2862, +633, +942, -750, -396, -1083, -2461, -216, +391, -668, -329, -673, -573, -389, -489, -318, -379, -677, +16, +122, -114, -18, -247, + +7756, +8469, +2432, +4304, +831, -834, +867, -757, -2207, -2102, -12, +321, -466, -174, -519, -1837, -871, +255, +23, -250, -677, -423, -326, -339, -330, -413, -490, -195, -73, -162, -2, -152, + +7061, +7757, +2298, +3660, +972, -50, +816, -871, -2023, -1762, +29, +39, -419, -270, -323, -1264, -738, +345, +74, -339, -535, -233, -317, -423, -530, -487, -350, -279, -220, -117, +68, -96, + +6469, +7209, +2035, +3061, +1233, +321, +690, -887, -1952, -1381, +126, -112, -325, -222, -261, -975, -473, +378, +46, -334, -435, -156, -344, -439, -577, -492, -370, -312, -132, -41, +48, -98, + +5924, +6587, +1791, +2840, +1306, +325, +630, -832, -1787, -1021, +168, -250, -169, -97, -250, -687, -289, +202, -37, -279, -361, -130, -348, -361, -448, -399, -386, -361, -133, -16, +50, -129, + +5282, +6011, +1719, +2545, +1130, +445, +720, -784, -1642, -749, +308, -187, +39, -21, -232, -423, -260, +27, -35, -215, -317, -45, -205, -222, -390, -439, -388, -320, -115, -45, +11, -94, + +4741, +5315, +1665, +2368, +986, +543, +781, -655, -1403, -392, +608, -36, +147, +49, -163, -239, -215, -100, -40, -117, -205, +8, -213, -171, -294, -397, -329, -264, -127, -36, +13, -103, + +4473, +4913, +1415, +2018, +802, +585, +981, -314, -1070, -10, +964, +194, +186, -38, -233, -201, -159, -68, +40, -54, -215, -5, -156, -100, -249, -363, -242, -160, -67, -14, -33, -215, + +4287, +4651, +1225, +2028, +1002, +772, +1151, -74, -767, +174, +960, +71, -57, -266, -220, -24, -57, -86, -63, -101, -197, +12, -123, -8, -137, -308, -225, -169, -123, -121, -128, -237, + +4337, +4965, +1624, +2246, +1058, +843, +1155, -266, -1056, -75, +799, +3, -60, -285, -202, -30, -153, -156, -30, -66, -178, +71, -100, -2, -76, -278, -279, -283, -274, -184, -98, -187, + +4443, +5025, +1531, +2119, +997, +856, +1205, -260, -1169, -213, +764, -10, -150, -366, -219, +89, +76, -16, -38, -108, -204, -23, -212, -56, -66, -154, -135, -246, -290, -240, -153, -192, + +4604, +5187, +1421, +1877, +708, +663, +1129, -291, -1278, -255, +968, +170, -109, -537, -478, +41, +175, +171, +207, -3, -219, -11, -242, -189, -190, -256, -119, -13, -31, -100, -174, -309, + +4923, +5652, +1529, +1902, +624, +528, +924, -671, -1743, -664, +996, +326, -100, -476, -372, +25, +128, +85, +100, +106, -73, +61, -152, -121, -199, -342, -237, -104, +32, +141, +70, -204, + +5421, +6220, +1615, +2041, +613, +476, +868, -945, -2209, -1062, +1028, +282, -361, -678, -462, +90, +247, +119, +166, +124, -141, +83, -164, -99, -131, -291, -197, -34, +4, +4, +72, -42, + +6190, +6818, +1507, +2236, +597, +518, +893, -1240, -2699, -1316, +1269, +222, -676, -957, -667, -54, +151, +26, +170, +185, -160, +80, -150, -125, -158, -266, -176, +4, -12, -12, +35, -111, + +7121, +7541, +1201, +2394, +583, +455, +869, -1653, -3075, -1304, +1541, +95, -937, -1178, -764, -132, +36, -84, +64, +109, -308, +44, -155, -103, -220, -385, -224, -28, +7, +54, +114, -67, + +7954, +8408, +983, +2438, +632, +359, +872, -2062, -3411, -1245, +1676, +31, -1048, -1363, -832, -150, -48, -120, +14, +94, -364, -58, -298, -170, -314, -457, -245, -56, +16, +70, +176, -53, + +8426, +9277, +1223, +2430, +532, +133, +944, -2316, -3533, -1292, +1244, -43, -818, -1449, -1029, -259, -53, +135, -32, -56, -402, -136, -404, -282, -407, -503, -267, -114, +46, +41, +136, -109, + +8583, +9860, +1762, +2634, +598, -282, +801, -2272, -3373, -1211, +481, -346, -524, -1183, -947, -470, -228, +324, +74, -228, -460, -132, -337, -273, -462, -518, -331, -270, -26, +19, +110, -100, + +8789, +10123, +2143, +3154, +907, -539, +350, -2551, -3191, -653, -134, -1144, -348, -706, -562, -559, -647, +213, +190, -170, -308, -125, -412, -293, -550, -593, -367, -441, -161, -3, +111, -113, + +9368, +10135, +1939, +3756, +1190, -650, -93, -2909, -2955, +75, -583, -2117, -371, -455, -4, -431, -1040, +118, +327, -275, -298, -31, -480, -340, -761, -730, -381, -524, -283, -44, +42, -215, + +10370, +10210, +1204, +4156, +1175, -623, -28, -3363, -2672, +1145, -623, -3309, -728, -270, +428, +27, -1178, -99, +420, -357, -415, +13, -626, -389, -869, -847, -326, -533, -414, -65, +33, -301, + +11635, +11075, -31, +3531, +952, -550, +724, -3443, -3032, +1791, +130, -3849, -1409, -370, +688, +391, -1323, -332, +504, -391, -598, +96, -680, -457, -950, -1002, -305, -479, -469, -136, +71, -286, + +13207, +11905, -1547, +2772, +301, -274, +1873, -3587, -3556, +2285, +1234, -3973, -2188, -835, +809, +672, -1631, -769, +602, -241, -847, +83, -674, -374, -941, -1208, -342, -448, -473, -101, +134, -318, + +14337, +12287, -2399, +2422, -469, +62, +2531, -3616, -3929, +2464, +2354, -3991, -2785, -1503, +623, +891, -1697, -1088, +457, -261, -1009, +151, -717, -276, -913, -1388, -372, -300, -384, -112, +67, -401, + +15087, +12820, -2744, +1910, -1184, +425, +3120, -3448, -4563, +2187, +3466, -3489, -3173, -2589, +266, +1446, -1532, -1382, +191, -327, -1016, +193, -847, -301, -888, -1367, -296, -177, -336, -114, +20, -474, + +15581, +13124, -2434, +1591, -1676, +521, +3195, -3036, -5227, +1724, +4250, -2658, -3404, -3573, -56, +1861, -986, -1649, +4, -355, -1041, +91, -1052, -239, -767, -1287, -362, -121, -296, -58, -65, -569, + +15601, +13452, -1914, +1563, -2007, +399, +3052, -2823, -5735, +1036, +4617, -1613, -3294, -4431, -451, +2051, -245, -1777, -331, -235, -1215, -48, -1032, -173, -736, -1221, -537, -142, -232, -189, -69, -580, + +15203, +13689, -870, +1955, -2244, +197, +2769, -2807, -6122, +172, +4587, -487, -2272, -5183, -1225, +2226, +446, -1489, -791, -175, -1171, -107, -880, -30, -790, -1309, -587, -320, -186, -316, -13, -442, + +14648, +13594, +409, +2248, -2137, -16, +2270, -2431, -6673, -665, +4167, +189, -766, -5403, -2316, +2230, +741, -1027, -813, -342, -840, -164, -978, +109, -745, -1474, -642, -547, -154, -159, +47, -247, + +13996, +13109, +1461, +2499, -1685, -37, +1524, -2013, -6863, -1546, +3712, +317, +445, -4840, -3714, +1807, +920, -566, -438, -485, -703, -148, -1075, +6, -791, -1647, -584, -567, -97, +72, +120, -190, + +13165, +12534, +1976, +3362, -1471, -314, +1381, -1961, -6484, -2520, +3399, +361, +831, -3679, -5026, +938, +1344, -192, -237, -452, -597, -58, -1183, -507, -582, -1548, -641, -480, -68, +246, +63, -219, + +12626, +12250, +1611, +3690, -681, -941, +1250, -1619, -5566, -2944, +3036, +177, +25, -1933, -5154, -665, +1470, +164, +107, -276, -664, -178, -1249, -762, -296, -1315, -631, -232, -234, +180, +66, -251, + +11980, +11934, +1167, +3735, +109, -727, +510, -1829, -3781, -3108, +2485, +496, -1203, -728, -4093, -2241, +1182, +347, -49, +233, -470, -711, -1173, -711, -7, -812, -944, -259, -161, +83, +61, -212, + +11247, +11010, +1120, +4114, +574, -764, +386, -1687, -3259, -2815, +2128, +825, -1544, -509, -2722, -2986, +467, +444, -350, +190, -276, -570, -1067, -700, +132, -512, -1156, -281, -35, -10, +123, -207, + +10116, +9947, +1402, +4469, +759, -942, +664, -954, -2962, -3136, +1495, +1323, -1375, -529, -1640, -2951, +60, +455, -723, -188, -423, -428, -490, -651, -326, -390, -839, -121, -11, -87, +128, -262, + +9934, +8876, +1128, +5737, +644, -1620, +1223, -109, -2816, -3751, +890, +1596, -1024, +3, -1280, -3531, +194, +690, -1086, -313, -780, -731, -285, -592, -233, -265, -834, +227, +227, -185, -20, -287, + +8502, +8500, +2204, +5212, +430, -1605, +1028, -561, -2155, -2773, -185, +874, -495, +321, -570, -2903, -846, +586, -74, -234, -828, -571, -225, -357, -205, -310, -640, -115, +58, -204, -18, -162, + +7584, +7772, +2171, +4547, +704, -725, +925, -716, -1861, -2401, -267, +505, -407, +183, -244, -2138, -927, +680, +60, -459, -671, -326, -222, -451, -469, -353, -358, -211, -203, -191, +84, -98, + +6877, +7100, +2027, +3726, +1015, +37, +675, -791, -1748, -2003, -196, +244, -318, +111, -88, -1694, -708, +748, +20, -457, -485, -226, -270, -512, -629, -427, -353, -293, -167, -97, +74, -60, + +6094, +6516, +1758, +3125, +1461, +313, +506, -750, -1620, -1508, -142, +48, -126, +224, -68, -1338, -382, +704, -7, -454, -398, -106, -300, -528, -626, -363, -337, -340, -80, +0, +68, -81, + +5474, +5821, +1573, +2970, +1494, +257, +449, -672, -1419, -1123, -157, -119, +81, +343, -71, -994, -247, +423, -94, -356, -314, -117, -307, -403, -455, -271, -389, -398, -91, +12, +63, -119, + +4706, +5219, +1556, +2650, +1342, +394, +527, -623, -1238, -816, -65, -106, +329, +424, -62, -677, -264, +193, -57, -276, -283, -47, -151, -234, -379, -329, -417, -360, -71, -27, +20, -78, + +3969, +4463, +1642, +2395, +1176, +599, +584, -518, -1032, -470, +216, +31, +488, +473, -5, -409, -215, +23, -78, -181, -137, +68, -136, -185, -309, -316, -333, -291, -98, -38, +10, -54, + +3424, +3827, +1536, +2086, +1002, +678, +738, -333, -681, +35, +605, +269, +533, +528, +71, -284, -241, -104, +39, -20, -139, +38, -65, -74, -225, -293, -257, -229, -78, +5, +12, -102, + +3209, +3445, +1231, +1747, +899, +784, +1000, +168, -305, +345, +880, +396, +496, +306, -68, -218, -102, -1, +55, -36, -135, +45, -28, -19, -180, -238, -160, -103, -27, -22, -94, -255, + +2989, +3191, +1074, +1836, +1186, +989, +1156, +381, -8, +502, +823, +223, +193, +66, +7, +5, -16, -56, -80, -81, -98, +68, +12, +88, -46, -191, -160, -138, -110, -149, -188, -250, + +3027, +3528, +1478, +2058, +1276, +1085, +1144, +149, -311, +281, +686, +149, +146, +19, +50, +25, -119, -132, -55, -57, -69, +143, +32, +105, +37, -167, -229, -266, -280, -209, -151, -192, + +3214, +3748, +1601, +2025, +1190, +1116, +1202, +89, -552, -87, +478, +220, +213, +9, +55, +81, -6, -61, -71, -93, -61, +81, -92, +76, +154, -10, -220, -365, -342, -251, -170, -159, + +3266, +3741, +1347, +1791, +1078, +1077, +1224, +91, -623, +51, +737, +114, -29, -162, -63, +235, +299, +125, +20, -78, -150, -17, -140, -29, -21, +31, +66, -141, -296, -306, -239, -221, + +3541, +4062, +1288, +1550, +718, +829, +1077, -44, -837, -142, +945, +448, +111, -311, -297, +101, +259, +279, +274, +70, -83, +51, -163, -131, -124, -170, -40, +66, +53, -44, -202, -351, + +3954, +4589, +1351, +1593, +636, +691, +854, -482, -1382, -587, +1032, +601, +79, -242, -184, +108, +254, +168, +138, +202, +51, +122, -43, -74, -123, -230, -173, -35, +112, +219, +65, -237, + +4535, +5212, +1390, +1740, +598, +607, +776, -814, -1908, -1025, +1099, +545, -214, -426, -239, +239, +413, +193, +207, +182, -47, +183, -57, -40, -30, -175, -148, +40, +73, +37, +118, +7, + +5318, +5785, +1269, +1968, +575, +658, +805, -1127, -2442, -1307, +1372, +466, -591, -725, -443, +119, +395, +164, +270, +354, -56, +110, -69, -55, -25, -139, -51, +109, +11, +15, +19, -56, + +6436, +6460, +882, +2236, +497, +666, +802, -1573, -2941, -1397, +1743, +286, -941, -976, -603, -18, +243, -4, +204, +282, -184, +170, -29, -57, -91, -187, -111, +112, +41, +27, +68, -96, + +7585, +7281, +373, +2458, +491, +542, +790, -2104, -3319, -1286, +2043, +126, -1200, -1227, -664, -50, +85, -70, +93, +172, -322, +133, -69, -86, -185, -297, -168, +53, +66, +96, +196, +7, + +8554, +8204, +13, +2518, +545, +433, +808, -2585, -3651, -1161, +2167, +23, -1301, -1412, -719, -73, +18, -111, +45, +202, -388, -7, -242, -122, -287, -383, -162, +38, +78, +115, +239, -27, + +9212, +9220, +103, +2448, +407, +223, +921, -2981, -3805, -1200, +1719, +26, -1055, -1626, -929, -188, +43, +226, -94, +18, -406, -89, -400, -275, -396, -440, -171, +13, +140, +43, +175, -97, + +9425, +9997, +611, +2554, +412, -263, +952, -2951, -3684, -1187, +857, -167, -621, -1410, -1053, -347, -65, +452, -3, -165, -453, -143, -340, -269, -451, -441, -242, -198, +101, +82, +181, -110, + +9602, +10483, +1219, +2947, +590, -759, +563, -2991, -3446, -797, -98, -815, -218, -921, -768, -633, -444, +563, +104, -246, -350, -155, -369, -240, -521, -488, -298, -401, -10, +50, +144, -115, + +9910, +10681, +1487, +3547, +923, -1024, +61, -3330, -3146, -137, -870, -1590, +8, -449, -298, -772, -939, +485, +312, -243, -240, -78, -399, -324, -669, -567, -332, -547, -156, +25, +160, -93, + +10699, +10561, +1144, +4345, +1148, -1198, -465, -3692, -2804, +756, -1507, -2809, +121, -169, +369, -651, -1433, +435, +473, -418, -220, +23, -526, -346, -932, -715, -318, -648, -289, -5, +58, -250, + +11865, +10458, +321, +5013, +1084, -1187, -415, -4235, -2391, +1999, -1758, -4266, -88, +147, +902, -193, -1705, +234, +619, -537, -297, +92, -743, -384, -1023, -815, -255, -684, -426, -12, +35, -330, + +13346, +11005, -1112, +4810, +949, -1079, +138, -4587, -2456, +3025, -1295, -5300, -712, +202, +1270, +293, -1889, -46, +762, -642, -552, +226, -817, -466, -1180, -995, -171, -630, -552, -62, +74, -399, + +14971, +12208, -3034, +3816, +594, -863, +1619, -4784, -3319, +3684, -109, -5706, -1550, +27, +1400, +652, -2108, -458, +869, -483, -776, +220, -858, -433, -1201, -1254, -117, -550, -640, -140, +204, -318, + +16995, +12596, -4875, +3443, -244, -334, +2668, -5173, -3649, +4366, +1153, -6044, -2514, -559, +1728, +927, -2652, -901, +1093, -410, -1143, +329, -841, -335, -1196, -1458, -195, -525, -564, -33, +194, -462, + +18241, +12894, -5826, +3138, -1130, +187, +3380, -5255, -4143, +4561, +2499, -6195, -3183, -1309, +1509, +1233, -2676, -1266, +894, -425, -1299, +432, -922, -204, -1176, -1686, -183, -313, -482, -86, +105, -535, + +19257, +13367, -6379, +2592, -1984, +792, +4070, -5179, -4919, +4384, +3882, -5784, -3709, -2594, +1250, +1947, -2577, -1645, +617, -476, -1302, +491, -1070, -197, -1169, -1676, -76, -162, -446, -100, +47, -614, + +19926, +13767, -6244, +2039, -2577, +1096, +4300, -4713, -5817, +3943, +5112, -5041, -4213, -3795, +981, +2627, -2147, -2070, +431, -519, -1281, +436, -1355, -148, -989, -1627, -104, -51, -433, -15, -50, -735, + +20240, +14125, -5799, +1784, -3007, +1064, +4265, -4313, -6590, +3386, +5836, -3972, -4474, -4840, +741, +2976, -1373, -2410, +167, -416, -1413, +247, -1435, -24, -966, -1480, -291, -55, -313, -65, -145, -781, + +20015, +14601, -5023, +1828, -3407, +908, +4058, -4144, -7140, +2450, +6274, -2630, -4153, -5964, +216, +3298, -453, -2534, -345, -178, -1641, +157, -1311, +64, -954, -1504, -457, -98, -260, -285, -55, -762, + +19554, +14863, -3770, +2150, -3733, +724, +3709, -4072, -7621, +1495, +6312, -1303, -3056, -6981, -603, +3594, +321, -2274, -920, -58, -1568, +72, -1120, +198, -1037, -1588, -525, -300, -179, -434, +24, -584, + +18917, +14814, -2183, +2351, -3715, +455, +3162, -3571, -8351, +569, +5938, -361, -1346, -7547, -1834, +3783, +700, -1769, -1070, -238, -1132, -62, -1211, +391, -1003, -1782, -585, -567, -111, -272, +77, -349, + +18106, +14727, -945, +2225, -3047, +302, +2302, -2969, -8873, -290, +5489, -62, +243, -7348, -3434, +3665, +911, -1246, -777, -513, -915, -51, -1324, +362, -1049, -1967, -506, -762, +16, -24, +82, -173, + +17254, +13805, +460, +2982, -2958, +154, +1644, -2479, -8779, -1643, +5145, +181, +1378, -6455, -5404, +3105, +1393, -741, -423, -612, -704, -72, -1484, +78, -955, -2125, -465, -626, +16, +278, +142, -257, + +16265, +13474, +690, +3849, -2566, -357, +1746, -2519, -8172, -2680, +5031, +100, +1311, -4691, -6912, +1980, +2040, -358, -216, -622, -649, +103, -1622, -626, -497, -1964, -571, -423, -30, +370, +49, -249, + +15646, +13159, +261, +4311, -1678, -1288, +1621, -1987, -7004, -3335, +4543, -14, +302, -2477, -7170, -48, +2406, +32, +137, -377, -773, -133, -1665, -841, -152, -1691, -589, -158, -270, +328, +50, -306, + +14914, +12999, -328, +4365, -702, -1133, +553, -2016, -4671, -4043, +4026, +360, -1378, -617, -6226, -2166, +2377, +298, -4, +327, -691, -899, -1434, -845, +201, -1106, -1032, -122, -210, +203, +45, -267, + +13958, +12124, -373, +4782, +21, -1129, +272, -2320, -3404, -3627, +3139, +1060, -2160, -3, -4519, -3752, +1820, +541, -476, +570, -311, -1038, -1434, -687, +457, -671, -1457, -167, -11, +62, +118, -218, + +12918, +10973, -67, +5240, +257, -1386, +443, -1503, -3392, -3835, +2924, +1581, -2328, -20, -2956, -4208, +1045, +694, -894, +202, -292, -645, -959, -841, +200, -409, -1380, -60, +24, -53, +228, -310, + +11453, +9857, +558, +5625, +370, -1608, +838, -661, -3107, -4122, +1928, +2028, -1762, -127, -1944, -4054, +595, +740, -1213, -166, -505, -568, -347, -773, -312, -278, -974, +83, +83, -136, +142, -319, + +11087, +8602, +495, +7107, +58, -2371, +1638, +267, -3072, -4860, +1382, +2390, -1510, +558, -1623, -4806, +939, +963, -1665, -194, -913, -908, -115, -747, -101, -144, -1056, +521, +304, -293, -8, -330, + +9334, +8472, +2057, +6324, -243, -2522, +1386, -290, -2159, -3680, -245, +1661, -676, +956, -788, -4263, -533, +965, -282, -154, -1031, -742, -56, -400, -21, -215, -885, +31, +223, -288, -38, -168, + +8202, +7850, +2127, +5711, +161, -1682, +1271, -489, -1744, -3323, -499, +1254, -540, +771, -297, -3344, -963, +1117, -26, -591, -845, -454, -64, -490, -350, -197, -438, -86, -170, -321, +106, -106, + +7291, +7027, +2168, +4730, +564, -540, +844, -580, -1481, -2901, -474, +853, -365, +616, -57, -2666, -805, +1195, -67, -613, -593, -252, -128, -623, -577, -254, -297, -288, -279, -138, +171, -54, + +6561, +6470, +2014, +3851, +1081, +55, +479, -597, -1428, -2456, -448, +615, -253, +562, +94, -2318, -595, +1226, -130, -587, -411, -244, -197, -635, -712, -320, -371, -307, -113, -95, +84, -14, + +5624, +5918, +1762, +3266, +1692, +206, +288, -499, -1267, -1883, -464, +389, +31, +706, +63, -1900, -243, +1098, -142, -584, -335, -87, -244, -648, -669, -209, -339, -372, -24, +17, +83, -55, + +4953, +5180, +1625, +3144, +1769, +106, +214, -394, -1053, -1453, -538, +193, +277, +807, +43, -1499, -93, +748, -239, -450, -232, -115, -285, -525, -481, -91, -398, -447, -39, +45, +83, -112, + +4115, +4607, +1619, +2888, +1682, +161, +244, -329, -812, -1141, -599, +67, +593, +924, +29, -1137, -210, +449, -129, -365, -249, -133, -121, -277, -340, -178, -530, -428, -2, -6, +39, -84, + +3177, +4024, +1786, +2341, +1485, +534, +375, -316, -681, -795, -329, +287, +817, +880, +57, -781, -190, +258, -112, -286, -153, +95, +56, -236, -403, -237, -370, -335, -19, -47, -2, +10, + +2412, +3137, +2012, +2211, +1367, +699, +342, -131, -395, -414, -56, +329, +935, +975, +138, -528, -171, +55, -126, -152, +41, +119, -74, -171, -229, -182, -327, -290, -76, -28, +10, -11, + +1837, +2561, +1897, +1806, +1200, +798, +563, +60, +7, +156, +349, +604, +923, +1022, +216, -431, -239, -64, +75, +24, -47, +67, +76, -40, -176, -179, -231, -224, -40, +27, +0, -75, + +1620, +2181, +1603, +1392, +1074, +916, +849, +620, +322, +470, +694, +763, +907, +764, +43, -376, -76, +71, +101, -3, -39, +86, +110, +0, -148, -121, -113, -69, +18, +9, -117, -268, + +1298, +1691, +1267, +1399, +1307, +1124, +1131, +1104, +891, +667, +567, +575, +628, +507, +105, -108, +52, +24, -45, -25, -34, +55, +160, +131, -29, -57, -79, -54, -16, -156, -247, -286, + +1179, +1848, +1466, +1730, +1760, +1293, +1046, +857, +729, +698, +565, +381, +236, +320, +318, +91, +9, -97, -187, -79, +91, +171, +186, +225, +142, -75, -156, -189, -210, -232, -263, -201, + +1352, +2405, +2052, +1820, +1528, +1334, +1064, +583, +298, +292, +336, +420, +473, +384, +247, -41, -172, -129, -4, +7, +46, +224, +188, +178, +173, -32, -241, -326, -370, -251, -162, -160, + +1579, +2518, +2005, +1719, +1482, +1383, +1139, +573, +88, -86, +163, +548, +481, +335, +281, +88, +49, -30, -101, -73, +80, +110, +12, +172, +343, +170, -228, -430, -393, -298, -216, -120, + +1583, +2450, +1680, +1499, +1447, +1389, +1184, +570, +27, +164, +464, +283, +128, +199, +220, +325, +423, +123, -72, -74, -43, -22, -19, +72, +115, +277, +185, -229, -439, -410, -283, -162, + +1893, +2685, +1508, +1157, +986, +1135, +1120, +583, -124, +57, +765, +643, +287, -137, -232, +275, +511, +407, +350, +8, -96, +73, -79, -165, +36, +100, +98, +172, -6, -229, -385, -374, + +2209, +3190, +1517, +1044, +774, +938, +848, +161, -496, -290, +950, +973, +315, -37, -73, +18, +254, +388, +315, +238, +180, +91, -63, -33, -110, -192, -12, +129, +232, +155, -164, -407, + +2814, +3765, +1508, +1224, +774, +836, +645, -346, -1219, -800, +1084, +985, +184, +33, +8, +229, +466, +169, +87, +354, +189, +192, +160, -56, +4, -65, -184, -15, +177, +366, +142, -203, + +3495, +4412, +1460, +1383, +688, +753, +615, -665, -1708, -1197, +1222, +875, -213, -223, -72, +363, +610, +259, +273, +267, +37, +270, +44, +9, +100, -45, -90, +149, +122, +13, +149, +90, + +4347, +4935, +1271, +1660, +643, +828, +646, -1007, -2278, -1449, +1567, +759, -633, -516, -277, +238, +622, +239, +355, +523, +20, +141, +46, -6, +111, -2, +46, +213, +21, +33, +1, +6, + +5621, +5545, +799, +2031, +504, +892, +652, -1492, -2860, -1584, +2032, +530, -1030, -782, -469, +89, +432, +59, +340, +429, -61, +279, +83, -74, +47, +39, -51, +241, +56, -19, +59, -78, + +6893, +6162, +149, +2382, +396, +828, +623, -2048, -3200, -1408, +2392, +211, -1344, -961, -526, -16, +350, -90, +203, +396, -312, +253, +114, +45, -53, -188, -37, +217, +87, +120, +108, -66, + +8235, +7080, -573, +2693, +417, +618, +659, -2697, -3569, -1230, +2683, +76, -1575, -1280, -539, +24, +87, -57, +104, +215, -351, +233, +5, -119, -156, -194, -147, +124, +129, +137, +322, +117, + +9244, +7992, -1030, +2743, +479, +517, +696, -3209, -3857, -1043, +2739, -57, -1623, -1427, -588, -20, +90, -120, +74, +343, -449, +31, -200, -78, -273, -310, -78, +136, +134, +157, +303, -20, + +10028, +9088, -1078, +2631, +294, +324, +855, -3729, -3984, -1086, +2220, +48, -1346, -1774, -793, -139, +148, +326, -185, +119, -427, -45, -395, -273, -382, -360, -77, +135, +222, +28, +223, -85, + +10294, +10035, -677, +2629, +250, -196, +1099, -3767, -3909, -1145, +1327, -1, -804, -1656, -1142, -169, +106, +562, -120, -57, -462, -169, -331, -270, -431, -351, -156, -128, +239, +131, +252, -134, + +10483, +10682, -44, +2812, +332, -824, +879, -3596, -3635, -1021, +145, -213, -350, -1319, -899, -635, -133, +919, -37, -375, -472, -69, -227, -286, -527, -354, -246, -281, +155, +54, +190, -76, + +10698, +11090, +572, +3361, +554, -1371, +356, -3757, -3360, -322, -956, -1204, +285, -664, -624, -896, -670, +916, +86, -272, -203, -223, -395, -193, -602, -435, -271, -578, +42, +87, +178, -136, + +11106, +11176, +704, +4050, +883, -1630, -180, -4140, -2927, +390, -1871, -1878, +528, -231, -70, -1098, -1213, +889, +383, -352, -139, -56, -382, -365, -792, -502, -300, -681, -116, +59, +212, -78, + +12036, +10896, +310, +5032, +1033, -1870, -823, -4447, -2503, +1349, -2741, -3214, +855, +29, +682, -1055, -1808, +920, +555, -599, -93, +53, -545, -351, -1135, -651, -258, -802, -256, +44, +72, -285, + +13249, +10533, -420, +6055, +876, -1900, -821, -5027, -1957, +2680, -3299, -4856, +928, +484, +1323, -695, -2251, +831, +740, -767, -47, +126, -881, -350, -1161, -698, -223, -889, -359, +46, +17, -320, + +14864, +10460, -1804, +6568, +665, -1731, -635, -5767, -1405, +4093, -3512, -6402, +622, +675, +1688, -26, -2440, +393, +956, -897, -408, +254, -945, -393, -1446, -932, -12, -855, -629, +79, +67, -544, + +16627, +11397, -3842, +5964, +612, -1624, +440, -5965, -2042, +5011, -2485, -7307, -214, +766, +2141, +296, -2808, +260, +1140, -1052, -587, +505, -1093, -517, -1488, -1064, +12, -788, -651, -39, +118, -479, + +18518, +12633, -6334, +4990, +229, -1244, +2367, -6506, -3133, +5859, -1129, -7799, -1129, +600, +2173, +719, -3075, -318, +1316, -740, -910, +425, -1093, -394, -1508, -1432, +145, -700, -804, -94, +327, -401, + +20973, +12619, -8500, +4951, -770, -461, +3392, -7134, -3315, +6719, +196, -8369, -2213, +3, +2743, +961, -3843, -722, +1691, -730, -1369, +644, -1082, -293, -1519, -1634, +52, -689, -686, +59, +271, -608, + +22297, +12836, -9690, +4807, -1655, +104, +4092, -7312, -3771, +7038, +1693, -8910, -3012, -482, +2558, +1188, -3919, -1129, +1548, -693, -1611, +794, -1184, -115, -1465, -1976, +34, -436, -598, -24, +171, -683, + +23980, +12855, -10608, +4407, -2867, +1228, +4914, -7539, -4560, +7253, +3208, -8777, -3558, -1999, +2512, +1964, -3980, -1552, +1290, -765, -1611, +896, -1300, -1, -1603, -2008, +250, -237, -601, -60, +99, -743, + +24531, +13684, -11034, +3704, -3405, +1665, +5463, -7291, -5568, +6806, +4893, -8341, -4325, -3233, +2310, +2880, -3885, -2013, +1022, -727, -1606, +925, -1552, -68, -1433, -1949, +261, -130, -552, -62, +43, -848, + +25399, +13806, -10659, +3086, -4032, +2086, +5508, -6663, -6694, +6473, +6232, -7551, -4944, -4555, +2202, +3628, -3339, -2592, +933, -785, -1566, +810, -1901, +111, -1220, -1934, +196, +16, -580, +86, -113, -983, + +25699, +14205, -10203, +2771, -4453, +2044, +5466, -6220, -7611, +5940, +7067, -6399, -5381, -5665, +2085, +3997, -2469, -3078, +674, -608, -1758, +594, -1930, +265, -1252, -1733, -62, +13, -409, -15, -218, -1005, + +25576, +14678, -9511, +2627, -4889, +1979, +5231, -5940, -8313, +5036, +7731, -5018, -5437, -6902, +1757, +4371, -1482, -3465, +202, -277, -2109, +514, -1803, +302, -1201, -1716, -327, +65, -365, -277, -95, -1022, + +24917, +15555, -8325, +2832, -5406, +1692, +5071, -5894, -8820, +3797, +8250, -3317, -4558, -8452, +986, +4981, -445, -3381, -624, +98, -2239, +474, -1567, +517, -1341, -1880, -275, -194, -234, -524, +73, -946, + +24560, +15279, -6686, +3008, -5680, +1683, +4433, -5659, -9447, +3055, +7994, -2069, -3264, -9450, +188, +5223, +139, -3059, -1138, +123, -1936, +284, -1347, +532, -1421, -1864, -486, -372, -126, -624, +111, -613, + +23630, +15485, -4781, +2918, -5523, +1209, +3879, -4787, -10506, +1989, +7668, -1020, -1165, -10262, -1408, +5686, +432, -2423, -1223, -173, -1294, +57, -1598, +885, -1360, -2222, -434, -735, -7, -301, +148, -390, + +22705, +15510, -3489, +2520, -4580, +974, +2845, -3997, -11138, +1148, +7254, -749, +544, -10123, -3273, +5720, +656, -1873, -901, -539, -1078, +82, -1698, +797, -1433, -2392, -307, -961, +186, -54, +102, -179, + +21833, +14435, -1480, +2989, -4502, +876, +1865, -3114, -11297, -386, +7023, -399, +2038, -9446, -5658, +5465, +1168, -1290, -470, -782, -783, -20, -1877, +659, -1411, -2696, -156, -783, +130, +317, +217, -316, + +20537, +13992, -708, +4279, -4744, +442, +1972, -3237, -10625, -1985, +6923, -199, +2505, -7991, -7936, +4778, +2128, -1048, -448, -664, -657, +84, -2053, -179, -858, -2526, -357, -737, +238, +571, -51, -298, + +19638, +14025, -1030, +4778, -3659, -452, +2274, -3224, -9891, -2808, +7103, -662, +1734, -5223, -9487, +3226, +2912, -583, -44, -906, -673, +388, -2239, -882, -152, -2483, -417, -219, -101, +496, +27, -274, + +19049, +13570, -1555, +5415, -2800, -1809, +2085, -2243, -8328, -3763, +6265, -489, +380, -2622, -9535, +545, +3560, -254, +273, -392, -940, -193, -2156, -847, +103, -2093, -472, -40, -391, +519, -11, -393, + +18168, +13590, -2249, +5443, -1644, -1455, +603, -2301, -5416, -4970, +5891, +62, -1742, -291, -8568, -1959, +3759, +29, -30, +506, -899, -1149, -1711, -913, +543, -1423, -1173, +54, -259, +333, +11, -312, + +17035, +12827, -2281, +5894, -726, -1489, +185, -2933, -3444, -4639, +4541, +1190, -2977, +751, -6689, -4331, +3534, +367, -666, +1029, -430, -1560, -1739, -617, +856, -909, -1806, +43, +2, +135, +104, -229, + +16109, +11603, -1857, +6452, -517, -1810, +245, -2043, -3755, -4481, +4547, +1368, -3096, +727, -4933, -5160, +2492, +733, -1012, +720, -307, -1028, -1535, -868, +957, -652, -2015, +138, +117, -22, +249, -321, + +14557, +10522, -1242, +6803, -315, -2135, +723, -1118, -3548, -5279, +4014, +2629, -3572, +779, -3115, -5769, +2018, +890, -1739, +290, -311, -714, -642, -1091, +163, -204, -1599, +276, +13, -124, +387, -488, + +12812, +9467, -224, +7139, -314, -2365, +1207, -230, -3341, -5355, +2557, +2879, -2315, +419, -2362, -5322, +1454, +982, -1883, -47, -628, -728, -93, -958, -294, -130, -1142, +362, +163, -228, +155, -376, + +13067, +8369, -144, +8730, -2405, -3459, +1450, -1502, -5332, -4279, +6473, +1714, -1900, +3709, -1903, -4707, +1918, +120, -2550, -1093, -1848, -621, -724, -1598, -147, -744, -877, +540, -151, -509, +318, -28, + +10904, +8241, +866, +7747, -891, -4073, +130, -1350, -3923, -2891, +4427, +2115, -885, +2373, -1299, -4343, +153, +77, -1658, -317, -1588, -605, +53, -1825, -85, -335, -1528, -11, -42, -273, +59, -76, + +9279, +7452, +1520, +7064, -405, -3081, +178, -1385, -2926, -2332, +3123, +1898, -776, +1781, -925, -3718, -102, -120, -1233, -82, -1199, -290, +2, -1550, -49, -380, -1428, -264, -245, -270, +11, -162, + +7668, +6712, +2160, +6267, +54, -2125, +134, -1110, -2049, -2036, +2189, +1460, -699, +1339, -688, -3011, -497, -119, -970, -142, -497, +186, +37, -1292, -184, -526, -1267, -503, -546, -437, +10, -9, + +6368, +6134, +2492, +5439, +623, -1515, +73, -449, -1505, -1848, +1544, +1044, -644, +955, -348, -2562, -737, -6, -786, +148, +175, +380, -63, -1068, -366, -637, -1119, -714, -616, -443, -44, +1, + +5309, +5691, +2463, +4700, +1132, -1190, +301, +59, -1194, -1566, +901, +654, -559, +719, -197, -2168, -766, +93, -248, +496, +263, +194, -53, -903, -530, -692, -1037, -585, -576, -463, -126, -99, + +4671, +5240, +2273, +4089, +1224, -820, +599, +183, -902, -1333, +289, +350, -412, +640, -190, -1832, -504, +307, +145, +562, +47, +10, -140, -891, -579, -467, -751, -658, -629, -412, -121, -71, + +4304, +4612, +2145, +3630, +1141, -235, +799, +247, -609, -1181, -104, +233, -152, +634, +32, -1399, -325, +524, +389, +368, -139, -41, -258, -648, -199, -313, -764, -659, -480, -282, -35, +38, + +3883, +4121, +1999, +3085, +1218, +245, +812, +308, -391, -1122, -309, +165, +293, +913, +46, -1198, -224, +714, +439, +55, -298, +56, +12, -400, -192, -282, -674, -589, -276, -72, +113, +77, + +3262, +3880, +1810, +2399, +1483, +674, +763, +273, -288, -1047, -181, +700, +489, +675, +71, -953, -158, +742, +296, -120, -45, +156, +92, -270, -319, -271, -421, -326, -57, +99, -64, -314, + +2385, +3308, +1933, +2191, +1681, +725, +640, +373, +136, -286, -143, +637, +683, +410, +103, -565, -257, +619, +421, -40, +28, +179, +55, -233, -135, -54, -204, -72, -29, -217, -320, -330, + +1874, +3072, +1941, +1419, +1419, +1279, +891, +484, +398, +297, +230, +463, +469, +136, +85, -228, -107, +538, +410, +40, -27, +98, +145, +77, +20, +54, +21, -272, -370, -309, -248, -206, + +1591, +2376, +1629, +1368, +1569, +1437, +1231, +1006, +583, +432, +297, +204, +299, +145, -140, +13, +312, +339, +220, +17, +14, +285, +382, +203, +101, -101, -334, -332, -302, -287, -184, -195, + +1470, +1787, +1502, +1987, +1911, +1545, +1043, +878, +865, +431, +197, +86, +12, +101, +92, +101, +251, +178, +190, +346, +300, +250, +251, +133, -107, -287, -400, -336, -238, -260, -239, -257, + +1914, +2455, +1662, +1958, +1844, +1522, +942, +380, +248, +262, +332, +128, +22, +126, +219, +6, -12, +304, +516, +586, +402, +88, -170, -256, -295, -306, -261, -267, -279, -273, -326, -327, + +1650, +2454, +1992, +2081, +1838, +1445, +722, +274, +244, +203, +344, +372, +259, +83, -81, -61, +209, +336, +515, +666, +466, +145, -229, -453, -374, -308, -238, -216, -280, -231, -312, -373, + +1972, +2726, +1615, +1875, +1444, +1065, +882, +237, +52, +429, +512, +299, +333, -155, -232, +94, +178, +234, +473, +659, +391, +136, -262, -514, -398, -381, -424, -222, -224, -324, -266, -374, + +1944, +2569, +1405, +1599, +1309, +1157, +866, +373, +250, +451, +528, +453, +471, +1, +55, +191, +129, +155, +283, +436, +597, +713, +68, -320, -396, -509, -294, -216, -242, -220, -186, -273, + +2213, +2847, +1259, +1256, +996, +980, +849, +260, -32, +445, +818, +478, +247, +265, +193, +76, +464, +202, +102, +347, +222, +450, +618, +397, -308, -565, -442, -327, -186, -168, -163, -249, + +2697, +3456, +1227, +1213, +572, +517, +850, +102, -387, +192, +924, +490, +415, +251, -28, +334, +487, +237, +455, +306, -44, +361, +407, +349, +369, -96, -484, -382, -224, -207, -148, -176, + +3120, +3716, +1221, +1448, +755, +624, +603, -564, -1136, +136, +1257, +246, +285, +171, -38, +383, +232, +372, +711, +324, +99, +204, -9, +285, +321, +68, +177, -36, -413, -443, -150, -173, + +3790, +4330, +1096, +1569, +784, +588, +463, -1059, -1653, +106, +1501, +73, -126, -239, -105, +460, +435, +368, +402, +389, +91, +309, +250, +37, -30, -24, +199, +248, +66, -210, -381, -373, + +4622, +5180, +929, +1541, +623, +502, +584, -1498, -2233, +215, +1742, -187, -310, -505, -413, +362, +388, +344, +575, +292, -268, +436, +270, +95, +161, -323, -90, +279, +151, -2, +128, -96, + +5681, +5925, +575, +1587, +609, +492, +477, -2071, -2626, +569, +1878, -446, -437, -854, -523, +332, +170, +294, +523, +68, -219, +380, -38, +251, +114, -335, +23, -101, -23, +248, +375, +75, + +6767, +6666, +205, +1705, +662, +498, +302, -2825, -2958, +1150, +2042, -710, -533, -1232, -642, +377, +122, +237, +348, -95, -351, +388, -30, +5, -60, -377, -119, +125, +76, -40, +330, +247, + +7914, +7510, -124, +1761, +488, +420, +174, -3558, -3104, +1640, +2028, -832, -567, -1607, -766, +361, +95, +311, +212, -352, -461, +375, -113, -24, -351, -633, -128, +128, +9, -5, +457, +80, + +8830, +8494, -246, +1750, +304, +130, +113, -4143, -3165, +1945, +1825, -857, -549, -1777, -958, +191, +133, +387, +88, -480, -608, +386, -265, -246, -302, -723, -280, -84, -50, +74, +350, +96, + +9314, +9665, +71, +1635, +346, -372, -34, -4328, -3176, +2030, +1536, -817, -547, -1732, -1016, -133, +66, +591, +24, -506, -733, +116, -40, -327, -495, -730, -460, +25, -137, -166, +374, -5, + +9168, +10764, +1097, +1383, +468, -796, -470, -4274, -3169, +1769, +1273, -725, -691, -1625, -1027, -452, -36, +630, +83, -652, -832, +127, -43, -349, -695, -737, -514, -168, -181, -314, +338, +138, + +8846, +11350, +2560, +1552, +433, -953, -869, -4243, -3192, +1361, +998, -476, -837, -1626, -886, -800, -125, +635, -124, -228, -816, -255, -7, -394, -552, -761, -755, -414, -246, -133, +444, +75, + +8964, +11306, +3527, +2438, +253, -982, -961, -4230, -3082, +755, +442, -71, -869, -1742, -700, -1038, -454, +793, +25, -389, -604, -243, +7, -464, -738, -765, -951, -330, -59, -171, +251, +95, + +9403, +11033, +3733, +3695, +308, -1271, -992, -4163, -2722, +92, -735, +217, -696, -1699, -422, -1673, -402, +984, -229, -198, -530, -373, +28, -463, -956, -681, -906, -518, -289, -162, +497, +102, + +10184, +10713, +3388, +4822, +577, -1450, -980, -3974, -2096, -266, -2455, +170, -229, -2033, +139, -1657, -867, +1176, -218, -154, -435, -585, +36, -392, -1039, -506, -950, -753, -269, -164, +336, -63, + +11469, +10305, +2546, +5881, +499, -1455, -857, -3843, -1101, -509, -4401, -50, +59, -2342, +782, -1732, -924, +1406, -569, -258, -144, -530, -49, -395, -1238, -446, -756, -782, -536, -315, +337, -105, + +12812, +9997, +1333, +7068, +255, -1649, -308, -3676, +7, -196, -6478, -1003, +993, -2770, +1003, -1205, -1230, +1463, -713, -345, +195, -392, -236, -389, -1244, -431, -777, -964, -608, -183, +371, -471, + +14298, +10024, -465, +8212, +114, -2512, +382, -3674, +1378, +663, -8685, -2459, +1859, -2562, +871, -988, -1367, +1466, -684, -580, +254, -110, -241, -347, -1398, -758, -715, -816, -729, -361, +154, -579, + +15791, +10811, -2667, +8435, +624, -3271, +1069, -3748, +2502, +2079, -10027, -4329, +2301, -1901, +666, -578, -1480, +1296, -627, -770, +123, +401, -53, -652, -1473, -822, -551, -788, -1234, -414, +540, -655, + +17964, +11856, -5206, +7310, +1001, -3366, +1912, -4139, +2658, +3650, -10394, -6002, +1938, -1051, +777, -287, -1664, +896, -566, -1001, +87, +651, -41, -918, -1419, -920, -813, -755, -1256, -323, +672, -811, + +20009, +12521, -7253, +6282, +961, -3398, +2583, -4837, +2731, +5771, -10940, -7407, +1508, -472, +1186, -388, -1734, +332, -519, -1043, -71, +553, -29, -952, -1661, -1165, -989, -425, -1171, -377, +657, -839, + +22177, +13864, -9457, +4361, +273, -2050, +3806, -6178, +2512, +7329, -10722, -7725, +990, -611, +1552, -139, -1889, -63, -466, -1163, -297, +596, -38, -1172, -1902, -1306, -955, -76, -1070, -458, +771, -742, + +24345, +14808, -11064, +2917, -761, -281, +4365, -7368, +2909, +8263, -9604, -7789, +243, -1094, +2044, +574, -2131, -536, -396, -1094, -498, +632, -243, -1137, -1962, -1496, -848, +190, -940, -375, +1054, -832, + +26147, +15550, -12303, +1685, -1810, +967, +4288, -7960, +2974, +9042, -8220, -8190, -317, -1893, +2641, +1163, -2716, -789, -273, -1142, -847, +531, -446, -868, -2137, -1852, -734, +364, -774, -243, +1065, -1025, + +27659, +16152, -13062, +755, -2711, +1616, +4052, -7901, +2526, +9678, -6491, -8602, -661, -2830, +3049, +1720, -3198, -833, -91, -1450, -1161, +618, -586, -618, -2344, -2144, -611, +510, -566, -204, +872, -1008, + +28303, +17220, -13451, +40, -3448, +1563, +3863, -7612, +1462, +10219, -4267, -9081, -1078, -3763, +2992, +2435, -3478, -882, -13, -1844, -1413, +823, -875, -471, -2328, -2410, -559, +601, -471, -315, +732, -991, + +29181, +17405, -13114, -304, -4240, +1458, +3452, -7492, +539, +10765, -2404, -8991, -1702, -4595, +2982, +2817, -3292, -1057, +74, -2172, -1478, +872, -1165, -289, -2195, -2469, -548, +634, -663, -287, +578, -1042, + +29321, +17827, -12348, -557, -5122, +1071, +3363, -7877, -467, +11248, -887, -8472, -2373, -5291, +2598, +3058, -2743, -1532, +107, -2142, -1752, +699, -1290, -111, -1997, -2388, -740, +468, -816, -385, +487, -985, + +28805, +18575, -11075, -519, -6256, +621, +3883, -8757, -1416, +11447, +404, -7310, -2751, -5966, +1821, +3238, -1902, -1967, -52, -1838, -2084, +568, -1247, +63, -1562, -2577, -1051, +401, -1056, -280, +613, -1053, + +27710, +19425, -9278, -279, -7398, +89, +4632, -9740, -2488, +11491, +1418, -5692, -2452, -7072, +956, +3436, -1270, -1977, -465, -1644, -2124, +549, -1018, +267, -1537, -2600, -1365, +17, -689, -160, +642, -1022, + +26524, +19729, -7061, +31, -8340, -267, +5003, -10177, -3987, +11429, +2435, -4362, -1321, -8478, +66, +3718, -1132, -1735, -895, -1806, -1690, +886, -1190, +400, -1479, -2883, -1377, -121, -394, -59, +689, -900, + +24731, +20271, -4631, +239, -8724, -1229, +4844, -9185, -6220, +10730, +4243, -3815, +672, -9539, -1506, +4100, -1430, -1335, -947, -2166, -1162, +1047, -1494, +767, -1758, -3042, -837, -474, -154, +165, +571, -941, + +23477, +19815, -2244, +479, -9027, -1898, +3618, -7399, -7878, +9201, +6108, -3552, +2583, -9590, -3747, +4198, -1760, -1193, -323, -2539, -1400, +1397, -1635, +542, -1400, -3228, -438, -316, -265, +162, +498, -845, + +22603, +18971, -668, +1272, -8642, -2638, +2333, -6179, -8347, +7433, +7800, -2940, +3459, -8248, -6239, +4034, -1687, -1398, +219, -2550, -1401, +1181, -1707, +569, -817, -3297, +15, -296, -506, +401, +364, -924, + +21958, +18536, -765, +2387, -7488, -4223, +1716, -5274, -8935, +6110, +9409, -2450, +3540, -6393, -8448, +3758, -1179, -2277, +576, -2418, -1529, +1177, -1880, +420, +14, -3051, -213, -188, -381, +229, +231, -793, + +22176, +17185, -1463, +4151, -7417, -5322, +1894, -4670, -9301, +4733, +10404, -1838, +3744, -5092, -9471, +2688, -467, -2307, -46, -2508, -1717, +1645, -1714, +18, +585, -2841, -290, -132, -583, +271, +215, -863, + +21283, +15947, -1061, +5846, -8289, -5644, +2856, -4640, -8855, +2098, +10641, -385, +3529, -2820, -10460, +1131, +531, -2119, -590, -2947, -2184, +2054, -1090, -387, +1198, -3026, -869, +546, -650, +116, +60, -894, + +19683, +14620, -396, +7001, -7790, -5818, +2880, -3841, -8800, -338, +10153, +959, +3167, -585, -10098, -824, +1447, -2278, -872, -2755, -2996, +1653, -697, +272, +1462, -3849, -1195, +1382, -669, -246, -11, -701, + +19043, +12870, -2025, +8715, -5341, -5810, +2282, -4136, -8408, -1971, +10181, +1931, +1229, +1395, -8274, -2327, +1832, -1907, -1520, -2677, -3203, +831, -255, +370, +1503, -3747, -1696, +1786, -499, -464, -64, -480, + +17772, +11494, -1905, +9490, -4457, -5781, +2323, -3030, -7953, -3525, +9683, +2138, -957, +3838, -5603, -4565, +2549, -1532, -2419, -1808, -2980, +12, -610, -213, +1746, -2508, -2211, +1172, +20, -342, -24, -448, + +16172, +10332, -1197, +9288, -3999, -4949, +1874, -2282, -7098, -4475, +8985, +1667, -1887, +4717, -3907, -5051, +2520, -1200, -2844, -1330, -2611, -280, -1072, -1112, +1423, -1375, -1811, +550, -258, -177, +416, -403, + +14861, +9191, -894, +9322, -3451, -4203, +1793, -2119, -6076, -4508, +7671, +1778, -2043, +4285, -2907, -4648, +2360, -879, -2603, -1241, -2298, -406, -1008, -1513, +521, -984, -1055, +584, -582, -325, +664, -263, + +15154, +9134, -4908, +9650, +694, -5568, -98, -860, -5127, -4048, +7837, -470, -3638, +3508, -972, -2437, +3394, +805, -1417, +31, -1653, -577, -2362, -2979, -580, -1077, -1684, -192, -259, +22, +565, -429, + +12672, +9048, -2546, +8370, +349, -5006, +73, -1080, -4272, -3672, +5900, +444, -2326, +2893, -1066, -2332, +2479, +666, -949, -82, -1657, -457, -1794, -2452, -454, -1165, -1497, -205, -372, -240, +406, -163, + +10640, +8312, -1031, +7498, +500, -3857, +463, -1057, -3977, -3222, +4691, +603, -1571, +2325, -824, -2114, +1780, +754, -897, -192, -1342, -620, -1307, -1779, -405, -857, -1348, -343, -250, -417, +44, -237, + +8848, +7462, +273, +6812, +521, -2799, +1008, -1064, -3777, -2718, +3754, +821, -1252, +1806, -375, -2145, +1225, +906, -817, -265, -1155, -585, -1036, -1174, -21, -762, -1257, -311, -233, -510, -203, -397, + +7576, +6767, +783, +6094, +949, -1930, +961, -934, -3200, -2533, +3115, +1137, -1365, +1382, -102, -2040, +908, +789, -690, -334, -1018, -480, -555, -707, -43, -640, -1047, -255, -386, -684, -317, -445, + +6758, +6214, +818, +5337, +1627, -1135, +432, -710, -2305, -2322, +2540, +1251, -1296, +892, -62, -1566, +663, +551, -577, -337, -682, -77, -179, -659, -184, -409, -797, -413, -574, -679, -216, -506, + +5676, +5613, +1210, +4774, +1859, -559, +347, -565, -1759, -1969, +1960, +1004, -1099, +525, -53, -1205, +350, +369, -435, -6, -319, -23, -94, -656, -285, -373, -741, -563, -562, -531, -260, -514, + +4838, +5040, +1571, +4251, +1972, -105, +267, -310, -1227, -1573, +1267, +789, -798, +205, +14, -944, +147, +508, -9, +9, -221, +150, -128, -742, -391, -376, -652, -447, -470, -469, -201, -405, + +3971, +4513, +1934, +3945, +1836, +92, +581, -63, -938, -1357, +811, +579, -793, +202, +181, -781, +327, +624, -92, +15, +0, +147, -352, -881, -357, -191, -505, -444, -412, -282, -88, -284, + +3487, +4143, +1924, +3589, +1775, +195, +713, +196, -635, -1287, +387, +393, -687, +361, +568, -535, +98, +502, -1, +100, +31, -150, -611, -593, -111, -190, -456, -382, -216, -81, -181, -553, + +3301, +3728, +1795, +3379, +1523, +332, +960, +396, -543, -1253, +191, +235, -129, +880, +351, -652, +117, +445, +130, +39, -216, -238, -343, -293, -61, -146, -363, -182, -162, -325, -424, -636, + +3158, +3429, +1574, +3069, +1415, +510, +1197, +428, -494, -1109, +222, +719, +168, +681, +275, -640, +81, +477, +19, -67, -36, -85, -122, -162, +45, -5, -361, -356, -380, -419, -409, -428, + +2927, +3070, +1345, +2819, +1417, +712, +1293, +444, -262, -476, +280, +510, +400, +568, +118, -618, -112, +442, +241, +165, -34, -72, +77, +111, +94, -334, -675, -432, -303, -274, -306, -497, + +2770, +2981, +1085, +2080, +1492, +1281, +1415, +707, +136, -480, +296, +711, +259, +268, -123, -614, +243, +742, +216, +47, +81, +319, +285, -194, -408, -500, -506, -280, -185, -330, -423, -456, + +2145, +2721, +1165, +1872, +1627, +1355, +2019, +1188, +250, -296, -84, +490, +282, +67, -115, -178, +405, +756, +354, +121, +267, +315, -30, -468, -422, -383, -385, -212, -269, -357, -406, -427, + +1842, +2681, +1515, +1848, +2108, +1608, +1340, +1172, +512, -174, -238, -168, -13, +491, +474, +113, +382, +613, +415, +165, +91, -47, -298, -384, -349, -382, -402, -278, -199, -319, -431, -344, + +1494, +2675, +2068, +1863, +2114, +2048, +1472, +644, +14, -248, -149, +107, +179, +299, +556, +612, +502, +443, +238, -13, -145, -180, -250, -339, -297, -336, -446, -377, -225, -244, -239, -265, + +1925, +2822, +1707, +2248, +2162, +1532, +1572, +666, -432, -363, +210, +212, +263, +498, +470, +699, +813, +253, -219, -217, -141, -158, -176, -306, -384, -385, -364, -200, -281, -326, -188, -200, + +1895, +2793, +1934, +2045, +1846, +1354, +1196, +799, +59, -3, +248, +165, +197, +407, +651, +831, +698, +67, -242, -221, -251, -169, -144, -186, -354, -464, -369, -235, -233, -217, -227, -253, + +2070, +3085, +1525, +1328, +1530, +1219, +1048, +1205, +562, -2, +387, +198, +130, +544, +658, +484, +722, +457, -348, -457, -175, -78, -253, -223, -258, -370, -406, -378, -222, -139, -199, -290, + +2157, +2952, +1156, +902, +1034, +1185, +1499, +1126, +501, +624, +479, -49, +331, +597, +587, +621, +629, +548, +175, -291, -470, -235, -85, -52, -278, -368, -303, -369, -323, -238, -97, -173, + +2202, +2907, +1140, +947, +996, +914, +968, +769, +506, +769, +808, +471, +171, +297, +838, +683, +510, +567, +580, +137, -151, -326, -508, -27, -10, -284, -285, -236, -358, -292, -161, -179, + +2228, +3053, +1096, +862, +1274, +1155, +755, +13, -357, +880, +1376, +402, +198, +406, +514, +671, +748, +486, +514, +663, +288, -200, -289, -329, -436, -55, -28, -272, -239, -283, -290, -193, + +2611, +3293, +974, +955, +1269, +1230, +755, -497, -748, +618, +1056, +494, +365, +41, +465, +810, +420, +494, +736, +416, +453, +551, -173, -405, -427, -456, -169, -36, -153, -282, -273, -363, + +3071, +3880, +1049, +902, +1063, +1099, +721, -721, -1094, +709, +1109, -47, +104, +119, +412, +545, +413, +580, +520, +543, +532, +362, +329, +140, -499, -431, -240, -372, -190, -30, -169, -356, + +3643, +4399, +965, +972, +1042, +1109, +628, -1277, -1336, +964, +1149, -203, -182, -383, +345, +664, +317, +410, +437, +373, +394, +662, +276, +180, +133, -200, -383, -376, -281, -286, -117, -162, + +4308, +4895, +774, +1151, +1170, +1121, +455, -1795, -1513, +1267, +1131, -396, -245, -566, +93, +375, +376, +540, +286, +94, +297, +541, +252, +439, +34, +129, +201, -368, -356, -264, -280, -354, + +5087, +5494, +565, +1262, +1166, +1002, +246, -2296, -1418, +1649, +899, -695, -391, -688, +139, +229, +44, +521, +312, -3, +101, +250, +192, +280, +43, +280, +150, +88, +29, -357, -310, -372, + +5947, +6051, +327, +1497, +1239, +800, -127, -2807, -1134, +2147, +640, -918, -589, -888, +220, +107, +62, +477, +59, -49, +73, +198, -35, +79, -132, +175, +309, +137, +146, +162, -75, -593, + +6826, +6642, +77, +1786, +1321, +527, -620, -3298, -663, +2560, +320, -1067, -693, -1064, +226, -95, -6, +673, -51, -262, -29, +141, -44, -11, -506, +62, +205, +6, +401, +111, +23, -56, + +7619, +7443, -127, +1929, +1356, +155, -1099, -3708, -137, +2846, -83, -1160, -806, -1101, +269, -385, -138, +769, -105, -266, -156, -64, -45, -101, -607, -105, -82, +19, +101, +44, +338, -87, + +8308, +8291, -181, +1996, +1443, -217, -1606, -4093, +424, +3041, -446, -1225, -972, -1051, +348, -589, -310, +757, -179, -230, -151, -213, -150, -169, -724, -105, -113, -531, +38, +251, +144, +14, + +8643, +9273, +110, +1817, +1665, -587, -2048, -4412, +705, +3223, -686, -1244, -1233, -1013, +428, -696, -381, +630, -323, -238, -129, -251, -193, -373, -663, -295, -481, -278, -3, -42, +123, -69, + +8492, +10281, +986, +1409, +1924, -770, -2443, -4558, +552, +3340, -711, -1234, -1461, -1100, +472, -719, -429, +587, -437, -400, -100, -332, -135, -347, -1076, -422, -280, -435, -79, -23, +2, -146, + +8125, +10926, +2345, +1150, +1899, -669, -2844, -4563, +156, +3228, -595, -1223, -1573, -1303, +463, -750, -482, +579, -448, -544, -287, -237, -139, -775, -987, -370, -466, -463, -189, -20, +78, -37, + +7991, +11060, +3529, +1603, +1541, -533, -3046, -4622, -35, +2877, -564, -1180, -1626, -1431, +402, -852, -505, +583, -405, -609, -263, -542, -401, -426, -1162, -560, -503, -504, -197, +50, +140, -226, + +8113, +10987, +4130, +2562, +1381, -747, -2977, -4641, -186, +2488, -599, -1166, -1769, -1438, +351, -1006, -539, +563, -351, -314, -744, -723, -154, -612, -1117, -726, -662, -455, -57, +40, -92, -256, + +8541, +10760, +4178, +3497, +1698, -1029, -2982, -4222, -351, +1963, -668, -970, -2110, -1515, +400, -1246, -614, +645, -262, -603, -476, -696, -449, -571, -1094, -668, -849, -390, -123, -169, +68, -29, + +9463, +10347, +3864, +4361, +1905, -1015, -3375, -3543, -178, +968, -787, -513, -2341, -1829, +501, -1686, -325, +497, -681, +38, -559, -871, -367, -691, -1137, -482, -872, -677, -284, +7, +225, -241, + +10674, +9874, +3106, +5362, +1727, -766, -3609, -3015, +543, -431, -1222, +153, -2336, -2209, +365, -1836, -554, +242, -426, +197, -633, -802, -399, -696, -1174, -325, -1145, -803, -31, -108, -43, -199, + +11979, +9620, +1869, +6561, +1461, -835, -3245, -2641, +1610, -1691, -2279, +974, -2010, -2575, +505, -2638, -686, +670, -1065, +774, -478, -978, -319, -585, -1119, -498, -1130, -708, -19, -296, -40, -290, + +13201, +9744, +157, +7624, +1518, -1581, -2587, -2110, +2716, -2532, -3960, +1424, -1264, -2535, -109, -3054, -615, +404, -1230, +1095, -263, -1158, -337, -435, -1109, -466, -1189, -812, +84, -300, -171, -443, + +14767, +10074, -1860, +8018, +1956, -2430, -2103, -1372, +3819, -2797, -5967, +1234, +173, -2924, -421, -3162, -1160, +752, -1619, +1210, +95, -1349, -306, -444, -1114, -283, -1142, -1053, +276, -314, -302, -597, + +16745, +11407, -4630, +6674, +3018, -2190, -1545, -1323, +4470, -2021, -7769, +629, +1347, -2958, -574, -3466, -1241, +900, -1709, +1083, +268, -1132, -420, -544, -1164, -33, -940, -1138, +189, -205, -362, -753, + +18725, +12859, -7380, +4619, +4068, -1417, -1079, -1554, +4711, -1055, -8876, -550, +1948, -2355, -915, -3587, -1380, +839, -1610, +894, +413, -1080, -618, -661, -1073, +37, -840, -1169, +44, -15, -345, -1019, + +20617, +14278, -9830, +2481, +4741, -181, -623, -1858, +4753, +25, -9421, -1889, +2095, -1425, -1076, -3758, -1263, +565, -1542, +933, +391, -1113, -672, -722, -1015, -8, -886, -996, +4, +105, -420, -1228, + +22971, +14648, -11936, +1010, +4670, +1158, -431, -2361, +5156, +1040, -10169, -3060, +2153, -790, -797, -4032, -1000, +16, -1618, +1257, +163, -1228, -657, -703, -1282, -23, -913, -801, -89, +33, -392, -1315, + +25010, +15029, -13660, +283, +4193, +2237, -295, -3037, +6357, +2181, -11344, -3815, +2283, -582, +157, -4078, -1205, -374, -1568, +1582, -149, -1216, -484, -731, -1677, +102, -841, -808, -116, +31, -256, -1422, + +26769, +15204, -15115, +212, +3256, +2746, -305, -3981, +8274, +2753, -12585, -4021, +1747, -336, +1272, -4084, -1750, -584, -1463, +1491, -429, -1113, -280, -912, -2029, +54, -759, -856, -175, +86, -304, -1461, + +28266, +15342, -16203, +581, +2138, +2848, -458, -4840, +10385, +2925, -13189, -4103, +831, +88, +2199, -3878, -2349, -502, -1510, +1038, -429, -929, -129, -1132, -2297, -63, -611, -925, -177, +40, -335, -1317, + +29815, +15252, -16897, +1083, +956, +2943, -891, -5377, +12108, +2999, -12962, -4416, +24, +360, +3011, -3485, -2819, -229, -1736, +410, -242, -574, -195, -1310, -2449, -114, -453, -1000, -245, +121, -272, -1376, + +30704, +15809, -17499, +1266, -67, +2973, -1441, -5841, +12884, +3441, -12109, -5095, -636, +265, +3716, -2998, -3240, +129, -2153, -287, -24, -180, -492, -1366, -2616, -99, -271, -1307, -188, +298, -393, -1578, + +31618, +16165, -17687, +1138, -966, +3162, -2242, -6103, +13031, +3994, -10855, -5814, -1132, -114, +4440, -2576, -3472, +441, -2571, -925, +179, +66, -731, -1305, -2901, +118, -240, -1556, +32, +256, -573, -1665, + +32352, +16428, -17457, +790, -1672, +3290, -2962, -6399, +12571, +4836, -9536, -6362, -1498, -662, +5052, -2203, -3513, +550, -2849, -1412, +253, +166, -883, -1139, -3109, +166, -209, -1529, +21, +58, -646, -1719, + +32443, +17279, -16999, +233, -2175, +3032, -2969, -7266, +11609, +6215, -8405, -6559, -1896, -1197, +5401, -1763, -3376, +385, -2990, -1689, +180, +133, -974, -846, -3214, -83, +9, -1520, -177, -60, -770, -1566, + +31892, +18478, -16118, -275, -2655, +2351, -2206, -8781, +10331, +8020, -7513, -6312, -2325, -1753, +5424, -1170, -3047, -34, -3062, -1782, +143, -158, -877, -571, -3280, -291, -54, -1441, -346, -233, -674, -1187, + +30789, +19780, -14759, -548, -3198, +1460, -1025, -10799, +8894, +10055, -6732, -5809, -2497, -2429, +5133, -346, -2659, -573, -3168, -1582, +53, -566, -705, -356, -3272, -629, -135, -1412, -494, -112, -434, -955, + +29203, +20906, -12769, -646, -3914, +632, +128, -12834, +7097, +11981, -5813, -5212, -2227, -3391, +4539, +673, -2372, -1121, -3072, -1520, +50, -953, -749, -83, -3467, -767, -412, -1439, -216, +10, -266, -671, + +27369, +21887, -10304, -719, -4689, +134, +1044, -14260, +4701, +13487, -4266, -4865, -1191, -4653, +3796, +1775, -2279, -1199, -3034, -1527, +71, -1028, -1358, +221, -3301, -1300, -376, -1263, +67, +149, +70, -544, + +25668, +22491, -8130, -702, -4924, -592, +1193, -14383, +1825, +13879, -1753, -4990, +70, -5585, +2485, +3061, -2364, -1028, -2910, -1941, +216, -1133, -2116, +371, -3234, -1474, -105, -1358, +438, +510, +66, -745, + +24445, +22594, -6916, -408, -4078, -1908, +266, -13241, -891, +13193, +1079, -5162, +987, -5936, +931, +4120, -2150, -1025, -2529, -2729, -156, -699, -2958, -77, -2635, -1480, +97, -1388, +718, +673, -84, -802, + +24036, +21606, -6204, +627, -3020, -3027, -1363, -11604, -2945, +12413, +3083, -5038, +1938, -6484, +131, +4636, -1658, -795, -2484, -3507, -351, -682, -3613, +80, -2402, -1272, +354, -1476, +898, +717, -205, -856, + +23746, +20456, -5957, +1984, -1938, -4319, -2729, -9544, -5054, +11531, +5123, -5779, +3222, -6434, -1058, +5531, -1261, -866, -2359, -3656, -1163, -839, -3784, +272, -1846, -1591, +565, -1292, +952, +517, -310, -562, + +23960, +19174, -6448, +3094, -1039, -5368, -3542, -7116, -6317, +9363, +7378, -6843, +3456, -4600, -3042, +6646, -852, -1642, -1443, -3885, -1943, -945, -3873, +318, -958, -2243, +620, -863, +528, +698, -367, -469, + +23567, +18274, -6810, +4250, -385, -6084, -3975, -5591, -6825, +6911, +9455, -6771, +1918, -2142, -4373, +6456, +835, -2708, -1024, -3507, -2457, -992, -4100, +133, -369, -2407, +311, -628, +321, +831, -178, -597, + +23143, +16836, -6902, +5727, -531, -6291, -3459, -5161, -7193, +5338, +10494, -6386, +648, -1274, -4124, +6012, +1743, -2864, -1093, -2840, -2832, -626, -4269, -880, -83, -2116, +209, -691, +146, +839, -37, -502, + +22711, +15714, -7208, +6876, -1112, -6813, -1895, -4170, -8096, +3464, +11809, -6438, -833, +596, -4557, +5103, +2952, -2724, -1144, -2460, -2916, -73, -4033, -2509, -346, -1558, +340, -324, -568, +509, +520, -161, + +21883, +15259, -8430, +8064, -235, -8167, -638, -2887, -8285, +800, +12561, -5050, -2930, +2356, -4439, +2991, +4720, -2205, -1490, -1642, -3457, +613, -3421, -4138, -736, -1237, +241, +437, -924, -343, +1118, +203, + +21336, +14054, -8898, +8815, +778, -8299, -1119, -1073, -7651, -2227, +13016, -3460, -4273, +3243, -3776, +1237, +5044, -803, -1471, -1297, -3268, +457, -2964, -4426, -1137, -1555, +51, +1032, -730, -630, +878, +351, + +20364, +12658, -8776, +9749, +928, -8029, -658, -913, -7055, -3196, +11978, -2563, -4312, +3779, -3422, -39, +4857, -93, -856, -1070, -2919, +46, -2987, -3874, -1261, -1841, -597, +1113, -366, -282, +474, -132, + +19013, +11105, -7802, +10307, +543, -7199, -275, -1181, -6482, -3416, +10634, -2108, -4042, +4151, -2777, -1409, +4761, +291, -1107, -73, -2791, -368, -2750, -3871, -721, -1726, -1380, +656, -107, +32, +532, -418, + +17238, +9876, -6359, +10305, +398, -6315, -102, -1089, -5867, -3730, +9349, -1363, -3939, +4046, -1704, -2280, +4126, +804, -1450, +148, -1982, -710, -2585, -3457, -636, -1203, -1796, +107, -115, +106, +736, -435, + +16850, +7680, -7300, +12520, +2285, -8479, -1087, +427, -4800, -1828, +6635, -3369, -2358, +3423, -1655, -892, +2571, -327, -160, +642, -662, +1201, -1048, -1605, +229, -1235, -1428, -365, -1650, -1331, -434, -718, + +14445, +7248, -5479, +10890, +2224, -6676, -847, +20, -3992, -1849, +5544, -2552, -2301, +2914, -1338, -1107, +2267, -66, -274, +451, -432, +1011, -1109, -1445, +210, -1200, -1152, -150, -1229, -1064, -619, -638, + +12262, +7034, -3826, +9064, +2556, -4912, -1000, -85, -3259, -1912, +4712, -1765, -2260, +2378, -779, -1142, +1866, +240, -211, +297, -362, +843, -852, -1395, +26, -936, -987, +115, -841, -918, -540, -612, + +10302, +6772, -2608, +7425, +3047, -3580, -1144, +38, -2705, -1968, +3948, -1167, -2245, +1845, -376, -1032, +1522, +265, -101, +261, -453, +682, -692, -1289, -83, -615, -752, -59, -567, -670, -472, -618, + +8655, +6443, -1690, +6216, +3422, -2584, -975, +289, -2316, -1951, +3369, -755, -2184, +1494, -28, -828, +1147, +375, +103, +99, -381, +549, -584, -1004, +111, -444, -718, -65, -432, -490, -423, -480, + +7221, +6029, -1043, +5350, +3704, -1861, -720, +491, -2015, -1932, +2857, -505, -2070, +1231, +249, -749, +916, +588, -26, +2, -231, +492, -373, -773, +146, -331, -639, -153, -420, -446, -268, -366, + +6149, +5337, -522, +4890, +3705, -1298, -409, +653, -1896, -1811, +2394, -329, -1930, +1021, +457, -665, +862, +483, -128, +133, -8, +453, -352, -564, +224, -355, -685, -251, -418, -327, -123, -232, + +5347, +4865, -12, +4345, +3331, -784, +8, +681, -1713, -1654, +1950, -310, -1698, +1128, +488, -580, +778, +296, +168, +368, -71, +403, -167, -481, +0, -380, -642, -237, -238, -203, -161, -399, + +4513, +4458, +327, +3862, +3291, -212, +50, +538, -1286, -1648, +1413, -6, -1274, +809, +432, -246, +709, +464, +342, +239, -48, +380, -170, -546, -158, -340, -484, -110, -208, -423, -383, -436, + +3737, +4010, +796, +3404, +3194, +416, -10, +338, -902, -1429, +1024, +156, -1024, +609, +727, +264, +595, +355, +422, +205, -29, +258, -264, -566, -23, -135, -442, -273, -489, -465, -296, -300, + +3244, +3768, +1128, +2910, +3135, +692, -253, +385, -416, -1327, +523, +399, -524, +860, +1068, +205, +374, +460, +341, +111, -88, +108, -72, -266, -80, -420, -614, -364, -338, -321, -247, -281, + +2573, +3501, +1542, +2422, +3009, +997, -86, +399, -529, -1166, +615, +927, +3, +728, +933, +166, +369, +430, +133, +29, +88, +270, -37, -461, -485, -479, -438, -286, -266, -299, -341, -359, + +2231, +3444, +1513, +2040, +3101, +1062, -319, +337, -154, -486, +938, +903, +105, +773, +781, +97, +163, +295, +372, +236, +56, -55, -435, -564, -350, -311, -370, -314, -370, -380, -309, -324, + +2099, +3103, +1628, +2260, +2332, +675, +355, +998, +218, -292, +974, +821, +239, +834, +457, -122, +408, +649, +268, -133, -357, -207, -248, -398, -297, -330, -451, -420, -307, -346, -285, -262, + +2122, +2791, +1338, +2074, +2185, +1299, +1098, +1022, +96, -224, +1143, +1002, +34, +360, +626, +337, +351, +217, -313, -387, -92, +1, -292, -456, -393, -443, -464, -373, -291, -249, -256, -321, + +1707, +2474, +1550, +2358, +2684, +1380, +926, +1182, +372, +34, +972, +722, +127, +725, +656, -121, -188, -80, -126, -77, -58, -130, -419, -521, -423, -415, -422, -288, -194, -281, -292, -289, + +2009, +3271, +2261, +2063, +1937, +1369, +1101, +993, +457, +278, +709, +981, +479, -169, -163, -155, -17, +78, -53, -120, -289, -340, -416, -495, -424, -327, -303, -303, -181, -220, -289, -318, + +2008, +3310, +2283, +1883, +1850, +1562, +1336, +1209, +776, +362, +614, +893, +94, -536, -228, +27, +139, +104, -127, -295, -281, -260, -428, -460, -357, -327, -324, -261, -177, -196, -244, -322, + +1917, +2862, +1700, +1658, +1732, +1613, +1699, +1958, +1364, +660, +516, +154, +109, -111, -309, -59, +186, +33, -209, -177, -238, -291, -369, -419, -336, -324, -384, -275, -151, -205, -230, -271, + +2083, +2983, +1506, +1369, +1260, +1246, +1868, +2065, +1340, +757, +550, +543, +648, -21, -250, -120, -176, +2, -56, -272, -389, -249, -240, -367, -275, -212, -264, -298, -255, -207, -278, -316, + +2198, +2902, +1108, +1182, +1319, +951, +937, +1441, +1654, +1337, +1100, +824, +681, +876, +211, -700, -323, -124, -65, -79, -310, -308, -251, -253, -245, -200, -273, -191, -287, -316, -203, -334, + +2056, +2797, +1106, +1111, +1388, +1207, +805, +382, +604, +1281, +1542, +1132, +810, +896, +1118, +443, -493, -486, -254, -141, -40, -152, -378, -280, -153, -282, -256, -141, -244, -319, -313, -273, + +2227, +2815, +713, +806, +1269, +1147, +860, +283, +11, +688, +1122, +928, +1193, +1393, +1389, +1011, +515, +126, -365, -592, -318, -110, -213, -289, -293, -274, -243, -88, -185, -280, -240, -271, + +2487, +3077, +731, +1027, +1384, +982, +654, -128, +18, +996, +561, +73, +591, +932, +1479, +1270, +870, +925, +448, -201, -501, -563, -415, -115, -143, -320, -310, -120, -171, -247, -175, -287, + +2775, +3186, +631, +1392, +1798, +1197, +294, -934, -91, +1380, +530, -194, +56, +369, +981, +652, +864, +1272, +870, +557, +177, -277, -677, -549, -265, -205, -167, -195, -284, -238, -143, -268, + +3354, +3952, +622, +1159, +1616, +1212, +384, -1193, -171, +1340, +276, -317, +73, +202, +505, +358, +412, +812, +941, +759, +457, +303, +14, -361, -589, -473, -252, -41, -106, -338, -312, -210, + +3851, +4360, +508, +1396, +1995, +1083, -118, -1646, +204, +1680, -168, -602, -109, +183, +637, +36, +22, +528, +357, +402, +649, +527, +382, +246, -154, -411, -536, -224, -139, -252, -213, -373, + +4411, +4791, +385, +1660, +2324, +1023, -690, -2047, +660, +1766, -479, -607, -315, +44, +662, -70, -18, +284, +30, +175, +102, +352, +562, +305, +304, +207, -224, -238, -340, -387, -265, -275, + +5196, +5589, +252, +1519, +2294, +877, -1040, -2105, +1073, +1563, -889, -523, -328, -3, +615, -267, -54, +275, -150, -65, -69, +83, +148, +190, +385, +349, +230, +269, -184, -470, -345, -462, + +5718, +5975, +175, +2056, +2782, +433, -1979, -2126, +1813, +1397, -1262, -508, -449, +38, +582, -483, -40, +268, -347, -79, -259, -144, +146, -223, +11, +368, +235, +504, +304, -118, -274, -506, + +6315, +6714, +139, +2135, +3020, +109, -2674, -1982, +2425, +978, -1604, -368, -505, +111, +586, -693, -117, +249, -464, -85, -325, -245, +4, -438, -62, +108, +23, +446, +291, +123, +139, -256, + +6745, +7502, +262, +2112, +3265, -191, -3399, -1845, +3011, +575, -2029, -233, -551, +131, +609, -828, -184, +190, -609, -176, -413, -318, +53, -619, -305, +55, -89, +207, +130, -29, +147, +100, + +7135, +8455, +528, +1753, +3383, -342, -3912, -1715, +3302, +347, -2377, -280, -478, +73, +666, -864, -309, +173, -675, -305, -523, -417, -31, -619, -370, -108, -188, +168, -8, -183, -48, -243, + +7313, +9335, +990, +1537, +3442, -503, -4294, -1670, +3510, +231, -2617, -467, -433, +51, +676, -780, -520, +145, -610, -381, -642, -599, -117, -669, -413, -163, -232, +54, +96, -400, -473, -157, + +7366, +10104, +1617, +1432, +3413, -641, -4433, -1789, +3563, +295, -2857, -581, -471, -47, +733, -715, -694, +95, -548, -428, -666, -773, -215, -762, -547, -237, -183, +203, -336, -503, -328, -397, + +7627, +10884, +2189, +1075, +3085, -556, -4178, -2011, +3118, +500, -2883, -799, -373, -262, +585, -455, -843, -134, -419, -461, -781, -795, -264, -872, -798, -151, -218, -232, -138, -459, -588, -350, + +7805, +11222, +3062, +1025, +2511, +140, -3881, -2575, +2792, +742, -2671, -862, -572, -376, +526, -340, -707, -443, -595, -287, -600, -934, -448, -730, -617, -528, -615, +39, -258, -504, -448, -459, + +8363, +10906, +3309, +2010, +2235, +305, -3931, -2743, +2509, +616, -2212, -1029, -818, -300, +441, -402, -584, -720, -757, -88, -693, -1025, -498, -478, -772, -805, -578, -256, -196, -436, -534, -482, + +9029, +10207, +3227, +3604, +2126, +318, -3990, -2699, +2282, -66, -1506, -870, -1243, -147, +313, -594, -347, -843, -960, -75, -980, -749, -429, -936, -470, -770, -924, -178, -239, -505, -518, -435, + +9921, +9094, +2287, +6032, +2825, -665, -3976, -1942, +1634, -1240, -452, -499, -1858, -63, +175, -661, -141, -1007, -1221, -134, -966, -783, -874, -746, -300, -913, -822, -399, -257, -376, -363, -634, + +11207, +8923, +714, +7384, +3504, -1787, -3331, -478, +667, -3182, +480, +632, -2340, -174, -41, -734, +254, -1209, -1563, +237, -1495, -1119, -374, -1179, -176, -742, -854, -326, -296, -187, -407, -889, + +12500, +9128, -1225, +8120, +4706, -2957, -3096, +1429, +224, -5655, +633, +2334, -2476, -521, -246, -1021, +659, -1250, -1598, -102, -1942, -946, -536, -1243, -56, -809, -795, -9, -245, -516, -388, -591, + +13676, +9715, -3224, +8146, +6300, -3786, -3252, +3385, +497, -7984, -273, +4084, -1795, -1036, -439, -1428, +900, -738, -2169, -270, -1884, -1560, -244, -1157, -225, -702, -726, +327, -337, -781, -147, -433, + +15154, +10710, -5567, +6975, +8141, -3612, -4028, +4575, +1224, -9451, -1863, +5048, -504, -1304, -849, -1887, +1317, -802, -2679, +65, -2243, -1967, -192, -1025, -170, -751, -680, +394, -331, -789, -111, -452, + +16751, +11590, -7670, +5697, +9423, -3002, -4671, +5673, +1938, -10472, -3508, +5316, +1125, -1098, -1562, -2113, +1531, -1067, -2689, -22, -2225, -2260, -408, -719, -88, -730, -829, +416, -248, -657, -207, -430, + +19048, +11932, -9850, +4534, +10090, -1984, -5054, +6461, +2293, -11027, -4690, +4999, +2637, -594, -2197, -2457, +1788, -1314, -2837, +89, -2336, -2296, -497, -623, +34, -680, -1066, +461, -55, -678, -251, -446, + +21615, +12285, -12393, +3218, +10447, -513, -5263, +6448, +2499, -11072, -5490, +4213, +3638, +192, -2622, -3085, +2128, -1593, -3108, +258, -2535, -2078, -721, -584, +167, -802, -1230, +548, +77, -824, -300, -503, + +23814, +13115, -14900, +2298, +10402, +898, -5101, +6133, +3297, -10978, -6160, +3330, +4213, +1402, -2845, -3633, +2406, -1782, -3197, +506, -2620, -1975, -705, -585, +213, -896, -1169, +725, -33, -930, -208, -501, + +26386, +12827, -16969, +2278, +9703, +1341, -4735, +5967, +4345, -11169, -7039, +2751, +4328, +2440, -3053, -3808, +2333, -2300, -2829, +717, -2947, -2030, -466, -759, +120, -952, -975, +828, -420, -898, -159, -497, + +27944, +13492, -18792, +2616, +8679, +1183, -4343, +5611, +6445, -11341, -8610, +2448, +4449, +2910, -2638, -3722, +1665, -2447, -2294, +737, -3191, -2075, -286, -1008, +16, -802, -857, +864, -755, -842, -70, -604, + +29685, +13246, -19821, +3525, +7289, +438, -4363, +5714, +8745, -11618, -10243, +2318, +4494, +2830, -1737, -3623, +798, -2252, -1923, +676, -3494, -1846, -281, -1396, -10, -574, -760, +810, -964, -876, +89, -884, + +30876, +13227, -20231, +4464, +5889, -395, -4997, +6035, +11190, -11731, -11571, +2002, +4359, +2564, -389, -3809, +115, -1644, -2030, +671, -3672, -1473, -429, -1750, -81, -276, -628, +609, -946, -950, +127, -1298, + +31278, +13828, -20217, +5005, +4867, -1003, -6198, +6112, +13378, -11330, -12204, +1134, +4093, +2243, +984, -3911, -507, -785, -2404, +550, -3517, -1127, -734, -1985, -167, -11, -527, +311, -626, -1201, -142, -1426, + +31763, +14606, -20213, +4922, +4300, -1334, -7821, +5934, +15019, -10488, -12296, -244, +3894, +2145, +1899, -3668, -996, -217, -2645, +278, -3186, -960, -1050, -2098, -246, +125, -509, +271, -479, -1663, -297, -1411, + +32059, +15063, -19624, +4534, +3996, -1550, -9300, +5401, +15706, -8935, -11963, -1825, +3576, +2337, +2148, -3207, -1061, -200, -2557, +23, -2815, -964, -1297, -2112, -372, +106, -371, +213, -866, -1642, -555, -1453, + +31594, +16148, -18709, +3873, +3953, -1965, -10020, +3854, +16002, -6585, -11621, -3362, +3109, +2803, +1915, -2572, -712, -591, -2348, +118, -2607, -1103, -1413, -2224, -397, +185, -559, -36, -1026, -1584, -771, -1168, + +30561, +17638, -17451, +3091, +3826, -2310, -9959, +1289, +16030, -3803, -11272, -4403, +2328, +3336, +1431, -1843, -11, -1291, -1874, +345, -2491, -1351, -1564, -2198, -272, -81, -1106, +216, -1299, -1439, -527, -1224, + +29054, +19377, -15810, +1898, +3337, -2040, -9228, -2236, +15567, -882, -10760, -4753, +1128, +3442, +1193, -1335, +949, -1929, -1501, +721, -2539, -1679, -1649, -1976, -762, -420, -1351, +363, -1271, -1184, -487, -1395, + +27602, +19984, -13330, +1384, +2220, -1553, -8967, -5440, +14956, +1794, -10257, -4554, -131, +2570, +2016, -1408, +1844, -1852, -1851, +1473, -2793, -1890, -1630, -2378, -1270, -515, -1540, +663, -952, -1427, -261, -1350, + +25630, +20290, -10249, +1324, +1107, -1114, -8918, -8485, +14115, +4665, -9857, -4277, -756, +606, +3451, -1301, +1865, -565, -2709, +1877, -2367, -2459, -1746, -2677, -1920, -340, -1413, +665, -508, -1675, -66, -1466, + +23903, +20683, -7286, +510, -377, -53, -7840, -11202, +11907, +7374, -9146, -4087, -105, -1982, +4052, -56, +1078, +860, -2851, +1241, -1622, -2794, -2100, -2674, -2293, -321, -1039, +386, -96, -1780, -277, -1191, + +22823, +20723, -6390, +1262, +38, -1708, -6903, -11540, +8654, +9407, -7731, -4726, +1287, -3835, +3356, +1929, +303, +1232, -2157, +96, -909, -2590, -2708, -1999, -2763, -486, -647, +74, -134, -1612, -437, -1074, + +23286, +19705, -6984, +2708, +768, -3874, -6807, -9892, +5577, +9767, -5818, -5461, +2601, -4494, +2384, +2776, +168, +931, -1602, -159, -1262, -1698, -2885, -1466, -2698, -1301, -450, -206, -5, -1620, -620, -969, + +23121, +19255, -7571, +3875, +1563, -5614, -6214, -8564, +2641, +9601, -3111, -6567, +3743, -4320, +945, +3692, -1043, +1590, -1282, -840, -479, -978, -2698, -1087, -2537, -2252, -520, -532, +376, -1513, -1259, -735, + +23895, +17231, -7926, +5603, +1022, -6360, -5559, -7729, +248, +9659, -1110, -7381, +4032, -2981, -753, +3497, -675, +212, -226, -663, -11, -138, -2841, -1009, -2052, -2616, -1508, -419, +202, -1307, -1387, -864, + +24342, +16471, -9991, +7124, +2357, -8386, -5329, -5315, -1440, +7468, +1850, -7622, +3025, -1191, -1868, +2925, -544, -837, +462, +724, -295, +355, -2494, -1379, -1397, -2680, -2066, -975, -223, -1077, -799, -950, + +24670, +15431, -12280, +9290, +3619, -10800, -4710, -2736, -2869, +4919, +4375, -7414, +1744, +298, -2787, +2517, -329, -1185, +786, +1117, +234, +534, -2350, -1334, -1274, -2503, -2002, -1594, -1255, -755, -99, -851, + +25053, +13472, -13783, +11903, +3737, -12350, -3755, -973, -3561, +2410, +5792, -6487, +903, +639, -3500, +2947, +120, -1823, +1427, +635, +328, +1654, -2795, -1081, -1079, -2818, -1321, -1807, -2368, -781, +236, -570, + +25116, +10992, -14060, +14345, +2919, -12891, -2578, +298, -4831, +849, +7344, -6355, -113, +1687, -3785, +2243, +1525, -1852, +673, +891, +28, +1939, -1939, -1636, -642, -2710, -1531, -1027, -2946, -1438, +260, -246, + +23985, +9052, -12782, +15373, +1674, -11878, -1468, -66, -5434, +491, +7676, -6469, -622, +2840, -3942, +1270, +2660, -1561, +29, +815, -200, +1925, -1493, -1644, -301, -2510, -1767, -674, -2584, -1874, -316, -165, + +21931, +7984, -10773, +14942, +1323, -10330, -1496, -41, -5153, -560, +7563, -5510, -1367, +3202, -3067, +472, +2598, -1083, +280, +328, -550, +2171, -1750, -1359, +265, -2505, -1617, -565, -2257, -1696, -689, -545, + +19430, +7714, -9051, +13883, +1898, -9550, -1479, +550, -5119, -1546, +7412, -4342, -2191, +3447, -2123, -382, +2504, -635, +149, +475, -754, +1639, -1244, -1582, +373, -1789, -1679, -351, -2065, -1520, -554, -754, + +15748, +5880, -5425, +14058, +1054, -9150, +6, +395, -3696, +26, +2379, -3599, +1707, +2155, -2493, -381, +1177, -628, -908, +221, -185, +13, -490, +744, +822, +168, +287, -448, -1045, -444, -892, -1472, + +13423, +5793, -3949, +12100, +1504, -7414, -200, +63, -3202, +36, +2192, -2942, +1203, +1913, -1964, -650, +802, -427, -791, -12, -102, +329, -386, +362, +832, +203, -6, -415, -837, -549, -728, -965, + +11547, +5785, -2873, +10302, +2118, -6063, -463, +55, -2706, -44, +2080, -2250, +641, +1766, -1389, -907, +655, -241, -693, -30, +34, +406, -343, +364, +574, +40, +171, -246, -795, -541, -534, -664, + +9992, +5645, -2205, +8952, +2516, -5038, -463, +97, -2247, -98, +1995, -1860, +247, +1695, -1144, -964, +569, -79, -605, +22, +220, +235, -242, +317, +304, +54, +320, -69, -720, -432, -411, -602, + +8782, +5267, -1688, +7925, +2586, -4032, -444, +186, -1797, -191, +1866, -1605, +27, +1498, -942, -933, +555, +32, -524, +199, +141, +118, -129, +149, +324, +142, +325, +78, -560, -385, -344, -545, + +7729, +4882, -1177, +6873, +2650, -3039, -407, +340, -1509, -165, +1693, -1465, -61, +1352, -781, -864, +627, +111, -305, +152, +24, +234, -129, +182, +391, +215, +338, +94, -398, -277, -266, -463, + +6682, +4405, -731, +6123, +2845, -2298, -387, +459, -1188, -176, +1393, -1251, -73, +1145, -660, -560, +620, +101, -161, +95, +165, +308, -117, +224, +453, +233, +340, +124, -276, -83, -284, -652, + +5690, +4114, -370, +5337, +2959, -1597, -302, +540, -969, -272, +1211, -1020, -123, +962, -388, -419, +496, +293, -68, +198, +277, +243, -1, +258, +446, +244, +316, +224, -197, -287, -538, -753, + +4886, +3783, -77, +4739, +3009, -1004, -171, +567, -808, -296, +1071, -732, -150, +762, -143, -243, +583, +495, +70, +295, +285, +282, +109, +300, +419, +303, +318, -41, -410, -429, -543, -696, + +4226, +3500, +214, +4230, +2888, -619, +78, +571, -807, -209, +1096, -674, -362, +872, +202, -45, +765, +519, +142, +420, +299, +326, +177, +298, +271, +19, +43, -216, -432, -470, -647, -770, + +3932, +3487, +332, +3583, +2646, -337, +285, +627, -784, -249, +992, -484, -225, +1185, +515, -8, +833, +683, +354, +372, +256, +357, +26, -114, -52, -13, -48, -275, -631, -669, -560, -678, + +3417, +3033, +572, +3583, +2497, -132, +512, +448, -821, -41, +1094, -215, +63, +1208, +613, +421, +1026, +661, +269, +268, +157, -77, -316, -230, -50, -15, -270, -450, -631, -506, -489, -682, + +3181, +2995, +715, +3281, +2345, -67, +347, +573, -324, +109, +1136, +26, +360, +1541, +983, +492, +841, +521, -21, -138, -249, -144, -314, -277, -62, -239, -335, -379, -509, -456, -497, -624, + +2727, +2772, +1072, +2985, +1995, +392, +618, +698, +14, +104, +1230, +616, +773, +1489, +881, +385, +451, -79, -396, -153, -251, -293, -476, -335, -58, -202, -314, -426, -485, -422, -544, -580, + +2494, +2557, +1043, +2809, +2364, +870, +612, +794, +496, +543, +1308, +960, +905, +1098, +463, -159, -22, -97, -245, -365, -543, -373, -259, -109, -161, -351, -340, -303, -434, -540, -495, -424, + +2244, +2930, +1654, +2496, +2296, +1063, +990, +1335, +682, +721, +1328, +513, +346, +642, +45, -321, -153, -280, -469, -425, -401, -290, -203, -148, -250, -401, -344, -391, -436, -433, -426, -380, + +2037, +3030, +1906, +2584, +3062, +1893, +990, +1134, +771, +385, +555, +134, +140, +441, -13, -448, -353, -397, -487, -345, -327, -238, -229, -306, -339, -347, -307, -358, -440, -470, -365, -304, + +2260, +3620, +2531, +2997, +2841, +1693, +1371, +1050, +54, -313, +437, +310, -186, +172, -15, -693, -347, -145, -477, -380, -271, -292, -232, -289, -368, -327, -359, -335, -337, -420, -362, -300, + +2676, +4646, +3139, +2421, +2169, +1461, +1102, +750, +196, +85, +103, -264, -85, +79, -270, -444, -278, -319, -366, -267, -356, -287, -310, -325, -320, -352, -353, -348, -336, -368, -283, -304, + +2949, +4690, +2841, +1992, +1689, +1410, +1437, +860, +277, +660, +273, -352, -345, -179, +121, -193, -595, -313, -69, -302, -301, -297, -388, -283, -359, -329, -293, -304, -317, -316, -248, -264, + +2663, +4197, +2446, +1659, +1599, +1195, +1150, +1390, +834, +702, +922, +74, -262, -12, -178, -353, -146, -141, -372, -189, -146, -406, -452, -309, -320, -299, -251, -248, -234, -286, -278, -279, + +2398, +3447, +2003, +1730, +1358, +984, +1031, +668, +683, +1466, +1326, +833, +547, +62, +124, -145, -512, -263, -44, -260, -496, -309, -241, -380, -321, -210, -197, -195, -288, -327, -348, -283, + +1987, +2518, +1256, +1700, +1770, +1374, +486, -161, +666, +1239, +1117, +1441, +1412, +1138, +952, +102, -154, -108, -471, -390, -130, -296, -423, -224, -149, -219, -273, -144, -187, -306, -316, -312, + +2277, +2839, +857, +1089, +1531, +1252, +447, -170, +485, +946, +625, +786, +1274, +1596, +1572, +803, +425, +213, -154, -308, -514, -316, -104, -287, -376, -112, -81, -229, -298, -346, -243, -269, + +2475, +3091, +1057, +1202, +1523, +1181, +155, -419, +779, +1083, +35, +243, +607, +800, +1330, +1039, +902, +962, +366, -99, -203, -378, -433, -305, -177, -196, -314, -134, -130, -427, -342, -186, + +2867, +3436, +954, +1406, +1896, +1116, -228, -668, +1005, +1052, -200, +160, +322, +441, +627, +249, +723, +1109, +691, +570, +250, -239, -146, -317, -437, -152, -136, -255, -367, -288, -235, -306, + +3223, +4037, +1059, +1327, +1971, +1123, -496, -724, +1262, +822, -504, +196, +267, +346, +542, -168, +79, +604, +516, +608, +511, +379, +188, -138, -157, -106, -291, -239, -240, -438, -390, -237, + +3604, +4513, +1093, +1460, +2232, +986, -1011, -692, +1601, +582, -689, +154, +137, +264, +549, -231, -112, +308, -5, +126, +288, +386, +454, +334, +190, +65, -9, -169, -440, -448, -309, -360, + +4214, +5204, +1001, +1333, +2363, +811, -1317, -468, +1657, +218, -774, +195, +54, +193, +477, -310, -143, +220, -205, -91, -167, -47, +273, +245, +485, +588, +199, -41, -178, -454, -469, -319, + +4699, +5772, +1037, +1391, +2580, +571, -1811, -137, +1930, -248, -876, +278, -102, +158, +529, -367, -232, +173, -250, -176, -332, -250, -145, -125, +369, +578, +501, +334, -24, -230, -185, -365, + +5288, +6343, +926, +1516, +2837, +116, -2274, +403, +2022, -767, -921, +321, -140, +29, +469, -385, -290, +151, -299, -257, -451, -381, -272, -339, +52, +314, +302, +289, +305, +49, -70, -194, + +5726, +6820, +1096, +1667, +3026, -179, -2850, +907, +2339, -1355, -1017, +450, -163, -66, +415, -378, -412, +166, -245, -345, -541, -415, -353, -452, -62, +81, +100, +97, +117, +54, +153, +24, + +6153, +7423, +1241, +1705, +3192, -342, -3363, +1287, +2593, -1875, -1019, +557, -240, -122, +319, -290, -434, +2, -201, -386, -582, -375, -458, -561, -160, +6, +81, -90, -141, -171, +10, +136, + +6828, +8181, +890, +1848, +3361, -805, -3382, +1527, +2488, -2165, -973, +617, -316, -246, +308, -188, -549, -125, -176, -412, -641, -381, -560, -633, -100, -94, -15, -180, -313, -244, -131, -157, + +7339, +8745, +841, +2086, +3460, -1152, -3508, +1614, +2597, -2420, -1103, +713, -354, -350, +308, -133, -681, -241, -127, -375, -784, -526, -527, -641, -141, -117, -177, -223, -325, -365, -249, -300, + +7574, +9152, +1067, +2490, +3582, -1504, -3603, +1572, +2713, -2475, -1389, +742, -241, -424, +146, -29, -689, -412, -49, -482, -922, -508, -528, -656, -326, -236, +0, -242, -494, -465, -250, -363, + +7771, +9477, +1527, +2680, +3445, -1316, -3581, +1119, +2776, -2355, -1714, +883, -172, -648, +99, -15, -445, -536, -388, -395, -960, -596, -496, -760, -479, -221, +19, -221, -514, -524, -422, -579, + +8021, +9527, +2130, +2911, +3042, -704, -3474, +429, +2652, -2057, -1809, +694, -37, -769, -100, +184, -247, -761, -609, -325, -1000, -680, -746, -736, -332, -408, -31, -128, -468, -729, -608, -586, + +8404, +9096, +2503, +3785, +2807, -578, -3480, +263, +2211, -1959, -1522, +174, -65, -508, -392, +128, +9, -898, -776, -193, -1245, -945, -832, -687, -337, -524, -93, -26, -595, -926, -547, -887, + +8807, +8295, +2417, +5558, +3298, -1393, -3611, +1274, +1418, -2498, -541, -286, -448, +137, -733, -107, +472, -919, -800, -132, -1516, -1020, -876, -819, -258, -573, -75, -222, -470, -870, -816, -827, + +9721, +7750, +1320, +7320, +3992, -2723, -3178, +2422, -20, -3129, +726, -465, -1243, +477, -680, -418, +820, -960, -919, -87, -1553, -1159, -1230, -839, -90, -743, -335, -154, -533, -893, -664, -1012, + +10870, +7707, -280, +8285, +5199, -3799, -2870, +3710, -1420, -4018, +2054, -220, -2214, +514, -188, -855, +1016, -762, -1123, +24, -1500, -1380, -1443, -763, -169, -955, -493, -100, -557, -806, -616, -1159, + +11833, +8327, -2134, +8341, +6953, -4401, -2931, +5077, -2393, -5396, +3185, +626, -3054, -50, +496, -988, +898, -338, -1369, +122, -1461, -1366, -1542, -1049, -218, -1029, -640, -181, -361, -866, -501, -1048, + +12829, +9031, -3811, +7670, +8588, -4509, -3175, +6408, -3118, -7036, +3841, +1817, -3527, -1043, +839, -699, +618, +2, -1465, -51, -1246, -1421, -1712, -1253, -467, -1107, -577, -354, -342, -807, -350, -891, + +14193, +9389, -5197, +6872, +9549, -4273, -3139, +7727, -3898, -8441, +3999, +3031, -3444, -2122, +727, -197, +556, +113, -1327, -318, -1040, -1564, -1813, -1380, -747, -1085, -601, -339, -469, -645, -199, -888, + +15661, +9657, -6466, +6233, +9751, -3871, -2723, +8959, -4623, -9557, +3687, +4006, -2825, -3063, +218, +188, +872, +40, -1085, -476, -1213, -1459, -1966, -1538, -758, -1196, -697, -106, -518, -710, -84, -846, + +17612, +9338, -7642, +6082, +9245, -3958, -1634, +10145, -5734, -10179, +3233, +4461, -2053, -3596, -499, +236, +1471, -53, -824, -783, -1511, -1205, -2322, -1376, -936, -1374, -531, +50, -558, -860, -125, -756, + +19463, +9219, -8893, +6261, +8413, -4281, -363, +11374, -6530, -10787, +2801, +4644, -1342, -3682, -1194, -39, +2157, +139, -767, -1072, -1682, -1101, -2364, -1296, -1186, -1329, -395, +235, -591, -1146, -127, -554, + +21650, +9391, -10922, +6081, +8229, -4220, +202, +11812, -6628, -11097, +2478, +4559, -1182, -3433, -1549, -554, +2784, +461, -1205, -1027, -1704, -1258, -2251, -1431, -1146, -1205, -447, +400, -669, -1391, -60, -370, + +23618, +9863, -13021, +6004, +8047, -4224, +416, +12157, -6101, -11654, +2261, +4560, -1406, -3057, -1488, -1343, +3208, +953, -1820, -705, -1697, -1485, -2065, -1531, -1035, -1118, -452, +413, -760, -1496, +104, -350, + +25507, +10091, -14633, +6037, +7728, -4437, +358, +12536, -5172, -12313, +2012, +4630, -1785, -2622, -1212, -2223, +3337, +1463, -2227, -360, -1728, -1658, -1788, -1625, -1024, -963, -484, +363, -873, -1530, +387, -597, + +26627, +10861, -15853, +5976, +7293, -4687, -371, +13070, -3740, -13126, +1550, +4641, -1970, -2334, -931, -3002, +3015, +1972, -2297, -262, -1622, -1706, -1631, -1718, -1043, -847, -523, +200, -913, -1491, +419, -863, + +27529, +11441, -16338, +5805, +6853, -5062, -1537, +13789, -2342, -13609, +1025, +4352, -1778, -2113, -836, -3461, +2445, +2244, -1905, -447, -1343, -1486, -1806, -1634, -1063, -761, -595, -38, -809, -1509, +121, -852, + +28224, +11700, -16026, +5571, +6480, -5603, -2945, +14554, -1154, -13550, +445, +3703, -1208, -1832, -1081, -3648, +1918, +2132, -1094, -755, -1071, -949, -2221, -1385, -1073, -728, -775, -144, -846, -1640, -17, -888, + +28214, +12317, -15132, +5336, +6093, -6385, -4398, +15063, +169, -13141, -349, +2865, -289, -1493, -1675, -3631, +1627, +1567, -67, -871, -1083, -137, -2567, -1204, -1005, -901, -818, -487, -1098, -1321, -264, -1047, + +27674, +13198, -13952, +5049, +5725, -7019, -5818, +14656, +1734, -12326, -1241, +1915, +642, -1155, -2395, -3373, +1425, +664, +785, -409, -1488, +642, -2474, -1372, -798, -1009, -1376, -899, -968, -1199, -318, -1143, + +26652, +14012, -12267, +5200, +5059, -7687, -7096, +13622, +3659, -11441, -2232, +1136, +1363, -745, -2920, -3117, +1275, -215, +1173, +578, -1926, +1018, -1813, -1727, -552, -1508, -1936, -882, -1218, -880, -117, -1274, + +25476, +14976, -10645, +5041, +4465, -7268, -8563, +11373, +5951, -10470, -2967, +695, +1268, -121, -2916, -3040, +1232, -1049, +1136, +1691, -1847, +783, -939, -1782, -1189, -1393, -2259, -1210, -1263, -527, +246, -1345, + +24418, +15887, -9483, +5106, +3650, -6572, -9308, +8066, +7947, -9122, -3698, +546, +799, +234, -2298, -3040, +979, -1401, +660, +2460, -1414, +581, -594, -1924, -1571, -1185, -2342, -1526, -1293, -276, +512, -1388, + +23795, +16122, -8471, +5677, +2738, -6335, -9272, +4879, +8930, -7283, -4533, +587, +584, -12, -1140, -3045, +596, -1168, -297, +2828, -664, +171, -697, -1636, -1755, -862, -2122, -1839, -1085, -590, +469, -1065, + +23181, +16390, -7741, +6442, +2203, -6740, -8434, +1898, +8933, -4752, -5617, +579, +1155, -849, +75, -2508, -62, -548, -1446, +2589, +243, -427, -620, -1078, -1599, -627, -1538, -1798, -1522, -1117, +586, -608, + +22030, +16813, -6552, +6365, +1905, -6491, -7923, -1054, +8742, -2377, -6611, +561, +1892, -1729, +1053, -1623, -1078, +90, -2143, +1121, +1073, -290, -801, -281, -1302, -213, -1096, -1925, -1798, -1686, +156, -224, + +21251, +16564, -5227, +6101, +1298, -5618, -7958, -3289, +8275, -752, -6864, +468, +2279, -1970, +1851, -1720, -1502, +720, -2997, -87, +1066, +346, -609, +374, -840, -207, -612, -1924, -1832, -2459, -669, -2, + +21059, +15707, -4300, +6487, +399, -4731, -7511, -5182, +7533, +993, -7053, +282, +3472, -2462, +1927, -1518, -1924, +1110, -3285, -499, +296, +615, +989, +279, -802, +498, -387, -1895, -1824, -2715, -1623, -344, + +21308, +14470, -4242, +7387, -252, -4583, -6956, -6093, +6238, +2376, -6555, -258, +4580, -2860, +1045, -858, -2358, +1013, -2617, -1140, +487, +118, +1239, +1477, -1144, +905, +15, -2196, -1670, -2549, -2403, -914, + +21749, +13551, -6010, +9423, +237, -6449, -5831, -5696, +4659, +3069, -5379, -988, +5203, -3101, -229, +148, -2474, +413, -1565, -777, +245, -263, +270, +2911, -521, +46, +1169, -2577, -2021, -1583, -2762, -1790, + +22949, +11670, -8631, +12918, +409, -9740, -4092, -3756, +2385, +3036, -3324, -2593, +5421, -2472, -2044, +991, -1723, -438, -884, +258, -444, -546, -80, +2348, +873, +112, +640, -1839, -2303, -1429, -2266, -2374, + +23912, +9195, -9740, +15651, -753, -10898, -2348, -2548, +736, +2645, -1865, -3420, +5193, -2092, -2914, +1332, -608, -827, -805, +690, -265, -735, -758, +2026, +1239, +685, +402, -1265, -2108, -2026, -1548, -2057, + +24116, +7253, -10354, +17453, -1244, -12053, -838, -452, -1755, +1608, +585, -4398, +4021, -759, -3062, +841, +208, -518, -792, +316, -185, -122, -1534, +1707, +1529, +201, +1161, -889, -2381, -1596, -1536, -1868, + +22899, +6009, -9723, +18156, -1387, -12297, +387, +197, -3319, +1403, +1627, -5089, +3452, +505, -3305, +713, +563, -709, -310, -26, -425, +286, -1418, +1157, +1256, +363, +1114, -493, -2226, -1184, -1308, -2261, + +20564, +5546, -8226, +17550, -828, -11490, +294, +435, -3523, +690, +1926, -4747, +2908, +1152, -2973, +467, +625, -707, -390, +101, -449, +40, -906, +959, +763, +546, +863, -551, -1476, -956, -1217, -2071, + +18013, +5812, -6919, +15896, +403, -10591, +67, +717, -3782, +91, +2336, -4162, +2130, +1919, -2779, -103, +1086, -691, -833, +297, -250, -202, -650, +1014, +731, +166, +703, -484, -1293, -477, -1156, -1837, + +15954, +7279, -4696, +11257, -415, -7760, +15, -732, -924, +300, -779, -1111, +2316, +31, -1667, -359, +362, -476, -1406, +77, +201, +160, +31, +184, +33, +618, +402, -142, -19, -131, -351, -177, + +13494, +6705, -2870, +10505, -334, -6612, +28, -1001, -670, +405, -783, -1035, +2308, +178, -1639, -390, +219, -411, -1192, +78, +48, +72, +135, +215, +200, +619, +296, -179, +63, -49, -474, -174, + +11237, +6344, -1097, +9098, -68, -4982, -506, -1321, -184, +563, -966, -831, +2204, +226, -1398, -487, +210, -400, -1067, +109, +7, -13, +137, +290, +364, +506, +81, -34, +85, -87, -211, -95, + +9435, +6226, -171, +7621, +609, -3889, -842, -1290, +79, +593, -877, -638, +1778, +372, -1115, -612, +133, -304, -919, +84, +28, -9, +49, +403, +518, +117, +63, +315, +9, -189, +148, +127, + +8281, +6134, -52, +6557, +1253, -3449, -792, -804, +3, +410, -398, -491, +1170, +585, -801, -816, +97, -92, -760, -8, +125, +10, +14, +591, +350, +20, +334, +355, -11, +73, +387, +50, + +7625, +5926, -212, +5732, +1440, -2973, -409, -538, -153, +402, +53, -528, +814, +714, -773, -751, +187, -25, -685, +71, +194, -126, +301, +656, +141, +177, +495, +460, +123, +277, +255, -206, + +6929, +5539, -213, +5156, +1489, -2470, -128, -421, -216, +512, +263, -626, +604, +666, -598, -609, +135, +2, -569, +170, +101, +124, +603, +290, +211, +558, +624, +396, +73, +189, -68, -300, + +6185, +4980, +12, +4844, +1476, -2007, +5, -218, -48, +475, +186, -579, +652, +583, -532, -454, +163, -44, -351, +323, +185, +454, +519, +323, +554, +596, +513, +149, -59, +27, -156, -301, + +5578, +4710, +139, +4160, +1511, -1429, +247, -167, -134, +535, +301, -478, +484, +512, -357, -355, +143, +139, +9, +323, +460, +774, +454, +456, +460, +265, +311, +29, -141, -56, -157, -425, + +4834, +4247, +381, +3890, +1667, -1077, +239, -52, +64, +515, +186, -374, +470, +446, -204, -178, +260, +402, +264, +582, +786, +717, +277, +144, +133, +174, +219, +36, -212, -220, -241, -491, + +4111, +3866, +739, +3569, +1573, -633, +462, -99, +98, +570, +132, -353, +509, +570, +1, -45, +535, +857, +514, +702, +653, +127, -67, +94, +33, +142, +132, -176, -297, -218, -361, -612, + +3730, +3751, +749, +2995, +1740, -73, +398, -128, +157, +562, +322, -106, +526, +653, +398, +535, +911, +896, +331, +268, +196, +17, -50, +13, -44, +14, +4, -239, -323, -300, -491, -605, + +2892, +3209, +1362, +3059, +1608, +182, +476, -76, +432, +661, +242, +160, +1034, +1084, +626, +638, +748, +381, -9, +164, +81, +56, -148, -220, -132, -95, -61, -252, -388, -412, -527, -492, + +2752, +3422, +1354, +2301, +1710, +560, +500, +0, +522, +1109, +816, +680, +1165, +1033, +440, -19, +152, +356, +205, +72, -219, -249, -230, -203, -210, -180, -256, -370, -297, -417, -460, -470, + +2213, +3015, +1710, +2495, +1858, +590, +641, +619, +1215, +1482, +1045, +756, +541, +266, +10, +87, +388, +325, -149, -273, -65, -313, -465, -315, -243, -222, -297, -239, -314, -374, -410, -472, + +2378, +3632, +1949, +1796, +1538, +1419, +1931, +1407, +1042, +906, +324, -55, +57, +281, +416, +73, -141, +104, -125, -338, -346, -567, -456, -178, -236, -293, -193, -168, -347, -459, -409, -412, + +2533, +3615, +2312, +2871, +2388, +1873, +1924, +743, -6, +118, +67, +58, +149, +131, +262, -115, -211, -1, -357, -465, -469, -597, -378, -114, -162, -284, -237, -201, -345, -426, -423, -455, + +2942, +4615, +3780, +3595, +1951, +1001, +577, -3, -9, +178, +100, -150, -79, +35, +232, -191, -343, -241, -527, -515, -469, -366, -285, -260, -253, -164, -168, -307, -405, -445, -401, -430, + +3532, +6354, +4764, +2112, +192, +502, +1060, +740, -280, -481, -6, +64, -3, -232, +35, -123, -425, -424, -500, -331, -403, -411, -380, -233, -195, -219, -156, -328, -390, -471, -421, -332, + +3754, +6378, +3302, +1176, +770, +1524, +1808, +405, -520, -9, +89, -401, +38, -134, -211, -179, -439, -279, -348, -439, -354, -411, -499, -252, -186, -273, -220, -306, -347, -364, -422, -391, + +2291, +3472, +1957, +1996, +2277, +2297, +2104, +987, +507, +706, +356, -152, -298, -91, -5, -385, -390, -196, -226, -195, -416, -447, -287, -389, -410, -244, -292, -350, -178, -230, -400, -417, + +1819, +2518, +1138, +1323, +2016, +2067, +1584, +1227, +1540, +1527, +1077, +599, +319, +222, -133, -344, -224, -354, -392, -98, -287, -313, -172, -348, -336, -273, -365, -452, -322, -244, -281, -244, + +1991, +2736, +1265, +1355, +1696, +1270, +711, +599, +1244, +1618, +1273, +1004, +935, +768, +344, -110, -219, -251, -264, -319, -400, -274, -131, -258, -317, -231, -396, -403, -299, -400, -335, -208, + +2251, +2968, +994, +1270, +1801, +1182, +278, +85, +960, +1169, +719, +996, +1351, +1194, +875, +354, +176, -35, -282, -178, -385, -406, -153, -263, -175, -84, -340, -346, -297, -435, -353, -295, + +2479, +3474, +1165, +1200, +1738, +845, +57, +328, +1004, +611, +199, +546, +759, +1002, +1149, +732, +519, +336, +110, +42, -306, -317, -221, -391, -190, -72, -254, -255, -285, -409, -356, -289, + +2648, +3711, +1310, +1382, +2036, +687, -508, +326, +1209, +455, +69, +381, +353, +462, +570, +467, +723, +755, +406, +258, +135, -71, -226, -267, -244, -225, -239, -248, -226, -295, -370, -333, + +2964, +4131, +1490, +1331, +2035, +615, -807, +460, +1251, +53, -30, +484, +328, +176, +292, +67, +31, +459, +630, +520, +346, +231, +64, -123, -179, -163, -253, -368, -325, -244, -286, -364, + +3240, +4589, +1670, +1277, +2158, +577, -1140, +581, +1323, -227, -122, +553, +290, +100, +235, -70, -152, +21, +69, +287, +434, +552, +333, +96, +114, -5, -177, -258, -330, -382, -258, -309, + +3730, +5196, +1638, +1123, +2168, +499, -1274, +755, +1209, -628, -139, +668, +292, -40, +122, -92, -234, -100, -101, -83, -135, +285, +479, +374, +279, +151, +85, -119, -293, -348, -282, -381, + +4119, +5684, +1732, +1126, +2228, +300, -1467, +1077, +1204, -1061, -263, +742, +305, -24, +37, -204, -274, -137, -131, -189, -340, -114, +44, +178, +404, +348, +234, +110, -83, -267, -257, -291, + +4622, +6186, +1693, +1242, +2320, -46, -1538, +1517, +1127, -1483, -304, +841, +294, -67, +5, -203, -308, -200, -102, -217, -386, -222, -141, -99, +23, +201, +346, +265, +65, -52, -11, -200, + +5193, +6638, +1553, +1499, +2388, -594, -1569, +2013, +985, -1862, -401, +847, +342, -127, -49, -265, -391, -279, -24, -258, -446, -237, -373, -107, -35, -174, -57, +100, +163, +130, +55, -58, + +5824, +7125, +1374, +1701, +2443, -1077, -1576, +2426, +806, -2127, -438, +769, +324, -176, +41, -326, -603, -328, -5, -213, -487, -284, -470, -142, -47, -263, -242, -262, -124, +12, +120, +33, + +6335, +7628, +1408, +1800, +2526, -1396, -1736, +2894, +798, -2493, -400, +738, +274, -165, +15, -222, -694, -482, +72, -261, -572, -116, -475, -277, -17, -291, -261, -317, -412, -297, -56, +28, + +6761, +8075, +1459, +2066, +2609, -1964, -1828, +3359, +727, -2782, -456, +715, +208, -232, -18, -148, -747, -627, +81, -302, -698, -121, -406, -325, -107, -219, -294, -466, -521, -391, -176, -288, + +7157, +8606, +1581, +2068, +2784, -2202, -2039, +3602, +767, -2899, -542, +707, +104, -260, -9, -128, -676, -844, +64, -130, -840, -253, -381, -284, -107, -233, -282, -564, -568, -421, -261, -447, + +7410, +9322, +1838, +1630, +3033, -1959, -2478, +3478, +916, -2764, -738, +578, +126, -372, +30, -107, -667, -935, -60, -32, -777, -452, -481, -148, -144, -362, -257, -530, -598, -498, -436, -437, + +7600, +9757, +2318, +1422, +3068, -1530, -2951, +3205, +1134, -2618, -848, +362, +153, -421, -49, -52, -609, -1028, -173, +13, -822, -437, -527, -269, -108, -428, -361, -411, -698, -654, -354, -475, + +8104, +9762, +2543, +1907, +2993, -1492, -3123, +3108, +1007, -2376, -799, +85, +225, -462, -207, +76, -422, -1156, -330, +104, -791, -492, -526, -345, -141, -393, -383, -537, -744, -705, -190, -505, + +8909, +9413, +2318, +2985, +3009, -1948, -3050, +3168, +425, -2046, -543, -270, +167, -483, -337, +79, -154, -1299, -550, +186, -643, -695, -585, -287, -262, -358, -406, -740, -843, -531, -265, -573, + +9426, +9025, +2181, +4009, +3640, -2472, -3407, +3777, -384, -2061, +272, -562, -296, -282, -348, -201, +397, -1463, -821, +375, -577, -753, -723, -199, -322, -387, -483, -747, -845, -590, -326, -571, + +10108, +8385, +1400, +6014, +4224, -3846, -2895, +4634, -1924, -2185, +1409, -691, -736, -445, -160, -496, +690, -1211, -1255, +419, -429, -745, -766, -201, -456, -411, -561, -544, -937, -907, -160, -739, + +10943, +8373, +46, +7110, +5244, -4697, -2467, +5334, -3432, -2574, +2681, -670, -1220, -664, +155, -796, +596, -633, -1639, +276, -169, -751, -786, -162, -512, -556, -561, -560, -872, -1006, -393, -823, + +12145, +8720, -1664, +7093, +6723, -4974, -2355, +5841, -4655, -3092, +3716, -397, -1752, -903, +493, -914, +75, -59, -1625, -196, +169, -746, -800, +30, -700, -607, -584, -846, -650, -980, -876, -718, + +13449, +9173, -3433, +6797, +7856, -4807, -2042, +6051, -5634, -3740, +4384, +233, -2242, -1265, +790, -884, -471, +114, -1201, -709, +233, -517, -817, +265, -855, -714, -702, -983, -688, -985, -936, -805, + +14554, +9843, -4692, +5589, +8876, -3969, -1993, +6452, -6471, -4465, +4658, +1064, -2464, -1808, +1040, -734, -892, -140, -587, -969, -47, -87, -824, +496, -902, -929, -759, -1132, -899, -928, -701, -988, + +15499, +10690, -5588, +4019, +9370, -2825, -1817, +6925, -7237, -5143, +4618, +1819, -2391, -2377, +1112, -527, -1082, -687, -144, -864, -451, +270, -610, +501, -919, -981, -876, -1386, -1039, -897, -490, -928, + +17184, +10743, -6654, +3458, +8941, -2496, -296, +6958, -8428, -5131, +4435, +2201, -2279, -2678, +1041, -465, -1059, -1191, -112, -563, -633, +396, -146, +255, -999, -772, -1178, -1541, -1165, -955, -285, -586, + +18439, +11433, -7884, +3086, +8223, -2330, +1154, +7363, -9381, -5433, +4476, +2299, -2058, -2772, +772, -429, -922, -1487, -412, -319, -459, +489, +179, +4, -920, -666, -1378, -1593, -1381, -989, -70, -199, + +20043, +11571, -8926, +2927, +7480, -2933, +2814, +7900, -10432, -5634, +4629, +2163, -2083, -2501, +322, -605, -660, -1666, -795, -420, +2, +773, +28, -86, -714, -788, -1426, -1661, -1631, -934, -18, +154, + +21100, +12438, -9991, +2658, +6924, -3598, +3640, +9112, -11048, -6263, +4923, +1936, -2083, -2127, -90, -1004, -241, -1755, -1109, -655, +353, +1477, -496, -26, -322, -1103, -1235, -1773, -1804, -950, -17, +340, + +22220, +13016, -10684, +2238, +6616, -4544, +3961, +10464, -11476, -6710, +4989, +1692, -2097, -1740, -471, -1509, +171, -1891, -1172, -1008, +446, +2361, -1007, -80, +206, -1448, -1059, -1719, -2148, -946, -187, +379, + +23160, +13514, -10970, +1648, +6564, -5582, +3717, +11856, -11585, -6851, +4668, +1415, -1888, -1527, -831, -1885, +423, -2020, -993, -1361, +246, +3145, -1090, -388, +815, -1543, -1101, -1488, -2586, -1060, -470, +329, + +23984, +13865, -11140, +1506, +6153, -6455, +3221, +12728, -11274, -6683, +4149, +879, -1350, -1515, -1321, -1966, +480, -2107, -735, -1620, -134, +3538, -695, -707, +1213, -1214, -1434, -1269, -3012, -1293, -736, +72, + +24782, +14120, -11236, +1961, +5253, -7111, +2788, +12880, -10420, -6360, +3471, +290, -601, -1551, -1881, -1800, +635, -2271, -409, -1692, -623, +3484, +102, -645, +1121, -484, -1860, -1402, -3095, -1550, -1113, -154, + +24478, +15178, -10478, +1270, +5126, -7637, +1416, +13108, -9038, -6194, +2475, -43, +4, -1635, -2240, -1773, +998, -2517, -301, -1320, -1403, +2910, +1377, -319, +543, +368, -2377, -1572, -2886, -2071, -1188, -610, + +23336, +16618, -8704, -223, +5298, -7565, -968, +13263, -6982, -6465, +1742, -449, +352, -1376, -2596, -1623, +1240, -2651, -286, -899, -1898, +1936, +2438, +528, -375, +750, -2161, -1941, -2664, -2274, -1304, -958, + +22712, +17229, -7217, -356, +4386, -7099, -2807, +12389, -4621, -6839, +1425, -975, +424, -777, -2826, -1526, +1422, -2734, -246, -516, -2068, +1271, +2387, +1470, -861, +696, -1581, -2206, -2447, -2243, -1214, -1282, + +22892, +17053, -6909, +1550, +2504, -7309, -2981, +10387, -2761, -6478, +847, -1462, +747, -527, -2541, -1653, +1330, -2326, -581, +131, -2018, +687, +1356, +2090, -263, +54, -772, -2199, -2423, -1678, -1280, -1950, + +22958, +16963, -6994, +3862, +804, -8094, -2421, +7964, -1267, -5599, -222, -1546, +1312, -701, -1892, -1941, +925, -1306, -1223, +805, -1822, -507, +577, +2232, +644, +10, -622, -1590, -2129, -1759, -1313, -2053, + +22795, +16811, -6665, +5414, -231, -8963, -2057, +5715, -140, -4502, -1495, -1224, +1967, -1203, -1238, -1944, +128, +141, -1762, +375, -1151, -1442, -293, +2236, +1381, +482, -421, -1050, -2081, -1865, -1013, -2075, + +22156, +16822, -5737, +5914, -531, -9248, -2574, +3914, +921, -3656, -2319, -843, +2476, -1480, -1050, -1438, -455, +614, -1691, -640, -770, -1051, -1218, +1623, +1962, +1863, -702, -1229, -1009, -2137, -1191, -1810, + +21420, +16785, -4799, +6154, -663, -9035, -3372, +2102, +2124, -2833, -3110, -133, +2641, -1601, -638, -1248, -923, +605, -1675, -1249, -658, -53, -1902, +1335, +2038, +2064, +272, -1486, -537, -2097, -1156, -1644, + +21361, +15629, -3750, +6528, -1323, -8215, -4323, +464, +3132, -1840, -3943, +437, +3186, -1861, -582, -1384, -980, +77, -1818, -753, -1149, +490, -779, +520, +1069, +2103, +1599, -1602, -997, -1118, -1205, -1803, + +20330, +15116, -2198, +6125, -1778, -6323, -6028, -1388, +5002, -1330, -4769, +1469, +3125, -2056, -350, -2178, -854, +367, -2722, -22, -540, -99, +456, +351, -11, +1824, +1553, -531, -893, -1195, -631, -1855, + +20062, +13940, -1073, +5901, -2918, -4148, -6485, -3763, +6395, -76, -5571, +1976, +3170, -2469, -500, -2482, -418, +183, -3077, +751, +150, -824, +890, +1089, -685, +923, +962, +419, -69, -1542, -261, -1391, + +21165, +12566, -2644, +7196, -3419, -4374, -5591, -3941, +6004, +491, -4989, +1625, +3132, -2899, -840, -2060, -308, +352, -2926, +725, +461, -401, +854, +946, -597, +286, +687, +245, +522, -714, -834, -655, + +22181, +10753, -4743, +9694, -3820, -6164, -3751, -3237, +4762, +962, -4786, +856, +3566, -3082, -1668, -1292, +74, +282, -2679, +317, +654, +206, +432, +672, -272, -199, +427, +115, +322, +278, -897, -731, + +21833, +9209, -6007, +12315, -3453, -8356, -2210, -1380, +3074, +222, -3684, +199, +3572, -2831, -2010, -495, +19, -33, -2094, +470, +147, +334, +628, +538, -358, +45, -17, -272, +825, +112, -396, -410, + +21222, +7854, -6428, +13904, -3314, -9841, -311, -717, +1107, +600, -2989, -732, +3598, -2074, -2105, -29, +34, -558, -1422, +552, -367, +238, +799, +488, -473, +119, +72, -314, +618, +130, -262, -1, + +19959, +7458, -6254, +13163, -2749, -8575, +168, -1541, +524, +795, -2410, -1167, +3370, -1359, -1981, +131, -37, -600, -1272, +322, -134, +241, +366, +572, -360, -40, +508, -76, -11, +77, -84, -39, + +18263, +7315, -5697, +12058, -1512, -7911, -155, -1097, -277, +440, -1476, -1163, +2794, -682, -1653, -226, +195, -447, -1525, +167, +243, +191, +5, +420, -166, +267, +536, -17, -141, -216, +13, -120, + +14574, +8295, -838, +5767, -2715, -2520, -1691, -1773, +1779, -38, -2463, +993, +2121, -1350, -803, -1187, +196, -325, -1656, +367, -300, -397, +308, +424, +622, +1154, -257, -779, -260, -661, -212, +363, + +12640, +8177, -514, +5232, -1427, -2829, -1332, -1356, +968, +94, -1951, +761, +1867, -950, -840, -1080, +224, -469, -1525, +376, -426, -453, +483, +403, +530, +830, -326, -345, -235, -760, -56, +349, + +11044, +7881, -148, +5139, -839, -2943, -771, -1231, +563, +131, -1472, +726, +1552, -637, -706, -854, +77, -516, -1176, +229, -479, -289, +444, +438, +558, +439, -291, +63, -149, -710, +13, +439, + +9448, +7315, +777, +4791, -766, -2291, -640, -1240, +566, +79, -1184, +670, +1401, -496, -584, -601, -102, -472, -972, +95, -341, -227, +329, +485, +481, +177, -40, +272, -35, -470, -18, +555, + +7784, +6813, +1919, +4053, -580, -1299, -807, -1308, +740, +180, -1143, +616, +1306, -404, -321, -523, -263, -345, -754, -11, -288, -134, +224, +482, +339, +206, +285, +426, +140, -377, +51, +463, + +6153, +6246, +2936, +3514, -265, -522, -963, -1330, +954, +278, -1137, +468, +1183, -27, -199, -727, -188, -39, -737, -145, -161, -167, +296, +467, +191, +475, +664, +574, +50, -370, +118, +236, + +5216, +5838, +3133, +3059, +1, -157, -756, -1165, +778, +326, -848, +372, +928, +178, -109, -801, -20, +104, -796, -199, -47, -58, +362, +449, +343, +811, +845, +385, -220, -311, +33, +113, + +4597, +5368, +3150, +2849, +47, +176, -392, -1164, +650, +523, -570, +155, +748, +467, -67, -777, +130, +87, -748, -20, -18, +143, +685, +510, +516, +926, +646, +76, -295, -314, +101, +201, + +4160, +4800, +2975, +2878, +215, +185, -346, -879, +720, +434, -577, +142, +805, +500, -153, -718, +261, +104, -689, +154, +246, +528, +763, +288, +509, +781, +225, -155, -161, -171, -27, -42, + +4047, +4610, +2554, +2523, +343, +309, -161, -677, +639, +395, -412, +331, +729, +219, -6, -351, +190, +142, -205, +534, +514, +540, +360, +158, +449, +446, +134, -82, -194, -248, -36, -79, + +3681, +4202, +2459, +2522, +468, +335, -124, -483, +720, +451, -371, +292, +718, +292, +137, -143, +474, +547, +124, +441, +403, +249, +3, +182, +383, +387, +48, -193, -191, -244, -51, -202, + +3418, +3958, +2332, +2406, +561, +275, -16, -147, +764, +316, -330, +555, +677, +300, +712, +391, +554, +506, -31, +195, +200, -92, +90, +358, +160, +198, -1, -186, -221, -248, -146, -268, + +3294, +3885, +2237, +2055, +440, +495, +330, -195, +594, +558, -92, +562, +1070, +915, +915, +255, +158, +177, -224, +85, +144, -90, +60, +179, +169, +71, -152, -244, -264, -222, -259, -374, + +3036, +3530, +2299, +2284, +540, +283, +250, +363, +785, +420, +481, +1288, +1245, +678, +546, -172, -123, +52, -133, +151, -76, -120, +87, +168, +37, -127, -184, -303, -217, -273, -383, -412, + +2951, +3684, +2445, +1884, +210, +635, +675, +547, +1250, +1227, +765, +965, +798, +86, +80, -228, +0, +39, -228, +30, -27, -42, +25, +53, -221, -186, -201, -304, -216, -403, -409, -382, + +2948, +3672, +2453, +1863, +191, +765, +1578, +1710, +1229, +774, +415, +256, +396, -103, +36, -65, -268, -80, -64, -3, -34, -116, -164, -71, -281, -296, -229, -301, -271, -378, -434, -341, + +2843, +3566, +2452, +2150, +1119, +1466, +1682, +1795, +928, -254, -261, +372, +403, -274, -165, -161, -184, -111, -88, -48, -200, -201, -180, -289, -413, -275, -295, -256, -268, -441, -348, -288, + +2564, +4101, +3460, +2647, +1410, +1412, +1574, +983, +11, +28, -27, +71, +225, -244, +4, -163, -265, +10, -151, -168, -99, -187, -352, -372, -357, -210, -195, -232, -258, -356, -289, -290, + +3244, +5969, +3950, +1503, +762, +1387, +767, +390, +603, -90, -364, -54, +452, -41, -367, -79, -184, -274, -111, -48, -196, -322, -399, -360, -258, -194, -183, -224, -289, -330, -316, -345, + +3784, +6054, +3526, +1790, +389, +352, +1278, +1092, -88, -197, +260, -59, +139, +65, -157, -256, -333, -279, -121, -80, -211, -244, -442, -312, -216, -247, -254, -250, -268, -326, -359, -335, + +2822, +5085, +3846, +2069, +435, +648, +1401, +1023, +236, -6, +341, +350, +172, -40, +34, -202, -361, -272, -304, -204, -29, -187, -395, -181, -217, -302, -314, -303, -311, -325, -288, -335, + +2707, +4855, +2989, +1364, +947, +1039, +1087, +968, +768, +256, +227, +682, +564, +111, +39, -39, -213, -415, -274, -193, -240, -136, -135, -139, -171, -174, -321, -402, -386, -337, -287, -323, + +2574, +4549, +2481, +1104, +1330, +907, +475, +1038, +988, +424, +619, +680, +540, +614, +433, -71, -59, -64, -397, -356, -134, -141, -286, +11, +52, -193, -195, -312, -434, -438, -356, -279, + +2422, +4172, +2328, +1283, +1472, +647, +125, +1006, +879, +224, +547, +905, +832, +557, +435, +418, +214, -78, -116, -201, -318, -253, -140, -84, -96, +29, -87, -310, -305, -394, -495, -381, + +2457, +4168, +2312, +1258, +1473, +568, -47, +1024, +903, -67, +189, +852, +771, +615, +723, +347, +177, +387, +190, -226, -97, -8, -307, -173, +62, -42, -182, -125, -211, -363, -347, -400, + +2479, +4135, +2339, +1562, +1610, +192, -248, +1300, +909, -337, +81, +690, +508, +388, +636, +433, +219, +291, +303, +164, +7, +21, +31, -36, -110, -67, -84, -238, -296, -215, -282, -331, + +2624, +4417, +2420, +1461, +1611, +190, -334, +1254, +921, -411, -37, +569, +431, +277, +366, +238, +20, +196, +411, +163, +23, +266, +197, +88, +161, +35, -197, -291, -298, -316, -320, -247, + +2857, +4661, +2448, +1599, +1644, -52, -369, +1426, +846, -542, -64, +578, +333, +106, +438, +207, -300, -149, +268, +191, +20, +247, +302, +342, +299, +211, +96, -235, -456, -375, -272, -328, + +3188, +5067, +2423, +1526, +1665, -114, -379, +1420, +746, -615, -22, +514, +244, +36, +349, +284, -291, -398, -114, +35, -95, +71, +386, +395, +370, +407, +245, -45, -298, -398, -392, -348, + +3392, +5464, +2575, +1426, +1705, -141, -510, +1546, +697, -819, -14, +541, +205, -81, +197, +362, -172, -517, -262, -166, -340, -129, +171, +384, +434, +397, +374, +107, -152, -237, -310, -366, + +3778, +5985, +2547, +1224, +1789, -132, -599, +1611, +647, -931, +4, +483, +130, -67, +79, +336, -105, -481, -339, -274, -374, -355, -90, +280, +364, +297, +401, +185, -84, -89, -184, -264, + +4238, +6510, +2468, +1077, +1860, -270, -600, +1756, +466, -1066, +75, +520, -27, -200, +61, +302, -74, -470, -390, -308, -412, -437, -214, +90, +251, +154, +227, +157, -56, -78, -125, -116, + +4791, +7085, +2292, +969, +1933, -473, -530, +1936, +231, -1156, +164, +537, -117, -309, +2, +238, -84, -390, -352, -407, -462, -398, -204, -73, +172, +87, +45, +57, -238, -129, -20, -64, + +5298, +7657, +2183, +875, +2016, -753, -494, +2218, -13, -1312, +267, +578, -182, -441, -93, +196, -122, -393, -302, -435, -513, -440, -113, -135, -14, +190, -70, -156, -337, -293, -128, -66, + +5772, +8287, +2120, +701, +2131, -1043, -540, +2502, -218, -1459, +344, +564, -207, -513, -279, +141, -129, -411, -314, -481, -509, -495, -83, -55, -189, +147, -1, -322, -411, -420, -358, -159, + +6156, +8940, +2162, +466, +2269, -1223, -655, +2753, -350, -1564, +441, +587, -308, -513, -366, -30, -129, -409, -289, -486, -560, -558, -73, +140, -206, -105, +70, -261, -507, -464, -575, -293, + +6742, +9493, +2028, +426, +2287, -1512, -626, +2857, -609, -1493, +499, +542, -410, -555, -338, -271, -242, -367, -235, -522, -637, -614, -88, +199, -77, -219, -130, -145, -572, -543, -605, -493, + +7455, +9892, +1817, +673, +2165, -1782, -526, +2877, -874, -1369, +613, +482, -471, -664, -187, -495, -430, -293, -210, -463, -712, -671, -39, +162, -43, -26, -317, -285, -509, -579, -619, -592, + +8019, +10193, +1826, +947, +2060, -1895, -616, +2838, -973, -1270, +603, +513, -417, -884, -78, -555, -646, -328, -167, -385, -659, -776, -74, +250, -111, +117, -295, -476, -508, -590, -658, -581, + +8488, +10358, +1977, +1265, +2015, -1887, -920, +2788, -1005, -1210, +617, +441, -268, -1020, -166, -487, -785, -574, -79, -286, -605, -796, -270, +464, -155, +23, -164, -502, -600, -692, -661, -560, + +9032, +10338, +2002, +1761, +2191, -2067, -1283, +2872, -1174, -1205, +746, +309, -249, -938, -329, -531, -744, -897, -123, -86, -627, -738, -388, +469, +0, -188, -125, -361, -727, -819, -607, -613, + +9864, +10088, +1523, +2776, +2578, -2733, -1373, +3075, -1563, -1189, +922, +251, -375, -786, -321, -773, -647, -1025, -380, +85, -536, -746, -274, +305, +98, -159, -216, -318, -746, -852, -593, -682, + +10598, +9701, +940, +4274, +3058, -3831, -1125, +3536, -2290, -1265, +1285, +276, -567, -754, -134, -923, -659, -1033, -713, +96, -164, -899, -154, +299, +14, +105, -391, -378, -574, -830, -773, -577, + +10878, +9347, +643, +5807, +3528, -5043, -576, +4279, -3492, -1535, +1951, +350, -873, -858, +153, -941, -755, -1006, -1030, -132, +274, -915, -234, +450, -136, +336, -408, -493, -454, -795, -947, -437, + +11510, +9866, -517, +5809, +4860, -5267, -967, +4693, -4147, -1854, +2440, +298, -1178, -888, +429, -1109, -918, -824, -1173, -606, +385, -531, -456, +537, -109, +345, -322, -566, -435, -822, -1034, -491, + +12635, +10354, -1762, +5073, +6221, -4898, -1391, +4717, -4535, -2049, +2756, +364, -1594, -867, +721, -1229, -1148, -678, -1099, -989, +154, -84, -438, +418, +119, +303, -273, -468, -478, -915, -1048, -631, + +13739, +10931, -3039, +4229, +7036, -3993, -1627, +4425, -4683, -2247, +2950, +515, -2020, -897, +930, -1302, -1368, -646, -958, -1207, -291, +233, -188, +154, +374, +357, -256, -270, -569, -1081, -1002, -747, + +14744, +11698, -4040, +3065, +7514, -2833, -1645, +3985, -4805, -2328, +2928, +769, -2368, -998, +1104, -1337, -1464, -742, -746, -1258, -738, +270, +219, -28, +461, +565, -183, -98, -674, -1208, -1015, -822, + +15661, +12563, -4797, +1712, +7684, -1798, -1303, +3560, -5128, -2181, +2756, +928, -2517, -1206, +1167, -1348, -1484, -913, -576, -1200, -996, -13, +556, +59, +345, +829, -12, -35, -778, -1229, -1099, -956, + +16364, +13610, -5417, +358, +7606, -1081, -694, +3363, -5713, -1853, +2574, +824, -2410, -1460, +1029, -1325, -1426, -1134, -452, -1081, -1063, -425, +647, +304, +234, +1059, +210, -50, -832, -1188, -1210, -1113, + +17301, +14490, -6249, -381, +7171, -884, +239, +3371, -6504, -1381, +2548, +400, -2128, -1591, +701, -1356, -1209, -1399, -313, -902, -1081, -684, +503, +524, +231, +1359, +398, -161, -776, -1179, -1300, -1239, + +19090, +14422, -7537, +119, +6088, -1186, +1568, +3110, -7218, -739, +2538, -295, -1756, -1656, +234, -1424, -1032, -1537, -233, -694, -1129, -779, +292, +571, +268, +1771, +559, -457, -623, -1262, -1420, -1267, + +20805, +14336, -8736, +920, +4704, -1494, +2649, +2925, -7561, -328, +2504, -973, -1224, -1901, -205, -1369, -1023, -1413, -248, -538, -1010, -940, +175, +531, +207, +2290, +770, -842, -494, -1328, -1610, -1150, + +22109, +14485, -9555, +1595, +3405, -1875, +3399, +2878, -7467, -159, +2320, -1375, -756, -2191, -602, -1235, -972, -1286, -262, -418, -788, -1088, +82, +594, -8, +2708, +1095, -1168, -535, -1285, -1751, -974, + +22911, +14859, -9889, +1889, +2263, -2415, +3753, +2933, -7127, -227, +1986, -1630, -415, -2450, -1051, -1037, -827, -1434, -165, -366, -647, -1068, -154, +882, -368, +2616, +1524, -1241, -905, -1145, -1703, -979, + +23245, +15363, -9604, +1856, +1322, -3040, +3776, +3098, -6633, -350, +1568, -1819, -103, -2618, -1435, -794, -655, -1757, +41, -318, -654, -746, -459, +1267, -738, +1911, +2006, -928, -1339, -994, -1484, -1026, + +23048, +16128, -8809, +1596, +486, -3594, +3405, +3364, -5994, -577, +1227, -2110, +338, -2650, -1697, -633, -515, -2058, +200, -158, -867, -14, -786, +1297, -792, +869, +2115, -163, -1403, -1180, -994, -927, + +22809, +16473, -7468, +1279, -304, -4094, +2691, +3769, -5530, -656, +858, -2440, +917, -2540, -1937, -596, -384, -2335, +377, -58, -950, +797, -1345, +1069, -434, -289, +1797, +898, -1234, -1327, -340, -1167, + +22287, +16759, -6019, +907, -957, -4847, +1807, +4137, -5333, -671, +434, -2757, +1592, -2484, -2177, -772, -331, -2403, +180, +397, -1148, +952, -1488, +457, +9, -900, +941, +1571, -432, -1370, -331, -1254, + +21687, +17120, -4653, +1201, -1531, -5605, +1233, +4224, -4907, -618, +334, -2824, +2339, -2255, -2444, -777, -345, -2119, +138, +690, -1476, +1035, -1282, -255, +720, -854, -197, +2118, +560, -1484, -235, -840, + +20812, +17571, -3517, +1604, -1925, -6559, +655, +3983, -4426, -559, +260, -2689, +2858, -2122, -2599, -1007, -244, -1381, -668, +771, -1403, +492, -756, -404, +502, +93, -695, +1167, +1322, -839, -247, -943, + +20139, +17539, -2371, +1932, -2101, -7422, -134, +3611, -3812, -412, +185, -2382, +3168, -1970, -3046, -567, -229, -1405, -1029, +419, -1307, +375, -467, -375, +380, +1214, -1001, -411, +2033, -274, -430, -799, + +19753, +17050, -1457, +2572, -2382, -8049, -965, +2983, -2716, -235, -326, -1321, +2916, -2171, -2296, -826, -571, -1104, -1712, +62, -637, +159, -684, +668, +232, +865, +69, -1322, +1025, +254, +67, -588, + +19313, +16611, -863, +3251, -2596, -8557, -2035, +2815, -1745, -84, -572, -839, +2943, -1918, -2229, -1014, -802, -1378, -1915, +318, -814, +322, -33, +499, +177, +995, +794, -1733, -313, +324, +698, -311, + +19432, +15373, -280, +4094, -3296, -8664, -2599, +2170, -225, -30, -1542, +594, +2691, -2281, -1544, -1686, -1307, -903, -1915, -153, -126, +698, -360, +340, +825, +1064, +273, -993, -998, -689, +1129, +142, + +19161, +14270, +164, +4902, -4023, -8420, -3080, +1712, +839, +173, -2097, +1066, +2771, -2396, -1584, -2406, -841, -783, -2457, +724, +24, +6, +115, +460, +603, +1331, -24, -638, -844, -1849, +898, +543, + +18185, +13294, +1396, +5056, -4975, -6537, -4217, +256, +3477, -142, -3597, +2330, +2565, -2744, -1485, -2544, -786, -568, -2073, +767, -278, -87, +712, +47, +286, +1855, +49, -975, -401, -2019, -110, +720, + +18313, +12559, +1145, +3915, -4788, -4611, -4800, -248, +4385, -385, -3737, +2444, +2059, -2542, -1236, -3085, -90, -60, -2227, +677, -342, +170, +590, -167, +444, +1928, +89, -943, -588, -1828, -345, +588, + +19047, +11703, -955, +4365, -4893, -3853, -3267, -1533, +4299, +134, -4009, +2112, +2030, -2635, -1305, -2227, -55, -224, -2038, +767, -148, -368, +345, +393, +586, +1413, +142, -763, -846, -1547, -218, +199, + +19014, +10464, -2335, +5732, -4481, -4151, -2526, -849, +3281, -472, -3208, +1847, +1902, -2824, -779, -1622, -183, -396, -1924, +1079, -378, -665, +394, +566, +672, +1279, -35, -701, -812, -1354, +31, +44, + +18162, +9492, -3044, +7090, -3964, -4906, -1033, -851, +1796, -66, -2783, +1424, +1900, -2369, -665, -1270, -198, -516, -1532, +747, -522, -404, +331, +314, +897, +1359, -338, -718, -601, -1136, +5, +342, + +16598, +8667, -2195, +6902, -3696, -3649, -980, -1771, +1921, -11, -2768, +1203, +2093, -1882, -722, -1121, -151, -296, -1570, +398, -363, -287, +171, +326, +918, +1214, -295, -849, -425, -762, -169, +362, + +14574, +8452, +258, +4430, -4365, -2407, +102, -220, -223, -832, -1852, +1615, +1202, -2022, +253, -1216, -444, -63, -1455, +368, -312, -727, +373, +217, -412, +849, +339, -186, +129, -916, -296, -195, + +12278, +8141, +1428, +3486, -3243, -1249, -493, -560, +165, -592, -1924, +1327, +1447, -1595, +92, -1011, -282, -108, -1214, +238, -313, -593, +289, +150, -236, +853, +317, -36, -85, -842, +19, -3, + +9818, +8134, +2487, +2440, -2082, -590, -823, -829, +309, -432, -1752, +1141, +1209, -1118, +27, -830, -297, -203, -900, +148, -415, -552, +316, +48, -77, +666, +249, +139, -158, -658, +206, +196, + +8218, +7700, +2637, +2474, -1307, -764, -546, -580, +192, -485, -1350, +993, +1042, -888, +8, -569, -372, -127, -680, -31, -355, -306, +131, -53, +119, +550, +383, +249, -130, -272, +357, +9, + +7260, +6952, +2528, +2729, -947, -957, -177, -207, -119, -455, -915, +762, +893, -798, +106, -330, -495, -95, -429, -94, -346, -203, -44, +24, +289, +567, +633, +250, -96, -40, +210, -228, + +6314, +6251, +2666, +2794, -629, -891, -34, +102, -183, -316, -716, +491, +887, -525, +110, -285, -414, +113, -262, -316, -185, -38, -118, +319, +459, +666, +731, +112, -104, -55, +52, -322, + +5417, +5613, +2827, +2816, -327, -838, +28, +455, -189, -286, -591, +343, +896, -378, +146, -174, -275, +223, -276, -286, +110, +144, +58, +429, +461, +747, +496, -173, -50, +14, -42, -390, + +4737, +5252, +2774, +2553, +28, -656, +97, +596, -174, -128, -477, +136, +904, -37, +86, -133, -68, +253, -71, +76, +414, +107, +44, +523, +339, +397, +292, -77, +23, -24, -184, -339, + +3981, +4689, +2974, +2705, +128, -673, +191, +862, -76, -188, -396, +170, +926, +95, +102, -7, +257, +567, +232, +227, +237, +46, +2, +205, +229, +329, +244, -63, +38, -31, -270, -262, + +3639, +4461, +2924, +2330, +166, -438, +386, +823, -29, -56, -316, +227, +932, +175, +339, +566, +570, +436, +183, +186, -95, -222, +17, +187, +153, +207, +145, +26, +72, -187, -282, -293, + +3259, +4171, +2982, +2255, +67, -366, +661, +923, -74, +111, -202, +162, +1330, +741, +513, +485, +402, +353, -62, -283, -157, +6, -120, +24, +146, +186, +148, -35, -33, -267, -322, -309, + +3122, +4118, +2900, +1944, +0, -98, +882, +1021, -181, +159, +515, +745, +1264, +473, +425, +351, -23, -30, -118, -265, -166, -97, -186, +192, +98, -114, +91, +11, -210, -322, -297, -412, + +3235, +4303, +2623, +1571, +77, +285, +881, +1185, +547, +613, +652, +402, +925, +370, -45, -8, +19, -59, -264, -364, +11, +81, -230, -1, -128, -117, +119, -34, -321, -411, -265, -385, + +3389, +4725, +2245, +1203, +58, +908, +2020, +1399, +334, +357, +538, +113, +387, +96, +39, -34, -209, -107, -173, -4, +62, -200, -339, -98, -124, -103, +123, -133, -427, -315, -196, -296, + +3432, +4882, +1947, +1109, +1266, +1747, +1687, +1007, +236, +86, +163, -84, +293, +0, -42, -68, -271, +122, +155, -210, -251, -156, -291, -288, -163, +38, -58, -180, -248, -250, -248, -317, + +3101, +4702, +2964, +1975, +929, +1541, +1764, +744, -57, -59, +188, -44, +87, -46, -2, +54, +100, +125, -120, -181, -166, -232, -402, -239, -149, -71, +43, -36, -164, -289, -356, -319, + +3896, +5904, +2447, +896, +1159, +1573, +1310, +595, -175, -62, +179, +2, +162, -166, +142, +495, +86, -291, -23, -10, -305, -361, -351, -199, -209, +43, +163, +6, -270, -382, -312, -377, + +4111, +6381, +2053, +273, +1154, +1396, +1209, +828, +5, -261, +331, +111, +75, +99, +333, +466, -15, -97, -25, -78, -294, -279, -352, -332, -105, +81, +175, -17, -195, -388, -359, -345, + +3095, +5772, +3360, +570, +281, +922, +1379, +1273, +83, -225, +436, +376, -8, +55, +499, +520, +210, -84, -45, +41, -164, -351, -289, -251, -244, +17, +144, +52, -153, -277, -319, -362, + +2581, +5083, +3747, +1205, +166, +554, +1050, +1250, +302, -212, +397, +598, +127, +67, +436, +383, +436, +172, +39, +53, -182, -180, -149, -287, -291, -5, +118, -12, -207, -177, -214, -333, + +2552, +4951, +3531, +1372, +349, +359, +972, +1271, +183, -443, +321, +679, +210, +58, +442, +429, +340, +218, +211, +180, -63, -124, -120, -161, -112, -103, +24, +72, -222, -300, -275, -209, + +2665, +4956, +3357, +1460, +482, +248, +879, +1296, +212, -508, +150, +505, +100, +12, +412, +341, +306, +406, +139, +62, +128, -3, -44, -39, -12, -31, +66, +41, -175, -338, -364, -294, + +2910, +5172, +3202, +1418, +526, +219, +908, +1323, +135, -544, +153, +494, +74, -268, +195, +282, +179, +422, +266, +64, +20, -95, +137, +155, -18, +190, +178, +50, -99, -282, -367, -378, + +3106, +5510, +3157, +1272, +654, +172, +826, +1393, +101, -594, +108, +460, +164, -335, -22, +133, -125, +219, +461, +52, -105, -110, +31, +176, +54, +285, +298, +145, +61, -223, -389, -316, + +3368, +5932, +3118, +1145, +758, +78, +765, +1468, +37, -717, +138, +457, +120, -290, -144, +62, -257, -129, +404, +63, -206, -153, -100, +152, +60, +155, +386, +264, +71, -31, -197, -377, + +3733, +6456, +3058, +942, +889, +25, +681, +1552, -15, -820, +148, +459, +69, -211, -190, -47, -265, -323, +274, +169, -372, -347, -72, +87, +21, +34, +374, +281, +11, +98, -68, -219, + +4188, +7066, +2967, +691, +995, -34, +635, +1651, -188, -887, +235, +437, -43, -227, -100, -139, -354, -381, +96, +266, -304, -584, -157, +39, -36, +7, +204, +218, +59, +6, -48, -108, + +4746, +7725, +2804, +457, +1072, -163, +664, +1759, -458, -963, +395, +430, -203, -287, -43, -200, -465, -426, -10, +200, -148, -659, -283, +63, -164, -51, +108, +49, +5, -21, -57, -176, + +5293, +8424, +2691, +200, +1075, -352, +722, +1883, -811, -1091, +593, +430, -407, -391, +9, -266, -633, -524, -73, +107, -103, -596, -428, +55, -134, -199, +69, -190, -167, +13, -143, -226, + +5863, +9141, +2667, +40, +1052, -543, +868, +2094, -1172, -1177, +878, +497, -546, -487, +104, -257, -732, -597, -153, +94, -40, -473, -388, -65, +22, -141, -52, -184, -372, -50, -90, -264, + +6256, +9830, +2894, -163, +970, -781, +879, +2372, -1514, -1408, +1131, +611, -714, -628, +124, -250, -817, -728, -318, +48, +3, -481, -237, -140, -63, +59, -165, -299, -349, -283, -158, -207, + +6594, +10538, +3188, -331, +878, -910, +803, +2530, -1667, -1658, +1306, +784, -813, -792, +152, -249, -880, -762, -546, -74, +192, -563, -200, +88, -247, +128, -7, -470, -416, -264, -343, -125, + +6837, +11211, +3624, -582, +873, -887, +585, +2486, -1630, -1804, +1272, +974, -837, -900, +104, -254, -971, -753, -648, -416, +302, -345, -395, +287, -167, -70, +229, -446, -659, -259, -391, -167, + +7304, +11778, +3694, -565, +932, -974, +429, +2281, -1610, -1825, +1167, +1061, -833, -962, +48, -273, -1134, -738, -667, -706, +131, -22, -389, +150, +154, -245, +198, -184, -827, -453, -344, -269, + +8235, +12147, +3165, -179, +1250, -1280, +244, +2247, -1802, -1646, +1035, +1095, -763, -1091, +127, -372, -1161, -866, -623, -801, -185, +121, -30, -44, +248, -32, -42, -16, -686, -726, -403, -227, + +9297, +12266, +2226, +787, +1787, -2113, +102, +2510, -2139, -1611, +994, +1052, -665, -1269, +199, -511, -1125, -991, -710, -778, -421, -49, +341, +106, +24, +220, -125, -69, -467, -801, -641, -218, + +10147, +12083, +1353, +2463, +2227, -3535, +293, +3115, -2724, -1863, +1270, +952, -736, -1330, +259, -696, -1131, -995, -849, -797, -533, -301, +461, +439, -103, +301, -72, -178, -379, -650, -774, -450, + +10811, +11594, +849, +4553, +2308, -5080, +959, +3783, -3596, -2129, +1832, +791, -1018, -1161, +326, -938, -1147, -869, -944, -907, -502, -461, +355, +652, +38, +401, -29, -244, -390, -373, -749, -645, + +12468, +11803, -955, +4782, +3329, -5109, +523, +3592, -3808, -2001, +2054, +456, -1328, -944, +309, -1271, -1148, -913, -864, -1037, -475, -486, +86, +849, +201, +318, +27, -164, -495, -300, -684, -554, + +14105, +12174, -2678, +4502, +4313, -4564, -152, +3309, -3818, -1885, +2202, +220, -1631, -822, +354, -1654, -1062, -1037, -689, -1076, -553, -275, -262, +847, +479, +306, -29, -31, -462, -290, -612, -344, + +15495, +12899, -4263, +3779, +5080, -3531, -900, +2885, -3629, -1828, +2258, +22, -1763, -951, +442, -1975, -1049, -1113, -557, -940, -769, +0, -446, +597, +677, +483, -199, +94, -302, -403, -398, -267, + +17119, +13318, -5617, +3044, +5263, -2373, -1299, +2236, -3473, -1545, +2114, -220, -1690, -1270, +432, -2146, -1156, -1068, -496, -761, -890, +68, -296, +183, +744, +728, -384, +229, -162, -523, -141, -307, + +18484, +13996, -6861, +2361, +5043, -1327, -1316, +1482, -3224, -1275, +1889, -488, -1425, -1754, +345, -2172, -1331, -893, -513, -608, -886, +7, -57, -56, +527, +1062, -513, +203, +21, -599, -22, -277, + +19664, +14808, -7930, +1852, +4472, -629, -944, +743, -2898, -1130, +1684, -714, -1190, -2160, +165, -2109, -1400, -723, -585, -442, -817, -87, +159, -22, +135, +1403, -577, -74, +264, -623, -30, -70, + +21117, +15043, -8651, +1665, +3562, -302, -433, +306, -2732, -998, +1479, -897, -1082, -2373, -85, -2001, -1270, -757, -612, -253, -784, -73, +231, +244, -130, +1411, -530, -488, +338, -544, +88, +69, + +22154, +15465, -8959, +1402, +2531, -346, +86, +155, -2719, -964, +1298, -1197, -837, -2538, -368, -1715, -1223, -911, -611, -54, -781, -33, +268, +653, -384, +1073, -318, -957, +90, -192, +241, +104, + +22859, +15907, -8818, +1234, +1297, -584, +637, +95, -2746, -892, +980, -1473, -344, -2665, -593, -1404, -1232, -1113, -586, +219, -920, +190, +386, +763, -501, +647, -217, -1200, -157, -60, +514, +428, + +23324, +16162, -8220, +1233, -271, -830, +1044, +4, -2761, -848, +545, -1644, +393, -2819, -805, -1116, -1381, -1232, -481, +245, -798, +446, +127, +832, -496, +109, -143, -1012, -512, -218, +1023, +636, + +23496, +16326, -7279, +1262, -1985, -1155, +1282, -135, -2863, -819, +135, -1617, +1191, -3031, -953, -1076, -1474, -1177, -641, +567, -852, +321, -9, +770, -595, -103, +21, -1077, -316, -427, +637, +1058, + +23095, +16685, -5961, +1382, -3468, -1694, +1418, -258, -2996, -670, +47, -1596, +2016, -3064, -1350, -839, -1582, -979, -545, +371, -989, +403, -350, +690, -257, -300, +78, -651, -207, -824, +183, +1360, + +23064, +16194, -4345, +1405, -4772, -2458, +1309, -309, -3246, -87, -265, -1329, +2641, -3203, -1669, -828, -1062, -1045, -1017, +329, -1074, +156, -379, +809, -266, -110, +348, -721, -327, -460, -318, +476, + +22166, +16307, -2720, +1513, -5503, -3602, +868, +57, -3167, +189, -262, -1102, +3165, -3419, -1892, +19, -1444, -1300, -1087, -50, -1052, +281, -440, +743, +297, +10, -121, -326, +62, -941, -205, -296, + +21370, +16040, -1198, +1538, -5866, -4987, +180, +1090, -3147, +120, +48, -770, +2709, -2688, -1726, -511, -1299, -1588, -1418, -44, -787, -13, -172, +1224, -173, +86, +190, -419, +152, -1134, +61, -580, + +20588, +15763, -447, +2263, -6362, -6502, +294, +1839, -3312, +732, -314, -780, +3610, -2936, -1826, -471, -1919, -1347, -1286, -339, -634, +489, -63, +635, +27, +550, -117, -722, +816, -1169, -430, +0, + +20517, +14351, +399, +2893, -7361, -6720, +201, +2186, -2610, +382, -514, +112, +3193, -2866, -1734, -1281, -1564, -810, -1919, -87, +325, -151, -301, +1086, -74, +249, +48, -598, +812, -904, -810, +141, + +19676, +13347, +1269, +2990, -7493, -6742, +83, +2235, -1954, +838, -1855, +980, +3383, -3609, -1607, -1296, -1241, -963, -1499, +306, -188, -169, +134, +680, -311, +474, +114, -498, +603, -657, -632, -512, + +18294, +12994, +1651, +2477, -6776, -5594, -1193, +2361, -74, -729, -2110, +2060, +2280, -3521, -925, -1755, -1040, +4, -1831, -24, +217, -146, -194, +523, -89, +412, +148, -368, +547, -585, -520, -748, + +18558, +12123, -346, +2881, -6362, -4645, -59, +1181, -164, -263, -2409, +2048, +1834, -3453, -616, -1525, -435, -206, -2101, +563, +264, -775, -79, +639, -65, +370, -42, -65, +678, -907, -609, -386, + +17685, +10480, -40, +3473, -6519, -2739, -508, +476, +794, -1230, -2572, +2593, +1476, -3576, +141, -1207, -497, -277, -1926, +798, -90, -892, +128, +624, -265, +467, +194, -122, +569, -901, -567, -322, + +16309, +9199, +186, +4082, -5385, -2804, -279, +710, -5, -1375, -2021, +2397, +953, -2773, +531, -1321, -456, -212, -1629, +612, -269, -841, +361, +372, -412, +797, +264, -230, +451, -838, -585, -226, + +15571, +11264, +2379, +478, -10208, -3446, +2999, +3275, -500, -1930, -3348, +266, +1652, -1984, +1186, -362, -580, +611, -665, +483, -71, -639, -236, -683, -414, +551, -551, -99, +973, -315, +229, -109, + +13108, +11000, +3186, +1280, -8696, -4695, +2112, +2705, +415, -824, -3163, -516, +1162, -1069, +990, -408, -449, +725, -557, +276, +252, -440, -211, -595, -598, +266, -697, +52, +1118, -108, +414, -97, + +11346, +10103, +3442, +1763, -7242, -4319, +1504, +1898, +542, -443, -2642, -793, +1114, -726, +553, -274, -403, +642, -397, +111, +268, -218, -281, -579, -486, +53, -591, +203, +993, +104, +363, -159, + +9333, +9181, +4026, +1891, -5737, -3665, +628, +1442, +686, -179, -2080, -924, +1011, -560, +271, -128, -344, +546, -210, +21, +313, -35, -349, -508, -402, +17, -265, +291, +786, +199, +233, -195, + +7824, +8565, +4450, +1794, -4594, -3174, +140, +1252, +671, +30, -1593, -927, +798, -461, +248, -40, -339, +534, -12, -10, +342, +33, -332, -281, -185, +20, -144, +273, +558, +171, +139, -239, + +6337, +7830, +4715, +1908, -3553, -2897, -163, +1081, +702, +211, -1249, -839, +616, -437, +196, +111, -267, +479, +135, +12, +326, +212, -47, -34, -177, -218, -105, +167, +266, +120, +84, -158, + +5342, +7158, +4878, +2188, -2903, -2714, -263, +1026, +804, +276, -973, -621, +425, -432, +323, +229, -177, +523, +156, +236, +666, +314, -37, +11, -270, -439, -68, +145, +155, +196, +77, -226, + +4764, +6717, +4705, +2043, -2555, -2349, -213, +866, +792, +353, -756, -574, +302, -362, +407, +259, -158, +679, +475, +400, +570, +170, -131, -157, -526, -408, +47, -28, +159, +57, -96, +32, + +4181, +6120, +4609, +2151, -2225, -2162, -181, +900, +848, +365, -518, -436, +242, -269, +393, +570, +370, +732, +393, +271, +373, -75, -324, -138, -536, -326, +93, -221, -12, +223, +50, -24, + +4015, +5982, +4273, +1823, -2038, -1791, +35, +933, +871, +389, -235, -337, +148, +75, +824, +806, +274, +455, +265, +150, +178, -130, -231, -188, -435, -270, -151, -8, +202, +32, -30, +38, + +3935, +5782, +3945, +1507, -1917, -1335, +323, +927, +964, +503, -86, -55, +602, +326, +626, +524, +61, +238, +130, +138, +142, -108, -297, -233, -424, -97, +144, -211, +2, +11, +59, +102, + +3902, +5745, +3557, +1311, -1656, -1075, +626, +1068, +893, +711, +517, +29, +271, +228, +356, +317, +28, +184, +167, +138, +52, -157, -344, -161, +13, -100, -239, -186, +14, +16, +22, +148, + +3628, +5656, +3399, +1258, -1213, -703, +858, +1220, +1301, +913, +184, -182, +3, -30, +266, +240, +91, +140, +96, +72, +8, -109, -120, +190, -242, -389, -174, -137, -134, -75, +225, -41, + +3635, +5627, +3156, +1153, -667, -305, +1152, +1542, +949, +463, +84, -274, -67, -129, +266, +232, +17, +66, +88, +199, -87, +174, +189, -310, -329, -218, -244, -286, -93, -9, -62, +33, + +3750, +5696, +2978, +1126, -254, +215, +1221, +1141, +606, +286, +8, -220, -48, -224, +233, +223, -143, +120, +323, +31, +156, +458, -282, -324, -203, -336, -370, -173, -80, -307, +26, +219, + +3708, +6007, +3252, +1084, -197, +131, +973, +976, +487, +259, +136, -370, -69, -106, +43, +210, -33, +247, +171, +273, +554, -86, -293, -37, -371, -530, -251, -143, -337, -184, +155, +321, + +3943, +6405, +3364, +855, -445, -300, +746, +1177, +555, +245, +158, -422, -186, -48, +127, +143, +129, +192, +83, +689, +384, -278, -109, -102, -392, -521, -225, -363, -322, +86, +221, +118, + +3963, +6788, +3553, +597, -677, -627, +588, +1136, +500, +391, +206, -514, -153, +22, +70, +197, +285, -39, +123, +985, +227, -286, +1, -155, -441, -352, -267, -542, -311, +209, +364, -112, + +3772, +6899, +3947, +501, -937, -727, +636, +1168, +340, +109, +160, -312, -140, -4, +244, +180, +122, +45, +73, +884, +451, -250, -58, -111, -413, -290, -294, -523, -289, +122, +331, -74, + +3462, +6882, +4502, +695, -1202, -904, +656, +1374, +518, -169, -142, -383, -288, +151, +492, +188, +134, +104, -153, +774, +761, -195, -124, +19, -277, -262, -247, -438, -285, +127, +319, -81, + +3402, +6922, +4775, +801, -1378, -1083, +663, +1537, +602, -245, -249, -453, -540, -124, +493, +404, +124, +134, -71, +426, +838, +18, -287, -73, -153, -110, -193, -451, -296, +175, +269, -23, + +3560, +7157, +4846, +842, -1601, -1246, +801, +1630, +679, -335, -317, -376, -611, -299, +272, +320, +96, +184, +134, +295, +750, +284, -376, -324, -110, -14, -46, -352, -273, +168, +253, +68, + +3781, +7518, +5064, +780, -1878, -1426, +861, +1887, +678, -490, -323, -360, -585, -337, +124, +225, -92, -87, +272, +304, +648, +580, -207, -590, -353, -33, +88, -214, -276, +256, +259, +93, + +4023, +8013, +5260, +520, -2126, -1537, +904, +2110, +621, -684, -367, -338, -545, -334, +31, +151, -90, -326, +98, +316, +484, +602, +136, -551, -624, -186, +88, -177, -281, +258, +226, +119, + +4437, +8672, +5470, +189, -2426, -1777, +1004, +2534, +471, -984, -417, -281, -536, -313, +40, +69, -119, -424, -33, +239, +301, +445, +325, -371, -639, -347, -13, -119, -335, +161, +141, +68, + +4952, +9349, +5539, -179, -2758, -2011, +1219, +2888, +279, -1276, -463, -211, -592, -300, +102, -4, -169, -480, -76, +194, +168, +301, +339, -242, -691, -395, -6, -107, -357, +112, +26, -204, + +5239, +10282, +5947, -647, -3196, -2226, +1311, +3315, +161, -1681, -491, -173, -597, -373, +170, -45, -294, -440, -175, +126, +127, +78, +331, -124, -648, -478, -149, -83, -176, +24, -84, -362, + +5839, +11149, +6005, -1123, -3665, -2327, +1613, +3627, -71, -2065, -429, -99, -639, -410, +251, -61, -421, -436, -166, +117, +55, -75, +317, -59, -558, -473, -198, -174, -157, +173, -146, -406, + +6264, +12031, +6260, -1503, -4165, -2511, +1902, +3881, -220, -2443, -428, +51, -706, -495, +320, -9, -559, -492, -144, +113, +44, -260, +228, +46, -480, -381, -268, -203, -217, +218, -114, -429, + +6813, +12945, +6569, -1945, -4848, -2783, +2188, +4127, -523, -2951, -443, +204, -809, -654, +274, +56, -695, -599, -243, +84, +37, -469, +12, +64, -398, -293, -252, -328, -254, +98, -55, -527, + +7209, +13717, +6921, -1967, -5316, -3090, +2544, +4308, -606, -3304, -485, +501, -832, -729, +300, +116, -725, -556, -280, +71, +96, -513, -156, +86, -225, -237, -54, -372, -184, +51, -70, -428, + +7996, +14426, +6885, -1822, -5825, -3511, +3030, +4353, -912, -3620, -593, +764, -830, -921, +358, +119, -837, -534, -312, +44, +63, -481, -430, -53, +49, -227, +88, -308, -219, +114, -168, -425, + +8882, +15071, +6412, -1835, -5966, -3673, +3408, +4119, -1227, -3662, -763, +899, -746, -1111, +359, +151, -942, -516, -330, +17, -16, -403, -535, -393, +280, -94, +75, -119, -291, +140, -109, -538, + +10567, +15752, +4909, -1935, -5684, -3567, +3668, +3636, -1744, -3453, -930, +847, -522, -1336, +279, +135, -969, -534, -297, -7, -169, -364, -497, -748, +299, +223, -60, +142, -209, -44, +74, -643, + +11943, +15859, +3693, -1168, -5342, -4152, +3859, +3672, -2239, -3456, -946, +824, -414, -1484, +211, +82, -987, -499, -174, -100, -272, -362, -415, -898, +70, +599, -127, +237, +12, -204, +166, -634, + +13286, +15772, +2438, -128, -4984, -4823, +4009, +3750, -2786, -3502, -799, +696, -411, -1556, +156, -56, -1055, -395, +29, -275, -377, -305, -450, -921, -205, +832, -22, +179, +243, -241, +88, -561, + +15203, +16245, +66, +61, -3930, -4645, +3668, +3392, -3154, -3516, -581, +453, -338, -1692, +34, -193, -1068, -347, +256, -295, -574, -274, -592, -759, -402, +757, +277, +182, +289, -131, -87, -538, + +17246, +16423, -2122, -11, -3063, -3961, +3236, +2949, -3315, -3590, -360, +310, -300, -1854, +21, -379, -1001, -238, +408, -257, -762, -185, -742, -584, -408, +586, +464, +330, +189, -58, -105, -673, + +19117, +17194, -4525, -594, -2040, -2928, +2541, +2436, -3174, -3955, -153, +154, -238, -2084, -35, -538, -893, -103, +477, -124, -1066, -60, -862, -458, -281, +408, +389, +584, +66, -198, +49, -844, + +20721, +17777, -6299, -1368, -1442, -1849, +1965, +2056, -2976, -4357, -43, +20, -202, -2215, -94, -626, -745, -20, +462, +11, -1311, +50, -912, -421, -24, +317, +54, +773, +39, -439, +197, -803, + +22510, +18390, -7885, -2507, -1141, -610, +1490, +1800, -2821, -4825, -36, -196, -92, -2264, -98, -656, -568, +0, +406, +174, -1496, +186, -1014, -271, +276, +136, -341, +713, +119, -602, +263, -543, + +23764, +19077, -8920, -3523, -1276, +188, +1429, +1689, -2771, -5201, -193, -427, +128, -2191, -88, -582, -532, -60, +345, +366, -1555, +193, -996, -85, +266, +23, -631, +431, +299, -553, +232, -344, + +24818, +19733, -9528, -4328, -1918, +770, +1688, +1610, -2757, -5522, -511, -645, +585, -2065, -55, -440, -631, -162, +378, +612, -1616, +251, -901, -119, +151, -32, -905, +195, +543, -403, +171, -190, + +25942, +20257, -9828, -5006, -3337, +1229, +2251, +1491, -2816, -5884, -1016, -737, +1357, -2026, +75, -408, -894, -120, +477, +717, -1428, +314, -1223, -176, -2, -219, -932, +91, +634, -169, +260, -194, + +26806, +20370, -9612, -5429, -4920, +1516, +2696, +1428, -3018, -6052, -1361, -633, +1984, -1981, +130, -617, -894, -5, +427, +963, -1258, -100, -1423, -216, -233, -165, -732, -55, +587, +188, +254, -445, + +27209, +20584, -8793, -5848, -6861, +1389, +3245, +1326, -3300, -5756, -1708, -571, +2761, -2008, -124, -572, -811, +83, +640, +854, -1485, -319, -1727, -286, -130, -52, -610, -82, +598, +192, +317, -394, + +26893, +21151, -7832, -5916, -8592, +716, +3831, +1043, -3056, -5275, -2081, -436, +3209, -2095, -313, -337, -686, +446, +148, +578, -1361, -677, -1772, -79, -85, -62, -326, -96, +288, +256, +729, -628, + +26953, +20650, -6193, -5839, -10706, -128, +4025, +1350, -2673, -4655, -2334, -397, +3476, -2270, -280, +333, -640, -63, -135, +292, -1261, -713, -1609, +24, -62, +134, -367, -195, +342, +253, +839, -600, + +26223, +20702, -4716, -5564, -12304, -1451, +4411, +2099, -2421, -4083, -2432, -598, +3439, -2035, +238, +317, -1138, -105, -496, +286, -908, -750, -1436, +173, -78, -80, -177, -33, +173, +164, +1062, -575, + +25928, +19969, -3485, -5141, -13936, -2549, +5094, +2717, -2372, -3260, -2726, -1115, +3984, -1704, +8, +193, -1565, -173, -413, +254, -689, -651, -1111, -74, -302, +129, -24, -206, +176, +212, +1048, -582, + +25176, +19122, -2331, -4479, -15530, -3096, +5493, +3261, -1783, -2862, -3340, -611, +4094, -2064, +150, -498, -1520, +306, -690, +346, -212, -559, -1329, -185, -92, +42, -36, -161, +240, +170, +921, -542, + +24482, +17970, -1385, -4296, -15673, -3520, +5482, +4107, -1928, -2384, -3245, -840, +4078, -2209, -307, -382, -1158, +232, -617, +670, -229, -809, -1085, -111, -314, +49, +102, -188, +256, +76, +933, -522, + +23018, +16730, -558, -3503, -15157, -4048, +5380, +4222, -1077, -2064, -4052, -288, +3518, -2565, -42, -296, -1035, +526, -341, +255, -181, -591, -933, -333, -446, +264, +149, -398, +317, +312, +625, -550, + +21612, +15388, -80, -2338, -14307, -4401, +4806, +4911, -877, -2366, -3925, -404, +3244, -2585, +155, -320, -674, +881, -905, +291, +164, -706, -883, -428, -426, +443, -108, -467, +714, +169, +330, -367, + +19859, +13489, +594, -510, -13595, -4524, +5021, +4279, -755, -2023, -4414, +179, +2843, -2732, +498, -73, -330, +471, -963, +610, +149, -898, -638, -432, -427, +380, -223, -282, +814, +29, +168, -248, + +17742, +12321, +1537, +213, -12421, -3676, +4012, +3612, -294, -2291, -3920, +331, +2249, -2515, +892, +37, -643, +510, -767, +581, +11, -855, -358, -539, -531, +491, -270, -331, +960, -123, +115, -173, + +16821, +11926, +463, -1706, -11380, -169, +5057, +1524, -1492, -1439, -2644, -359, +2193, -2391, +635, +125, -644, +317, -422, +472, -172, -610, -637, -211, -252, -7, -26, -80, -218, -217, +829, -147, + +13656, +11995, +3238, -883, -11164, -2746, +3338, +2611, +688, -1041, -2888, -1083, +1213, -1539, +1161, +189, -818, +634, -355, +123, +274, -342, -515, +152, -873, -436, -4, -321, +327, +309, +783, -46, + +11207, +10925, +3942, -83, -8816, -2936, +2399, +2271, +597, -709, -2174, -1110, +823, -992, +937, +143, -694, +584, -237, +52, +375, -217, -303, +162, -792, -361, +105, -252, +214, +381, +632, -19, + +9243, +9941, +4245, +657, -6939, -2976, +1760, +1792, +578, -304, -1653, -1098, +643, -655, +689, +159, -542, +528, -131, +56, +430, -13, -221, +210, -469, -319, +52, -319, +110, +335, +494, +43, + +7775, +9004, +4364, +1074, -5566, -2771, +1288, +1356, +632, -19, -1266, -996, +487, -456, +486, +214, -418, +456, -8, +91, +463, +193, -8, +266, -378, -438, -88, -360, -112, +272, +544, +30, + +6749, +8329, +4226, +1199, -4454, -2378, +954, +1109, +723, +141, -897, -819, +428, -339, +428, +308, -281, +463, +96, +331, +672, +327, +10, +166, -357, -510, -211, -393, -151, +319, +576, +31, + +5988, +7653, +4116, +1168, -3765, -2038, +743, +915, +737, +259, -623, -668, +285, -262, +442, +295, -206, +564, +342, +402, +543, +169, -105, +70, -443, -594, -251, -433, -272, +334, +502, -77, + +5467, +7250, +3847, +1019, -3110, -1692, +669, +871, +822, +369, -365, -484, +245, -133, +474, +473, +20, +567, +337, +288, +369, +117, -150, +13, -324, -594, -356, -414, -226, +271, +602, +138, + +5122, +6973, +3542, +803, -2565, -1389, +713, +947, +893, +463, -170, -291, +235, +82, +633, +446, -49, +345, +308, +240, +201, +133, -77, -9, -324, -573, -352, -476, -45, +494, +363, +16, + +4855, +6836, +3247, +531, -2098, -1103, +840, +1094, +882, +577, -75, -121, +401, +26, +454, +321, -151, +130, +276, +269, +118, +152, -61, -115, -199, -507, -538, -83, +76, +24, +184, +126, + +4686, +6807, +3020, +381, -1698, -797, +985, +1300, +880, +654, +193, -260, +327, -18, +295, +312, -217, +5, +244, +427, +89, +60, +69, +22, -305, -328, -97, -385, -172, +69, +91, +154, + +4632, +6769, +2880, +360, -1379, -630, +1032, +1346, +1008, +601, +155, -416, +54, +91, +208, +254, -266, -94, +300, +314, +94, +118, +154, -112, -59, +83, -557, -570, -137, +42, +28, +65, + +4540, +6825, +2991, +442, -1145, -666, +903, +1315, +922, +656, +103, -490, -32, -70, +234, +239, -193, -130, +219, +288, +5, +292, +9, +89, +428, -439, -684, -356, -314, -42, +168, -24, + +4565, +7043, +3133, +398, -1092, -628, +698, +1105, +781, +505, +302, -393, -208, -57, +80, +210, -27, -27, +131, +97, +164, +95, +10, +715, +96, -727, -439, -390, -341, +7, +168, -278, + +4628, +7376, +3330, +175, -1131, -632, +658, +1096, +468, +306, +276, -396, -10, -64, +41, +226, -104, +83, +212, +65, +61, -40, +256, +815, -181, -624, -368, -423, -196, +109, -11, -411, + +4617, +7799, +3588, -63, -1282, -806, +761, +1267, +342, +103, +9, -566, -109, +89, +288, +207, -102, +37, +103, +149, +142, -173, +222, +878, -329, -612, -244, -446, -47, +197, -164, -416, + +4660, +8175, +3965, -277, -1581, -952, +885, +1487, +358, +16, -136, -742, -411, +6, +351, +359, +99, +41, +67, +54, +185, -145, +158, +875, -393, -637, -194, -414, +89, +273, -162, -421, + +4721, +8663, +4296, -438, -1910, -1208, +1075, +1666, +396, -64, -205, -776, -575, -199, +234, +288, +60, +190, +260, +39, +105, -43, -107, +796, -78, -840, -343, -310, +149, +286, -89, -348, + +4872, +9194, +4729, -774, -2386, -1225, +1197, +1899, +429, -345, -152, -738, -728, -229, +85, +167, -114, +11, +383, +94, +153, +194, -391, +530, +269, -869, -518, -280, +55, +314, -13, -367, + +5066, +9823, +5271, -1107, -2955, -1313, +1335, +2152, +396, -624, -133, -598, -828, -241, +24, +42, -162, -203, +299, +184, -39, +336, -145, +68, +454, -442, -819, -503, +69, +300, -63, -319, + +5153, +10511, +6095, -1484, -3588, -1456, +1423, +2504, +356, -975, -219, -396, -876, -284, +78, -92, -239, -325, +171, +296, -163, +80, +60, -117, +343, +144, -711, -771, -136, +164, +7, -305, + +5279, +11273, +7005, -1898, -4346, -1576, +1570, +2874, +319, -1413, -325, -192, -896, -360, +145, -111, -363, -399, +61, +261, +19, -193, -117, -56, -9, +423, -34, -872, -482, +162, -138, -388, + +6056, +12428, +7017, -2743, -5015, -1595, +2092, +3133, -74, -1835, -369, -82, -887, -433, +159, -124, -505, -444, +1, +176, +57, -207, -371, -191, -116, +297, +399, -455, -738, -65, -85, -546, + +6550, +13417, +7566, -3351, -5854, -1576, +2466, +3359, -262, -2321, -480, +199, -992, -483, +233, -211, -561, -459, -82, +172, +17, -196, -387, -532, -129, +223, +460, +107, -612, -458, -73, -511, + +7012, +14309, +8271, -3829, -6828, -1561, +2860, +3523, -456, -2805, -697, +575, -1040, -702, +326, -213, -692, -488, -58, +49, +67, -318, -318, -681, -441, +323, +421, +317, -109, -624, -463, -340, + +8016, +15374, +8120, -4423, -7514, -1497, +3500, +3557, -967, -3143, -754, +778, -1014, -873, +371, -263, -697, -565, +8, +40, -65, -294, -389, -676, -607, +208, +557, +311, +173, -239, -863, -535, + +8871, +16239, +8063, -4588, -8132, -1638, +4115, +3491, -1344, -3391, -963, +994, -922, -1121, +393, -248, -762, -536, +34, +55, -184, -324, -431, -662, -593, -42, +629, +427, +134, +214, -755, -1041, + +9741, +17020, +7674, -4576, -8426, -2000, +4611, +3393, -1757, -3551, -1213, +1115, -851, -1378, +299, -217, -824, -499, +46, +51, -282, -489, -415, -741, -447, -171, +355, +641, +79, +272, -284, -1349, + +11312, +17790, +6362, -4799, -8173, -2096, +4973, +3237, -2301, -3658, -1190, +1112, -886, -1482, +185, -250, -754, -451, +117, +102, -439, -579, -427, -793, -304, +10, -28, +635, +235, +100, +114, -1241, + +13177, +18485, +4498, -4942, -7590, -1947, +5032, +3048, -2673, -3843, -991, +968, -867, -1596, +107, -286, -639, -361, +165, +232, -672, -529, -499, -772, -195, +286, -298, +389, +407, -34, +287, -927, + +15061, +19221, +2298, -5197, -6823, -1696, +4782, +2846, -2873, -4171, -778, +660, -800, -1706, -5, -268, -588, -254, +120, +358, -929, -400, -614, -747, -72, +413, -441, -8, +458, -76, +301, -594, + +17417, +19661, -218, -5533, -6027, -1097, +4358, +2666, -3090, -4449, -601, +308, -686, -1718, -14, -284, -463, -238, +124, +408, -1064, -243, -713, -651, +62, +367, -575, -268, +316, -31, +381, -321, + +19867, +19942, -2698, -5917, -5419, -356, +3943, +2529, -3315, -4768, -533, -59, -432, -1576, -30, -272, -359, -356, +203, +452, -1089, -118, -778, -495, +49, +184, -640, -440, +103, +121, +489, -151, + +22000, +20274, -4928, -6244, -5183, +422, +3657, +2387, -3535, -5191, -499, -408, +124, -1486, -39, -209, -489, -410, +327, +558, -1091, -6, -842, -510, -62, +53, -686, -527, +27, +247, +412, +120, + +23867, +20630, -6764, -6611, -5435, +1219, +3584, +2132, -3790, -5664, -426, -579, +849, -1544, +115, -346, -693, -253, +402, +737, -1086, +70, -1208, -570, -77, -89, -681, -321, -84, +142, +497, +304, + +25427, +20921, -8048, -7062, -6069, +1884, +3693, +1754, -4141, -5893, -210, -678, +1594, -1604, +126, -548, -678, -23, +392, +982, -1152, -266, -1531, -447, -207, -3, -478, -227, -288, +201, +484, +187, + +26670, +20956, -8821, -7361, -6968, +2286, +3959, +1161, -4414, -5482, -257, -597, +2261, -1827, +18, -485, -493, +96, +432, +895, -1493, -446, -1665, -450, +33, +175, -509, -150, -228, -15, +349, +351, + +27247, +21029, -9279, -7221, -8186, +2443, +4316, +433, -4111, -5058, -277, -461, +2624, -2135, +8, -68, -470, +172, -50, +659, -1495, -578, -1725, -94, +295, -26, -297, -74, -411, -173, +430, +303, + +27900, +20315, -8903, -7184, -9921, +2431, +4704, +385, -3980, -4367, -496, -493, +2857, -2265, +375, +207, -681, -337, -225, +556, -1409, -535, -1534, +66, +228, +14, -233, -136, -400, -267, +410, +268, + +27607, +19995, -8273, -6960, -11863, +2111, +5727, +206, -3669, -3625, -950, -750, +3372, -2159, +511, +126, -1428, -249, -334, +460, -1027, -385, -1566, +110, +211, -88, -105, -186, -370, -401, +501, +177, + +27622, +18453, -7307, -6733, -13561, +2585, +6218, +129, -3285, -2980, -1630, -393, +3761, -2468, +529, -441, -1518, +13, -480, +602, -588, -563, -1536, +165, +105, -89, -91, -163, -357, -425, +580, -7, + +26712, +17271, -6277, -6285, -14362, +2609, +6500, +415, -3110, -2459, -1751, -325, +3747, -2769, +192, -404, -1346, +67, -259, +700, -500, -685, -1381, +215, -122, -46, -21, -142, -291, -476, +628, -31, + +24769, +16230, -5111, -5257, -14397, +2104, +6670, +474, -2600, -1910, -2144, -355, +3491, -3153, +319, -229, -1416, +584, -304, +502, -383, -651, -1149, -88, -115, +8, -18, -89, -321, -449, +713, -173, + +22531, +14663, -3328, -4140, -13801, +1449, +6057, +1180, -2109, -1891, -2239, -499, +2901, -2827, +365, -277, -887, +650, -524, +392, -96, -669, -1178, -67, -149, -9, +23, -125, -229, -396, +626, -144, + +19895, +13154, -1419, -2898, -12707, +438, +5719, +1680, -2070, -1480, -2520, -641, +2754, -2677, +403, +34, -653, +479, -618, +548, -55, -828, -839, -119, -236, +37, -10, -61, -202, -414, +734, -50, + +15813, +10164, -3306, -1259, -4293, +3357, +1973, -2111, -1944, +200, +219, -308, +1352, -2193, +64, -117, -1126, +153, -436, +60, -137, -521, -663, +805, -86, +19, +120, -674, -64, -483, -254, +28, + +13540, +9962, -1922, -1329, -4062, +2676, +2356, -1429, -1777, +3, -53, -302, +1192, -1816, -26, +30, -863, +65, -256, +68, -137, -483, -700, +634, +28, +18, +255, -495, -126, -392, -252, -65, + +11634, +9561, -699, -1265, -3629, +2134, +2474, -898, -1471, -172, -210, -167, +1001, -1414, -33, +173, -616, +55, -78, +97, -92, -391, -629, +503, +182, +60, +264, -359, -148, -296, -278, -94, + +10116, +9195, +85, -1190, -3168, +1756, +2451, -457, -1159, -296, -215, -72, +824, -1068, +57, +267, -418, +80, +67, +164, -62, -236, -495, +399, +241, +62, +228, -255, -153, -255, -222, -97, + +8972, +8865, +505, -1212, -2723, +1474, +2315, -138, -916, -335, -184, -65, +679, -767, +131, +280, -267, +100, +140, +232, -22, -124, -428, +222, +224, +45, +106, -204, -143, -199, -220, -223, + +8143, +8550, +717, -1226, -2288, +1267, +2150, +132, -720, -286, -144, -49, +640, -554, +197, +300, -154, +119, +220, +280, -45, -61, -392, +43, +178, +16, +16, -111, -123, -218, -232, -196, + +7519, +8353, +812, -1237, -1913, +1117, +2025, +376, -587, -178, -1, -84, +685, -393, +217, +358, -60, +126, +213, +332, -84, -72, -329, -119, +124, +96, -34, -68, -117, -163, -197, -307, + +7138, +8193, +814, -1279, -1576, +1064, +1902, +541, -519, -85, +237, -175, +678, -205, +145, +407, -22, +33, +193, +347, -106, -168, -290, -132, +40, +147, -63, -81, -15, -226, -137, +56, + +6765, +8188, +868, -1293, -1277, +1051, +1806, +584, -405, -124, +486, -108, +449, +28, +127, +224, +67, +7, +73, +339, -51, -243, -320, +0, -67, +74, +55, -80, -93, +50, +86, -210, + +6619, +8107, +942, -1282, -1022, +1117, +1715, +528, -435, -63, +479, +47, +396, -99, +275, +103, -92, +116, +36, +186, -20, -104, -395, -86, -10, +55, +1, -128, +248, +155, -185, -146, + +6506, +8197, +996, -1294, -821, +1178, +1651, +459, -560, -146, +509, -44, +460, -45, +85, +200, -171, -75, +154, +145, -147, -20, -290, -290, -60, +165, -210, +91, +457, -145, -98, -174, + +6582, +8378, +972, -1387, -629, +1360, +1678, +371, -630, -289, +430, -31, +347, +59, +235, +84, -170, +9, -19, +188, -18, -105, -290, -206, -28, -83, -58, +442, +120, -133, +100, -328, + +6729, +8662, +933, -1675, -529, +1529, +1750, +352, -860, -415, +386, -244, +217, +58, +206, +210, -193, -125, +73, +64, -149, +23, -388, -231, +36, -212, +36, +433, -79, -64, +4, -312, + +6891, +9095, +950, -1986, -500, +1682, +1851, +373, -983, -585, +394, -308, -13, -44, +240, +173, -175, +14, +14, +51, -151, -125, -432, -103, +46, -279, +169, +405, -280, -72, +3, -309, + +7140, +9633, +936, -2394, -433, +1844, +1940, +403, -1165, -606, +441, -410, -140, -123, +140, +125, -224, -22, +162, +113, -243, -123, -493, -210, +171, -184, +103, +464, -305, -188, -101, -278, + +7579, +10153, +808, -2790, -377, +2061, +1958, +319, -1378, -620, +599, -484, -299, -248, +140, +31, -407, -65, +163, +117, -205, -114, -553, -215, +158, -225, +53, +587, -241, -398, -127, -310, + +8098, +10746, +572, -3255, -297, +2282, +1951, +145, -1630, -671, +779, -545, -492, -334, +56, -74, -517, -231, +85, +61, -318, -68, -487, -259, +155, -163, -275, +532, +118, -570, -295, -288, + +8856, +11416, +228, -3688, -131, +2625, +1937, -65, -1888, -582, +1023, -544, -642, -393, +130, -159, -647, -205, +40, -68, -349, -125, -337, -110, +114, -18, -391, +244, +381, -387, -478, -229, + +9699, +12034, -166, -4109, -4, +2965, +1853, -341, -2231, -485, +1256, -561, -825, -509, +157, -201, -806, -277, +86, -284, -419, -202, -354, +141, +75, -8, -343, -105, +372, -52, -654, -293, + +10543, +12775, -545, -4510, +87, +3328, +1796, -636, -2510, -451, +1566, -593, -960, -599, +156, -239, -879, -366, +153, -404, -550, -174, -435, +353, +148, -50, -279, -255, +87, +310, -515, -582, + +11200, +13601, -758, -4805, +51, +3618, +1817, -936, -2667, -529, +1865, -619, -1077, -658, +152, -290, -948, -411, +137, -381, -707, -102, -513, +487, +276, -91, -256, -301, -183, +365, -56, -808, + +11970, +14337, -1048, -4982, -71, +3819, +1800, -1224, -2823, -587, +2067, -657, -1227, -698, +129, -342, -1036, -477, +85, -363, -801, -49, -525, +479, +403, -110, -295, -362, -353, +170, +366, -705, + +12952, +14790, -1411, -4961, -192, +3874, +1746, -1433, -2954, -613, +2172, -717, -1346, -744, +115, -409, -1087, -567, +16, -356, -787, -59, -428, +439, +419, -85, -317, -480, -441, -15, +471, -306, + +13912, +15283, -1898, -4796, -288, +3733, +1713, -1566, -3031, -703, +2247, -785, -1394, -782, +55, -432, -1125, -661, -51, -311, -721, -96, -300, +422, +338, -39, -314, -612, -519, -71, +296, +100, + +14855, +15823, -2738, -4516, -305, +3389, +1721, -1674, -3103, -885, +2277, -894, -1325, -878, -28, -456, -1189, -726, -166, -184, -719, -109, -219, +375, +189, +34, -370, -698, -563, -131, +49, +307, + +16338, +16003, -4097, -3971, -183, +3015, +1641, -1812, -3218, -959, +2300, -1062, -1053, -1052, -10, -553, -1252, -711, -213, -61, -766, +9, -305, +359, +93, +64, -446, -677, -520, -329, -54, +380, + +18251, +15738, -5808, -3185, -135, +2789, +1385, -1959, -3407, -901, +2346, -1243, -701, -1229, +42, -723, -1269, -588, -226, -66, -699, +25, -533, +532, -57, +38, -378, -632, -576, -478, +14, +227, + +20108, +15232, -7463, -2359, -182, +2680, +993, -2135, -3628, -757, +2465, -1466, -282, -1397, +30, -889, -1150, -413, -456, +70, -740, -222, -483, +617, -261, +207, -289, -809, -541, -427, -149, +45, + +21818, +14565, -8920, -1528, -323, +2633, +590, -2360, -3741, -408, +2485, -1626, +257, -1681, +37, -834, -979, -443, -529, +77, -986, -154, -547, +693, -157, +334, -410, -839, -327, -606, -328, +75, + +23103, +13939, -10069, -743, -746, +2659, +301, -2677, -3587, -100, +2394, -1612, +709, -2069, +297, -672, -1108, -278, -883, +30, -908, -351, -497, +1045, -177, +252, -316, -804, -379, -726, -359, +57, + +23945, +13086, -10548, -173, -1474, +2865, +166, -2907, -3401, +227, +2202, -1525, +1022, -2203, +552, -677, -1107, -549, -996, +157, -1089, -304, -261, +1165, -310, +418, -308, -941, -344, -785, -396, +51, + +24255, +12118, -10245, -13, -2426, +3265, +310, -3204, -3183, +647, +1733, -1352, +1565, -2480, +734, -599, -1582, -399, -1019, +24, -846, -257, -242, +1202, -199, +374, -346, -1003, -311, -777, -466, +127, + +23709, +11520, -9531, -151, -3388, +3855, +550, -3483, -2789, +731, +1250, -841, +1752, -2633, +801, -862, -1583, -318, -1087, +206, -657, -373, -274, +1353, -271, +302, -334, -1032, -204, -865, -432, +235, + +22428, +11143, -8405, -496, -4041, +4230, +889, -3448, -2615, +728, +1070, -660, +1947, -2748, +486, -621, -1697, -171, -896, +282, -583, -459, -269, +1324, -316, +161, -148, -1048, -191, -833, -297, +216, + +20761, +10556, -6721, -940, -4366, +4259, +1328, -3270, -2442, +888, +519, -254, +1808, -2851, +481, -564, -1534, -32, -625, +157, -458, -456, -349, +1175, -358, +206, -68, -1025, -144, -651, -305, +204, + +18483, +10322, -5051, -1232, -4488, +3998, +1699, -2851, -2083, +521, +346, -174, +1484, -2533, +230, -316, -1365, +115, -496, +12, -245, -474, -558, +987, -219, +124, +13, -912, -46, -573, -264, +159, + +15151, +10407, -3905, -1083, -1883, +2118, +367, -2185, -1952, +542, +790, -175, +1158, -1491, +303, +11, -942, -141, -277, +14, -417, -305, -403, +619, -260, -27, +128, -617, -289, -452, -406, -109, + +12885, +10154, -2446, -1435, -1886, +1994, +819, -1625, -1685, +115, +676, -116, +950, -1122, +70, +152, -656, +7, -100, +33, -249, -339, -518, +467, -154, -64, +221, -437, -240, -376, -360, -167, + +11026, +9815, -1373, -1604, -1732, +1727, +1082, -1042, -1489, -153, +594, -120, +851, -783, -35, +259, -348, +25, +24, +163, -205, -275, -535, +286, -60, -104, +181, -299, -203, -314, -276, -258, + +9638, +9479, -718, -1704, -1525, +1463, +1205, -627, -1291, -289, +532, -105, +728, -476, -29, +265, -147, +9, +102, +238, -168, -228, -548, +99, -70, -181, +55, -160, -166, -274, -267, -318, + +8752, +9179, -333, -1745, -1266, +1296, +1255, -331, -1103, -308, +517, +6, +654, -256, +108, +218, -57, +66, +139, +248, -132, -162, -550, -73, -107, -216, +35, -13, -164, -279, -126, -282, + +8140, +9001, -85, -1784, -995, +1204, +1247, -134, -1072, -291, +536, +70, +685, -204, +206, +280, -165, +40, +195, +187, -211, -72, -529, -292, -102, -127, -36, -76, -58, -138, -270, -89, + +7821, +8936, +29, -1810, -714, +1265, +1138, -40, -1096, -420, +649, +5, +642, -11, +138, +306, -111, -183, +147, +285, -330, -213, -387, -248, -250, -102, -97, -86, +22, -265, +130, +187, + +7807, +9028, -50, -1866, -441, +1451, +1138, -195, -1118, -490, +518, +2, +517, +35, +307, +254, -153, -103, +7, +126, -244, -245, -496, -140, -99, -332, -144, +49, -205, +61, +387, -266, + +7883, +9354, -84, -2058, -175, +1671, +1191, -268, -1313, -554, +542, -204, +353, +81, +268, +401, -95, -139, +119, +41, -495, -190, -362, -215, -155, -154, -74, -308, -29, +393, -17, -331, + +8309, +9731, -294, -2293, +42, +1934, +1203, -363, -1445, -664, +574, -270, +131, -85, +298, +391, -163, +29, +228, -28, -529, -302, -516, -77, -71, -224, -65, -236, +37, +234, -157, -305, + +8910, +10272, -662, -2606, +320, +2118, +1145, -521, -1640, -652, +647, -370, -95, -197, +260, +249, -276, +1, +311, +7, -540, -340, -597, -115, -162, -109, -41, -330, +23, +288, -224, -561, + +9705, +10883, -1159, -2876, +618, +2308, +939, -735, -1827, -569, +847, -551, -252, -350, +282, +190, -540, -53, +297, -89, -533, -247, -636, +1, -229, -304, +0, -239, -164, +169, +30, -627, + +10729, +11542, -1791, -3053, +931, +2475, +682, -1055, -1976, -419, +1145, -742, -457, -399, +293, +130, -657, -195, +215, -136, -668, -129, -569, +112, -117, -431, -109, -273, -261, +33, +231, -480, + +11880, +12255, -2434, -3089, +1163, +2572, +450, -1357, -2085, -232, +1467, -892, -621, -438, +381, +30, -732, -214, +65, -162, -709, -100, -437, +212, -28, -368, -165, -380, -411, -90, +291, -64, + +13138, +12910, -3157, -3037, +1198, +2492, +221, -1627, -2212, -103, +1693, -1094, -727, -513, +408, -69, -857, -306, -36, -187, -773, -78, -367, +223, -33, -259, -244, -476, -574, -270, +164, +260, + +14397, +13579, -3910, -2827, +1090, +2265, +96, -1784, -2287, -52, +1872, -1249, -736, -567, +401, -118, -956, -410, -92, -132, -795, +4, -347, +213, -84, -122, -283, -544, -622, -487, +74, +387, + +15830, +13982, -4898, -2472, +856, +1874, -58, -1916, -2412, -69, +1931, -1394, -672, -679, +358, -219, -1064, -512, -131, -146, -801, +55, -460, +223, -217, -78, -273, -623, -663, -737, +48, +327, + +17467, +14082, -6145, -1897, +641, +1483, -284, -1985, -2544, -62, +2082, -1574, -443, -758, +315, -348, -1052, -474, -316, -34, -792, -77, -456, +264, -381, +42, -169, -787, -651, -765, -87, +204, + +19204, +13692, -7428, -1120, +469, +1144, -634, -1991, -2737, +205, +2197, -1785, +24, -916, +275, -357, -852, -637, -399, +114, -1061, -13, -468, +245, -296, +208, -219, -909, -451, -819, -365, +209, + +20434, +13223, -8548, -342, +182, +828, -924, -2160, -2725, +468, +2161, -1789, +445, -1242, +435, -205, -999, -575, -649, -4, -1029, -158, -482, +542, -293, +181, -169, -874, -514, -927, -442, +127, + +21071, +12403, -8865, +245, -318, +823, -1130, -2243, -2635, +724, +2101, -1684, +725, -1293, +626, -269, -883, -830, -829, +105, -1203, -105, -238, +653, -371, +371, -143, -1016, -532, -886, -493, +33, + +20789, +11662, -8363, +332, -911, +1138, -984, -2430, -2493, +1026, +1715, -1379, +1228, -1581, +803, -170, -1256, -633, -926, +9, -905, -125, -208, +782, -256, +313, -208, -993, -501, -825, -526, -5, + +19596, +11016, -7150, -54, -1442, +1677, -696, -2554, -2277, +940, +1405, -817, +1246, -1536, +683, -288, -1142, -645, -762, +96, -739, -256, -171, +923, -379, +209, -146, -915, -439, -791, -471, +64, + +17572, +10705, -5607, -659, -1779, +2017, -199, -2475, -2231, +834, +1110, -554, +1413, -1693, +462, -69, -1229, -319, -565, +61, -598, -344, -187, +729, -361, +89, -38, -790, -417, -617, -384, -60, + +13984, +10256, -4374, -387, +520, +1170, -465, -1651, -1737, +620, +1299, -598, +593, -692, +507, -106, -759, -500, -601, +13, -482, -134, -166, +603, -169, +64, -79, -688, -462, -543, -415, -231, + +12758, +10312, -3687, -1357, +269, +1735, +98, -1444, -1892, +26, +1171, -327, +678, -523, +452, +210, -645, -277, -231, -18, -408, -233, -377, +567, -155, -104, +72, -516, -401, -434, -355, -174, + +11716, +10426, -3021, -2050, -38, +1840, +528, -1068, -1835, -336, +989, -214, +710, -348, +420, +365, -440, -231, -16, +39, -429, -185, -574, +332, -35, -237, +26, -307, -370, -373, -221, -235, + +11134, +10529, -2662, -2372, -80, +1872, +687, -929, -1758, -466, +868, -263, +670, -278, +447, +463, -382, -147, +37, -28, -515, -135, -648, +44, +50, -206, -64, -271, -287, -346, -196, -161, + +11076, +10636, -2726, -2397, +319, +2006, +654, -1075, -1802, -427, +898, -371, +393, -170, +406, +444, -274, -100, +119, -97, -686, -259, -554, +17, -61, -105, -68, -278, -240, -444, -157, +31, + +11612, +10554, -3129, -2035, +925, +2135, +343, -1322, -1834, -253, +981, -508, +127, -339, +524, +263, -428, +146, +113, -216, -691, -403, -615, +161, -3, -171, -98, -195, -334, -500, -145, +70, + +12375, +10683, -3543, -1496, +1375, +1878, -63, -1524, -1717, +100, +1163, -755, -161, -335, +443, +21, -544, +0, +88, -275, -693, -316, -565, +159, -85, -8, -150, -333, -390, -555, -137, +51, + +13451, +11029, -4018, -1046, +1272, +1286, -363, -1499, -1496, +592, +1316, -1108, -273, -352, +296, -275, -635, -344, -118, -175, -740, -127, -424, +105, -164, +113, -179, -568, -399, -627, -271, +78, + +14734, +11620, -4801, -879, +695, +632, -389, -1350, -1318, +1007, +1424, -1500, -74, -505, -4, -282, -945, -711, -166, -124, -792, +39, -391, +77, -83, +118, -326, -662, -381, -867, -393, +164, + +15985, +11630, -5516, -532, +203, +208, -354, -1214, -1189, +1341, +1442, -1615, +268, -744, -62, -254, -1183, -868, -259, -11, -770, +72, -261, +154, +24, +109, -377, -617, -514, -967, -389, +157, + +16167, +11377, -5735, -169, +103, +84, -542, -1299, -1254, +1362, +1544, -1556, +422, -670, -103, -248, -1015, -1157, -377, +88, -926, +197, -106, +201, +13, +190, -354, -777, -517, -923, -458, +58, + +15468, +10670, -5248, +0, +346, +442, -693, -1493, -1502, +1200, +1468, -1209, +625, -745, +218, -158, -964, -895, -623, +11, -688, +93, -44, +335, -4, +183, -327, -757, -508, -710, -494, -108, + +11864, +10338, -3078, -621, +1333, +599, -268, -1143, -1003, +1077, +1244, -764, -17, -195, +147, -60, -510, -758, -332, -70, -719, -16, -15, +316, +287, +250, -355, -886, -747, -549, -54, +215, +}; + +/* HRIR Delays */ +static const ALubyte defaultDelays[828] = +{ + 12, 12, 13, 14, 14, 14, 13, 12, 11, 10, 10, 10, 11, 12, 13, 14, 15, 15, 16, 16, 16, 15, 15, 14, 13, 12, 11, 10, 9, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 17, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 7, 6, 6, 6, 6, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 19, 20, 20, 20, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 5, 5, 5, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 21, 22, 22, 22, 22, 22, 21, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 24, 24, 24, 24, 23, 22, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 24, 25, 26, 26, 26, 26, 26, 25, 24, 24, 23, 22, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 28, 28, 27, 26, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 28, 28, 27, 26, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 24, 25, 26, 26, 26, 26, 26, 25, 24, 24, 23, 22, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 24, 24, 24, 24, 23, 22, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 21, 22, 22, 22, 22, 22, 21, 21, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 6, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 19, 20, 20, 20, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 8, 7, 6, 5, 5, 5, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 18, 18, 18, 18, 18, 17, 16, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 7, 6, 6, 6, 6, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 16, 16, 16, 15, 15, 14, 13, 12, 11, 10, 9, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 14, 14, 13, 12, 11, 10, 10, 10, 11, 12, +}; + +/* Default HRTF Definition */ +static const struct Hrtf DefaultHrtf = { + 44100, 32, 19, defaultAzCount, defaultEvOffset, + defaultCoeffs, defaultDelays, NULL +}; diff --git a/src/eepp/helper/android/openal-soft/Alc/mixer.c b/src/eepp/helper/android/openal-soft/Alc/mixer.c new file mode 100644 index 000000000..f75a7803c --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/mixer.c @@ -0,0 +1,421 @@ +/** + * 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 ALfloat Sample_ALbyte(ALbyte val) +{ return val * (1.0f/127.0f); } + +static __inline ALfloat Sample_ALshort(ALshort val) +{ return val * (1.0f/32767.0f); } + +static __inline ALfloat Sample_ALfloat(ALfloat val) +{ return val; } + +#define DECL_TEMPLATE(T) \ +static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\ +{ \ + ALuint i; \ + for(i = 0;i < samples;i++) \ + dst[i] = Sample_##T(src[i*srcstep]); \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALfloat) + +#undef DECL_TEMPLATE + +static void LoadData(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples) +{ + switch(srctype) + { + case FmtByte: + Load_ALbyte(dst, src, srcstep, samples); + break; + case FmtShort: + Load_ALshort(dst, src, srcstep, samples); + break; + case FmtFloat: + Load_ALfloat(dst, src, srcstep, samples); + break; + } +} + +static void SilenceData(ALfloat *dst, ALuint samples) +{ + ALuint i; + for(i = 0;i < samples;i++) + dst[i] = 0.0f; +} + + +static void Filter2P(FILTER *filter, ALuint chan, ALfloat *RESTRICT dst, + const ALfloat *RESTRICT src, ALuint numsamples) +{ + ALuint i; + for(i = 0;i < numsamples;i++) + dst[i] = lpFilter2P(filter, chan, src[i]); + dst[i] = lpFilter2PC(filter, chan, src[i]); +} + + +ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo) +{ + ALbufferlistitem *BufferListItem; + ALuint DataPosInt, DataPosFrac; + ALuint BuffersPlayed; + ALboolean Looping; + ALuint increment; + enum Resampler Resampler; + ALenum State; + ALuint OutPos; + ALuint NumChannels; + ALuint SampleSize; + ALint64 DataSize64; + ALuint chan, j; + + /* Get source info */ + State = Source->state; + BuffersPlayed = Source->BuffersPlayed; + DataPosInt = Source->position; + DataPosFrac = Source->position_fraction; + Looping = Source->Looping; + increment = Source->Params.Step; + Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler; + NumChannels = Source->NumChannels; + SampleSize = Source->SampleSize; + + /* Get current buffer queue item */ + BufferListItem = Source->queue; + for(j = 0;j < BuffersPlayed;j++) + BufferListItem = BufferListItem->next; + + OutPos = 0; + do { + const ALuint BufferPrePadding = ResamplerPrePadding[Resampler]; + const ALuint BufferPadding = ResamplerPadding[Resampler]; + ALuint SrcBufferSize, DstBufferSize; + + /* Figure out how many buffer bytes will be needed */ + DataSize64 = SamplesToDo-OutPos+1; + DataSize64 *= increment; + DataSize64 += DataPosFrac+FRACTIONMASK; + DataSize64 >>= FRACTIONBITS; + DataSize64 += BufferPadding+BufferPrePadding; + + SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE); + + /* Figure out how many samples we can actually mix from this. */ + DataSize64 = SrcBufferSize; + DataSize64 -= BufferPadding+BufferPrePadding; + DataSize64 <<= FRACTIONBITS; + DataSize64 -= increment; + DataSize64 -= DataPosFrac; + + DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment); + DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos)); + + /* Some mixers like having a multiple of 4, so try to give that unless + * this is the last update. */ + if(OutPos+DstBufferSize < SamplesToDo) + DstBufferSize &= ~3; + + for(chan = 0;chan < NumChannels;chan++) + { + ALfloat *SrcData = Device->SampleData1; + ALfloat *ResampledData = Device->SampleData2; + ALuint SrcDataSize = 0; + + if(Source->SourceType == AL_STATIC) + { + const ALbuffer *ALBuffer = Source->queue->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; + else + { + DataSize = BufferPrePadding - DataPosInt; + DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); + + SilenceData(&SrcData[SrcDataSize], DataSize); + SrcDataSize += DataSize; + + pos = 0; + } + + /* Copy what's left to play in the source buffer, and clear the + * rest of the temp buffer */ + DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos); + + LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize], + NumChannels, ALBuffer->FmtType, DataSize); + SrcDataSize += DataSize; + + SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize); + SrcDataSize += SrcBufferSize - SrcDataSize; + } + 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; + } + else if(DataPosInt >= BufferPrePadding) + pos = DataPosInt - BufferPrePadding; + else + { + DataSize = BufferPrePadding - DataPosInt; + DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); + + SilenceData(&SrcData[SrcDataSize], DataSize); + SrcDataSize += DataSize; + + pos = 0; + } + + /* Copy what's left of this loop iteration, then copy repeats + * of the loop section */ + DataSize = LoopEnd - pos; + DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); + + LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize], + NumChannels, ALBuffer->FmtType, DataSize); + SrcDataSize += DataSize; + + DataSize = LoopEnd-LoopStart; + while(SrcBufferSize > SrcDataSize) + { + DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); + + LoadData(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize], + NumChannels, ALBuffer->FmtType, DataSize); + SrcDataSize += DataSize; + } + } + } + else + { + /* Crawl the buffer queue to fill in the temp buffer */ + ALbufferlistitem *tmpiter = BufferListItem; + ALuint pos; + + if(DataPosInt >= BufferPrePadding) + pos = DataPosInt - BufferPrePadding; + else + { + pos = BufferPrePadding - DataPosInt; + while(pos > 0) + { + if(!tmpiter->prev && !Looping) + { + ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos); + + SilenceData(&SrcData[SrcDataSize], DataSize); + SrcDataSize += DataSize; + + pos = 0; + break; + } + + if(tmpiter->prev) + tmpiter = tmpiter->prev; + else + { + while(tmpiter->next) + tmpiter = tmpiter->next; + } + + if(tmpiter->buffer) + { + if((ALuint)tmpiter->buffer->SampleLen > pos) + { + pos = tmpiter->buffer->SampleLen - pos; + break; + } + pos -= tmpiter->buffer->SampleLen; + } + } + } + + while(tmpiter && SrcBufferSize > SrcDataSize) + { + const ALbuffer *ALBuffer; + if((ALBuffer=tmpiter->buffer) != NULL) + { + const ALubyte *Data = ALBuffer->data; + ALuint DataSize = ALBuffer->SampleLen; + + /* Skip the data already played */ + if(DataSize <= pos) + pos -= DataSize; + else + { + Data += (pos*NumChannels + chan)*SampleSize; + DataSize -= pos; + pos -= pos; + + DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); + LoadData(&SrcData[SrcDataSize], Data, NumChannels, + ALBuffer->FmtType, DataSize); + SrcDataSize += DataSize; + } + } + tmpiter = tmpiter->next; + if(!tmpiter && Looping) + tmpiter = Source->queue; + else if(!tmpiter) + { + SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize); + SrcDataSize += SrcBufferSize - SrcDataSize; + } + } + } + + /* Now resample, then filter and mix to the appropriate outputs. */ + Source->Params.Resample(&SrcData[BufferPrePadding], DataPosFrac, + increment, ResampledData, DstBufferSize); + + { + DirectParams *directparms = &Source->Params.Direct; + + Filter2P(&directparms->iirFilter, chan, SrcData, ResampledData, + DstBufferSize); + Source->Params.DryMix(directparms, SrcData, chan, OutPos, + SamplesToDo, DstBufferSize); + } + + for(j = 0;j < Device->NumAuxSends;j++) + { + SendParams *sendparms = &Source->Params.Send[j]; + if(!sendparms->Slot) + continue; + + Filter2P(&sendparms->iirFilter, chan, SrcData, ResampledData, + DstBufferSize); + Source->Params.WetMix(sendparms, SrcData, OutPos, + SamplesToDo, DstBufferSize); + } + } + /* Update positions */ + for(j = 0;j < DstBufferSize;j++) + { + DataPosFrac += increment; + DataPosInt += DataPosFrac>>FRACTIONBITS; + DataPosFrac &= FRACTIONMASK; + } + OutPos += DstBufferSize; + + /* Handle looping sources */ + while(1) + { + const ALbuffer *ALBuffer; + ALuint DataSize = 0; + ALuint LoopStart = 0; + ALuint LoopEnd = 0; + + if((ALBuffer=BufferListItem->buffer) != NULL) + { + DataSize = ALBuffer->SampleLen; + LoopStart = ALBuffer->LoopStart; + LoopEnd = ALBuffer->LoopEnd; + if(LoopEnd > DataPosInt) + break; + } + + if(Looping && Source->SourceType == AL_STATIC) + { + 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->Hrtf.Offset += OutPos; + if(State == AL_PLAYING) + Source->Hrtf.Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos; + else + { + Source->Hrtf.Counter = 0; + Source->Hrtf.Moving = AL_FALSE; + } +} diff --git a/src/eepp/helper/android/openal-soft/Alc/mixer_c.c b/src/eepp/helper/android/openal-soft/Alc/mixer_c.c new file mode 100644 index 000000000..d9c8ca25e --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/mixer_c.c @@ -0,0 +1,131 @@ +#include "config.h" + +#include + +#include "alMain.h" +#include "alu.h" +#include "alSource.h" +#include "alAuxEffectSlot.h" + + +static __inline ALfloat point32(const ALfloat *vals, ALuint frac) +{ return vals[0]; (void)frac; } +static __inline ALfloat lerp32(const ALfloat *vals, ALuint frac) +{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } +static __inline ALfloat cubic32(const ALfloat *vals, ALuint frac) +{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); } + +void Resample_copy32_C(const ALfloat *data, ALuint frac, + ALuint increment, ALfloat *RESTRICT OutBuffer, ALuint BufferSize) +{ + (void)frac; + assert(increment==FRACTIONONE); + memcpy(OutBuffer, data, (BufferSize+1)*sizeof(ALfloat)); +} + +#define DECL_TEMPLATE(Sampler) \ +void Resample_##Sampler##_C(const ALfloat *data, ALuint frac, \ + ALuint increment, ALfloat *RESTRICT OutBuffer, ALuint BufferSize) \ +{ \ + ALuint pos = 0; \ + ALuint i; \ + \ + for(i = 0;i < BufferSize+1;i++) \ + { \ + OutBuffer[i] = Sampler(data + pos, frac); \ + \ + frac += increment; \ + pos += frac>>FRACTIONBITS; \ + frac &= FRACTIONMASK; \ + } \ +} + +DECL_TEMPLATE(point32) +DECL_TEMPLATE(lerp32) +DECL_TEMPLATE(cubic32) + +#undef DECL_TEMPLATE + + +static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint IrSize, + ALfloat (*RESTRICT Coeffs)[2], + const ALfloat (*RESTRICT CoeffStep)[2], + ALfloat left, ALfloat right) +{ + ALuint c; + for(c = 0;c < IrSize;c++) + { + const ALuint off = (Offset+c)&HRIR_MASK; + Values[off][0] += Coeffs[c][0] * left; + Values[off][1] += Coeffs[c][1] * right; + Coeffs[c][0] += CoeffStep[c][0]; + Coeffs[c][1] += CoeffStep[c][1]; + } +} + +static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint IrSize, + ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right) +{ + ALuint c; + for(c = 0;c < IrSize;c++) + { + const ALuint off = (Offset+c)&HRIR_MASK; + Values[off][0] += Coeffs[c][0] * left; + Values[off][1] += Coeffs[c][1] * right; + } +} + +#define SUFFIX C +#include "mixer_inc.c" +#undef SUFFIX + + +void MixDirect_C(const DirectParams *params, const ALfloat *RESTRICT data, ALuint srcchan, + ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) +{ + ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = params->OutBuffer; + ALfloat *RESTRICT ClickRemoval = params->ClickRemoval; + ALfloat *RESTRICT PendingClicks = params->PendingClicks; + ALfloat DrySend; + ALuint pos; + ALuint c; + + for(c = 0;c < MaxChannels;c++) + { + DrySend = params->Gains[srcchan][c]; + if(DrySend < 0.00001f) + continue; + + if(OutPos == 0) + ClickRemoval[c] -= data[0]*DrySend; + for(pos = 0;pos < BufferSize;pos++) + DryBuffer[c][OutPos+pos] += data[pos]*DrySend; + if(OutPos+pos == SamplesToDo) + PendingClicks[c] += data[pos]*DrySend; + } +} + + +void MixSend_C(const SendParams *params, const ALfloat *RESTRICT data, + ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) +{ + ALeffectslot *Slot = params->Slot; + ALfloat (*RESTRICT WetBuffer)[BUFFERSIZE] = Slot->WetBuffer; + ALfloat *RESTRICT WetClickRemoval = Slot->ClickRemoval; + ALfloat *RESTRICT WetPendingClicks = Slot->PendingClicks; + ALfloat WetSend = params->Gain; + ALuint pos; + + if(WetSend < 0.00001f) + return; + + if(OutPos == 0) + WetClickRemoval[0] -= data[0] * WetSend; + for(pos = 0;pos < BufferSize;pos++) + WetBuffer[0][OutPos+pos] += data[pos] * WetSend; + if(OutPos+pos == SamplesToDo) + WetPendingClicks[0] += data[pos] * WetSend; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/mixer_defs.h b/src/eepp/helper/android/openal-soft/Alc/mixer_defs.h new file mode 100644 index 000000000..6d3390c8e --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/mixer_defs.h @@ -0,0 +1,31 @@ +#ifndef MIXER_DEFS_H +#define MIXER_DEFS_H + +#include "AL/alc.h" +#include "AL/al.h" +#include "alMain.h" + +struct DirectParams; +struct SendParams; + +/* C resamplers */ +void Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen); +void Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen); +void Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen); +void Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *RESTRICT dst, ALuint dstlen); + + +/* C mixers */ +void MixDirect_Hrtf_C(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint); +void MixDirect_C(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint); +void MixSend_C(const struct SendParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint); + +/* SSE mixers */ +void MixDirect_Hrtf_SSE(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint); +void MixDirect_SSE(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint); +void MixSend_SSE(const struct SendParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint); + +/* Neon mixers */ +void MixDirect_Hrtf_Neon(const struct DirectParams*,const ALfloat*RESTRICT,ALuint,ALuint,ALuint,ALuint); + +#endif /* MIXER_DEFS_H */ diff --git a/src/eepp/helper/android/openal-soft/Alc/mixer_inc.c b/src/eepp/helper/android/openal-soft/Alc/mixer_inc.c new file mode 100644 index 000000000..97266d404 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/mixer_inc.c @@ -0,0 +1,141 @@ +#include "config.h" + +#include "alMain.h" +#include "alSource.h" +#include "mixer_defs.h" + +#ifdef __GNUC__ +#define LIKELY(x) __builtin_expect(!!(x), 1) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define LIKELY(x) (x) +#define UNLIKELY(x) (x) +#endif + +#define REAL_MERGE2(a,b) a##b +#define MERGE2(a,b) REAL_MERGE2(a,b) + +#define MixDirect_Hrtf MERGE2(MixDirect_Hrtf_,SUFFIX) + + +static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint irSize, + ALfloat (*RESTRICT Coeffs)[2], + const ALfloat (*RESTRICT CoeffStep)[2], + ALfloat left, ALfloat right); +static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint irSize, + ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right); + + +void MixDirect_Hrtf(const DirectParams *params, const ALfloat *RESTRICT data, ALuint srcchan, + ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) +{ + ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = params->OutBuffer; + ALfloat *RESTRICT ClickRemoval = params->ClickRemoval; + ALfloat *RESTRICT PendingClicks = params->PendingClicks; + const ALuint IrSize = params->Hrtf.Params.IrSize; + const ALint *RESTRICT DelayStep = params->Hrtf.Params.DelayStep; + const ALfloat (*RESTRICT CoeffStep)[2] = params->Hrtf.Params.CoeffStep; + const ALfloat (*RESTRICT TargetCoeffs)[2] = params->Hrtf.Params.Coeffs[srcchan]; + const ALuint *RESTRICT TargetDelay = params->Hrtf.Params.Delay[srcchan]; + ALfloat *RESTRICT History = params->Hrtf.State->History[srcchan]; + ALfloat (*RESTRICT Values)[2] = params->Hrtf.State->Values[srcchan]; + ALint Counter = maxu(params->Hrtf.State->Counter, OutPos) - OutPos; + ALuint Offset = params->Hrtf.State->Offset + OutPos; + ALIGN(16) ALfloat Coeffs[HRIR_LENGTH][2]; + ALuint Delay[2]; + ALfloat left, right; + ALuint pos; + ALuint c; + + pos = 0; + for(c = 0;c < IrSize;c++) + { + Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter); + Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter); + } + + Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter); + Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter); + + if(LIKELY(OutPos == 0)) + { + History[Offset&SRC_HISTORY_MASK] = data[pos]; + left = lerp(History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], + History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], + (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); + right = lerp(History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], + History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], + (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); + + ClickRemoval[FrontLeft] -= Values[(Offset+1)&HRIR_MASK][0] + + Coeffs[0][0] * left; + ClickRemoval[FrontRight] -= Values[(Offset+1)&HRIR_MASK][1] + + Coeffs[0][1] * right; + } + for(pos = 0;pos < BufferSize && Counter > 0;pos++) + { + History[Offset&SRC_HISTORY_MASK] = data[pos]; + left = lerp(History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], + History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], + (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); + right = lerp(History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], + History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], + (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); + + Delay[0] += DelayStep[0]; + Delay[1] += DelayStep[1]; + + Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + ApplyCoeffsStep(Offset, Values, IrSize, Coeffs, CoeffStep, left, right); + DryBuffer[FrontLeft][OutPos] += Values[Offset&HRIR_MASK][0]; + DryBuffer[FrontRight][OutPos] += Values[Offset&HRIR_MASK][1]; + + OutPos++; + Counter--; + } + + Delay[0] >>= HRTFDELAY_BITS; + Delay[1] >>= HRTFDELAY_BITS; + for(;pos < BufferSize;pos++) + { + History[Offset&SRC_HISTORY_MASK] = data[pos]; + left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; + right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; + + Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; + Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; + Offset++; + + ApplyCoeffs(Offset, Values, IrSize, Coeffs, left, right); + DryBuffer[FrontLeft][OutPos] += Values[Offset&HRIR_MASK][0]; + DryBuffer[FrontRight][OutPos] += Values[Offset&HRIR_MASK][1]; + + OutPos++; + } + if(LIKELY(OutPos == SamplesToDo)) + { + History[Offset&SRC_HISTORY_MASK] = data[pos]; + left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; + right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; + + PendingClicks[FrontLeft] += Values[(Offset+1)&HRIR_MASK][0] + + Coeffs[0][0] * left; + PendingClicks[FrontRight] += Values[(Offset+1)&HRIR_MASK][1] + + Coeffs[0][1] * right; + } +} + + +#undef MixDirect_Hrtf + +#undef MERGE2 +#undef REAL_MERGE2 + +#undef UNLIKELY +#undef LIKELY diff --git a/src/eepp/helper/android/openal-soft/Alc/mixer_neon.c b/src/eepp/helper/android/openal-soft/Alc/mixer_neon.c new file mode 100644 index 000000000..23dc792c9 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/mixer_neon.c @@ -0,0 +1,61 @@ +#include "config.h" + +#ifdef HAVE_ARM_NEON_H +#include +#endif + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alu.h" + + +static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint IrSize, + ALfloat (*RESTRICT Coeffs)[2], + const ALfloat (*RESTRICT CoeffStep)[2], + ALfloat left, ALfloat right) +{ + ALuint c; + for(c = 0;c < IrSize;c++) + { + const ALuint off = (Offset+c)&HRIR_MASK; + Values[off][0] += Coeffs[c][0] * left; + Values[off][1] += Coeffs[c][1] * right; + Coeffs[c][0] += CoeffStep[c][0]; + Coeffs[c][1] += CoeffStep[c][1]; + } +} + +static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint IrSize, + ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right) +{ + ALuint c; + float32x4_t leftright4; + { + float32x2_t leftright2 = vdup_n_f32(0.0); + leftright2 = vset_lane_f32(left, leftright2, 0); + leftright2 = vset_lane_f32(right, leftright2, 1); + leftright4 = vcombine_f32(leftright2, leftright2); + } + for(c = 0;c < IrSize;c += 2) + { + const ALuint o0 = (Offset+c)&HRIR_MASK; + const ALuint o1 = (o0+1)&HRIR_MASK; + float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), + vld1_f32((float32_t*)&Values[o1][0])); + float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); + + vals = vmlaq_f32(vals, coefs, leftright4); + + vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); + vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); + } +} + + +#define SUFFIX Neon +#include "mixer_inc.c" +#undef SUFFIX diff --git a/src/eepp/helper/android/openal-soft/Alc/mixer_sse.c b/src/eepp/helper/android/openal-soft/Alc/mixer_sse.c new file mode 100644 index 000000000..540a0d728 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/mixer_sse.c @@ -0,0 +1,204 @@ +#include "config.h" + +#ifdef HAVE_XMMINTRIN_H +#include +#endif + +#include "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alu.h" + +#include "alSource.h" +#include "alAuxEffectSlot.h" +#include "mixer_defs.h" + + +static __inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint IrSize, + ALfloat (*RESTRICT Coeffs)[2], + const ALfloat (*RESTRICT CoeffStep)[2], + ALfloat left, ALfloat right) +{ + const __m128 lrlr = { left, right, left, right }; + __m128 coeffs, deltas, imp0, imp1; + __m128 vals = _mm_setzero_ps(); + ALuint i; + + if((Offset&1)) + { + const ALuint o0 = Offset&HRIR_MASK; + const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[0][0]); + deltas = _mm_load_ps(&CoeffStep[0][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); + imp0 = _mm_mul_ps(lrlr, coeffs); + coeffs = _mm_add_ps(coeffs, deltas); + vals = _mm_add_ps(imp0, vals); + _mm_store_ps(&Coeffs[0][0], coeffs); + _mm_storel_pi((__m64*)&Values[o0][0], vals); + for(i = 1;i < IrSize-1;i += 2) + { + const ALuint o2 = (Offset+i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i+1][0]); + deltas = _mm_load_ps(&CoeffStep[i+1][0]); + vals = _mm_load_ps(&Values[o2][0]); + imp1 = _mm_mul_ps(lrlr, coeffs); + coeffs = _mm_add_ps(coeffs, deltas); + imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); + vals = _mm_add_ps(imp0, vals); + _mm_store_ps(&Coeffs[i+1][0], coeffs); + _mm_store_ps(&Values[o2][0], vals); + imp0 = imp1; + } + vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]); + imp0 = _mm_movehl_ps(imp0, imp0); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi((__m64*)&Values[o1][0], vals); + } + else + { + for(i = 0;i < IrSize;i += 2) + { + const ALuint o = (Offset + i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i][0]); + deltas = _mm_load_ps(&CoeffStep[i][0]); + vals = _mm_load_ps(&Values[o][0]); + imp0 = _mm_mul_ps(lrlr, coeffs); + coeffs = _mm_add_ps(coeffs, deltas); + vals = _mm_add_ps(imp0, vals); + _mm_store_ps(&Coeffs[i][0], coeffs); + _mm_store_ps(&Values[o][0], vals); + } + } +} + +static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2], + const ALuint IrSize, + ALfloat (*RESTRICT Coeffs)[2], + ALfloat left, ALfloat right) +{ + const __m128 lrlr = { left, right, left, right }; + __m128 vals = _mm_setzero_ps(); + __m128 coeffs; + ALuint i; + + if((Offset&1)) + { + const ALuint o0 = Offset&HRIR_MASK; + const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK; + __m128 imp0, imp1; + + coeffs = _mm_load_ps(&Coeffs[0][0]); + vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); + imp0 = _mm_mul_ps(lrlr, coeffs); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi((__m64*)&Values[o0][0], vals); + for(i = 1;i < IrSize-1;i += 2) + { + const ALuint o2 = (Offset+i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i+1][0]); + vals = _mm_load_ps(&Values[o2][0]); + imp1 = _mm_mul_ps(lrlr, coeffs); + imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); + vals = _mm_add_ps(imp0, vals); + _mm_store_ps(&Values[o2][0], vals); + imp0 = imp1; + } + vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]); + imp0 = _mm_movehl_ps(imp0, imp0); + vals = _mm_add_ps(imp0, vals); + _mm_storel_pi((__m64*)&Values[o1][0], vals); + } + else + { + for(i = 0;i < IrSize;i += 2) + { + const ALuint o = (Offset + i)&HRIR_MASK; + + coeffs = _mm_load_ps(&Coeffs[i][0]); + vals = _mm_load_ps(&Values[o][0]); + vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); + _mm_store_ps(&Values[o][0], vals); + } + } +} + +#define SUFFIX SSE +#include "mixer_inc.c" +#undef SUFFIX + + +void MixDirect_SSE(const DirectParams *params, const ALfloat *RESTRICT data, ALuint srcchan, + ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) +{ + ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = params->OutBuffer; + ALfloat *RESTRICT ClickRemoval = params->ClickRemoval; + ALfloat *RESTRICT PendingClicks = params->PendingClicks; + ALfloat DrySend; + ALuint pos; + ALuint c; + + for(c = 0;c < MaxChannels;c++) + { + __m128 gain; + + DrySend = params->Gains[srcchan][c]; + if(DrySend < 0.00001f) + continue; + + if(OutPos == 0) + ClickRemoval[c] -= data[0]*DrySend; + + gain = _mm_set1_ps(DrySend); + for(pos = 0;pos < BufferSize-3;pos += 4) + { + const __m128 val4 = _mm_load_ps(&data[pos]); + __m128 dry4 = _mm_load_ps(&DryBuffer[c][OutPos+pos]); + dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain)); + _mm_store_ps(&DryBuffer[c][OutPos+pos], dry4); + } + for(;pos < BufferSize;pos++) + DryBuffer[c][OutPos+pos] += data[pos]*DrySend; + + if(OutPos+pos == SamplesToDo) + PendingClicks[c] += data[pos]*DrySend; + } +} + + +void MixSend_SSE(const SendParams *params, const ALfloat *RESTRICT data, + ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) +{ + ALeffectslot *Slot = params->Slot; + ALfloat (*RESTRICT WetBuffer)[BUFFERSIZE] = Slot->WetBuffer; + ALfloat *RESTRICT WetClickRemoval = Slot->ClickRemoval; + ALfloat *RESTRICT WetPendingClicks = Slot->PendingClicks; + const ALfloat WetGain = params->Gain; + __m128 gain; + ALuint pos; + + if(WetGain < 0.00001f) + return; + + if(OutPos == 0) + WetClickRemoval[0] -= data[0] * WetGain; + + gain = _mm_set1_ps(WetGain); + for(pos = 0;pos < BufferSize-3;pos+=4) + { + const __m128 val4 = _mm_load_ps(&data[pos]); + __m128 wet4 = _mm_load_ps(&WetBuffer[0][OutPos+pos]); + wet4 = _mm_add_ps(wet4, _mm_mul_ps(val4, gain)); + _mm_store_ps(&WetBuffer[0][OutPos+pos], wet4); + } + for(;pos < BufferSize;pos++) + WetBuffer[0][OutPos+pos] += data[pos] * WetGain; + + if(OutPos+pos == SamplesToDo) + WetPendingClicks[0] += data[pos] * WetGain; +} diff --git a/src/eepp/helper/android/openal-soft/Alc/panning.c b/src/eepp/helper/android/openal-soft/Alc/panning.c new file mode 100644 index 000000000..d8191d8d8 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/Alc/panning.c @@ -0,0 +1,450 @@ +/** + * 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, ALfloat SpeakerAngle[MaxChannels], + enum Channel Speaker2Chan[MaxChannels], ALint chans) +{ + char *confkey, *next; + char *layout_str; + char *sep, *end; + enum Channel val; + const char *str; + int i; + + if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str)) + return; + + layout_str = strdup(str); + 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) + { + ERR("Malformed speaker key: %s\n", confkey); + continue; + } + + end = sep - 1; + while(isspace(*end) && end != confkey) + end--; + *(++end) = 0; + + if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0) + val = FrontLeft; + else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0) + val = FrontRight; + else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0) + val = FrontCenter; + else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0) + val = BackLeft; + else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0) + val = BackRight; + else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0) + val = BackCenter; + else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0) + val = SideLeft; + else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0) + val = SideRight; + else + { + ERR("Unknown speaker for %s: \"%s\"\n", name, confkey); + continue; + } + + *(sep++) = 0; + while(isspace(*sep)) + sep++; + + for(i = 0;i < chans;i++) + { + if(Speaker2Chan[i] == val) + { + long angle = strtol(sep, NULL, 10); + if(angle >= -180 && angle <= 180) + SpeakerAngle[i] = angle * F_PI/180.0f; + else + ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle); + break; + } + } + } + free(layout_str); + layout_str = NULL; + + for(i = 0;i < chans;i++) + { + int min = i; + int i2; + + for(i2 = i+1;i2 < chans;i2++) + { + if(SpeakerAngle[i2] < SpeakerAngle[min]) + min = i2; + } + + if(min != i) + { + ALfloat tmpf; + enum Channel tmpc; + + tmpf = SpeakerAngle[i]; + SpeakerAngle[i] = SpeakerAngle[min]; + SpeakerAngle[min] = tmpf; + + tmpc = Speaker2Chan[i]; + Speaker2Chan[i] = Speaker2Chan[min]; + Speaker2Chan[min] = tmpc; + } + } +} + + +/** + * ComputeAngleGains + * + * Sets channel gains based on a given source's angle and its half-width. The + * angle and hwidth parameters are in radians. + */ +ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains) +{ + ALfloat tmpgains[MaxChannels] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + enum Channel Speaker2Chan[MaxChannels]; + ALfloat SpeakerAngle[MaxChannels]; + ALfloat langle, rangle; + ALfloat a; + ALuint i; + + for(i = 0;i < device->NumChan;i++) + Speaker2Chan[i] = device->Speaker2Chan[i]; + for(i = 0;i < device->NumChan;i++) + SpeakerAngle[i] = device->SpeakerAngle[i]; + + /* Some easy special-cases first... */ + if(device->NumChan == 1 || hwidth >= F_PI) + { + /* Full coverage for all speakers. */ + for(i = 0;i < device->NumChan;i++) + { + enum Channel chan = Speaker2Chan[i]; + gains[chan] = ingain; + } + return; + } + if(hwidth <= 0.0f) + { + /* Infinitely small sound point. */ + for(i = 0;i < device->NumChan-1;i++) + { + if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1]) + { + /* Sound is between speakers i and i+1 */ + a = (angle-SpeakerAngle[i]) / + (SpeakerAngle[i+1]-SpeakerAngle[i]); + gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain; + gains[Speaker2Chan[i+1]] = sqrtf( a) * ingain; + return; + } + } + /* Sound is between last and first speakers */ + if(angle < SpeakerAngle[0]) + angle += F_PI*2.0f; + a = (angle-SpeakerAngle[i]) / + (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]); + gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain; + gains[Speaker2Chan[0]] = sqrtf( a) * ingain; + return; + } + + if(fabsf(angle)+hwidth > F_PI) + { + /* The coverage area would go outside of -pi...+pi. Instead, rotate the + * speaker angles so it would be as if angle=0, and keep them wrapped + * within -pi...+pi. */ + if(angle > 0.0f) + { + ALuint done = 0; + ALuint i = 0; + while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI) + i++; + for(done = 0;i < device->NumChan;done++) + { + SpeakerAngle[done] = device->SpeakerAngle[i]-angle; + Speaker2Chan[done] = device->Speaker2Chan[i]; + i++; + } + for(i = 0;done < device->NumChan;i++) + { + SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_PI*2.0f; + Speaker2Chan[done] = device->Speaker2Chan[i]; + done++; + } + } + else + { + /* NOTE: '< device->NumChan' on the iterators is correct here since + * we need to handle index 0. Because the iterators are unsigned, + * they'll underflow and wrap to become 0xFFFFFFFF, which will + * break as expected. */ + ALuint done = device->NumChan-1; + ALuint i = device->NumChan-1; + while(i < device->NumChan && device->SpeakerAngle[i]-angle > F_PI) + i--; + for(done = device->NumChan-1;i < device->NumChan;done--) + { + SpeakerAngle[done] = device->SpeakerAngle[i]-angle; + Speaker2Chan[done] = device->Speaker2Chan[i]; + i--; + } + for(i = device->NumChan-1;done < device->NumChan;i--) + { + SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_PI*2.0f; + Speaker2Chan[done] = device->Speaker2Chan[i]; + done--; + } + } + angle = 0.0f; + } + langle = angle - hwidth; + rangle = angle + hwidth; + + /* First speaker */ + i = 0; + do { + ALuint last = device->NumChan-1; + enum Channel chan = Speaker2Chan[i]; + + if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle) + { + tmpgains[chan] = 1.0f; + continue; + } + + if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle) + { + a = (langle-SpeakerAngle[i]) / + (SpeakerAngle[i+1]-SpeakerAngle[i]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); + } + if(SpeakerAngle[i] > rangle) + { + a = (F_PI*2.0f + rangle-SpeakerAngle[last]) / + (F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); + } + else if(SpeakerAngle[last] < rangle) + { + a = (rangle-SpeakerAngle[last]) / + (F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); + } + } while(0); + + for(i = 1;i < device->NumChan-1;i++) + { + enum Channel chan = Speaker2Chan[i]; + if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle) + { + tmpgains[chan] = 1.0f; + continue; + } + + if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle) + { + a = (langle-SpeakerAngle[i]) / + (SpeakerAngle[i+1]-SpeakerAngle[i]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); + } + if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle) + { + a = (rangle-SpeakerAngle[i-1]) / + (SpeakerAngle[i]-SpeakerAngle[i-1]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); + } + } + + /* Last speaker */ + i = device->NumChan-1; + do { + enum Channel chan = Speaker2Chan[i]; + if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle) + { + tmpgains[Speaker2Chan[i]] = 1.0f; + continue; + } + if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle) + { + a = (rangle-SpeakerAngle[i-1]) / + (SpeakerAngle[i]-SpeakerAngle[i-1]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); + } + if(SpeakerAngle[i] < langle) + { + a = (langle-SpeakerAngle[i]) / + (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); + } + else if(SpeakerAngle[0] > langle) + { + a = (F_PI*2.0f + langle-SpeakerAngle[i]) / + (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]); + tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); + } + } while(0); + + for(i = 0;i < device->NumChan;i++) + { + enum Channel chan = device->Speaker2Chan[i]; + gains[chan] = sqrtf(tmpgains[chan]) * ingain; + } +} + + +ALvoid aluInitPanning(ALCdevice *Device) +{ + const char *layoutname = NULL; + enum Channel *Speaker2Chan; + ALfloat *SpeakerAngle; + + Speaker2Chan = Device->Speaker2Chan; + SpeakerAngle = Device->SpeakerAngle; + switch(Device->FmtChans) + { + case DevFmtMono: + Device->NumChan = 1; + Speaker2Chan[0] = FrontCenter; + SpeakerAngle[0] = F_PI/180.0f * 0.0f; + layoutname = NULL; + break; + + case DevFmtStereo: + Device->NumChan = 2; + Speaker2Chan[0] = FrontLeft; + Speaker2Chan[1] = FrontRight; + SpeakerAngle[0] = F_PI/180.0f * -90.0f; + SpeakerAngle[1] = F_PI/180.0f * 90.0f; + layoutname = "layout_stereo"; + break; + + case DevFmtQuad: + Device->NumChan = 4; + Speaker2Chan[0] = BackLeft; + Speaker2Chan[1] = FrontLeft; + Speaker2Chan[2] = FrontRight; + Speaker2Chan[3] = BackRight; + SpeakerAngle[0] = F_PI/180.0f * -135.0f; + SpeakerAngle[1] = F_PI/180.0f * -45.0f; + SpeakerAngle[2] = F_PI/180.0f * 45.0f; + SpeakerAngle[3] = F_PI/180.0f * 135.0f; + layoutname = "layout_quad"; + break; + + case DevFmtX51: + Device->NumChan = 5; + Speaker2Chan[0] = BackLeft; + Speaker2Chan[1] = FrontLeft; + Speaker2Chan[2] = FrontCenter; + Speaker2Chan[3] = FrontRight; + Speaker2Chan[4] = BackRight; + SpeakerAngle[0] = F_PI/180.0f * -110.0f; + SpeakerAngle[1] = F_PI/180.0f * -30.0f; + SpeakerAngle[2] = F_PI/180.0f * 0.0f; + SpeakerAngle[3] = F_PI/180.0f * 30.0f; + SpeakerAngle[4] = F_PI/180.0f * 110.0f; + layoutname = "layout_surround51"; + break; + + case DevFmtX51Side: + Device->NumChan = 5; + Speaker2Chan[0] = SideLeft; + Speaker2Chan[1] = FrontLeft; + Speaker2Chan[2] = FrontCenter; + Speaker2Chan[3] = FrontRight; + Speaker2Chan[4] = SideRight; + SpeakerAngle[0] = F_PI/180.0f * -90.0f; + SpeakerAngle[1] = F_PI/180.0f * -30.0f; + SpeakerAngle[2] = F_PI/180.0f * 0.0f; + SpeakerAngle[3] = F_PI/180.0f * 30.0f; + SpeakerAngle[4] = F_PI/180.0f * 90.0f; + layoutname = "layout_side51"; + break; + + case DevFmtX61: + Device->NumChan = 6; + Speaker2Chan[0] = SideLeft; + Speaker2Chan[1] = FrontLeft; + Speaker2Chan[2] = FrontCenter; + Speaker2Chan[3] = FrontRight; + Speaker2Chan[4] = SideRight; + Speaker2Chan[5] = BackCenter; + SpeakerAngle[0] = F_PI/180.0f * -90.0f; + SpeakerAngle[1] = F_PI/180.0f * -30.0f; + SpeakerAngle[2] = F_PI/180.0f * 0.0f; + SpeakerAngle[3] = F_PI/180.0f * 30.0f; + SpeakerAngle[4] = F_PI/180.0f * 90.0f; + SpeakerAngle[5] = F_PI/180.0f * 180.0f; + layoutname = "layout_surround61"; + break; + + case DevFmtX71: + Device->NumChan = 7; + Speaker2Chan[0] = BackLeft; + Speaker2Chan[1] = SideLeft; + Speaker2Chan[2] = FrontLeft; + Speaker2Chan[3] = FrontCenter; + Speaker2Chan[4] = FrontRight; + Speaker2Chan[5] = SideRight; + Speaker2Chan[6] = BackRight; + SpeakerAngle[0] = F_PI/180.0f * -150.0f; + SpeakerAngle[1] = F_PI/180.0f * -90.0f; + SpeakerAngle[2] = F_PI/180.0f * -30.0f; + SpeakerAngle[3] = F_PI/180.0f * 0.0f; + SpeakerAngle[4] = F_PI/180.0f * 30.0f; + SpeakerAngle[5] = F_PI/180.0f * 90.0f; + SpeakerAngle[6] = F_PI/180.0f * 150.0f; + layoutname = "layout_surround71"; + break; + } + if(layoutname && Device->Type != Loopback) + SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan); +} diff --git a/src/eepp/helper/android/openal-soft/COPYING b/src/eepp/helper/android/openal-soft/COPYING new file mode 100644 index 000000000..d0c897869 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/COPYING @@ -0,0 +1,484 @@ + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alAuxEffectSlot.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alAuxEffectSlot.h new file mode 100644 index 000000000..4c14b1f7d --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alAuxEffectSlot.h @@ -0,0 +1,61 @@ +#ifndef _AL_AUXEFFECTSLOT_H_ +#define _AL_AUXEFFECTSLOT_H_ + +#include "alMain.h" +#include "alEffect.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALeffectState { + ALvoid (*Destroy)(struct ALeffectState *State); + ALboolean (*DeviceUpdate)(struct ALeffectState *State, ALCdevice *Device); + ALvoid (*Update)(struct ALeffectState *State, ALCdevice *Device, const struct ALeffectslot *Slot); + ALvoid (*Process)(struct ALeffectState *State, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]); +} ALeffectState; + + +typedef struct ALeffectslot +{ + ALeffect effect; + + volatile ALfloat Gain; + volatile ALboolean AuxSendAuto; + + volatile ALenum NeedsUpdate; + ALeffectState *EffectState; + + ALIGN(16) ALfloat WetBuffer[1][BUFFERSIZE]; + + ALfloat ClickRemoval[1]; + ALfloat PendingClicks[1]; + + RefCount ref; + + /* Self ID */ + ALuint id; +} ALeffectslot; + + +ALenum InitEffectSlot(ALeffectslot *slot); +ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context); + +ALeffectState *NoneCreate(void); +ALeffectState *ReverbCreate(void); +ALeffectState *EchoCreate(void); +ALeffectState *ModulatorCreate(void); +ALeffectState *DedicatedCreate(void); + +#define ALeffectState_Destroy(a) ((a)->Destroy((a))) +#define ALeffectState_DeviceUpdate(a,b) ((a)->DeviceUpdate((a),(b))) +#define ALeffectState_Update(a,b,c) ((a)->Update((a),(b),(c))) +#define ALeffectState_Process(a,b,c,d) ((a)->Process((a),(b),(c),(d))) + +ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alBuffer.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alBuffer.h new file mode 100644 index 000000000..8ecc4dd82 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alBuffer.h @@ -0,0 +1,102 @@ +#ifndef _AL_BUFFER_H_ +#define _AL_BUFFER_H_ + +#include "alMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* User formats */ +enum UserFmtType { + UserFmtByte = AL_BYTE_SOFT, + UserFmtUByte = AL_UNSIGNED_BYTE_SOFT, + UserFmtShort = AL_SHORT_SOFT, + UserFmtUShort = AL_UNSIGNED_SHORT_SOFT, + UserFmtInt = AL_INT_SOFT, + UserFmtUInt = AL_UNSIGNED_INT_SOFT, + UserFmtFloat = AL_FLOAT_SOFT, + UserFmtDouble = AL_DOUBLE_SOFT, + UserFmtByte3 = AL_BYTE3_SOFT, + UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT, + UserFmtMulaw, + UserFmtAlaw, + UserFmtIMA4, +}; +enum UserFmtChannels { + UserFmtMono = AL_MONO_SOFT, + UserFmtStereo = AL_STEREO_SOFT, + UserFmtRear = AL_REAR_SOFT, + UserFmtQuad = AL_QUAD_SOFT, + UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */ + UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */ + UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */ +}; + +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 { + FmtByte = UserFmtByte, + FmtShort = UserFmtShort, + FmtFloat = UserFmtFloat, +}; +enum FmtChannels { + FmtMono = UserFmtMono, + FmtStereo = UserFmtStereo, + FmtRear = UserFmtRear, + FmtQuad = UserFmtQuad, + FmtX51 = UserFmtX51, + FmtX61 = UserFmtX61, + FmtX71 = UserFmtX71, +}; + +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 Frequency; + ALenum Format; + ALsizei SampleLen; + + enum FmtChannels FmtChannels; + enum FmtType FmtType; + + enum UserFmtChannels OriginalChannels; + enum UserFmtType OriginalType; + ALsizei OriginalSize; + + ALsizei LoopStart; + ALsizei LoopEnd; + + /* Number of times buffer was attached to a source (deletion can only occur when 0) */ + RefCount ref; + + RWLock lock; + + /* Self ID */ + ALuint id; +} ALbuffer; + +ALvoid ReleaseALBuffers(ALCdevice *device); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alEffect.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alEffect.h new file mode 100644 index 000000000..ba894c8b2 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alEffect.h @@ -0,0 +1,114 @@ +#ifndef _AL_EFFECT_H_ +#define _AL_EFFECT_H_ + +#include "alMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + EAXREVERB = 0, + REVERB, + ECHO, + MODULATOR, + DEDICATED, + + MAX_EFFECTS +}; +extern ALboolean DisabledEffects[MAX_EFFECTS]; + +extern ALfloat ReverbBoost; +extern ALboolean EmulateEAXReverb; + +typedef struct ALeffect +{ + // Effect type (AL_EFFECT_NULL, ...) + ALenum type; + + struct { + // Shared Reverb Properties + ALfloat Density; + ALfloat Diffusion; + ALfloat Gain; + ALfloat GainHF; + ALfloat DecayTime; + ALfloat DecayHFRatio; + ALfloat ReflectionsGain; + ALfloat ReflectionsDelay; + ALfloat LateReverbGain; + ALfloat LateReverbDelay; + ALfloat AirAbsorptionGainHF; + ALfloat RoomRolloffFactor; + ALboolean DecayHFLimit; + + // Additional EAX Reverb Properties + ALfloat GainLF; + ALfloat DecayLFRatio; + ALfloat ReflectionsPan[3]; + ALfloat LateReverbPan[3]; + ALfloat EchoTime; + ALfloat EchoDepth; + ALfloat ModulationTime; + ALfloat ModulationDepth; + ALfloat HFReference; + ALfloat LFReference; + } Reverb; + + struct { + ALfloat Delay; + ALfloat LRDelay; + + ALfloat Damping; + ALfloat Feedback; + + ALfloat Spread; + } Echo; + + struct { + ALfloat Frequency; + ALfloat HighPassCutoff; + ALint Waveform; + } Modulator; + + struct { + ALfloat Gain; + } Dedicated; + + void (*SetParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val); + void (*SetParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals); + void (*SetParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val); + void (*SetParamfv)(struct ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*GetParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *val); + void (*GetParamiv)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals); + void (*GetParamf)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val); + void (*GetParamfv)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals); + + /* Self ID */ + ALuint id; +} ALeffect; + +#define ALeffect_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v))) +#define ALeffect_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v))) +#define ALeffect_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v))) +#define ALeffect_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v))) + +#define ALeffect_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v))) +#define ALeffect_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v))) +#define ALeffect_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v))) +#define ALeffect_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v))) + +static __inline ALboolean IsReverbEffect(ALenum type) +{ return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; } + +ALenum InitEffect(ALeffect *effect); +ALvoid ReleaseALEffects(ALCdevice *device); + +ALvoid LoadReverbPreset(const char *name, ALeffect *effect); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alError.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alError.h new file mode 100644 index 000000000..0ade342d3 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alError.h @@ -0,0 +1,18 @@ +#ifndef _AL_ERROR_H_ +#define _AL_ERROR_H_ + +#include "alMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern ALboolean TrapALError; + +ALvoid alSetError(ALCcontext *Context, ALenum errorCode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alFilter.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alFilter.h new file mode 100644 index 000000000..09cef93c0 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alFilter.h @@ -0,0 +1,90 @@ +#ifndef _AL_FILTER_H_ +#define _AL_FILTER_H_ + +#include "alMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOWPASSFREQREF (5000) + +typedef struct { + ALfloat coeff; +#ifndef _MSC_VER + ALfloat history[0]; +#else + ALfloat history[1]; +#endif +} FILTER; + +static __inline ALfloat lpFilter2P(FILTER *iir, ALuint offset, ALfloat input) +{ + ALfloat *history = &iir->history[offset*2]; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + history[0] = output; + output = output + (history[1]-output)*a; + history[1] = output; + + return output; +} + +static __inline ALfloat lpFilter2PC(const FILTER *iir, ALuint offset, ALfloat input) +{ + const ALfloat *history = &iir->history[offset*2]; + ALfloat a = iir->coeff; + ALfloat output = input; + + output = output + (history[0]-output)*a; + output = output + (history[1]-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) */ +ALfloat lpCoeffCalc(ALfloat g, ALfloat cw); + + +typedef struct ALfilter { + // Filter type (AL_FILTER_NULL, ...) + ALenum type; + + ALfloat Gain; + ALfloat GainHF; + + void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val); + void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); + void (*SetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); + void (*SetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); + + void (*GetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); + void (*GetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); + void (*GetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); + void (*GetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); + + /* Self ID */ + ALuint id; +} ALfilter; + +#define ALfilter_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v))) +#define ALfilter_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v))) +#define ALfilter_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v))) +#define ALfilter_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v))) + +#define ALfilter_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v))) +#define ALfilter_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v))) +#define ALfilter_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v))) +#define ALfilter_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v))) + +ALvoid ReleaseALFilters(ALCdevice *device); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alListener.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alListener.h new file mode 100644 index 000000000..ee07d87cf --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alListener.h @@ -0,0 +1,28 @@ +#ifndef _AL_LISTENER_H_ +#define _AL_LISTENER_H_ + +#include "alMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALlistener { + volatile ALfloat Position[3]; + volatile ALfloat Velocity[3]; + volatile ALfloat Forward[3]; + volatile ALfloat Up[3]; + volatile ALfloat Gain; + volatile ALfloat MetersPerUnit; + + struct { + ALfloat Matrix[4][4]; + ALfloat Velocity[3]; + } Params; +} ALlistener; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alMain.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alMain.h new file mode 100644 index 000000000..ec44bdeeb --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alMain.h @@ -0,0 +1,884 @@ +#ifndef AL_MAIN_H +#define AL_MAIN_H + +#include +#include +#include +#include +#include + +#ifdef HAVE_FENV_H +#include +#endif + +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" + +#ifndef AL_SOFT_deferred_updates +#define AL_SOFT_deferred_updates 1 +#define AL_DEFERRED_UPDATES_SOFT 0xC002 +typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); +typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void); +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void); +#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 + +typedef ptrdiff_t ALintptrEXT; +typedef ptrdiff_t ALsizeiptrEXT; + +#define MAKEU64(x,y) (((ALuint64)(x)<<32)|(ALuint64)(y)) + +#ifdef HAVE_GCC_FORMAT +#define PRINTF_STYLE(x, y) __attribute__((format(printf, (x), (y)))) +#else +#define PRINTF_STYLE(x, y) +#endif + + +static const union { + ALuint u; + ALubyte b[sizeof(ALuint)]; +} EndianTest = { 1 }; +#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) + +#define COUNTOF(x) (sizeof((x))/sizeof((x)[0])) + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +typedef DWORD pthread_key_t; +int pthread_key_create(pthread_key_t *key, void (*callback)(void*)); +int pthread_key_delete(pthread_key_t key); +void *pthread_getspecific(pthread_key_t key); +int pthread_setspecific(pthread_key_t key, void *val); + +#define HAVE_DYNLOAD 1 +void *LoadLib(const char *name); +void CloseLib(void *handle); +void *GetSymbol(void *handle, const char *name); + +WCHAR *strdupW(const WCHAR *str); + +typedef LONG pthread_once_t; +#define PTHREAD_ONCE_INIT 0 +void pthread_once(pthread_once_t *once, void (*callback)(void)); + +static __inline int sched_yield(void) +{ SwitchToThread(); return 0; } + +#else + +#include +#include +#include +#include +#include +#include + +#define IsBadWritePtr(a,b) ((a) == NULL && (b) != 0) + +typedef pthread_mutex_t CRITICAL_SECTION; +void InitializeCriticalSection(CRITICAL_SECTION *cs); +void DeleteCriticalSection(CRITICAL_SECTION *cs); +void EnterCriticalSection(CRITICAL_SECTION *cs); +void LeaveCriticalSection(CRITICAL_SECTION *cs); + +ALuint timeGetTime(void); +void Sleep(ALuint t); + +#if defined(HAVE_DLFCN_H) +#define HAVE_DYNLOAD 1 +void *LoadLib(const char *name); +void CloseLib(void *handle); +void *GetSymbol(void *handle, const char *name); +#endif + +#endif + +typedef void *volatile XchgPtr; + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) +typedef ALuint RefCount; +static __inline RefCount IncrementRef(volatile RefCount *ptr) +{ return __sync_add_and_fetch(ptr, 1); } +static __inline RefCount DecrementRef(volatile RefCount *ptr) +{ return __sync_sub_and_fetch(ptr, 1); } + +static __inline int ExchangeInt(volatile int *ptr, int newval) +{ + return __sync_lock_test_and_set(ptr, newval); +} +static __inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + return __sync_lock_test_and_set(ptr, newval); +} +static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +static __inline int xaddl(volatile int *dest, int incr) +{ + int ret; + __asm__ __volatile__("lock; xaddl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (incr) + : "memory"); + return ret; +} + +typedef int RefCount; +static __inline RefCount IncrementRef(volatile RefCount *ptr) +{ return xaddl(ptr, 1)+1; } +static __inline RefCount DecrementRef(volatile RefCount *ptr) +{ return xaddl(ptr, -1)-1; } + +static __inline int ExchangeInt(volatile int *dest, int newval) +{ + int ret; + __asm__ __volatile__("lock; xchgl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (newval) + : "memory"); + return ret; +} + +static __inline ALboolean CompExchangeInt(volatile int *dest, int oldval, int newval) +{ + int ret; + __asm__ __volatile__("lock; cmpxchgl %2,(%1)" + : "=a" (ret) + : "r" (dest), "r" (newval), "0" (oldval) + : "memory"); + return ret == oldval; +} + +static __inline void *ExchangePtr(XchgPtr *dest, void *newval) +{ + void *ret; + __asm__ __volatile__( +#ifdef __i386__ + "lock; xchgl %0,(%1)" +#else + "lock; xchgq %0,(%1)" +#endif + : "=r" (ret) + : "r" (dest), "0" (newval) + : "memory" + ); + return ret; +} + +static __inline ALboolean CompExchangePtr(XchgPtr *dest, void *oldval, void *newval) +{ + void *ret; + __asm__ __volatile__( +#ifdef __i386__ + "lock; cmpxchgl %2,(%1)" +#else + "lock; cmpxchgq %2,(%1)" +#endif + : "=a" (ret) + : "r" (dest), "r" (newval), "0" (oldval) + : "memory" + ); + return ret == oldval; +} + +#elif defined(_WIN32) + +typedef LONG RefCount; +static __inline RefCount IncrementRef(volatile RefCount *ptr) +{ return InterlockedIncrement(ptr); } +static __inline RefCount DecrementRef(volatile RefCount *ptr) +{ return InterlockedDecrement(ptr); } + +extern ALbyte LONG_size_does_not_match_int[(sizeof(LONG)==sizeof(int))?1:-1]; + +static __inline int ExchangeInt(volatile int *ptr, int newval) +{ + union { + volatile int *i; + volatile LONG *l; + } u = { ptr }; + return InterlockedExchange(u.l, newval); +} +static __inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + return InterlockedExchangePointer(ptr, newval); +} +static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + union { + volatile int *i; + volatile LONG *l; + } u = { ptr }; + return InterlockedCompareExchange(u.l, newval, oldval) == oldval; +} +static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return InterlockedCompareExchangePointer(ptr, newval, oldval) == oldval; +} + +#elif defined(__APPLE__) + +#include + +typedef int32_t RefCount; +static __inline RefCount IncrementRef(volatile RefCount *ptr) +{ return OSAtomicIncrement32Barrier(ptr); } +static __inline RefCount DecrementRef(volatile RefCount *ptr) +{ return OSAtomicDecrement32Barrier(ptr); } + +static __inline int ExchangeInt(volatile int *ptr, int newval) +{ + /* Really? No regular old atomic swap? */ + int oldval; + do { + oldval = *ptr; + } while(!OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr)); + return oldval; +} +static __inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + void *oldval; + do { + oldval = *ptr; + } while(!OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr)); + return oldval; +} +static __inline ALboolean CompExchangeInt(volatile int *ptr, int oldval, int newval) +{ + return OSAtomicCompareAndSwap32Barrier(oldval, newval, ptr); +} +static __inline ALboolean CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval) +{ + return OSAtomicCompareAndSwapPtrBarrier(oldval, newval, ptr); +} + +#else +#error "No atomic functions available on this platform!" +typedef ALuint RefCount; +#endif + + +typedef struct { + volatile RefCount read_count; + volatile RefCount write_count; + volatile ALenum read_lock; + volatile ALenum read_entry_lock; + volatile ALenum write_lock; +} RWLock; + +void RWLockInit(RWLock *lock); +void ReadLock(RWLock *lock); +void ReadUnlock(RWLock *lock); +void WriteLock(RWLock *lock); +void WriteUnlock(RWLock *lock); + + +typedef struct UIntMap { + struct { + ALuint key; + ALvoid *value; + } *array; + ALsizei size; + ALsizei maxsize; + ALsizei limit; + RWLock lock; +} UIntMap; +extern UIntMap TlsDestructor; + +void InitUIntMap(UIntMap *map, ALsizei limit); +void ResetUIntMap(UIntMap *map); +ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value); +ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key); +ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key); + +static __inline void LockUIntMapRead(UIntMap *map) +{ ReadLock(&map->lock); } +static __inline void UnlockUIntMapRead(UIntMap *map) +{ ReadUnlock(&map->lock); } +static __inline void LockUIntMapWrite(UIntMap *map) +{ WriteLock(&map->lock); } +static __inline void UnlockUIntMapWrite(UIntMap *map) +{ WriteUnlock(&map->lock); } + + +#ifdef __cplusplus +extern "C" { +#endif + +struct Hrtf; + + +#define DEFAULT_OUTPUT_RATE (44100) +#define MIN_OUTPUT_RATE (8000) + + +// Find the next power-of-2 for non-power-of-2 numbers. +static __inline ALuint NextPowerOf2(ALuint value) +{ + if(value > 0) + { + value--; + value |= value>>1; + value |= value>>2; + value |= value>>4; + value |= value>>8; + value |= value>>16; + } + return value+1; +} + +/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero + * mode. */ +static __inline ALint fastf2i(ALfloat f) +{ +#ifdef HAVE_LRINTF + return lrintf(f); +#elif defined(_MSC_VER) && defined(_M_IX86) + ALint i; + __asm fld f + __asm fistp i + return i; +#else + return (ALint)f; +#endif +} + +/* Fast float-to-uint conversion. Assumes the FPU is already in round-to-zero + * mode. */ +static __inline ALuint fastf2u(ALfloat f) +{ return fastf2i(f); } + + +enum DevProbe { + ALL_DEVICE_PROBE, + CAPTURE_DEVICE_PROBE +}; + +typedef struct { + ALCenum (*OpenPlayback)(ALCdevice*, const ALCchar*); + void (*ClosePlayback)(ALCdevice*); + ALCboolean (*ResetPlayback)(ALCdevice*); + ALCboolean (*StartPlayback)(ALCdevice*); + void (*StopPlayback)(ALCdevice*); + + ALCenum (*OpenCapture)(ALCdevice*, const ALCchar*); + void (*CloseCapture)(ALCdevice*); + void (*StartCapture)(ALCdevice*); + void (*StopCapture)(ALCdevice*); + ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint); + ALCuint (*AvailableSamples)(ALCdevice*); + + void (*Lock)(ALCdevice*); + void (*Unlock)(ALCdevice*); + + ALint64 (*GetLatency)(ALCdevice*); +} BackendFuncs; + +struct BackendInfo { + const char *name; + ALCboolean (*Init)(BackendFuncs*); + void (*Deinit)(void); + void (*Probe)(enum DevProbe); + BackendFuncs Funcs; +}; + +ALCboolean alc_alsa_init(BackendFuncs *func_list); +void alc_alsa_deinit(void); +void alc_alsa_probe(enum DevProbe type); +ALCboolean alc_oss_init(BackendFuncs *func_list); +void alc_oss_deinit(void); +void alc_oss_probe(enum DevProbe type); +ALCboolean alc_solaris_init(BackendFuncs *func_list); +void alc_solaris_deinit(void); +void alc_solaris_probe(enum DevProbe type); +ALCboolean alc_sndio_init(BackendFuncs *func_list); +void alc_sndio_deinit(void); +void alc_sndio_probe(enum DevProbe type); +ALCboolean alcMMDevApiInit(BackendFuncs *func_list); +void alcMMDevApiDeinit(void); +void alcMMDevApiProbe(enum DevProbe type); +ALCboolean alcDSoundInit(BackendFuncs *func_list); +void alcDSoundDeinit(void); +void alcDSoundProbe(enum DevProbe type); +ALCboolean alcWinMMInit(BackendFuncs *FuncList); +void alcWinMMDeinit(void); +void alcWinMMProbe(enum DevProbe type); +ALCboolean alc_pa_init(BackendFuncs *func_list); +void alc_pa_deinit(void); +void alc_pa_probe(enum DevProbe type); +ALCboolean alc_wave_init(BackendFuncs *func_list); +void alc_wave_deinit(void); +void alc_wave_probe(enum DevProbe type); +ALCboolean alc_pulse_init(BackendFuncs *func_list); +void alc_pulse_deinit(void); +void alc_pulse_probe(enum DevProbe type); +ALCboolean alc_ca_init(BackendFuncs *func_list); +void alc_ca_deinit(void); +void alc_ca_probe(enum DevProbe type); +ALCboolean alc_opensl_init(BackendFuncs *func_list); +void alc_opensl_deinit(void); +void alc_opensl_probe(enum DevProbe type); +ALCboolean alc_null_init(BackendFuncs *func_list); +void alc_null_deinit(void); +void alc_null_probe(enum DevProbe type); +ALCboolean alc_loopback_init(BackendFuncs *func_list); +void alc_loopback_deinit(void); +void alc_loopback_probe(enum DevProbe type); + + +enum DistanceModel { + InverseDistanceClamped = AL_INVERSE_DISTANCE_CLAMPED, + LinearDistanceClamped = AL_LINEAR_DISTANCE_CLAMPED, + ExponentDistanceClamped = AL_EXPONENT_DISTANCE_CLAMPED, + InverseDistance = AL_INVERSE_DISTANCE, + LinearDistance = AL_LINEAR_DISTANCE, + ExponentDistance = AL_EXPONENT_DISTANCE, + DisableDistance = AL_NONE, + + DefaultDistanceModel = InverseDistanceClamped +}; + +enum Resampler { + PointResampler, + LinearResampler, + CubicResampler, + + ResamplerMax, +}; + +enum Channel { + FrontLeft = 0, + FrontRight, + FrontCenter, + LFE, + BackLeft, + BackRight, + BackCenter, + SideLeft, + SideRight, + + MaxChannels, +}; + + +/* Device formats */ +enum DevFmtType { + DevFmtByte = ALC_BYTE_SOFT, + DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, + DevFmtShort = ALC_SHORT_SOFT, + DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, + DevFmtInt = ALC_INT_SOFT, + DevFmtUInt = ALC_UNSIGNED_INT_SOFT, + DevFmtFloat = ALC_FLOAT_SOFT, + + DevFmtTypeDefault = DevFmtFloat +}; +enum DevFmtChannels { + DevFmtMono = ALC_MONO_SOFT, + DevFmtStereo = ALC_STEREO_SOFT, + DevFmtQuad = ALC_QUAD_SOFT, + DevFmtX51 = ALC_5POINT1_SOFT, + DevFmtX61 = ALC_6POINT1_SOFT, + DevFmtX71 = ALC_7POINT1_SOFT, + + /* Similar to 5.1, except using the side channels instead of back */ + DevFmtX51Side = 0x80000000, + + DevFmtChannelsDefault = DevFmtStereo +}; + +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); +} + + +extern const struct EffectList { + const char *name; + int type; + const char *ename; + ALenum val; +} EffectList[]; + + +enum DeviceType { + Playback, + Capture, + Loopback +}; + + +/* Size for temporary storage of buffer data, in ALfloats. Larger values need + * more memory, while smaller values may need more iterations. The value needs + * to be a sensible size, however, as it constrains the max stepping value used + * for mixing, as well as the maximum number of samples per mixing iteration. + * + * The mixer requires being able to do two samplings per mixing loop. With the + * cubic resampler (which requires 3 padding samples), this limits a 2048 + * buffer size to about 2044. This means that buffer_freq*source_pitch cannot + * exceed device_freq*2044 for a 32-bit buffer. + */ +#ifndef BUFFERSIZE +#define BUFFERSIZE 2048 +#endif + + +struct ALCdevice_struct +{ + volatile RefCount ref; + + ALCboolean Connected; + enum DeviceType Type; + + CRITICAL_SECTION Mutex; + + ALuint Frequency; + ALuint UpdateSize; + ALuint NumUpdates; + enum DevFmtChannels FmtChans; + enum DevFmtType FmtType; + + ALCchar *DeviceName; + + volatile 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; + + /* HRTF filter tables */ + const struct Hrtf *Hrtf; + + // Stereo-to-binaural filter + struct bs2b *Bs2b; + ALCint Bs2bLevel; + + // Device flags + ALuint Flags; + + ALuint ChannelOffsets[MaxChannels]; + + enum Channel Speaker2Chan[MaxChannels]; + ALfloat SpeakerAngle[MaxChannels]; + ALuint NumChan; + + /* Temp storage used for mixing. +1 for the predictive sample. */ + ALIGN(16) ALfloat SampleData1[BUFFERSIZE+1]; + ALIGN(16) ALfloat SampleData2[BUFFERSIZE+1]; + + // Dry path buffer mix + ALIGN(16) ALfloat DryBuffer[MaxChannels][BUFFERSIZE]; + + ALIGN(16) ALfloat ClickRemoval[MaxChannels]; + ALIGN(16) ALfloat PendingClicks[MaxChannels]; + + /* Default effect slot */ + struct ALeffectslot *DefaultSlot; + + // Contexts created on this device + ALCcontext *volatile ContextList; + + BackendFuncs *Funcs; + void *ExtraData; // For the backend's use + + ALCdevice *volatile 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_StartPlayback(a) ((a)->Funcs->StartPlayback((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))) +#define ALCdevice_Lock(a) ((a)->Funcs->Lock((a))) +#define ALCdevice_Unlock(a) ((a)->Funcs->Unlock((a))) +#define ALCdevice_GetLatency(a) ((a)->Funcs->GetLatency((a))) + +// Frequency was requested by the app or config file +#define DEVICE_FREQUENCY_REQUEST (1<<1) +// Channel configuration was requested by the config file +#define DEVICE_CHANNELS_REQUEST (1<<2) +// Sample type was requested by the config file +#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3) + +// Stereo sources cover 120-degree angles around +/-90 +#define DEVICE_WIDE_STEREO (1<<16) + +// Specifies if the device is currently running +#define DEVICE_RUNNING (1<<31) + +/* Invalid channel offset */ +#define INVALID_OFFSET (~0u) + + +#define LookupBuffer(m, k) ((struct ALbuffer*)LookupUIntMapKey(&(m)->BufferMap, (k))) +#define LookupEffect(m, k) ((struct ALeffect*)LookupUIntMapKey(&(m)->EffectMap, (k))) +#define LookupFilter(m, k) ((struct ALfilter*)LookupUIntMapKey(&(m)->FilterMap, (k))) +#define RemoveBuffer(m, k) ((struct ALbuffer*)RemoveUIntMapKey(&(m)->BufferMap, (k))) +#define RemoveEffect(m, k) ((struct ALeffect*)RemoveUIntMapKey(&(m)->EffectMap, (k))) +#define RemoveFilter(m, k) ((struct ALfilter*)RemoveUIntMapKey(&(m)->FilterMap, (k))) + + +struct ALCcontext_struct +{ + volatile RefCount ref; + + struct ALlistener *Listener; + + UIntMap SourceMap; + UIntMap EffectSlotMap; + + ALenum LastError; + + volatile ALenum UpdateSources; + + volatile enum DistanceModel DistanceModel; + volatile ALboolean SourceDistanceModel; + + volatile ALfloat DopplerFactor; + volatile ALfloat DopplerVelocity; + volatile ALfloat SpeedOfSound; + volatile ALenum DeferUpdates; + + struct ALsource **ActiveSources; + ALsizei ActiveSourceCount; + ALsizei MaxActiveSources; + + struct ALeffectslot **ActiveEffectSlots; + ALsizei ActiveEffectSlotCount; + ALsizei MaxActiveEffectSlots; + + ALCdevice *Device; + const ALCchar *ExtensionList; + + ALCcontext *volatile next; +}; + +#define LookupSource(m, k) ((struct ALsource*)LookupUIntMapKey(&(m)->SourceMap, (k))) +#define LookupEffectSlot(m, k) ((struct ALeffectslot*)LookupUIntMapKey(&(m)->EffectSlotMap, (k))) +#define RemoveSource(m, k) ((struct ALsource*)RemoveUIntMapKey(&(m)->SourceMap, (k))) +#define RemoveEffectSlot(m, k) ((struct ALeffectslot*)RemoveUIntMapKey(&(m)->EffectSlotMap, (k))) + + +ALCcontext *GetContextRef(void); + +void ALCcontext_IncRef(ALCcontext *context); +void ALCcontext_DecRef(ALCcontext *context); + +void AppendAllDevicesList(const ALCchar *name); +void AppendCaptureDeviceList(const ALCchar *name); + +void ALCdevice_LockDefault(ALCdevice *device); +void ALCdevice_UnlockDefault(ALCdevice *device); +ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device); + +static __inline void LockContext(ALCcontext *context) +{ ALCdevice_Lock(context->Device); } +static __inline void UnlockContext(ALCcontext *context) +{ ALCdevice_Unlock(context->Device); } + + +void *al_malloc(size_t alignment, size_t size); +void *al_calloc(size_t alignment, size_t size); +void al_free(void *ptr); + +typedef struct { + int state; +#ifdef HAVE_SSE + int sse_state; +#endif +} FPUCtl; +void SetMixerFPUMode(FPUCtl *ctl); +void RestoreFPUMode(const FPUCtl *ctl); + +ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr); +ALuint StopThread(ALvoid *thread); + +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 GetConfigValueBool(const char *blockName, const char *keyName, int def); +int ConfigValueStr(const char *blockName, const char *keyName, const char **ret); +int ConfigValueInt(const char *blockName, const char *keyName, int *ret); +int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret); +int ConfigValueFloat(const char *blockName, const char *keyName, float *ret); + +void SetRTPriority(void); + +void SetDefaultChannelOrder(ALCdevice *device); +void SetDefaultWFXChannelOrder(ALCdevice *device); + +const ALCchar *DevFmtTypeString(enum DevFmtType type); +const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans); + +#define HRIR_BITS (7) +#define HRIR_LENGTH (1<= LogRef) \ + AL_PRINT("(--)", __VA_ARGS__); \ +} while(0) + +#define TRACE(...) do { \ + if(LogLevel >= LogTrace) \ + AL_PRINT("(II)", __VA_ARGS__); \ +} while(0) + +#define WARN(...) do { \ + if(LogLevel >= LogWarning) \ + AL_PRINT("(WW)", __VA_ARGS__); \ +} while(0) + +#define ERR(...) do { \ + if(LogLevel >= LogError) \ + AL_PRINT("(EE)", __VA_ARGS__); \ +} while(0) + + +extern ALint RTPrioLevel; + + +extern ALuint CPUCapFlags; +enum { + CPU_CAP_SSE = 1<<0, + CPU_CAP_NEON = 1<<1, +}; + +void FillCPUCaps(ALuint capfilter); + + +/** + * Starts a try block. Must not be nested within another try block within the + * same function. + */ +#define al_try do { \ + int _al_err=0; \ +_al_try_label: \ + if(_al_err == 0) +/** + * After a try or another catch block, runs the next block if the given value + * was thrown. + */ +#define al_catch(val) else if(_al_err == (val)) +/** + * After a try or catch block, runs the next block for any value thrown and not + * caught. + */ +#define al_catchany() else +/** Marks the end of the final catch (or the try) block. */ +#define al_endtry } while(0) + +/** + * The given integer value is "thrown" so as to be caught by a catch block. + * Must be called in a try block within the same function. The value must not + * be 0. + */ +#define al_throw(e) do { \ + _al_err = (e); \ + assert(_al_err != 0); \ + goto _al_try_label; \ +} while(0) +/** Sets an AL error on the given context, before throwing the error code. */ +#define al_throwerr(ctx, err) do { \ + alSetError((ctx), (err)); \ + al_throw((err)); \ +} while(0) + +/** + * Throws an AL_INVALID_VALUE error with the given ctx if the given condition + * is false. + */ +#define CHECK_VALUE(ctx, cond) do { \ + if(!(cond)) \ + al_throwerr((ctx), AL_INVALID_VALUE); \ +} while(0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alSource.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alSource.h new file mode 100644 index 000000000..d8ffc9aa8 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alSource.h @@ -0,0 +1,190 @@ +#ifndef _AL_SOURCE_H_ +#define _AL_SOURCE_H_ + +#define MAX_SENDS 4 + +#include "alMain.h" +#include "alu.h" +#include "alFilter.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SRC_HISTORY_BITS (6) +#define SRC_HISTORY_LENGTH (1<Update(s,a)) + +ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); +ALboolean ApplyOffset(ALsource *Source); + +ALvoid ReleaseALSources(ALCcontext *Context); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alThunk.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alThunk.h new file mode 100644 index 000000000..adc77dec9 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alThunk.h @@ -0,0 +1,20 @@ +#ifndef ALTHUNK_H +#define ALTHUNK_H + +#include "alMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void ThunkInit(void); +void ThunkExit(void); +ALenum NewThunkEntry(ALuint *index); +void FreeThunkEntry(ALuint index); + +#ifdef __cplusplus +} +#endif + +#endif //ALTHUNK_H + diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/alu.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alu.h new file mode 100644 index 000000000..01d3ca29e --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/alu.h @@ -0,0 +1,127 @@ +#ifndef _ALU_H_ +#define _ALU_H_ + +#include "alMain.h" + +#include +#include +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_IEEEFP_H +#include +#endif + + +#define F_PI (3.14159265358979323846f) /* pi */ +#define F_PI_2 (1.57079632679489661923f) /* pi/2 */ + +#ifndef FLT_EPSILON +#define FLT_EPSILON (1.19209290e-07f) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +struct ALsource; +struct ALbuffer; +struct DirectParams; +struct SendParams; + +typedef void (*ResamplerFunc)(const ALfloat *src, ALuint frac, ALuint increment, + ALfloat *RESTRICT dst, ALuint dstlen); + +typedef ALvoid (*DryMixerFunc)(const struct DirectParams *params, + const ALfloat *RESTRICT data, ALuint srcchan, + ALuint OutPos, ALuint SamplesToDo, + ALuint BufferSize); +typedef ALvoid (*WetMixerFunc)(const struct SendParams *params, + const ALfloat *RESTRICT data, + ALuint OutPos, ALuint SamplesToDo, + ALuint BufferSize); + + +#define SPEEDOFSOUNDMETRESPERSEC (343.3f) +#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ + +#define FRACTIONBITS (14) +#define FRACTIONONE (1< b) ? b : a); } +static __inline ALfloat maxf(ALfloat a, ALfloat b) +{ return ((a > b) ? a : b); } +static __inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max) +{ return minf(max, maxf(min, val)); } + +static __inline ALuint minu(ALuint a, ALuint b) +{ return ((a > b) ? b : a); } +static __inline ALuint maxu(ALuint a, ALuint b) +{ return ((a > b) ? a : b); } +static __inline ALuint clampu(ALuint val, ALuint min, ALuint max) +{ return minu(max, maxu(min, val)); } + +static __inline ALint mini(ALint a, ALint b) +{ return ((a > b) ? b : a); } +static __inline ALint maxi(ALint a, ALint b) +{ return ((a > b) ? a : b); } +static __inline ALint clampi(ALint val, ALint min, ALint max) +{ return mini(max, maxi(min, val)); } + +static __inline ALint64 mini64(ALint64 a, ALint64 b) +{ return ((a > b) ? b : a); } +static __inline ALint64 maxi64(ALint64 a, ALint64 b) +{ return ((a > b) ? a : b); } +static __inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max) +{ return mini64(max, maxi64(min, val)); } + +static __inline ALuint64 minu64(ALuint64 a, ALuint64 b) +{ return ((a > b) ? b : a); } +static __inline ALuint64 maxu64(ALuint64 a, ALuint64 b) +{ return ((a > b) ? a : b); } +static __inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) +{ return minu64(max, maxu64(min, val)); } + + +static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) +{ + return val1 + (val2-val1)*mu; +} +static __inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu) +{ + ALfloat mu2 = mu*mu; + ALfloat a0 = -0.5f*val0 + 1.5f*val1 + -1.5f*val2 + 0.5f*val3; + ALfloat a1 = val0 + -2.5f*val1 + 2.0f*val2 + -0.5f*val3; + ALfloat a2 = -0.5f*val0 + 0.5f*val2; + ALfloat a3 = val1; + + return a0*mu*mu2 + a1*mu2 + a2*mu + a3; +} + + +ALvoid aluInitPanning(ALCdevice *Device); + +ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains); + +ALvoid CalcSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext); +ALvoid CalcNonAttnSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext); + +ALvoid MixSource(struct ALsource *Source, ALCdevice *Device, ALuint SamplesToDo); + +ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); +/* Caller must lock the device. */ +ALvoid aluHandleDisconnect(ALCdevice *device); + +extern ALfloat ConeScale; +extern ALfloat ZScale; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/Include/bs2b.h b/src/eepp/helper/android/openal-soft/OpenAL32/Include/bs2b.h new file mode 100644 index 000000000..0f06b1ca5 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/Include/bs2b.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2005 Boris Mikhaylov + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BS2B_H +#define BS2B_H + +/* Number of crossfeed levels */ +#define BS2B_CLEVELS 3 + +/* Normal crossfeed levels */ +#define BS2B_HIGH_CLEVEL 3 +#define BS2B_MIDDLE_CLEVEL 2 +#define BS2B_LOW_CLEVEL 1 + +/* Easy crossfeed levels */ +#define BS2B_HIGH_ECLEVEL BS2B_HIGH_CLEVEL + BS2B_CLEVELS +#define BS2B_MIDDLE_ECLEVEL BS2B_MIDDLE_CLEVEL + BS2B_CLEVELS +#define BS2B_LOW_ECLEVEL BS2B_LOW_CLEVEL + BS2B_CLEVELS + +/* Default crossfeed levels */ +#define BS2B_DEFAULT_CLEVEL BS2B_HIGH_ECLEVEL +/* Default sample rate (Hz) */ +#define BS2B_DEFAULT_SRATE 44100 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct bs2b { + int level; /* Crossfeed level */ + int srate; /* Sample rate (Hz) */ + + /* Lowpass IIR filter coefficients */ + double a0_lo; + double b1_lo; + + /* Highboost IIR filter coefficients */ + double a0_hi; + double a1_hi; + double b1_hi; + + /* Global gain against overloading */ + float gain; + + /* Buffer of last filtered sample. + * [0] - first channel, [1] - second channel + */ + struct t_last_sample { + double asis[2]; + double lo[2]; + double hi[2]; + } last_sample; +}; + +/* Clear buffers and set new coefficients with new crossfeed level value. + * level - crossfeed level of *LEVEL values. + */ +void bs2b_set_level(struct bs2b *bs2b, int level); + +/* Return current crossfeed level value */ +int bs2b_get_level(struct bs2b *bs2b); + +/* Clear buffers and set new coefficients with new sample rate value. + * srate - sample rate by Hz. + */ +void bs2b_set_srate(struct bs2b *bs2b, int srate); + +/* Return current sample rate value */ +int bs2b_get_srate(struct bs2b *bs2b); + +/* Clear buffer */ +void bs2b_clear(struct bs2b *bs2b); + +/* Crossfeeds one stereo sample that are pointed by sample. + * [0] - first channel, [1] - second channel. + * Returns crossfided samle by sample pointer. + */ + +/* sample poits to floats */ +void bs2b_cross_feed(struct bs2b *bs2b, float *sample); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* BS2B_H */ diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alAuxEffectSlot.c b/src/eepp/helper/android/openal-soft/OpenAL32/alAuxEffectSlot.c new file mode 100644 index 000000000..230fe5fcd --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alAuxEffectSlot.c @@ -0,0 +1,609 @@ +/** + * 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 "alAuxEffectSlot.h" +#include "alThunk.h" +#include "alError.h" +#include "alSource.h" + + +static ALenum AddEffectSlotArray(ALCcontext *Context, ALsizei count, const ALuint *slots); +static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot); + + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots) +{ + ALCcontext *Context; + ALsizei cur = 0; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALenum err; + + CHECK_VALUE(Context, n >= 0); + for(cur = 0;cur < n;cur++) + { + ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot)); + err = AL_OUT_OF_MEMORY; + if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR) + { + al_free(slot); + al_throwerr(Context, err); + break; + } + + err = NewThunkEntry(&slot->id); + if(err == AL_NO_ERROR) + err = InsertUIntMapEntry(&Context->EffectSlotMap, slot->id, slot); + if(err != AL_NO_ERROR) + { + FreeThunkEntry(slot->id); + ALeffectState_Destroy(slot->EffectState); + al_free(slot); + + al_throwerr(Context, err); + } + + effectslots[cur] = slot->id; + } + err = AddEffectSlotArray(Context, n, effectslots); + if(err != AL_NO_ERROR) + al_throwerr(Context, err); + } + al_catchany() + { + if(cur > 0) + alDeleteAuxiliaryEffectSlots(cur, effectslots); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) +{ + ALCcontext *Context; + ALeffectslot *slot; + ALsizei i; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if((slot=LookupEffectSlot(Context, effectslots[i])) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + if(slot->ref != 0) + al_throwerr(Context, AL_INVALID_OPERATION); + } + + // All effectslots are valid + for(i = 0;i < n;i++) + { + if((slot=RemoveEffectSlot(Context, effectslots[i])) == NULL) + continue; + FreeThunkEntry(slot->id); + + RemoveEffectSlotArray(Context, slot); + ALeffectState_Destroy(slot->EffectState); + + memset(slot, 0, sizeof(*slot)); + al_free(slot); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + result = (LookupEffectSlot(Context, effectslot) ? AL_TRUE : AL_FALSE); + + ALCcontext_DecRef(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint value) +{ + ALCcontext *Context; + ALeffectslot *Slot; + ALeffect *effect = NULL; + ALenum err; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if((Slot=LookupEffectSlot(Context, effectslot)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + CHECK_VALUE(Context, value == 0 || (effect=LookupEffect(device, value)) != NULL); + + err = InitializeEffect(device, Slot, effect); + if(err != AL_NO_ERROR) + al_throwerr(Context, err); + Context->UpdateSources = AL_TRUE; + break; + + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + CHECK_VALUE(Context, value == AL_TRUE || value == AL_FALSE); + + Slot->AuxSendAuto = value; + Context->UpdateSources = AL_TRUE; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *values) +{ + ALCcontext *Context; + + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + alAuxiliaryEffectSloti(effectslot, param, values[0]); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + if(LookupEffectSlot(Context, effectslot) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat value) +{ + ALCcontext *Context; + ALeffectslot *Slot; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + if((Slot=LookupEffectSlot(Context, effectslot)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + case AL_EFFECTSLOT_GAIN: + CHECK_VALUE(Context, value >= 0.0f && value <= 1.0f); + + Slot->Gain = value; + Slot->NeedsUpdate = AL_TRUE; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alAuxiliaryEffectSlotf(effectslot, param, values[0]); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + if(LookupEffectSlot(Context, effectslot) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALeffectslot *Slot; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + if((Slot=LookupEffectSlot(Context, effectslot)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + *value = Slot->effect.id; + break; + + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + *value = Slot->AuxSendAuto; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *values) +{ + ALCcontext *Context; + + switch(param) + { + case AL_EFFECTSLOT_EFFECT: + case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO: + alGetAuxiliaryEffectSloti(effectslot, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + if(LookupEffectSlot(Context, effectslot) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALeffectslot *Slot; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + if((Slot=LookupEffectSlot(Context, effectslot)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + case AL_EFFECTSLOT_GAIN: + *value = Slot->Gain; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + + switch(param) + { + case AL_EFFECTSLOT_GAIN: + alGetAuxiliaryEffectSlotf(effectslot, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + if(LookupEffectSlot(Context, effectslot) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(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, ALCdevice *Device, const ALeffectslot *Slot) +{ + (void)State; + (void)Device; + (void)Slot; +} +static ALvoid NoneProcess(ALeffectState *State, ALuint SamplesToDo, const ALfloat *RESTRICT SamplesIn, ALfloat (*RESTRICT SamplesOut)[BUFFERSIZE]) +{ + (void)State; + (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 RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot) +{ + ALeffectslot **slotlist, **slotlistend; + + LockContext(Context); + slotlist = Context->ActiveEffectSlots; + slotlistend = slotlist + Context->ActiveEffectSlotCount; + while(slotlist != slotlistend) + { + if(*slotlist == slot) + { + *slotlist = *(--slotlistend); + Context->ActiveEffectSlotCount--; + break; + } + slotlist++; + } + UnlockContext(Context); +} + +static ALenum AddEffectSlotArray(ALCcontext *Context, ALsizei count, const ALuint *slots) +{ + ALsizei i; + + LockContext(Context); + if(count > Context->MaxActiveEffectSlots-Context->ActiveEffectSlotCount) + { + ALsizei newcount; + void *temp = NULL; + + newcount = Context->MaxActiveEffectSlots ? (Context->MaxActiveEffectSlots<<1) : 1; + if(newcount > Context->MaxActiveEffectSlots) + temp = realloc(Context->ActiveEffectSlots, + newcount * sizeof(*Context->ActiveEffectSlots)); + if(!temp) + { + UnlockContext(Context); + return AL_OUT_OF_MEMORY; + } + Context->ActiveEffectSlots = temp; + Context->MaxActiveEffectSlots = newcount; + } + for(i = 0;i < count;i++) + { + ALeffectslot *slot = LookupEffectSlot(Context, slots[i]); + assert(slot != NULL); + Context->ActiveEffectSlots[Context->ActiveEffectSlotCount++] = slot; + } + UnlockContext(Context); + return AL_NO_ERROR; +} + +ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect) +{ + ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); + ALeffectState *State = NULL; + ALenum err = AL_NO_ERROR; + + ALCdevice_Lock(Device); + if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL) + { + State = NoneCreate(); + if(!State) err = AL_OUT_OF_MEMORY; + } + else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB) + { + if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB) + { + State = ReverbCreate(); + if(!State) err = AL_OUT_OF_MEMORY; + } + } + else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO) + { + State = EchoCreate(); + if(!State) err = AL_OUT_OF_MEMORY; + } + else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR) + { + State = ModulatorCreate(); + if(!State) err = AL_OUT_OF_MEMORY; + } + else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + { + if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + { + State = DedicatedCreate(); + if(!State) err = AL_OUT_OF_MEMORY; + } + } + + if(err != AL_NO_ERROR) + { + ALCdevice_Unlock(Device); + return err; + } + + if(State) + { + FPUCtl oldMode; + SetMixerFPUMode(&oldMode); + + if(ALeffectState_DeviceUpdate(State, Device) == AL_FALSE) + { + RestoreFPUMode(&oldMode); + ALCdevice_Unlock(Device); + ALeffectState_Destroy(State); + return AL_OUT_OF_MEMORY; + } + State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State); + + if(!effect) + memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect)); + else + memcpy(&EffectSlot->effect, effect, sizeof(*effect)); + /* FIXME: This should be done asynchronously, but since the EffectState + * object was changed, it needs an update before its Process method can + * be called. */ + EffectSlot->NeedsUpdate = AL_FALSE; + ALeffectState_Update(EffectSlot->EffectState, Device, EffectSlot); + ALCdevice_Unlock(Device); + + RestoreFPUMode(&oldMode); + + ALeffectState_Destroy(State); + State = NULL; + } + else + { + if(!effect) + memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect)); + else + memcpy(&EffectSlot->effect, effect, sizeof(*effect)); + ALCdevice_Unlock(Device); + EffectSlot->NeedsUpdate = AL_TRUE; + } + + return AL_NO_ERROR; +} + + +ALenum InitEffectSlot(ALeffectslot *slot) +{ + ALint i, c; + + if(!(slot->EffectState=NoneCreate())) + return AL_OUT_OF_MEMORY; + + slot->Gain = 1.0; + slot->AuxSendAuto = AL_TRUE; + slot->NeedsUpdate = AL_FALSE; + for(c = 0;c < 1;c++) + { + for(i = 0;i < BUFFERSIZE;i++) + slot->WetBuffer[c][i] = 0.0f; + slot->ClickRemoval[c] = 0.0f; + slot->PendingClicks[c] = 0.0f; + } + slot->ref = 0; + + return AL_NO_ERROR; +} + +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; + + ALeffectState_Destroy(temp->EffectState); + + FreeThunkEntry(temp->id); + memset(temp, 0, sizeof(ALeffectslot)); + al_free(temp); + } +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alBuffer.c b/src/eepp/helper/android/openal-soft/OpenAL32/alBuffer.c new file mode 100644 index 000000000..29f3e6174 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alBuffer.c @@ -0,0 +1,2242 @@ +/** + * 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 "alu.h" +#include "alError.h" +#include "alBuffer.h" +#include "alThunk.h" + + +static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels chans, enum UserFmtType type, const ALvoid *data, ALboolean storesrc); +static void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len); +static ALboolean IsValidType(ALenum type); +static ALboolean IsValidChannels(ALenum channels); +static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type); +static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type); + + +/* + * Global Variables + */ + +/* IMA ADPCM Stepsize table */ +static const int 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 int 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 int 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 +}; + + +/* A quick'n'dirty lookup table to decode an aLaw-encoded byte sample into a + * signed 16-bit sample */ +static const ALshort aLawDecompressionTable[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, + -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, + -11008,-10496,-12032,-11520, -8960, -8448, -9984, -9472, + -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 +}; + +/* Values used when encoding an aLaw sample */ +static const int aLawClip = 32635; +static const char aLawCompressTable[128] = { + 1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, + 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, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + + +AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers) +{ + ALCcontext *Context; + ALsizei cur = 0; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + ALenum err; + + CHECK_VALUE(Context, n >= 0); + for(cur = 0;cur < n;cur++) + { + ALbuffer *buffer = calloc(1, sizeof(ALbuffer)); + if(!buffer) + al_throwerr(Context, AL_OUT_OF_MEMORY); + RWLockInit(&buffer->lock); + + err = NewThunkEntry(&buffer->id); + if(err == AL_NO_ERROR) + err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer); + if(err != AL_NO_ERROR) + { + FreeThunkEntry(buffer->id); + memset(buffer, 0, sizeof(ALbuffer)); + free(buffer); + + al_throwerr(Context, err); + } + + buffers[cur] = buffer->id; + } + } + al_catchany() + { + if(cur > 0) + alDeleteBuffers(cur, buffers); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + ALsizei i; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if(!buffers[i]) + continue; + + /* Check for valid Buffer ID */ + if((ALBuf=LookupBuffer(device, buffers[i])) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + if(ALBuf->ref != 0) + al_throwerr(Context, AL_INVALID_OPERATION); + } + + for(i = 0;i < n;i++) + { + if((ALBuf=RemoveBuffer(device, buffers[i])) == NULL) + continue; + FreeThunkEntry(ALBuf->id); + + free(ALBuf->data); + + memset(ALBuf, 0, sizeof(*ALBuf)); + free(ALBuf); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + result = ((!buffer || LookupBuffer(Context->Device, buffer)) ? + AL_TRUE : AL_FALSE); + + ALCcontext_DecRef(Context); + + return result; +} + + +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; + ALuint FrameSize; + ALenum NewFormat; + ALbuffer *ALBuf; + ALenum err; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if((ALBuf=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + CHECK_VALUE(Context, size >= 0 && freq >= 0); + if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE) + al_throwerr(Context, AL_INVALID_ENUM); + switch(SrcType) + { + case UserFmtByte: + case UserFmtUByte: + case UserFmtShort: + case UserFmtUShort: + case UserFmtFloat: + FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType); + CHECK_VALUE(Context, (size%FrameSize) == 0); + + err = LoadData(ALBuf, freq, format, size/FrameSize, + SrcChannels, SrcType, data, AL_TRUE); + if(err != AL_NO_ERROR) + al_throwerr(Context, err); + break; + + case UserFmtInt: + case UserFmtUInt: + case UserFmtByte3: + case UserFmtUByte3: + case UserFmtDouble: + FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType); + CHECK_VALUE(Context, (size%FrameSize) == 0); + + 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/FrameSize, + SrcChannels, SrcType, data, AL_TRUE); + if(err != AL_NO_ERROR) + al_throwerr(Context, err); + break; + + case UserFmtMulaw: + case UserFmtAlaw: + FrameSize = FrameSizeFromUserFmt(SrcChannels, SrcType); + CHECK_VALUE(Context, (size%FrameSize) == 0); + + 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/FrameSize, + SrcChannels, SrcType, data, AL_TRUE); + if(err != AL_NO_ERROR) + al_throwerr(Context, err); + break; + + case UserFmtIMA4: + /* 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 + */ + FrameSize = ChannelsFromUserFmt(SrcChannels) * 36; + CHECK_VALUE(Context, (size%FrameSize) == 0); + + 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/FrameSize*65, + SrcChannels, SrcType, data, AL_TRUE); + if(err != AL_NO_ERROR) + al_throwerr(Context, err); + break; + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +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; + ALbuffer *ALBuf; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + ALuint original_align; + ALuint Channels; + ALuint Bytes; + + if((ALBuf=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + CHECK_VALUE(Context, length >= 0 && offset >= 0); + if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE) + al_throwerr(Context, AL_INVALID_ENUM); + + WriteLock(&ALBuf->lock); + original_align = ((ALBuf->OriginalType == UserFmtIMA4) ? + (ChannelsFromUserFmt(ALBuf->OriginalChannels)*36) : + FrameSizeFromUserFmt(ALBuf->OriginalChannels, + ALBuf->OriginalType)); + + if(SrcChannels != ALBuf->OriginalChannels || SrcType != ALBuf->OriginalType) + { + WriteUnlock(&ALBuf->lock); + al_throwerr(Context, AL_INVALID_ENUM); + } + if(offset > ALBuf->OriginalSize || length > ALBuf->OriginalSize-offset || + (offset%original_align) != 0 || (length%original_align) != 0) + { + WriteUnlock(&ALBuf->lock); + al_throwerr(Context, AL_INVALID_VALUE); + } + + Channels = ChannelsFromFmt(ALBuf->FmtChannels); + Bytes = BytesFromFmt(ALBuf->FmtType); + /* offset -> byte offset, length -> sample count */ + if(SrcType == UserFmtIMA4) + { + offset = offset/36*65 * Bytes; + length = length/original_align * 65; + } + else + { + ALuint OldBytes = BytesFromUserFmt(SrcType); + offset = offset/OldBytes * Bytes; + length = length/OldBytes/Channels; + } + ConvertData(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType, + data, SrcType, Channels, length); + WriteUnlock(&ALBuf->lock); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, + ALuint samplerate, ALenum internalformat, ALsizei samples, + ALenum channels, ALenum type, const ALvoid *data) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + ALenum err; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if((ALBuf=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + CHECK_VALUE(Context, samples >= 0 && samplerate != 0); + if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE) + al_throwerr(Context, AL_INVALID_ENUM); + + err = LoadData(ALBuf, samplerate, internalformat, samples, + channels, type, data, AL_FALSE); + if(err != AL_NO_ERROR) + al_throwerr(Context, err); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, + ALsizei offset, ALsizei samples, + ALenum channels, ALenum type, const ALvoid *data) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + ALuint FrameSize; + + if((ALBuf=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + CHECK_VALUE(Context, samples >= 0 && offset >= 0); + if(IsValidType(type) == AL_FALSE) + al_throwerr(Context, AL_INVALID_ENUM); + + WriteLock(&ALBuf->lock); + FrameSize = FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType); + if(channels != (ALenum)ALBuf->FmtChannels) + { + WriteUnlock(&ALBuf->lock); + al_throwerr(Context, AL_INVALID_ENUM); + } + else if(offset > ALBuf->SampleLen || samples > ALBuf->SampleLen-offset) + { + WriteUnlock(&ALBuf->lock); + al_throwerr(Context,AL_INVALID_VALUE); + } + + /* offset -> byte offset */ + offset *= FrameSize; + ConvertData(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType, + data, type, ChannelsFromFmt(ALBuf->FmtChannels), samples); + WriteUnlock(&ALBuf->lock); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, + ALsizei offset, ALsizei samples, + ALenum channels, ALenum type, ALvoid *data) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + ALuint FrameSize; + + if((ALBuf=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + CHECK_VALUE(Context, samples >= 0 && offset >= 0); + if(IsValidType(type) == AL_FALSE) + al_throwerr(Context, AL_INVALID_ENUM); + + ReadLock(&ALBuf->lock); + FrameSize = FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType); + if(channels != (ALenum)ALBuf->FmtChannels) + { + ReadUnlock(&ALBuf->lock); + al_throwerr(Context, AL_INVALID_ENUM); + } + if(offset > ALBuf->SampleLen || samples > ALBuf->SampleLen-offset) + { + ReadUnlock(&ALBuf->lock); + al_throwerr(Context,AL_INVALID_VALUE); + } + if(type == UserFmtIMA4 && (samples%65) != 0) + { + ReadUnlock(&ALBuf->lock); + al_throwerr(Context, AL_INVALID_VALUE); + } + + /* offset -> byte offset */ + offset *= FrameSize; + ConvertData(data, type, &((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType, + ChannelsFromFmt(ALBuf->FmtChannels), samples); + ReadUnlock(&ALBuf->lock); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format) +{ + enum FmtChannels DstChannels; + enum FmtType DstType; + ALCcontext *Context; + ALboolean ret; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + ret = DecomposeFormat(format, &DstChannels, &DstType); + + ALCcontext_DecRef(Context); + + return ret; +} + + +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value) +{ + ALCcontext *Context; + + (void)value; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +{ + ALCcontext *Context; + + (void)value1; + (void)value2; + (void)value3; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, values); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) +{ + ALCcontext *Context; + + (void)value; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3) +{ + ALCcontext *Context; + + (void)value1; + (void)value2; + (void)value3; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if((ALBuf=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, values); + switch(param) + { + case AL_LOOP_POINTS_SOFT: + WriteLock(&ALBuf->lock); + if(ALBuf->ref != 0) + { + WriteUnlock(&ALBuf->lock); + al_throwerr(Context, AL_INVALID_OPERATION); + } + if(values[0] >= values[1] || values[0] < 0 || + values[1] > ALBuf->SampleLen) + { + WriteUnlock(&ALBuf->lock); + al_throwerr(Context, AL_INVALID_VALUE); + } + + ALBuf->LoopStart = values[0]; + ALBuf->LoopEnd = values[1]; + WriteUnlock(&ALBuf->lock); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALbuffer *Buffer; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if((Buffer=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, value); + switch(param) + { + case AL_SEC_LENGTH_SOFT: + ReadLock(&Buffer->lock); + if(Buffer->SampleLen != 0) + *value = Buffer->SampleLen / (ALfloat)Buffer->Frequency; + else + *value = 0.0f; + ReadUnlock(&Buffer->lock); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, value1 && value2 && value3); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + + switch(param) + { + case AL_SEC_LENGTH_SOFT: + alGetBufferf(buffer, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, values); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALbuffer *Buffer; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if((Buffer=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, value); + switch(param) + { + case AL_FREQUENCY: + *value = Buffer->Frequency; + break; + + case AL_BITS: + *value = BytesFromFmt(Buffer->FmtType) * 8; + break; + + case AL_CHANNELS: + *value = ChannelsFromFmt(Buffer->FmtChannels); + break; + + case AL_SIZE: + ReadLock(&Buffer->lock); + *value = Buffer->SampleLen * FrameSizeFromFmt(Buffer->FmtChannels, + Buffer->FmtType); + ReadUnlock(&Buffer->lock); + break; + + case AL_INTERNAL_FORMAT_SOFT: + *value = Buffer->Format; + break; + + case AL_BYTE_LENGTH_SOFT: + *value = Buffer->OriginalSize; + break; + + case AL_SAMPLE_LENGTH_SOFT: + *value = Buffer->SampleLen; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if(LookupBuffer(device, buffer) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, value1 && value2 && value3); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + + switch(param) + { + case AL_FREQUENCY: + case AL_BITS: + case AL_CHANNELS: + case AL_SIZE: + case AL_INTERNAL_FORMAT_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + alGetBufferi(buffer, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + if((ALBuf=LookupBuffer(device, buffer)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + CHECK_VALUE(Context, values); + switch(param) + { + case AL_LOOP_POINTS_SOFT: + ReadLock(&ALBuf->lock); + values[0] = ALBuf->LoopStart; + values[1] = ALBuf->LoopEnd; + ReadUnlock(&ALBuf->lock); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +typedef ALubyte ALmulaw; +typedef ALubyte ALalaw; +typedef ALubyte ALima4; +typedef struct { + ALbyte b[3]; +} ALbyte3; +extern ALbyte ALbyte3_size_is_not_3[(sizeof(ALbyte3)==sizeof(ALbyte[3]))?1:-1]; +typedef struct { + ALubyte b[3]; +} ALubyte3; +extern ALbyte ALubyte3_size_is_not_3[(sizeof(ALubyte3)==sizeof(ALubyte[3]))?1:-1]; + +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 = maxi(val, -32767); + val = -val; + } + + val = mini(val, muLawClip); + val += muLawBias; + + exp = muLawCompressTable[(val>>7) & 0xff]; + mant = (val >> (exp+3)) & 0x0f; + + return ~(sign | (exp<<4) | mant); +} + +static __inline ALshort DecodeALaw(ALalaw val) +{ return aLawDecompressionTable[val]; } + +static ALalaw EncodeALaw(ALshort val) +{ + ALint mant, exp, sign; + + sign = ((~val) >> 8) & 0x80; + if(!sign) + { + val = maxi(val, -32767); + val = -val; + } + val = mini(val, aLawClip); + + if(val >= 256) + { + exp = aLawCompressTable[(val>>8) & 0x7f]; + mant = (val >> (exp+3)) & 0x0f; + } + else + { + exp = 0; + mant = val >> 4; + } + + return ((exp<<4) | mant) ^ (sign^0x55); +} + +static void DecodeIMA4Block(ALshort *dst, const ALima4 *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] = clampi(index[c], 0, 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] = clampi(sample[c], -32768, 32767); + + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 88); + + dst[j*numchans + c] = sample[c]; + } + } + } +} + +static void EncodeIMA4Block(ALima4 *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 = mini(step*2, diff); + nibble |= (diff*8/step - 1) / 2; + + sample[c] += IMA4Codeword[nibble] * step / 8; + sample[c] = clampi(sample[c], -32768, 32767); + + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 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 = mini(step*2, diff); + nibble |= (diff*8/step - 1) / 2; + + sample[c] += IMA4Codeword[nibble] * step / 8; + sample[c] = clampi(sample[c], -32768, 32767); + + index[c] += IMA4Index_adjust[nibble]; + index[c] = clampi(index[c], 0, 88); + + if(!(k&1)) *dst = nibble; + else *(dst++) |= nibble<<4; + } + } + j += 8; + } +} + + +static __inline ALint DecodeByte3(ALbyte3 val) +{ + if(IS_LITTLE_ENDIAN) + return (val.b[2]<<16) | (((ALubyte)val.b[1])<<8) | ((ALubyte)val.b[0]); + return (val.b[0]<<16) | (((ALubyte)val.b[1])<<8) | ((ALubyte)val.b[2]); +} + +static __inline ALbyte3 EncodeByte3(ALint val) +{ + if(IS_LITTLE_ENDIAN) + { + ALbyte3 ret = {{ val, val>>8, val>>16 }}; + return ret; + } + else + { + ALbyte3 ret = {{ val>>16, val>>8, val }}; + return ret; + } +} + +static __inline ALint DecodeUByte3(ALubyte3 val) +{ + if(IS_LITTLE_ENDIAN) + return (val.b[2]<<16) | (val.b[1]<<8) | (val.b[0]); + return (val.b[0]<<16) | (val.b[1]<<8) | val.b[2]; +} + +static __inline ALubyte3 EncodeUByte3(ALint val) +{ + if(IS_LITTLE_ENDIAN) + { + ALubyte3 ret = {{ val, val>>8, val>>16 }}; + return ret; + } + else + { + ALubyte3 ret = {{ val>>16, val>>8, val }}; + return ret; + } +} + + +static __inline ALbyte Conv_ALbyte_ALbyte(ALbyte val) +{ return val; } +static __inline ALbyte Conv_ALbyte_ALubyte(ALubyte val) +{ return val-128; } +static __inline ALbyte Conv_ALbyte_ALshort(ALshort val) +{ return val>>8; } +static __inline ALbyte Conv_ALbyte_ALushort(ALushort val) +{ return (val>>8)-128; } +static __inline ALbyte Conv_ALbyte_ALint(ALint val) +{ return val>>24; } +static __inline ALbyte Conv_ALbyte_ALuint(ALuint val) +{ return (val>>24)-128; } +static __inline ALbyte Conv_ALbyte_ALfloat(ALfloat val) +{ + if(val > 1.0f) return 127; + if(val < -1.0f) return -128; + return (ALint)(val * 127.0f); +} +static __inline ALbyte Conv_ALbyte_ALdouble(ALdouble val) +{ + if(val > 1.0) return 127; + if(val < -1.0) return -128; + return (ALint)(val * 127.0); +} +static __inline ALbyte Conv_ALbyte_ALmulaw(ALmulaw val) +{ return Conv_ALbyte_ALshort(DecodeMuLaw(val)); } +static __inline ALbyte Conv_ALbyte_ALalaw(ALalaw val) +{ return Conv_ALbyte_ALshort(DecodeALaw(val)); } +static __inline ALbyte Conv_ALbyte_ALbyte3(ALbyte3 val) +{ return DecodeByte3(val)>>16; } +static __inline ALbyte Conv_ALbyte_ALubyte3(ALubyte3 val) +{ return (DecodeUByte3(val)>>16)-128; } + +static __inline ALubyte Conv_ALubyte_ALbyte(ALbyte val) +{ return val+128; } +static __inline ALubyte Conv_ALubyte_ALubyte(ALubyte val) +{ return val; } +static __inline ALubyte Conv_ALubyte_ALshort(ALshort val) +{ return (val>>8)+128; } +static __inline ALubyte Conv_ALubyte_ALushort(ALushort val) +{ return val>>8; } +static __inline ALubyte Conv_ALubyte_ALint(ALint val) +{ return (val>>24)+128; } +static __inline ALubyte Conv_ALubyte_ALuint(ALuint val) +{ return val>>24; } +static __inline ALubyte Conv_ALubyte_ALfloat(ALfloat val) +{ + if(val > 1.0f) return 255; + if(val < -1.0f) return 0; + return (ALint)(val * 127.0f) + 128; +} +static __inline ALubyte Conv_ALubyte_ALdouble(ALdouble val) +{ + if(val > 1.0) return 255; + if(val < -1.0) return 0; + return (ALint)(val * 127.0) + 128; +} +static __inline ALubyte Conv_ALubyte_ALmulaw(ALmulaw val) +{ return Conv_ALubyte_ALshort(DecodeMuLaw(val)); } +static __inline ALubyte Conv_ALubyte_ALalaw(ALalaw val) +{ return Conv_ALubyte_ALshort(DecodeALaw(val)); } +static __inline ALubyte Conv_ALubyte_ALbyte3(ALbyte3 val) +{ return (DecodeByte3(val)>>16)+128; } +static __inline ALubyte Conv_ALubyte_ALubyte3(ALubyte3 val) +{ return DecodeUByte3(val)>>16; } + +static __inline ALshort Conv_ALshort_ALbyte(ALbyte val) +{ return val<<8; } +static __inline ALshort Conv_ALshort_ALubyte(ALubyte val) +{ return (val-128)<<8; } +static __inline ALshort Conv_ALshort_ALshort(ALshort val) +{ return val; } +static __inline ALshort Conv_ALshort_ALushort(ALushort val) +{ return val-32768; } +static __inline ALshort Conv_ALshort_ALint(ALint val) +{ return val>>16; } +static __inline ALshort Conv_ALshort_ALuint(ALuint val) +{ return (val>>16)-32768; } +static __inline ALshort Conv_ALshort_ALfloat(ALfloat val) +{ + if(val > 1.0f) return 32767; + if(val < -1.0f) return -32768; + return (ALint)(val * 32767.0f); +} +static __inline ALshort Conv_ALshort_ALdouble(ALdouble val) +{ + if(val > 1.0) return 32767; + if(val < -1.0) return -32768; + return (ALint)(val * 32767.0); +} +static __inline ALshort Conv_ALshort_ALmulaw(ALmulaw val) +{ return Conv_ALshort_ALshort(DecodeMuLaw(val)); } +static __inline ALshort Conv_ALshort_ALalaw(ALalaw val) +{ return Conv_ALshort_ALshort(DecodeALaw(val)); } +static __inline ALshort Conv_ALshort_ALbyte3(ALbyte3 val) +{ return DecodeByte3(val)>>8; } +static __inline ALshort Conv_ALshort_ALubyte3(ALubyte3 val) +{ return (DecodeUByte3(val)>>8)-32768; } + +static __inline ALushort Conv_ALushort_ALbyte(ALbyte val) +{ return (val+128)<<8; } +static __inline ALushort Conv_ALushort_ALubyte(ALubyte val) +{ return val<<8; } +static __inline ALushort Conv_ALushort_ALshort(ALshort val) +{ return val+32768; } +static __inline ALushort Conv_ALushort_ALushort(ALushort val) +{ return val; } +static __inline ALushort Conv_ALushort_ALint(ALint val) +{ return (val>>16)+32768; } +static __inline ALushort Conv_ALushort_ALuint(ALuint val) +{ return val>>16; } +static __inline ALushort Conv_ALushort_ALfloat(ALfloat val) +{ + if(val > 1.0f) return 65535; + if(val < -1.0f) return 0; + return (ALint)(val * 32767.0f) + 32768; +} +static __inline ALushort Conv_ALushort_ALdouble(ALdouble val) +{ + if(val > 1.0) return 65535; + if(val < -1.0) return 0; + return (ALint)(val * 32767.0) + 32768; +} +static __inline ALushort Conv_ALushort_ALmulaw(ALmulaw val) +{ return Conv_ALushort_ALshort(DecodeMuLaw(val)); } +static __inline ALushort Conv_ALushort_ALalaw(ALalaw val) +{ return Conv_ALushort_ALshort(DecodeALaw(val)); } +static __inline ALushort Conv_ALushort_ALbyte3(ALbyte3 val) +{ return (DecodeByte3(val)>>8)+32768; } +static __inline ALushort Conv_ALushort_ALubyte3(ALubyte3 val) +{ return DecodeUByte3(val)>>8; } + +static __inline ALint Conv_ALint_ALbyte(ALbyte val) +{ return val<<24; } +static __inline ALint Conv_ALint_ALubyte(ALubyte val) +{ return (val-128)<<24; } +static __inline ALint Conv_ALint_ALshort(ALshort val) +{ return val<<16; } +static __inline ALint Conv_ALint_ALushort(ALushort val) +{ return (val-32768)<<16; } +static __inline ALint Conv_ALint_ALint(ALint val) +{ return val; } +static __inline ALint Conv_ALint_ALuint(ALuint val) +{ return val-2147483648u; } +static __inline ALint Conv_ALint_ALfloat(ALfloat val) +{ + if(val > 1.0f) return 2147483647; + if(val < -1.0f) return -2147483647-1; + return (ALint)(val * 2147483647.0); +} +static __inline ALint Conv_ALint_ALdouble(ALdouble val) +{ + if(val > 1.0) return 2147483647; + if(val < -1.0) return -2147483647-1; + return (ALint)(val * 2147483647.0); +} +static __inline ALint Conv_ALint_ALmulaw(ALmulaw val) +{ return Conv_ALint_ALshort(DecodeMuLaw(val)); } +static __inline ALint Conv_ALint_ALalaw(ALalaw val) +{ return Conv_ALint_ALshort(DecodeALaw(val)); } +static __inline ALint Conv_ALint_ALbyte3(ALbyte3 val) +{ return DecodeByte3(val)<<8; } +static __inline ALint Conv_ALint_ALubyte3(ALubyte3 val) +{ return (DecodeUByte3(val)-8388608)<<8; } + +static __inline ALuint Conv_ALuint_ALbyte(ALbyte val) +{ return (val+128)<<24; } +static __inline ALuint Conv_ALuint_ALubyte(ALubyte val) +{ return val<<24; } +static __inline ALuint Conv_ALuint_ALshort(ALshort val) +{ return (val+32768)<<16; } +static __inline ALuint Conv_ALuint_ALushort(ALushort val) +{ return val<<16; } +static __inline ALuint Conv_ALuint_ALint(ALint val) +{ return val+2147483648u; } +static __inline ALuint Conv_ALuint_ALuint(ALuint val) +{ return val; } +static __inline ALuint Conv_ALuint_ALfloat(ALfloat val) +{ + if(val > 1.0f) return 4294967295u; + if(val < -1.0f) return 0; + return (ALint)(val * 2147483647.0) + 2147483648u; +} +static __inline ALuint Conv_ALuint_ALdouble(ALdouble val) +{ + if(val > 1.0) return 4294967295u; + if(val < -1.0) return 0; + return (ALint)(val * 2147483647.0) + 2147483648u; +} +static __inline ALuint Conv_ALuint_ALmulaw(ALmulaw val) +{ return Conv_ALuint_ALshort(DecodeMuLaw(val)); } +static __inline ALuint Conv_ALuint_ALalaw(ALalaw val) +{ return Conv_ALuint_ALshort(DecodeALaw(val)); } +static __inline ALuint Conv_ALuint_ALbyte3(ALbyte3 val) +{ return (DecodeByte3(val)+8388608)<<8; } +static __inline ALuint Conv_ALuint_ALubyte3(ALubyte3 val) +{ return DecodeUByte3(val)<<8; } + +static __inline ALfloat Conv_ALfloat_ALbyte(ALbyte val) +{ return val * (1.0f/127.0f); } +static __inline ALfloat Conv_ALfloat_ALubyte(ALubyte val) +{ return (val-128) * (1.0f/127.0f); } +static __inline ALfloat Conv_ALfloat_ALshort(ALshort val) +{ return val * (1.0f/32767.0f); } +static __inline ALfloat Conv_ALfloat_ALushort(ALushort val) +{ return (val-32768) * (1.0f/32767.0f); } +static __inline ALfloat Conv_ALfloat_ALint(ALint val) +{ return (ALfloat)(val * (1.0/2147483647.0)); } +static __inline ALfloat Conv_ALfloat_ALuint(ALuint val) +{ return (ALfloat)((ALint)(val-2147483648u) * (1.0/2147483647.0)); } +static __inline ALfloat Conv_ALfloat_ALfloat(ALfloat val) +{ return (val==val) ? val : 0.0f; } +static __inline ALfloat Conv_ALfloat_ALdouble(ALdouble val) +{ return (val==val) ? (ALfloat)val : 0.0f; } +static __inline ALfloat Conv_ALfloat_ALmulaw(ALmulaw val) +{ return Conv_ALfloat_ALshort(DecodeMuLaw(val)); } +static __inline ALfloat Conv_ALfloat_ALalaw(ALalaw val) +{ return Conv_ALfloat_ALshort(DecodeALaw(val)); } +static __inline ALfloat Conv_ALfloat_ALbyte3(ALbyte3 val) +{ return (ALfloat)(DecodeByte3(val) * (1.0/8388607.0)); } +static __inline ALfloat Conv_ALfloat_ALubyte3(ALubyte3 val) +{ return (ALfloat)((DecodeUByte3(val)-8388608) * (1.0/8388607.0)); } + +static __inline ALdouble Conv_ALdouble_ALbyte(ALbyte val) +{ return val * (1.0/127.0); } +static __inline ALdouble Conv_ALdouble_ALubyte(ALubyte val) +{ return (val-128) * (1.0/127.0); } +static __inline ALdouble Conv_ALdouble_ALshort(ALshort val) +{ return val * (1.0/32767.0); } +static __inline ALdouble Conv_ALdouble_ALushort(ALushort val) +{ return (val-32768) * (1.0/32767.0); } +static __inline ALdouble Conv_ALdouble_ALint(ALint val) +{ return val * (1.0/2147483647.0); } +static __inline ALdouble Conv_ALdouble_ALuint(ALuint val) +{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); } +static __inline ALdouble Conv_ALdouble_ALfloat(ALfloat val) +{ return (val==val) ? val : 0.0f; } +static __inline ALdouble Conv_ALdouble_ALdouble(ALdouble val) +{ return (val==val) ? val : 0.0; } +static __inline ALdouble Conv_ALdouble_ALmulaw(ALmulaw val) +{ return Conv_ALdouble_ALshort(DecodeMuLaw(val)); } +static __inline ALdouble Conv_ALdouble_ALalaw(ALalaw val) +{ return Conv_ALdouble_ALshort(DecodeALaw(val)); } +static __inline ALdouble Conv_ALdouble_ALbyte3(ALbyte3 val) +{ return DecodeByte3(val) * (1.0/8388607.0); } +static __inline ALdouble Conv_ALdouble_ALubyte3(ALubyte3 val) +{ return (DecodeUByte3(val)-8388608) * (1.0/8388607.0); } + +#define DECL_TEMPLATE(T) \ +static __inline ALmulaw Conv_ALmulaw_##T(T val) \ +{ return EncodeMuLaw(Conv_ALshort_##T(val)); } + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +static __inline ALmulaw Conv_ALmulaw_ALmulaw(ALmulaw val) +{ return val; } +DECL_TEMPLATE(ALalaw) +DECL_TEMPLATE(ALbyte3) +DECL_TEMPLATE(ALubyte3) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T) \ +static __inline ALalaw Conv_ALalaw_##T(T val) \ +{ return EncodeALaw(Conv_ALshort_##T(val)); } + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +static __inline ALalaw Conv_ALalaw_ALalaw(ALalaw val) +{ return val; } +DECL_TEMPLATE(ALbyte3) +DECL_TEMPLATE(ALubyte3) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T) \ +static __inline ALbyte3 Conv_ALbyte3_##T(T val) \ +{ return EncodeByte3(Conv_ALint_##T(val)>>8); } + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) +static __inline ALbyte3 Conv_ALbyte3_ALbyte3(ALbyte3 val) +{ return val; } +DECL_TEMPLATE(ALubyte3) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T) \ +static __inline ALubyte3 Conv_ALubyte3_##T(T val) \ +{ return EncodeUByte3(Conv_ALuint_##T(val)>>8); } + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) +DECL_TEMPLATE(ALbyte3) +static __inline ALubyte3 Conv_ALubyte3_ALubyte3(ALubyte3 val) +{ return val; } + +#undef DECL_TEMPLATE + + +#define DECL_TEMPLATE(T1, T2) \ +static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALuint numchans, \ + ALuint len) \ +{ \ + ALuint i, j; \ + for(i = 0;i < len;i++) \ + { \ + for(j = 0;j < numchans;j++) \ + *(dst++) = Conv_##T1##_##T2(*(src++)); \ + } \ +} + +DECL_TEMPLATE(ALbyte, ALbyte) +DECL_TEMPLATE(ALbyte, ALubyte) +DECL_TEMPLATE(ALbyte, ALshort) +DECL_TEMPLATE(ALbyte, ALushort) +DECL_TEMPLATE(ALbyte, ALint) +DECL_TEMPLATE(ALbyte, ALuint) +DECL_TEMPLATE(ALbyte, ALfloat) +DECL_TEMPLATE(ALbyte, ALdouble) +DECL_TEMPLATE(ALbyte, ALmulaw) +DECL_TEMPLATE(ALbyte, ALalaw) +DECL_TEMPLATE(ALbyte, ALbyte3) +DECL_TEMPLATE(ALbyte, ALubyte3) + +DECL_TEMPLATE(ALubyte, ALbyte) +DECL_TEMPLATE(ALubyte, ALubyte) +DECL_TEMPLATE(ALubyte, ALshort) +DECL_TEMPLATE(ALubyte, ALushort) +DECL_TEMPLATE(ALubyte, ALint) +DECL_TEMPLATE(ALubyte, ALuint) +DECL_TEMPLATE(ALubyte, ALfloat) +DECL_TEMPLATE(ALubyte, ALdouble) +DECL_TEMPLATE(ALubyte, ALmulaw) +DECL_TEMPLATE(ALubyte, ALalaw) +DECL_TEMPLATE(ALubyte, ALbyte3) +DECL_TEMPLATE(ALubyte, ALubyte3) + +DECL_TEMPLATE(ALshort, ALbyte) +DECL_TEMPLATE(ALshort, ALubyte) +DECL_TEMPLATE(ALshort, ALshort) +DECL_TEMPLATE(ALshort, ALushort) +DECL_TEMPLATE(ALshort, ALint) +DECL_TEMPLATE(ALshort, ALuint) +DECL_TEMPLATE(ALshort, ALfloat) +DECL_TEMPLATE(ALshort, ALdouble) +DECL_TEMPLATE(ALshort, ALmulaw) +DECL_TEMPLATE(ALshort, ALalaw) +DECL_TEMPLATE(ALshort, ALbyte3) +DECL_TEMPLATE(ALshort, ALubyte3) + +DECL_TEMPLATE(ALushort, ALbyte) +DECL_TEMPLATE(ALushort, ALubyte) +DECL_TEMPLATE(ALushort, ALshort) +DECL_TEMPLATE(ALushort, ALushort) +DECL_TEMPLATE(ALushort, ALint) +DECL_TEMPLATE(ALushort, ALuint) +DECL_TEMPLATE(ALushort, ALfloat) +DECL_TEMPLATE(ALushort, ALdouble) +DECL_TEMPLATE(ALushort, ALmulaw) +DECL_TEMPLATE(ALushort, ALalaw) +DECL_TEMPLATE(ALushort, ALbyte3) +DECL_TEMPLATE(ALushort, ALubyte3) + +DECL_TEMPLATE(ALint, ALbyte) +DECL_TEMPLATE(ALint, ALubyte) +DECL_TEMPLATE(ALint, ALshort) +DECL_TEMPLATE(ALint, ALushort) +DECL_TEMPLATE(ALint, ALint) +DECL_TEMPLATE(ALint, ALuint) +DECL_TEMPLATE(ALint, ALfloat) +DECL_TEMPLATE(ALint, ALdouble) +DECL_TEMPLATE(ALint, ALmulaw) +DECL_TEMPLATE(ALint, ALalaw) +DECL_TEMPLATE(ALint, ALbyte3) +DECL_TEMPLATE(ALint, ALubyte3) + +DECL_TEMPLATE(ALuint, ALbyte) +DECL_TEMPLATE(ALuint, ALubyte) +DECL_TEMPLATE(ALuint, ALshort) +DECL_TEMPLATE(ALuint, ALushort) +DECL_TEMPLATE(ALuint, ALint) +DECL_TEMPLATE(ALuint, ALuint) +DECL_TEMPLATE(ALuint, ALfloat) +DECL_TEMPLATE(ALuint, ALdouble) +DECL_TEMPLATE(ALuint, ALmulaw) +DECL_TEMPLATE(ALuint, ALalaw) +DECL_TEMPLATE(ALuint, ALbyte3) +DECL_TEMPLATE(ALuint, ALubyte3) + +DECL_TEMPLATE(ALfloat, ALbyte) +DECL_TEMPLATE(ALfloat, ALubyte) +DECL_TEMPLATE(ALfloat, ALshort) +DECL_TEMPLATE(ALfloat, ALushort) +DECL_TEMPLATE(ALfloat, ALint) +DECL_TEMPLATE(ALfloat, ALuint) +DECL_TEMPLATE(ALfloat, ALfloat) +DECL_TEMPLATE(ALfloat, ALdouble) +DECL_TEMPLATE(ALfloat, ALmulaw) +DECL_TEMPLATE(ALfloat, ALalaw) +DECL_TEMPLATE(ALfloat, ALbyte3) +DECL_TEMPLATE(ALfloat, ALubyte3) + +DECL_TEMPLATE(ALdouble, ALbyte) +DECL_TEMPLATE(ALdouble, ALubyte) +DECL_TEMPLATE(ALdouble, ALshort) +DECL_TEMPLATE(ALdouble, ALushort) +DECL_TEMPLATE(ALdouble, ALint) +DECL_TEMPLATE(ALdouble, ALuint) +DECL_TEMPLATE(ALdouble, ALfloat) +DECL_TEMPLATE(ALdouble, ALdouble) +DECL_TEMPLATE(ALdouble, ALmulaw) +DECL_TEMPLATE(ALdouble, ALalaw) +DECL_TEMPLATE(ALdouble, ALbyte3) +DECL_TEMPLATE(ALdouble, ALubyte3) + +DECL_TEMPLATE(ALmulaw, ALbyte) +DECL_TEMPLATE(ALmulaw, ALubyte) +DECL_TEMPLATE(ALmulaw, ALshort) +DECL_TEMPLATE(ALmulaw, ALushort) +DECL_TEMPLATE(ALmulaw, ALint) +DECL_TEMPLATE(ALmulaw, ALuint) +DECL_TEMPLATE(ALmulaw, ALfloat) +DECL_TEMPLATE(ALmulaw, ALdouble) +DECL_TEMPLATE(ALmulaw, ALmulaw) +DECL_TEMPLATE(ALmulaw, ALalaw) +DECL_TEMPLATE(ALmulaw, ALbyte3) +DECL_TEMPLATE(ALmulaw, ALubyte3) + +DECL_TEMPLATE(ALalaw, ALbyte) +DECL_TEMPLATE(ALalaw, ALubyte) +DECL_TEMPLATE(ALalaw, ALshort) +DECL_TEMPLATE(ALalaw, ALushort) +DECL_TEMPLATE(ALalaw, ALint) +DECL_TEMPLATE(ALalaw, ALuint) +DECL_TEMPLATE(ALalaw, ALfloat) +DECL_TEMPLATE(ALalaw, ALdouble) +DECL_TEMPLATE(ALalaw, ALmulaw) +DECL_TEMPLATE(ALalaw, ALalaw) +DECL_TEMPLATE(ALalaw, ALbyte3) +DECL_TEMPLATE(ALalaw, ALubyte3) + +DECL_TEMPLATE(ALbyte3, ALbyte) +DECL_TEMPLATE(ALbyte3, ALubyte) +DECL_TEMPLATE(ALbyte3, ALshort) +DECL_TEMPLATE(ALbyte3, ALushort) +DECL_TEMPLATE(ALbyte3, ALint) +DECL_TEMPLATE(ALbyte3, ALuint) +DECL_TEMPLATE(ALbyte3, ALfloat) +DECL_TEMPLATE(ALbyte3, ALdouble) +DECL_TEMPLATE(ALbyte3, ALmulaw) +DECL_TEMPLATE(ALbyte3, ALalaw) +DECL_TEMPLATE(ALbyte3, ALbyte3) +DECL_TEMPLATE(ALbyte3, ALubyte3) + +DECL_TEMPLATE(ALubyte3, ALbyte) +DECL_TEMPLATE(ALubyte3, ALubyte) +DECL_TEMPLATE(ALubyte3, ALshort) +DECL_TEMPLATE(ALubyte3, ALushort) +DECL_TEMPLATE(ALubyte3, ALint) +DECL_TEMPLATE(ALubyte3, ALuint) +DECL_TEMPLATE(ALubyte3, ALfloat) +DECL_TEMPLATE(ALubyte3, ALdouble) +DECL_TEMPLATE(ALubyte3, ALmulaw) +DECL_TEMPLATE(ALubyte3, ALalaw) +DECL_TEMPLATE(ALubyte3, ALbyte3) +DECL_TEMPLATE(ALubyte3, ALubyte3) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T) \ +static void Convert_##T##_ALima4(T *dst, const ALima4 *src, ALuint numchans, \ + ALuint len) \ +{ \ + ALshort tmp[65*MaxChannels]; /* Max samples an IMA4 frame can be */ \ + ALuint i, j, k; \ + \ + i = 0; \ + while(i < len) \ + { \ + DecodeIMA4Block(tmp, src, numchans); \ + src += 36*numchans; \ + \ + for(j = 0;j < 65 && i < len;j++,i++) \ + { \ + for(k = 0;k < numchans;k++) \ + *(dst++) = Conv_##T##_ALshort(tmp[j*numchans + k]); \ + } \ + } \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) +DECL_TEMPLATE(ALbyte3) +DECL_TEMPLATE(ALubyte3) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T) \ +static void Convert_ALima4_##T(ALima4 *dst, const T *src, ALuint numchans, \ + ALuint len) \ +{ \ + 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}; \ + ALuint i, j; \ + \ + for(i = 0;i < len;i += 65) \ + { \ + for(j = 0;j < 65*numchans;j++) \ + tmp[j] = Conv_ALshort_##T(*(src++)); \ + EncodeIMA4Block(dst, tmp, sample, index, numchans); \ + dst += 36*numchans; \ + } \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) +static void Convert_ALima4_ALima4(ALima4 *dst, const ALima4 *src, + ALuint numchans, ALuint numblocks) +{ memcpy(dst, src, numblocks*36*numchans); } +DECL_TEMPLATE(ALbyte3) +DECL_TEMPLATE(ALubyte3) + +#undef DECL_TEMPLATE + +#define DECL_TEMPLATE(T) \ +static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType, \ + ALsizei numchans, ALsizei len) \ +{ \ + switch(srcType) \ + { \ + case UserFmtByte: \ + Convert_##T##_ALbyte(dst, src, numchans, len); \ + break; \ + case UserFmtUByte: \ + Convert_##T##_ALubyte(dst, src, numchans, len); \ + break; \ + case UserFmtShort: \ + Convert_##T##_ALshort(dst, src, numchans, len); \ + break; \ + case UserFmtUShort: \ + Convert_##T##_ALushort(dst, src, numchans, len); \ + break; \ + case UserFmtInt: \ + Convert_##T##_ALint(dst, src, numchans, len); \ + break; \ + case UserFmtUInt: \ + Convert_##T##_ALuint(dst, src, numchans, len); \ + break; \ + case UserFmtFloat: \ + Convert_##T##_ALfloat(dst, src, numchans, len); \ + break; \ + case UserFmtDouble: \ + Convert_##T##_ALdouble(dst, src, numchans, len); \ + break; \ + case UserFmtMulaw: \ + Convert_##T##_ALmulaw(dst, src, numchans, len); \ + break; \ + case UserFmtAlaw: \ + Convert_##T##_ALalaw(dst, src, numchans, len); \ + break; \ + case UserFmtIMA4: \ + Convert_##T##_ALima4(dst, src, numchans, len); \ + break; \ + case UserFmtByte3: \ + Convert_##T##_ALbyte3(dst, src, numchans, len); \ + break; \ + case UserFmtUByte3: \ + Convert_##T##_ALubyte3(dst, src, numchans, len); \ + break; \ + } \ +} + +DECL_TEMPLATE(ALbyte) +DECL_TEMPLATE(ALubyte) +DECL_TEMPLATE(ALshort) +DECL_TEMPLATE(ALushort) +DECL_TEMPLATE(ALint) +DECL_TEMPLATE(ALuint) +DECL_TEMPLATE(ALfloat) +DECL_TEMPLATE(ALdouble) +DECL_TEMPLATE(ALmulaw) +DECL_TEMPLATE(ALalaw) +DECL_TEMPLATE(ALima4) +DECL_TEMPLATE(ALbyte3) +DECL_TEMPLATE(ALubyte3) + +#undef DECL_TEMPLATE + + +static void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len) +{ + switch(dstType) + { + case UserFmtByte: + Convert_ALbyte(dst, src, srcType, numchans, len); + break; + case UserFmtUByte: + Convert_ALubyte(dst, src, srcType, numchans, len); + break; + case UserFmtShort: + Convert_ALshort(dst, src, srcType, numchans, len); + break; + case UserFmtUShort: + Convert_ALushort(dst, src, srcType, numchans, len); + break; + case UserFmtInt: + Convert_ALint(dst, src, srcType, numchans, len); + break; + case UserFmtUInt: + Convert_ALuint(dst, src, srcType, numchans, len); + break; + case UserFmtFloat: + Convert_ALfloat(dst, src, srcType, numchans, len); + break; + case UserFmtDouble: + Convert_ALdouble(dst, src, srcType, numchans, len); + break; + case UserFmtMulaw: + Convert_ALmulaw(dst, src, srcType, numchans, len); + break; + case UserFmtAlaw: + Convert_ALalaw(dst, src, srcType, numchans, len); + break; + case UserFmtIMA4: + Convert_ALima4(dst, src, srcType, numchans, len); + break; + case UserFmtByte3: + Convert_ALbyte3(dst, src, srcType, numchans, len); + break; + case UserFmtUByte3: + Convert_ALubyte3(dst, src, srcType, numchans, len); + break; + } +} + + +/* + * 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 frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALboolean storesrc) +{ + ALuint NewChannels, NewBytes; + enum FmtChannels DstChannels; + enum FmtType DstType; + ALuint64 newsize; + ALvoid *temp; + + if(DecomposeFormat(NewFormat, &DstChannels, &DstType) == AL_FALSE || + (long)SrcChannels != (long)DstChannels) + return AL_INVALID_ENUM; + + NewChannels = ChannelsFromFmt(DstChannels); + NewBytes = BytesFromFmt(DstType); + + newsize = frames; + newsize *= NewBytes; + newsize *= NewChannels; + if(newsize > INT_MAX) + return AL_OUT_OF_MEMORY; + + WriteLock(&ALBuf->lock); + if(ALBuf->ref != 0) + { + WriteUnlock(&ALBuf->lock); + return AL_INVALID_OPERATION; + } + + temp = realloc(ALBuf->data, (size_t)newsize); + if(!temp && newsize) + { + WriteUnlock(&ALBuf->lock); + return AL_OUT_OF_MEMORY; + } + ALBuf->data = temp; + + if(data != NULL) + ConvertData(ALBuf->data, DstType, data, SrcType, NewChannels, frames); + + if(storesrc) + { + ALBuf->OriginalChannels = SrcChannels; + ALBuf->OriginalType = SrcType; + if(SrcType == UserFmtIMA4) + ALBuf->OriginalSize = frames / 65 * 36 * ChannelsFromUserFmt(SrcChannels); + else + ALBuf->OriginalSize = frames * FrameSizeFromUserFmt(SrcChannels, SrcType); + } + else + { + ALBuf->OriginalChannels = DstChannels; + ALBuf->OriginalType = DstType; + ALBuf->OriginalSize = frames * NewBytes * NewChannels; + } + + ALBuf->Frequency = freq; + ALBuf->FmtChannels = DstChannels; + ALBuf->FmtType = DstType; + ALBuf->Format = NewFormat; + + ALBuf->SampleLen = frames; + ALBuf->LoopStart = 0; + ALBuf->LoopEnd = ALBuf->SampleLen; + + WriteUnlock(&ALBuf->lock); + return AL_NO_ERROR; +} + + +ALuint BytesFromUserFmt(enum UserFmtType type) +{ + switch(type) + { + case UserFmtByte: return sizeof(ALbyte); + case UserFmtUByte: return sizeof(ALubyte); + case UserFmtShort: return sizeof(ALshort); + case UserFmtUShort: return sizeof(ALushort); + case UserFmtInt: return sizeof(ALint); + case UserFmtUInt: return sizeof(ALuint); + case UserFmtFloat: return sizeof(ALfloat); + case UserFmtDouble: return sizeof(ALdouble); + case UserFmtByte3: return sizeof(ALbyte3); + case UserFmtUByte3: return sizeof(ALubyte3); + case UserFmtMulaw: return sizeof(ALubyte); + case UserFmtAlaw: 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; +} +static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, + enum UserFmtType *type) +{ + static const struct { + ALenum format; + enum UserFmtChannels channels; + enum UserFmtType type; + } list[] = { + { AL_FORMAT_MONO8, UserFmtMono, UserFmtUByte }, + { AL_FORMAT_MONO16, UserFmtMono, UserFmtShort }, + { AL_FORMAT_MONO_FLOAT32, UserFmtMono, UserFmtFloat }, + { AL_FORMAT_MONO_DOUBLE_EXT, UserFmtMono, UserFmtDouble }, + { AL_FORMAT_MONO_IMA4, UserFmtMono, UserFmtIMA4 }, + { AL_FORMAT_MONO_MULAW, UserFmtMono, UserFmtMulaw }, + { AL_FORMAT_MONO_ALAW_EXT, UserFmtMono, UserFmtAlaw }, + + { AL_FORMAT_STEREO8, UserFmtStereo, UserFmtUByte }, + { AL_FORMAT_STEREO16, UserFmtStereo, UserFmtShort }, + { AL_FORMAT_STEREO_FLOAT32, UserFmtStereo, UserFmtFloat }, + { AL_FORMAT_STEREO_DOUBLE_EXT, UserFmtStereo, UserFmtDouble }, + { AL_FORMAT_STEREO_IMA4, UserFmtStereo, UserFmtIMA4 }, + { AL_FORMAT_STEREO_MULAW, UserFmtStereo, UserFmtMulaw }, + { AL_FORMAT_STEREO_ALAW_EXT, UserFmtStereo, UserFmtAlaw }, + + { AL_FORMAT_REAR8, UserFmtRear, UserFmtUByte }, + { AL_FORMAT_REAR16, UserFmtRear, UserFmtShort }, + { AL_FORMAT_REAR32, UserFmtRear, UserFmtFloat }, + { AL_FORMAT_REAR_MULAW, UserFmtRear, UserFmtMulaw }, + + { AL_FORMAT_QUAD8_LOKI, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16_LOKI, UserFmtQuad, UserFmtShort }, + + { AL_FORMAT_QUAD8, UserFmtQuad, UserFmtUByte }, + { AL_FORMAT_QUAD16, UserFmtQuad, UserFmtShort }, + { AL_FORMAT_QUAD32, UserFmtQuad, UserFmtFloat }, + { AL_FORMAT_QUAD_MULAW, UserFmtQuad, UserFmtMulaw }, + + { AL_FORMAT_51CHN8, UserFmtX51, UserFmtUByte }, + { AL_FORMAT_51CHN16, UserFmtX51, UserFmtShort }, + { AL_FORMAT_51CHN32, UserFmtX51, UserFmtFloat }, + { AL_FORMAT_51CHN_MULAW, UserFmtX51, UserFmtMulaw }, + + { AL_FORMAT_61CHN8, UserFmtX61, UserFmtUByte }, + { AL_FORMAT_61CHN16, UserFmtX61, UserFmtShort }, + { AL_FORMAT_61CHN32, UserFmtX61, UserFmtFloat }, + { AL_FORMAT_61CHN_MULAW, UserFmtX61, UserFmtMulaw }, + + { AL_FORMAT_71CHN8, UserFmtX71, UserFmtUByte }, + { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, + { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, + { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, + }; + ALuint i; + + for(i = 0;i < COUNTOF(list);i++) + { + if(list[i].format == format) + { + *chans = list[i].channels; + *type = list[i].type; + return AL_TRUE; + } + } + + return AL_FALSE; +} + +ALuint BytesFromFmt(enum FmtType type) +{ + switch(type) + { + case FmtByte: return sizeof(ALbyte); + case FmtShort: return sizeof(ALshort); + case FmtFloat: return sizeof(ALfloat); + } + return 0; +} +ALuint ChannelsFromFmt(enum FmtChannels chans) +{ + switch(chans) + { + case FmtMono: return 1; + case FmtStereo: return 2; + case FmtRear: return 2; + case FmtQuad: return 4; + case FmtX51: return 6; + case FmtX61: return 7; + case FmtX71: return 8; + } + return 0; +} +static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type) +{ + static const struct { + ALenum format; + enum FmtChannels channels; + enum FmtType type; + } list[] = { + { AL_MONO8_SOFT, FmtMono, FmtByte }, + { AL_MONO16_SOFT, FmtMono, FmtShort }, + { AL_MONO32F_SOFT, FmtMono, FmtFloat }, + + { AL_STEREO8_SOFT, FmtStereo, FmtByte }, + { AL_STEREO16_SOFT, FmtStereo, FmtShort }, + { AL_STEREO32F_SOFT, FmtStereo, FmtFloat }, + + { AL_REAR8_SOFT, FmtRear, FmtByte }, + { AL_REAR16_SOFT, FmtRear, FmtShort }, + { AL_REAR32F_SOFT, FmtRear, FmtFloat }, + + { AL_FORMAT_QUAD8_LOKI, FmtQuad, FmtByte }, + { AL_FORMAT_QUAD16_LOKI, FmtQuad, FmtShort }, + + { AL_QUAD8_SOFT, FmtQuad, FmtByte }, + { AL_QUAD16_SOFT, FmtQuad, FmtShort }, + { AL_QUAD32F_SOFT, FmtQuad, FmtFloat }, + + { AL_5POINT1_8_SOFT, FmtX51, FmtByte }, + { AL_5POINT1_16_SOFT, FmtX51, FmtShort }, + { AL_5POINT1_32F_SOFT, FmtX51, FmtFloat }, + + { AL_6POINT1_8_SOFT, FmtX61, FmtByte }, + { AL_6POINT1_16_SOFT, FmtX61, FmtShort }, + { AL_6POINT1_32F_SOFT, FmtX61, FmtFloat }, + + { AL_7POINT1_8_SOFT, FmtX71, FmtByte }, + { AL_7POINT1_16_SOFT, FmtX71, FmtShort }, + { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat }, + }; + ALuint i; + + for(i = 0;i < COUNTOF(list);i++) + { + if(list[i].format == format) + { + *chans = list[i].channels; + *type = list[i].type; + return AL_TRUE; + } + } + + return AL_FALSE; +} + + +static ALboolean IsValidType(ALenum type) +{ + switch(type) + { + case AL_BYTE_SOFT: + case AL_UNSIGNED_BYTE_SOFT: + case AL_SHORT_SOFT: + case AL_UNSIGNED_SHORT_SOFT: + case AL_INT_SOFT: + case AL_UNSIGNED_INT_SOFT: + case AL_FLOAT_SOFT: + case AL_DOUBLE_SOFT: + case AL_BYTE3_SOFT: + case AL_UNSIGNED_BYTE3_SOFT: + return AL_TRUE; + } + return AL_FALSE; +} + +static ALboolean IsValidChannels(ALenum channels) +{ + switch(channels) + { + case AL_MONO_SOFT: + case AL_STEREO_SOFT: + case AL_REAR_SOFT: + case AL_QUAD_SOFT: + case AL_5POINT1_SOFT: + case AL_6POINT1_SOFT: + case AL_7POINT1_SOFT: + 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); + + FreeThunkEntry(temp->id); + memset(temp, 0, sizeof(ALbuffer)); + free(temp); + } +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alEffect.c b/src/eepp/helper/android/openal-soft/OpenAL32/alEffect.c new file mode 100644 index 000000000..4d2576416 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alEffect.c @@ -0,0 +1,1516 @@ +/** + * 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 "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); + + +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects) +{ + ALCcontext *Context; + ALsizei cur = 0; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + ALenum err; + + CHECK_VALUE(Context, n >= 0); + for(cur = 0;cur < n;cur++) + { + ALeffect *effect = calloc(1, sizeof(ALeffect)); + err = AL_OUT_OF_MEMORY; + if(!effect || (err=InitEffect(effect)) != AL_NO_ERROR) + { + free(effect); + al_throwerr(Context, err); + } + + err = NewThunkEntry(&effect->id); + if(err == AL_NO_ERROR) + err = InsertUIntMapEntry(&device->EffectMap, effect->id, effect); + if(err != AL_NO_ERROR) + { + FreeThunkEntry(effect->id); + memset(effect, 0, sizeof(ALeffect)); + free(effect); + + al_throwerr(Context, err); + } + + effects[cur] = effect->id; + } + } + al_catchany() + { + if(cur > 0) + alDeleteEffects(cur, effects); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects) +{ + ALCcontext *Context; + ALeffect *Effect; + ALsizei i; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if(effects[i] && LookupEffect(device, effects[i]) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + } + + for(i = 0;i < n;i++) + { + if((Effect=RemoveEffect(device, effects[i])) == NULL) + continue; + FreeThunkEntry(Effect->id); + + memset(Effect, 0, sizeof(*Effect)); + free(Effect); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + result = ((!effect || LookupEffect(Context->Device, effect)) ? + AL_TRUE : AL_FALSE); + + ALCcontext_DecRef(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + if(param == AL_EFFECT_TYPE) + { + ALboolean isOk = (value == AL_EFFECT_NULL); + ALint i; + for(i = 0;!isOk && EffectList[i].val;i++) + { + if(value == EffectList[i].val && + !DisabledEffects[EffectList[i].type]) + isOk = AL_TRUE; + } + + if(isOk) + InitEffectParams(ALEffect, value); + else + alSetError(Context, AL_INVALID_VALUE); + } + else + { + /* Call the appropriate handler */ + ALeffect_SetParami(ALEffect, Context, param, value); + } + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + switch(param) + { + case AL_EFFECT_TYPE: + alEffecti(effect, param, values[0]); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALeffect_SetParamiv(ALEffect, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALeffect_SetParamf(ALEffect, Context, param, value); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALeffect_SetParamfv(ALEffect, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + if(param == AL_EFFECT_TYPE) + *value = ALEffect->type; + else + { + /* Call the appropriate handler */ + ALeffect_GetParami(ALEffect, Context, param, value); + } + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + switch(param) + { + case AL_EFFECT_TYPE: + alGetEffecti(effect, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALeffect_GetParamiv(ALEffect, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALeffect_GetParamf(ALEffect, Context, param, value); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALeffect *ALEffect; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALEffect=LookupEffect(Device, effect)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALeffect_GetParamfv(ALEffect, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + + +static void eaxreverb_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + if(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT) + effect->Reverb.DecayHFLimit = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void eaxreverb_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + eaxreverb_SetParami(effect, context, param, vals[0]); +} +static void eaxreverb_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_EAXREVERB_DENSITY: + if(val >= AL_EAXREVERB_MIN_DENSITY && + val <= AL_EAXREVERB_MAX_DENSITY) + effect->Reverb.Density = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DIFFUSION: + if(val >= AL_EAXREVERB_MIN_DIFFUSION && + val <= AL_EAXREVERB_MAX_DIFFUSION) + effect->Reverb.Diffusion = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_GAIN: + if(val >= AL_EAXREVERB_MIN_GAIN && + val <= AL_EAXREVERB_MAX_GAIN) + effect->Reverb.Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_GAINHF: + if(val >= AL_EAXREVERB_MIN_GAINHF && + val <= AL_EAXREVERB_MAX_GAINHF) + effect->Reverb.GainHF = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_GAINLF: + if(val >= AL_EAXREVERB_MIN_GAINLF && + val <= AL_EAXREVERB_MAX_GAINLF) + effect->Reverb.GainLF = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DECAY_TIME: + if(val >= AL_EAXREVERB_MIN_DECAY_TIME && + val <= AL_EAXREVERB_MAX_DECAY_TIME) + effect->Reverb.DecayTime = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + if(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && + val <= AL_EAXREVERB_MAX_DECAY_HFRATIO) + effect->Reverb.DecayHFRatio = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + if(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && + val <= AL_EAXREVERB_MAX_DECAY_LFRATIO) + effect->Reverb.DecayLFRatio = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + if(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && + val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN) + effect->Reverb.ReflectionsGain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + if(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && + val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY) + effect->Reverb.ReflectionsDelay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + if(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && + val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN) + effect->Reverb.LateReverbGain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + if(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && + val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY) + effect->Reverb.LateReverbDelay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + if(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && + val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF) + effect->Reverb.AirAbsorptionGainHF = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_ECHO_TIME: + if(val >= AL_EAXREVERB_MIN_ECHO_TIME && + val <= AL_EAXREVERB_MAX_ECHO_TIME) + effect->Reverb.EchoTime = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_ECHO_DEPTH: + if(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && + val <= AL_EAXREVERB_MAX_ECHO_DEPTH) + effect->Reverb.EchoDepth = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_MODULATION_TIME: + if(val >= AL_EAXREVERB_MIN_MODULATION_TIME && + val <= AL_EAXREVERB_MAX_MODULATION_TIME) + effect->Reverb.ModulationTime = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + if(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && + val <= AL_EAXREVERB_MAX_MODULATION_DEPTH) + effect->Reverb.ModulationDepth = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_HFREFERENCE: + if(val >= AL_EAXREVERB_MIN_HFREFERENCE && + val <= AL_EAXREVERB_MAX_HFREFERENCE) + effect->Reverb.HFReference = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_LFREFERENCE: + if(val >= AL_EAXREVERB_MIN_LFREFERENCE && + val <= AL_EAXREVERB_MAX_LFREFERENCE) + effect->Reverb.LFReference = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + if(val >= 0.0f && val <= 10.0f) + effect->Reverb.RoomRolloffFactor = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void eaxreverb_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + switch(param) + { + case AL_EAXREVERB_REFLECTIONS_PAN: + if(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])) + { + LockContext(context); + effect->Reverb.ReflectionsPan[0] = vals[0]; + effect->Reverb.ReflectionsPan[1] = vals[1]; + effect->Reverb.ReflectionsPan[2] = vals[2]; + UnlockContext(context); + } + else + alSetError(context, AL_INVALID_VALUE); + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + if(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2])) + { + LockContext(context); + effect->Reverb.LateReverbPan[0] = vals[0]; + effect->Reverb.LateReverbPan[1] = vals[1]; + effect->Reverb.LateReverbPan[2] = vals[2]; + UnlockContext(context); + } + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + eaxreverb_SetParamf(effect, context, param, vals[0]); + break; + } +} + +static void eaxreverb_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_EAXREVERB_DECAY_HFLIMIT: + *val = effect->Reverb.DecayHFLimit; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void eaxreverb_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + eaxreverb_GetParami(effect, context, param, vals); +} +static void eaxreverb_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_EAXREVERB_DENSITY: + *val = effect->Reverb.Density; + break; + + case AL_EAXREVERB_DIFFUSION: + *val = effect->Reverb.Diffusion; + break; + + case AL_EAXREVERB_GAIN: + *val = effect->Reverb.Gain; + break; + + case AL_EAXREVERB_GAINHF: + *val = effect->Reverb.GainHF; + break; + + case AL_EAXREVERB_GAINLF: + *val = effect->Reverb.GainLF; + break; + + case AL_EAXREVERB_DECAY_TIME: + *val = effect->Reverb.DecayTime; + break; + + case AL_EAXREVERB_DECAY_HFRATIO: + *val = effect->Reverb.DecayHFRatio; + break; + + case AL_EAXREVERB_DECAY_LFRATIO: + *val = effect->Reverb.DecayLFRatio; + break; + + case AL_EAXREVERB_REFLECTIONS_GAIN: + *val = effect->Reverb.ReflectionsGain; + break; + + case AL_EAXREVERB_REFLECTIONS_DELAY: + *val = effect->Reverb.ReflectionsDelay; + break; + + case AL_EAXREVERB_LATE_REVERB_GAIN: + *val = effect->Reverb.LateReverbGain; + break; + + case AL_EAXREVERB_LATE_REVERB_DELAY: + *val = effect->Reverb.LateReverbDelay; + break; + + case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: + *val = effect->Reverb.AirAbsorptionGainHF; + break; + + case AL_EAXREVERB_ECHO_TIME: + *val = effect->Reverb.EchoTime; + break; + + case AL_EAXREVERB_ECHO_DEPTH: + *val = effect->Reverb.EchoDepth; + break; + + case AL_EAXREVERB_MODULATION_TIME: + *val = effect->Reverb.ModulationTime; + break; + + case AL_EAXREVERB_MODULATION_DEPTH: + *val = effect->Reverb.ModulationDepth; + break; + + case AL_EAXREVERB_HFREFERENCE: + *val = effect->Reverb.HFReference; + break; + + case AL_EAXREVERB_LFREFERENCE: + *val = effect->Reverb.LFReference; + break; + + case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: + *val = effect->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void eaxreverb_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + switch(param) + { + case AL_EAXREVERB_REFLECTIONS_PAN: + LockContext(context); + vals[0] = effect->Reverb.ReflectionsPan[0]; + vals[1] = effect->Reverb.ReflectionsPan[1]; + vals[2] = effect->Reverb.ReflectionsPan[2]; + UnlockContext(context); + break; + case AL_EAXREVERB_LATE_REVERB_PAN: + LockContext(context); + vals[0] = effect->Reverb.LateReverbPan[0]; + vals[1] = effect->Reverb.LateReverbPan[1]; + vals[2] = effect->Reverb.LateReverbPan[2]; + UnlockContext(context); + break; + + default: + eaxreverb_GetParamf(effect, context, param, vals); + break; + } +} + + +static void reverb_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + if(val >= AL_REVERB_MIN_DECAY_HFLIMIT && + val <= AL_REVERB_MAX_DECAY_HFLIMIT) + effect->Reverb.DecayHFLimit = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void reverb_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + reverb_SetParami(effect, context, param, vals[0]); +} +static void reverb_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_REVERB_DENSITY: + if(val >= AL_REVERB_MIN_DENSITY && + val <= AL_REVERB_MAX_DENSITY) + effect->Reverb.Density = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_DIFFUSION: + if(val >= AL_REVERB_MIN_DIFFUSION && + val <= AL_REVERB_MAX_DIFFUSION) + effect->Reverb.Diffusion = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_GAIN: + if(val >= AL_REVERB_MIN_GAIN && + val <= AL_REVERB_MAX_GAIN) + effect->Reverb.Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_GAINHF: + if(val >= AL_REVERB_MIN_GAINHF && + val <= AL_REVERB_MAX_GAINHF) + effect->Reverb.GainHF = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_DECAY_TIME: + if(val >= AL_REVERB_MIN_DECAY_TIME && + val <= AL_REVERB_MAX_DECAY_TIME) + effect->Reverb.DecayTime = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_DECAY_HFRATIO: + if(val >= AL_REVERB_MIN_DECAY_HFRATIO && + val <= AL_REVERB_MAX_DECAY_HFRATIO) + effect->Reverb.DecayHFRatio = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_REFLECTIONS_GAIN: + if(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && + val <= AL_REVERB_MAX_REFLECTIONS_GAIN) + effect->Reverb.ReflectionsGain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_REFLECTIONS_DELAY: + if(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && + val <= AL_REVERB_MAX_REFLECTIONS_DELAY) + effect->Reverb.ReflectionsDelay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_LATE_REVERB_GAIN: + if(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && + val <= AL_REVERB_MAX_LATE_REVERB_GAIN) + effect->Reverb.LateReverbGain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_LATE_REVERB_DELAY: + if(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && + val <= AL_REVERB_MAX_LATE_REVERB_DELAY) + effect->Reverb.LateReverbDelay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + if(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && + val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF) + effect->Reverb.AirAbsorptionGainHF = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + if(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && + val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR) + effect->Reverb.RoomRolloffFactor = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void reverb_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + reverb_SetParamf(effect, context, param, vals[0]); +} + +static void reverb_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_REVERB_DECAY_HFLIMIT: + *val = effect->Reverb.DecayHFLimit; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void reverb_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + reverb_GetParami(effect, context, param, vals); +} +static void reverb_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_REVERB_DENSITY: + *val = effect->Reverb.Density; + break; + + case AL_REVERB_DIFFUSION: + *val = effect->Reverb.Diffusion; + break; + + case AL_REVERB_GAIN: + *val = effect->Reverb.Gain; + break; + + case AL_REVERB_GAINHF: + *val = effect->Reverb.GainHF; + break; + + case AL_REVERB_DECAY_TIME: + *val = effect->Reverb.DecayTime; + break; + + case AL_REVERB_DECAY_HFRATIO: + *val = effect->Reverb.DecayHFRatio; + break; + + case AL_REVERB_REFLECTIONS_GAIN: + *val = effect->Reverb.ReflectionsGain; + break; + + case AL_REVERB_REFLECTIONS_DELAY: + *val = effect->Reverb.ReflectionsDelay; + break; + + case AL_REVERB_LATE_REVERB_GAIN: + *val = effect->Reverb.LateReverbGain; + break; + + case AL_REVERB_LATE_REVERB_DELAY: + *val = effect->Reverb.LateReverbDelay; + break; + + case AL_REVERB_AIR_ABSORPTION_GAINHF: + *val = effect->Reverb.AirAbsorptionGainHF; + break; + + case AL_REVERB_ROOM_ROLLOFF_FACTOR: + *val = effect->Reverb.RoomRolloffFactor; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void reverb_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + reverb_GetParamf(effect, context, param, vals); +} + + +static void echo_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void echo_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + echo_SetParami(effect, context, param, vals[0]); +} +static void echo_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_ECHO_DELAY: + if(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY) + effect->Echo.Delay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_LRDELAY: + if(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY) + effect->Echo.LRDelay = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_DAMPING: + if(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING) + effect->Echo.Damping = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_FEEDBACK: + if(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK) + effect->Echo.Feedback = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_ECHO_SPREAD: + if(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD) + effect->Echo.Spread = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void echo_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + echo_SetParamf(effect, context, param, vals[0]); +} + +static void echo_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void echo_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + echo_GetParami(effect, context, param, vals); +} +static void echo_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_ECHO_DELAY: + *val = effect->Echo.Delay; + break; + + case AL_ECHO_LRDELAY: + *val = effect->Echo.LRDelay; + break; + + case AL_ECHO_DAMPING: + *val = effect->Echo.Damping; + break; + + case AL_ECHO_FEEDBACK: + *val = effect->Echo.Feedback; + break; + + case AL_ECHO_SPREAD: + *val = effect->Echo.Spread; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void echo_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + echo_GetParamf(effect, context, param, vals); +} + + +static void mod_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + if(val >= AL_RING_MODULATOR_MIN_FREQUENCY && + val <= AL_RING_MODULATOR_MAX_FREQUENCY) + effect->Modulator.Frequency = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + if(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && + val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF) + effect->Modulator.HighPassCutoff = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void mod_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + mod_SetParamf(effect, context, param, vals[0]); +} +static void mod_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + mod_SetParamf(effect, context, param, (ALfloat)val); + break; + + case AL_RING_MODULATOR_WAVEFORM: + if(val >= AL_RING_MODULATOR_MIN_WAVEFORM && + val <= AL_RING_MODULATOR_MAX_WAVEFORM) + effect->Modulator.Waveform = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void mod_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + mod_SetParami(effect, context, param, vals[0]); +} + +static void mod_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = (ALint)effect->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = (ALint)effect->Modulator.HighPassCutoff; + break; + case AL_RING_MODULATOR_WAVEFORM: + *val = effect->Modulator.Waveform; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void mod_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + mod_GetParami(effect, context, param, vals); +} +static void mod_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_RING_MODULATOR_FREQUENCY: + *val = effect->Modulator.Frequency; + break; + case AL_RING_MODULATOR_HIGHPASS_CUTOFF: + *val = effect->Modulator.HighPassCutoff; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void mod_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + mod_GetParamf(effect, context, param, vals); +} + + +static void ded_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void ded_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ + ded_SetParami(effect, context, param, vals[0]); +} +static void ded_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_DEDICATED_GAIN: + if(val >= 0.0f && isfinite(val)) + effect->Dedicated.Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void ded_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + ded_SetParamf(effect, context, param, vals[0]); +} + +static void ded_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void ded_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ + ded_GetParami(effect, context, param, vals); +} +static void ded_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_DEDICATED_GAIN: + *val = effect->Dedicated.Gain; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void ded_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ + ded_GetParamf(effect, context, param, vals); +} + + +static void null_SetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_SetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) +{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } +static void null_SetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_SetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) +{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } + +static void null_GetParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_GetParamiv(ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) +{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } +static void null_GetParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) +{ (void)effect;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_GetParamfv(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) +{ (void)effect;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } + + +ALenum InitEffect(ALeffect *effect) +{ + InitEffectParams(effect, AL_EFFECT_NULL); + return AL_NO_ERROR; +} + +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 + FreeThunkEntry(temp->id); + memset(temp, 0, sizeof(ALeffect)); + free(temp); + } +} + + +static void InitEffectParams(ALeffect *effect, ALenum type) +{ + switch(type) + { + case AL_EFFECT_EAXREVERB: + effect->Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY; + effect->Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION; + effect->Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN; + effect->Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF; + effect->Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF; + effect->Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME; + effect->Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO; + effect->Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO; + effect->Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN; + effect->Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ; + effect->Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN; + effect->Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ; + effect->Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME; + effect->Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH; + effect->Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME; + effect->Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH; + effect->Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE; + effect->Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE; + effect->Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + effect->Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT; + effect->SetParami = eaxreverb_SetParami; + effect->SetParamiv = eaxreverb_SetParamiv; + effect->SetParamf = eaxreverb_SetParamf; + effect->SetParamfv = eaxreverb_SetParamfv; + effect->GetParami = eaxreverb_GetParami; + effect->GetParamiv = eaxreverb_GetParamiv; + effect->GetParamf = eaxreverb_GetParamf; + effect->GetParamfv = eaxreverb_GetParamfv; + break; + case AL_EFFECT_REVERB: + effect->Reverb.Density = AL_REVERB_DEFAULT_DENSITY; + effect->Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; + effect->Reverb.Gain = AL_REVERB_DEFAULT_GAIN; + effect->Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; + effect->Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; + effect->Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; + effect->Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; + effect->Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; + effect->Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; + effect->Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; + effect->SetParami = reverb_SetParami; + effect->SetParamiv = reverb_SetParamiv; + effect->SetParamf = reverb_SetParamf; + effect->SetParamfv = reverb_SetParamfv; + effect->GetParami = reverb_GetParami; + effect->GetParamiv = reverb_GetParamiv; + effect->GetParamf = reverb_GetParamf; + effect->GetParamfv = reverb_GetParamfv; + break; + case AL_EFFECT_ECHO: + effect->Echo.Delay = AL_ECHO_DEFAULT_DELAY; + effect->Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY; + effect->Echo.Damping = AL_ECHO_DEFAULT_DAMPING; + effect->Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK; + effect->Echo.Spread = AL_ECHO_DEFAULT_SPREAD; + effect->SetParami = echo_SetParami; + effect->SetParamiv = echo_SetParamiv; + effect->SetParamf = echo_SetParamf; + effect->SetParamfv = echo_SetParamfv; + effect->GetParami = echo_GetParami; + effect->GetParamiv = echo_GetParamiv; + effect->GetParamf = echo_GetParamf; + effect->GetParamfv = echo_GetParamfv; + break; + case AL_EFFECT_RING_MODULATOR: + effect->Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY; + effect->Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF; + effect->Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM; + effect->SetParami = mod_SetParami; + effect->SetParamiv = mod_SetParamiv; + effect->SetParamf = mod_SetParamf; + effect->SetParamfv = mod_SetParamfv; + effect->GetParami = mod_GetParami; + effect->GetParamiv = mod_GetParamiv; + effect->GetParamf = mod_GetParamf; + effect->GetParamfv = mod_GetParamfv; + break; + case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT: + case AL_EFFECT_DEDICATED_DIALOGUE: + effect->Dedicated.Gain = 1.0f; + effect->SetParami = ded_SetParami; + effect->SetParamiv = ded_SetParamiv; + effect->SetParamf = ded_SetParamf; + effect->SetParamfv = ded_SetParamfv; + effect->GetParami = ded_GetParami; + effect->GetParamiv = ded_GetParamiv; + effect->GetParamf = ded_GetParamf; + effect->GetParamfv = ded_GetParamfv; + break; + default: + effect->SetParami = null_SetParami; + effect->SetParamiv = null_SetParamiv; + effect->SetParamf = null_SetParamf; + effect->SetParamfv = null_SetParamfv; + effect->GetParami = null_GetParami; + effect->GetParamiv = null_GetParamiv; + effect->GetParamf = null_GetParamf; + effect->GetParamfv = null_GetParamfv; + break; + } + effect->type = type; +} + + +#include "AL/efx-presets.h" + +#define DECL(x) { #x, EFX_REVERB_PRESET_##x } +static const struct { + const char name[32]; + EFXEAXREVERBPROPERTIES props; +} reverblist[] = { + DECL(GENERIC), + DECL(PADDEDCELL), + DECL(ROOM), + DECL(BATHROOM), + DECL(LIVINGROOM), + DECL(STONEROOM), + DECL(AUDITORIUM), + DECL(CONCERTHALL), + DECL(CAVE), + DECL(ARENA), + DECL(HANGAR), + DECL(CARPETEDHALLWAY), + DECL(HALLWAY), + DECL(STONECORRIDOR), + DECL(ALLEY), + DECL(FOREST), + DECL(CITY), + DECL(MOUNTAINS), + DECL(QUARRY), + DECL(PLAIN), + DECL(PARKINGLOT), + DECL(SEWERPIPE), + DECL(UNDERWATER), + DECL(DRUGGED), + DECL(DIZZY), + DECL(PSYCHOTIC), + + DECL(CASTLE_SMALLROOM), + DECL(CASTLE_SHORTPASSAGE), + DECL(CASTLE_MEDIUMROOM), + DECL(CASTLE_LARGEROOM), + DECL(CASTLE_LONGPASSAGE), + DECL(CASTLE_HALL), + DECL(CASTLE_CUPBOARD), + DECL(CASTLE_COURTYARD), + DECL(CASTLE_ALCOVE), + + DECL(FACTORY_SMALLROOM), + DECL(FACTORY_SHORTPASSAGE), + DECL(FACTORY_MEDIUMROOM), + DECL(FACTORY_LARGEROOM), + DECL(FACTORY_LONGPASSAGE), + DECL(FACTORY_HALL), + DECL(FACTORY_CUPBOARD), + DECL(FACTORY_COURTYARD), + DECL(FACTORY_ALCOVE), + + DECL(ICEPALACE_SMALLROOM), + DECL(ICEPALACE_SHORTPASSAGE), + DECL(ICEPALACE_MEDIUMROOM), + DECL(ICEPALACE_LARGEROOM), + DECL(ICEPALACE_LONGPASSAGE), + DECL(ICEPALACE_HALL), + DECL(ICEPALACE_CUPBOARD), + DECL(ICEPALACE_COURTYARD), + DECL(ICEPALACE_ALCOVE), + + DECL(SPACESTATION_SMALLROOM), + DECL(SPACESTATION_SHORTPASSAGE), + DECL(SPACESTATION_MEDIUMROOM), + DECL(SPACESTATION_LARGEROOM), + DECL(SPACESTATION_LONGPASSAGE), + DECL(SPACESTATION_HALL), + DECL(SPACESTATION_CUPBOARD), + DECL(SPACESTATION_ALCOVE), + + DECL(WOODEN_SMALLROOM), + DECL(WOODEN_SHORTPASSAGE), + DECL(WOODEN_MEDIUMROOM), + DECL(WOODEN_LARGEROOM), + DECL(WOODEN_LONGPASSAGE), + DECL(WOODEN_HALL), + DECL(WOODEN_CUPBOARD), + DECL(WOODEN_COURTYARD), + DECL(WOODEN_ALCOVE), + + DECL(SPORT_EMPTYSTADIUM), + DECL(SPORT_SQUASHCOURT), + DECL(SPORT_SMALLSWIMMINGPOOL), + DECL(SPORT_LARGESWIMMINGPOOL), + DECL(SPORT_GYMNASIUM), + DECL(SPORT_FULLSTADIUM), + DECL(SPORT_STADIUMTANNOY), + + DECL(PREFAB_WORKSHOP), + DECL(PREFAB_SCHOOLROOM), + DECL(PREFAB_PRACTISEROOM), + DECL(PREFAB_OUTHOUSE), + DECL(PREFAB_CARAVAN), + + DECL(DOME_TOMB), + DECL(PIPE_SMALL), + DECL(DOME_SAINTPAULS), + DECL(PIPE_LONGTHIN), + DECL(PIPE_LARGE), + DECL(PIPE_RESONANT), + + DECL(OUTDOORS_BACKYARD), + DECL(OUTDOORS_ROLLINGPLAINS), + DECL(OUTDOORS_DEEPCANYON), + DECL(OUTDOORS_CREEK), + DECL(OUTDOORS_VALLEY), + + DECL(MOOD_HEAVEN), + DECL(MOOD_HELL), + DECL(MOOD_MEMORY), + + DECL(DRIVING_COMMENTATOR), + DECL(DRIVING_PITGARAGE), + DECL(DRIVING_INCAR_RACER), + DECL(DRIVING_INCAR_SPORTS), + DECL(DRIVING_INCAR_LUXURY), + DECL(DRIVING_FULLGRANDSTAND), + DECL(DRIVING_EMPTYGRANDSTAND), + DECL(DRIVING_TUNNEL), + + DECL(CITY_STREETS), + DECL(CITY_SUBWAY), + DECL(CITY_MUSEUM), + DECL(CITY_LIBRARY), + DECL(CITY_UNDERPASS), + DECL(CITY_ABANDONED), + + DECL(DUSTYROOM), + DECL(CHAPEL), + DECL(SMALLWATERROOM), +}; +#undef DECL +static const ALsizei reverblistsize = COUNTOF(reverblist); + +ALvoid LoadReverbPreset(const char *name, ALeffect *effect) +{ + int i; + + if(strcasecmp(name, "NONE") == 0) + { + InitEffectParams(effect, AL_EFFECT_NULL); + TRACE("Loading reverb '%s'\n", "NONE"); + return; + } + + if(!DisabledEffects[EAXREVERB]) + InitEffectParams(effect, AL_EFFECT_EAXREVERB); + else if(!DisabledEffects[REVERB]) + InitEffectParams(effect, AL_EFFECT_REVERB); + else + InitEffectParams(effect, AL_EFFECT_NULL); + for(i = 0;i < reverblistsize;i++) + { + const EFXEAXREVERBPROPERTIES *props; + + if(strcasecmp(name, reverblist[i].name) != 0) + continue; + + TRACE("Loading reverb '%s'\n", reverblist[i].name); + props = &reverblist[i].props; + effect->Reverb.Density = props->flDensity; + effect->Reverb.Diffusion = props->flDiffusion; + effect->Reverb.Gain = props->flGain; + effect->Reverb.GainHF = props->flGainHF; + effect->Reverb.GainLF = props->flGainLF; + effect->Reverb.DecayTime = props->flDecayTime; + effect->Reverb.DecayHFRatio = props->flDecayHFRatio; + effect->Reverb.DecayLFRatio = props->flDecayLFRatio; + effect->Reverb.ReflectionsGain = props->flReflectionsGain; + effect->Reverb.ReflectionsDelay = props->flReflectionsDelay; + effect->Reverb.ReflectionsPan[0] = props->flReflectionsPan[0]; + effect->Reverb.ReflectionsPan[1] = props->flReflectionsPan[1]; + effect->Reverb.ReflectionsPan[2] = props->flReflectionsPan[2]; + effect->Reverb.LateReverbGain = props->flLateReverbGain; + effect->Reverb.LateReverbDelay = props->flLateReverbDelay; + effect->Reverb.LateReverbPan[0] = props->flLateReverbPan[0]; + effect->Reverb.LateReverbPan[1] = props->flLateReverbPan[1]; + effect->Reverb.LateReverbPan[2] = props->flLateReverbPan[2]; + effect->Reverb.EchoTime = props->flEchoTime; + effect->Reverb.EchoDepth = props->flEchoDepth; + effect->Reverb.ModulationTime = props->flModulationTime; + effect->Reverb.ModulationDepth = props->flModulationDepth; + effect->Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF; + effect->Reverb.HFReference = props->flHFReference; + effect->Reverb.LFReference = props->flLFReference; + effect->Reverb.RoomRolloffFactor = props->flRoomRolloffFactor; + effect->Reverb.DecayHFLimit = props->iDecayHFLimit; + break; + } + if(i == reverblistsize) + WARN("Reverb preset '%s' not found\n", name); +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alError.c b/src/eepp/helper/android/openal-soft/OpenAL32/alError.c new file mode 100644 index 000000000..d18c1867a --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alError.c @@ -0,0 +1,71 @@ +/** + * 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 "alError.h" + +ALboolean TrapALError = AL_FALSE; + +ALvoid alSetError(ALCcontext *Context, ALenum errorCode) +{ + if(TrapALError) + { +#ifdef _WIN32 + /* DebugBreak will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + CompExchangeInt(&Context->LastError, AL_NO_ERROR, errorCode); +} + +AL_API ALenum AL_APIENTRY alGetError(void) +{ + ALCcontext *Context; + ALenum errorCode; + + Context = GetContextRef(); + if(!Context) + { + if(TrapALError) + { +#ifdef _WIN32 + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + return AL_INVALID_OPERATION; + } + + errorCode = ExchangeInt(&Context->LastError, AL_NO_ERROR); + + ALCcontext_DecRef(Context); + + return errorCode; +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alExtension.c b/src/eepp/helper/android/openal-soft/OpenAL32/alExtension.c new file mode 100644 index 000000000..c73200d0f --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alExtension.c @@ -0,0 +1,100 @@ +/** + * 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 "alSource.h" +#include "alBuffer.h" +#include "AL/al.h" +#include "AL/alc.h" + + +const struct EffectList EffectList[] = { + { "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB }, + { "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB }, + { "echo", ECHO, "AL_EFFECT_ECHO", AL_EFFECT_ECHO }, + { "modulator", MODULATOR, "AL_EFFECT_RING_MODULATOR", AL_EFFECT_RING_MODULATOR }, + { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT", AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT }, + { "dedicated", DEDICATED, "AL_EFFECT_DEDICATED_DIALOGUE", AL_EFFECT_DEDICATED_DIALOGUE }, + { NULL, 0, NULL, (ALenum)0 } +}; + + +AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName) +{ + ALboolean ret = AL_FALSE; + ALCcontext *Context; + const char *ptr; + size_t len; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + al_try + { + CHECK_VALUE(Context, extName); + + len = strlen(extName); + ptr = Context->ExtensionList; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extName, len) == 0 && + (ptr[len] == '\0' || isspace(ptr[len]))) + { + ret = AL_TRUE; + break; + } + if((ptr=strchr(ptr, ' ')) != NULL) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + } + al_endtry; + + ALCcontext_DecRef(Context); + return ret; +} + + +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) +{ + if(!enumName) + return (ALenum)0; + return alcGetEnumValue(NULL, enumName); +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alFilter.c b/src/eepp/helper/android/openal-soft/OpenAL32/alFilter.c new file mode 100644 index 000000000..a03ee2d83 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alFilter.c @@ -0,0 +1,468 @@ +/** + * 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 "alu.h" +#include "alFilter.h" +#include "alThunk.h" +#include "alError.h" + + +static void InitFilterParams(ALfilter *filter, ALenum type); + + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters) +{ + ALCcontext *Context; + ALsizei cur = 0; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + ALenum err; + + CHECK_VALUE(Context, n >= 0); + for(cur = 0;cur < n;cur++) + { + ALfilter *filter = calloc(1, sizeof(ALfilter)); + if(!filter) + al_throwerr(Context, AL_OUT_OF_MEMORY); + InitFilterParams(filter, AL_FILTER_NULL); + + err = NewThunkEntry(&filter->id); + if(err == AL_NO_ERROR) + err = InsertUIntMapEntry(&device->FilterMap, filter->id, filter); + if(err != AL_NO_ERROR) + { + FreeThunkEntry(filter->id); + memset(filter, 0, sizeof(ALfilter)); + free(filter); + + al_throwerr(Context, err); + } + + filters[cur] = filter->id; + } + } + al_catchany() + { + if(cur > 0) + alDeleteFilters(cur, filters); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters) +{ + ALCcontext *Context; + ALfilter *Filter; + ALsizei i; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if(filters[i] && LookupFilter(device, filters[i]) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + } + + for(i = 0;i < n;i++) + { + if((Filter=RemoveFilter(device, filters[i])) == NULL) + continue; + FreeThunkEntry(Filter->id); + + memset(Filter, 0, sizeof(*Filter)); + free(Filter); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + result = ((!filter || LookupFilter(Context->Device, filter)) ? + AL_TRUE : AL_FALSE); + + ALCcontext_DecRef(Context); + + return result; +} + +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + if(param == AL_FILTER_TYPE) + { + if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS) + InitFilterParams(ALFilter, value); + else + alSetError(Context, AL_INVALID_VALUE); + } + else + { + /* Call the appropriate handler */ + ALfilter_SetParami(ALFilter, Context, param, value); + } + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + switch(param) + { + case AL_FILTER_TYPE: + alFilteri(filter, param, values[0]); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALfilter_SetParamiv(ALFilter, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALfilter_SetParamf(ALFilter, Context, param, value); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALfilter_SetParamfv(ALFilter, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + if(param == AL_FILTER_TYPE) + *value = ALFilter->type; + else + { + /* Call the appropriate handler */ + ALfilter_GetParami(ALFilter, Context, param, value); + } + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + switch(param) + { + case AL_FILTER_TYPE: + alGetFilteri(filter, param, values); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALfilter_GetParamiv(ALFilter, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALfilter_GetParamf(ALFilter, Context, param, value); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + ALCdevice *Device; + ALfilter *ALFilter; + + Context = GetContextRef(); + if(!Context) return; + + Device = Context->Device; + if((ALFilter=LookupFilter(Device, filter)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else + { + /* Call the appropriate handler */ + ALfilter_GetParamfv(ALFilter, Context, param, values); + } + + ALCcontext_DecRef(Context); +} + + +ALfloat lpCoeffCalc(ALfloat g, ALfloat cw) +{ + ALfloat a = 0.0f; + + if(g < 0.9999f) /* 1-epsilon */ + { + /* Be careful with gains < 0.001, as that causes the coefficient head + * towards 1, which will flatten the signal */ + g = maxf(g, 0.001f); + a = (1 - g*cw - sqrtf(2*g*(1-cw) - g*g*(1 - cw*cw))) / + (1 - g); + } + + return a; +} + + +static void lp_SetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint val) +{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void lp_SetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals) +{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } +static void lp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + if(val >= AL_LOWPASS_MIN_GAIN && val <= AL_LOWPASS_MAX_GAIN) + filter->Gain = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + case AL_LOWPASS_GAINHF: + if(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF) + filter->GainHF = val; + else + alSetError(context, AL_INVALID_VALUE); + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void lp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ + lp_SetParamf(filter, context, param, vals[0]); +} + +static void lp_GetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val) +{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void lp_GetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals) +{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } +static void lp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ + switch(param) + { + case AL_LOWPASS_GAIN: + *val = filter->Gain; + break; + + case AL_LOWPASS_GAINHF: + *val = filter->GainHF; + break; + + default: + alSetError(context, AL_INVALID_ENUM); + break; + } +} +static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ + lp_GetParamf(filter, context, param, vals); +} + + +static void null_SetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint val) +{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_SetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals) +{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } +static void null_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val) +{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals) +{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } + +static void null_GetParami(ALfilter *filter, ALCcontext *context, ALenum param, ALint *val) +{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_GetParamiv(ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals) +{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } +static void null_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val) +{ (void)filter;(void)param;(void)val; alSetError(context, AL_INVALID_ENUM); } +static void null_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals) +{ (void)filter;(void)param;(void)vals; alSetError(context, AL_INVALID_ENUM); } + + +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 + FreeThunkEntry(temp->id); + memset(temp, 0, sizeof(ALfilter)); + free(temp); + } +} + + +static void InitFilterParams(ALfilter *filter, ALenum type) +{ + if(type == AL_FILTER_LOWPASS) + { + filter->Gain = AL_LOWPASS_DEFAULT_GAIN; + filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF; + + filter->SetParami = lp_SetParami; + filter->SetParamiv = lp_SetParamiv; + filter->SetParamf = lp_SetParamf; + filter->SetParamfv = lp_SetParamfv; + filter->GetParami = lp_GetParami; + filter->GetParamiv = lp_GetParamiv; + filter->GetParamf = lp_GetParamf; + filter->GetParamfv = lp_GetParamfv; + } + else + { + filter->SetParami = null_SetParami; + filter->SetParamiv = null_SetParamiv; + filter->SetParamf = null_SetParamf; + filter->SetParamfv = null_SetParamfv; + filter->GetParami = null_GetParami; + filter->GetParamiv = null_GetParamiv; + filter->GetParamf = null_GetParamf; + filter->GetParamfv = null_GetParamfv; + } + filter->type = type; +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alListener.c b/src/eepp/helper/android/openal-soft/OpenAL32/alListener.c new file mode 100644 index 000000000..682acbb53 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alListener.c @@ -0,0 +1,472 @@ +/** + * 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 param, ALfloat value) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + switch(param) + { + case AL_GAIN: + CHECK_VALUE(Context, value >= 0.0f && isfinite(value)); + + Context->Listener->Gain = value; + Context->UpdateSources = AL_TRUE; + break; + + case AL_METERS_PER_UNIT: + CHECK_VALUE(Context, value >= 0.0f && isfinite(value)); + + Context->Listener->MetersPerUnit = value; + Context->UpdateSources = AL_TRUE; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + switch(param) + { + case AL_POSITION: + CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3)); + + LockContext(Context); + Context->Listener->Position[0] = value1; + Context->Listener->Position[1] = value2; + Context->Listener->Position[2] = value3; + Context->UpdateSources = AL_TRUE; + UnlockContext(Context); + break; + + case AL_VELOCITY: + CHECK_VALUE(Context, isfinite(value1) && isfinite(value2) && isfinite(value3)); + + LockContext(Context); + Context->Listener->Velocity[0] = value1; + Context->Listener->Velocity[1] = value2; + Context->Listener->Velocity[2] = value3; + Context->UpdateSources = AL_TRUE; + UnlockContext(Context); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + + if(values) + { + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alListenerf(param, values[0]); + return; + + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, values[0], values[1], values[2]); + return; + } + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(param) + { + case AL_ORIENTATION: + CHECK_VALUE(Context, isfinite(values[0]) && isfinite(values[1]) && + isfinite(values[2]) && isfinite(values[3]) && + isfinite(values[4]) && isfinite(values[5])); + + LockContext(Context); + /* AT then UP */ + Context->Listener->Forward[0] = values[0]; + Context->Listener->Forward[1] = values[1]; + Context->Listener->Forward[2] = values[2]; + Context->Listener->Up[0] = values[3]; + Context->Listener->Up[1] = values[4]; + Context->Listener->Up[2] = values[5]; + Context->UpdateSources = AL_TRUE; + UnlockContext(Context); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alListeneri(ALenum param, ALint value) +{ + ALCcontext *Context; + + (void)value; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3) +{ + ALCcontext *Context; + + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, (ALfloat)value1, (ALfloat)value2, (ALfloat)value3); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values) +{ + ALCcontext *Context; + + if(values) + { + ALfloat fvals[6]; + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(param, (ALfloat)values[0], (ALfloat)values[1], (ALfloat)values[2]); + return; + + case AL_ORIENTATION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + fvals[3] = (ALfloat)values[3]; + fvals[4] = (ALfloat)values[4]; + fvals[5] = (ALfloat)values[5]; + alListenerfv(param, fvals); + return; + } + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value); + switch(param) + { + case AL_GAIN: + *value = Context->Listener->Gain; + break; + + case AL_METERS_PER_UNIT: + *value = Context->Listener->MetersPerUnit; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value1 && value2 && value3); + switch(param) + { + case AL_POSITION: + LockContext(Context); + *value1 = Context->Listener->Position[0]; + *value2 = Context->Listener->Position[1]; + *value3 = Context->Listener->Position[2]; + UnlockContext(Context); + break; + + case AL_VELOCITY: + LockContext(Context); + *value1 = Context->Listener->Velocity[0]; + *value2 = Context->Listener->Velocity[1]; + *value3 = Context->Listener->Velocity[2]; + UnlockContext(Context); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values) +{ + ALCcontext *Context; + + switch(param) + { + case AL_GAIN: + case AL_METERS_PER_UNIT: + alGetListenerf(param, values); + return; + + case AL_POSITION: + case AL_VELOCITY: + alGetListener3f(param, values+0, values+1, values+2); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(param) + { + case AL_ORIENTATION: + LockContext(Context); + // AT then UP + values[0] = Context->Listener->Forward[0]; + values[1] = Context->Listener->Forward[1]; + values[2] = Context->Listener->Forward[2]; + values[3] = Context->Listener->Up[0]; + values[4] = Context->Listener->Up[1]; + values[5] = Context->Listener->Up[2]; + UnlockContext(Context); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum param, ALint *value) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value); + switch(param) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value1 && value2 && value3); + switch (param) + { + case AL_POSITION: + LockContext(Context); + *value1 = (ALint)Context->Listener->Position[0]; + *value2 = (ALint)Context->Listener->Position[1]; + *value3 = (ALint)Context->Listener->Position[2]; + UnlockContext(Context); + break; + + case AL_VELOCITY: + LockContext(Context); + *value1 = (ALint)Context->Listener->Velocity[0]; + *value2 = (ALint)Context->Listener->Velocity[1]; + *value3 = (ALint)Context->Listener->Velocity[2]; + UnlockContext(Context); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values) +{ + ALCcontext *Context; + + switch(param) + { + case AL_POSITION: + case AL_VELOCITY: + alGetListener3i(param, values+0, values+1, values+2); + return; + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(param) + { + case AL_ORIENTATION: + LockContext(Context); + // AT then UP + values[0] = (ALint)Context->Listener->Forward[0]; + values[1] = (ALint)Context->Listener->Forward[1]; + values[2] = (ALint)Context->Listener->Forward[2]; + values[3] = (ALint)Context->Listener->Up[0]; + values[4] = (ALint)Context->Listener->Up[1]; + values[5] = (ALint)Context->Listener->Up[2]; + UnlockContext(Context); + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alSource.c b/src/eepp/helper/android/openal-soft/OpenAL32/alSource.c new file mode 100644 index 000000000..5dbea3145 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alSource.c @@ -0,0 +1,2735 @@ +/** + * 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 "AL/al.h" +#include "AL/alc.h" +#include "alMain.h" +#include "alError.h" +#include "alSource.h" +#include "alBuffer.h" +#include "alThunk.h" +#include "alAuxEffectSlot.h" + + +enum Resampler DefaultResampler = LinearResampler; +const ALsizei ResamplerPadding[ResamplerMax] = { + 0, /* Point */ + 1, /* Linear */ + 2, /* Cubic */ +}; +const ALsizei ResamplerPrePadding[ResamplerMax] = { + 0, /* Point */ + 0, /* Linear */ + 1, /* Cubic */ +}; + + +static ALvoid InitSourceParams(ALsource *Source); +static ALint64 GetSourceOffset(const ALsource *Source); +static ALdouble GetSourceSecOffset(const ALsource *Source); +static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen); +static ALint GetSampleOffset(ALsource *Source); + +typedef enum SrcFloatProp { + sfPitch = AL_PITCH, + sfGain = AL_GAIN, + sfMinGain = AL_MIN_GAIN, + sfMaxGain = AL_MAX_GAIN, + sfMaxDistance = AL_MAX_DISTANCE, + sfRolloffFactor = AL_ROLLOFF_FACTOR, + sfDopplerFactor = AL_DOPPLER_FACTOR, + sfConeOuterGain = AL_CONE_OUTER_GAIN, + sfSecOffset = AL_SEC_OFFSET, + sfSampleOffset = AL_SAMPLE_OFFSET, + sfByteOffset = AL_BYTE_OFFSET, + sfConeInnerAngle = AL_CONE_INNER_ANGLE, + sfConeOuterAngle = AL_CONE_OUTER_ANGLE, + sfRefDistance = AL_REFERENCE_DISTANCE, + + sfPosition = AL_POSITION, + sfVelocity = AL_VELOCITY, + sfDirection = AL_DIRECTION, + + sfSourceRelative = AL_SOURCE_RELATIVE, + sfLooping = AL_LOOPING, + sfBuffer = AL_BUFFER, + sfSourceState = AL_SOURCE_STATE, + sfBuffersQueued = AL_BUFFERS_QUEUED, + sfBuffersProcessed = AL_BUFFERS_PROCESSED, + sfSourceType = AL_SOURCE_TYPE, + + /* ALC_EXT_EFX */ + sfConeOuterGainHF = AL_CONE_OUTER_GAINHF, + sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, + sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, + sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, + sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, + sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + + /* AL_SOFT_direct_channels */ + sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, + + /* AL_EXT_source_distance_model */ + sfDistanceModel = AL_DISTANCE_MODEL, + + /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */ + sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT, + sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT, + + /* AL_SOFT_source_latency */ + sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, +} SrcFloatProp; + +typedef enum SrcIntProp { + siMaxDistance = AL_MAX_DISTANCE, + siRolloffFactor = AL_ROLLOFF_FACTOR, + siRefDistance = AL_REFERENCE_DISTANCE, + siSourceRelative = AL_SOURCE_RELATIVE, + siConeInnerAngle = AL_CONE_INNER_ANGLE, + siConeOuterAngle = AL_CONE_OUTER_ANGLE, + siLooping = AL_LOOPING, + siBuffer = AL_BUFFER, + siSourceState = AL_SOURCE_STATE, + siBuffersQueued = AL_BUFFERS_QUEUED, + siBuffersProcessed = AL_BUFFERS_PROCESSED, + siSourceType = AL_SOURCE_TYPE, + siSecOffset = AL_SEC_OFFSET, + siSampleOffset = AL_SAMPLE_OFFSET, + siByteOffset = AL_BYTE_OFFSET, + siDopplerFactor = AL_DOPPLER_FACTOR, + siPosition = AL_POSITION, + siVelocity = AL_VELOCITY, + siDirection = AL_DIRECTION, + + /* ALC_EXT_EFX */ + siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, + siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, + siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + siDirectFilter = AL_DIRECT_FILTER, + siAuxSendFilter = AL_AUXILIARY_SEND_FILTER, + + /* AL_SOFT_direct_channels */ + siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, + + /* AL_EXT_source_distance_model */ + siDistanceModel = AL_DISTANCE_MODEL, + + /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */ + siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT, + siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT, + + /* AL_SOFT_source_latency */ + siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, +} SrcIntProp; + +static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values); +static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values); +static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values); + +static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values); +static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values); +static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values); + +static ALint FloatValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SrcFloatProp)prop)) + return 0; + switch((SrcFloatProp)prop) + { + case sfPitch: + case sfGain: + case sfMinGain: + case sfMaxGain: + case sfMaxDistance: + case sfRolloffFactor: + case sfDopplerFactor: + case sfConeOuterGain: + case sfSecOffset: + case sfSampleOffset: + case sfByteOffset: + case sfConeInnerAngle: + case sfConeOuterAngle: + case sfRefDistance: + case sfConeOuterGainHF: + case sfAirAbsorptionFactor: + case sfRoomRolloffFactor: + case sfDirectFilterGainHFAuto: + case sfAuxSendFilterGainAuto: + case sfAuxSendFilterGainHFAuto: + case sfDirectChannelsSOFT: + case sfDistanceModel: + case sfSourceRelative: + case sfLooping: + case sfBuffer: + case sfSourceState: + case sfBuffersQueued: + case sfBuffersProcessed: + case sfSourceType: + return 1; + + case sfSampleRWOffsetsSOFT: + case sfByteRWOffsetsSOFT: + return 2; + + case sfPosition: + case sfVelocity: + case sfDirection: + return 3; + + case sfSecOffsetLatencySOFT: + break; /* Double only */ + } + return 0; +} +static ALint DoubleValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SrcFloatProp)prop)) + return 0; + switch((SrcFloatProp)prop) + { + case sfPitch: + case sfGain: + case sfMinGain: + case sfMaxGain: + case sfMaxDistance: + case sfRolloffFactor: + case sfDopplerFactor: + case sfConeOuterGain: + case sfSecOffset: + case sfSampleOffset: + case sfByteOffset: + case sfConeInnerAngle: + case sfConeOuterAngle: + case sfRefDistance: + case sfConeOuterGainHF: + case sfAirAbsorptionFactor: + case sfRoomRolloffFactor: + case sfDirectFilterGainHFAuto: + case sfAuxSendFilterGainAuto: + case sfAuxSendFilterGainHFAuto: + case sfDirectChannelsSOFT: + case sfDistanceModel: + case sfSourceRelative: + case sfLooping: + case sfBuffer: + case sfSourceState: + case sfBuffersQueued: + case sfBuffersProcessed: + case sfSourceType: + return 1; + + case sfSampleRWOffsetsSOFT: + case sfByteRWOffsetsSOFT: + case sfSecOffsetLatencySOFT: + return 2; + + case sfPosition: + case sfVelocity: + case sfDirection: + return 3; + } + return 0; +} + +static ALint IntValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SrcIntProp)prop)) + return 0; + switch((SrcIntProp)prop) + { + case siMaxDistance: + case siRolloffFactor: + case siRefDistance: + case siSourceRelative: + case siConeInnerAngle: + case siConeOuterAngle: + case siLooping: + case siBuffer: + case siSourceState: + case siBuffersQueued: + case siBuffersProcessed: + case siSourceType: + case siSecOffset: + case siSampleOffset: + case siByteOffset: + case siDopplerFactor: + case siDirectFilterGainHFAuto: + case siAuxSendFilterGainAutio: + case siAuxSendFilterGainHFAuto: + case siDirectFilter: + case siDirectChannelsSOFT: + case siDistanceModel: + return 1; + + case siSampleRWOffsetsSOFT: + case siByteRWOffsetsSOFT: + return 2; + + case siPosition: + case siVelocity: + case siDirection: + case siAuxSendFilter: + return 3; + + case siSampleOffsetLatencySOFT: + break; /* i64 only */ + } + return 0; +} +static ALint Int64ValsByProp(ALenum prop) +{ + if(prop != (ALenum)((SrcIntProp)prop)) + return 0; + switch((SrcIntProp)prop) + { + case siMaxDistance: + case siRolloffFactor: + case siRefDistance: + case siSourceRelative: + case siConeInnerAngle: + case siConeOuterAngle: + case siLooping: + case siBuffer: + case siSourceState: + case siBuffersQueued: + case siBuffersProcessed: + case siSourceType: + case siSecOffset: + case siSampleOffset: + case siByteOffset: + case siDopplerFactor: + case siDirectFilterGainHFAuto: + case siAuxSendFilterGainAutio: + case siAuxSendFilterGainHFAuto: + case siDirectFilter: + case siDirectChannelsSOFT: + case siDistanceModel: + return 1; + + case siSampleRWOffsetsSOFT: + case siByteRWOffsetsSOFT: + case siSampleOffsetLatencySOFT: + return 2; + + case siPosition: + case siVelocity: + case siDirection: + case siAuxSendFilter: + return 3; + } + return 0; +} + + +#define RETERR(x) do { \ + alSetError(Context, (x)); \ + return (x); \ +} while(0) + +#define CHECKVAL(x) do { \ + if(!(x)) \ + RETERR(AL_INVALID_VALUE); \ +} while(0) + +static ALenum SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values) +{ + ALint ival; + + switch(prop) + { + case AL_PITCH: + CHECKVAL(*values >= 0.0f); + + Source->Pitch = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_CONE_INNER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->InnerAngle = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_CONE_OUTER_ANGLE: + CHECKVAL(*values >= 0.0f && *values <= 360.0f); + + Source->OuterAngle = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_GAIN: + CHECKVAL(*values >= 0.0f); + + Source->Gain = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_MAX_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->MaxDistance = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f); + + Source->RollOffFactor = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_REFERENCE_DISTANCE: + CHECKVAL(*values >= 0.0f); + + Source->RefDistance = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_MIN_GAIN: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->MinGain = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_MAX_GAIN: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->MaxGain = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_CONE_OUTER_GAIN: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGain = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_CONE_OUTER_GAINHF: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->OuterGainHF = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_AIR_ABSORPTION_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->AirAbsorptionFactor = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_ROOM_ROLLOFF_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 10.0f); + + Source->RoomRolloffFactor = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_DOPPLER_FACTOR: + CHECKVAL(*values >= 0.0f && *values <= 1.0f); + + Source->DopplerFactor = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0.0f); + + LockContext(Context); + Source->OffsetType = prop; + Source->Offset = *values; + + if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && + !Context->DeferUpdates) + { + if(ApplyOffset(Source) == AL_FALSE) + { + UnlockContext(Context); + RETERR(AL_INVALID_VALUE); + } + } + UnlockContext(Context); + return AL_NO_ERROR; + + + case AL_SEC_OFFSET_LATENCY_SOFT: + /* Query only */ + RETERR(AL_INVALID_OPERATION); + + + case AL_POSITION: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + + LockContext(Context); + Source->Position[0] = values[0]; + Source->Position[1] = values[1]; + Source->Position[2] = values[2]; + UnlockContext(Context); + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_VELOCITY: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + + LockContext(Context); + Source->Velocity[0] = values[0]; + Source->Velocity[1] = values[1]; + Source->Velocity[2] = values[2]; + UnlockContext(Context); + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_DIRECTION: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); + + LockContext(Context); + Source->Orientation[0] = values[0]; + Source->Orientation[1] = values[1]; + Source->Orientation[2] = values[2]; + UnlockContext(Context); + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + + case sfSampleRWOffsetsSOFT: + case sfByteRWOffsetsSOFT: + RETERR(AL_INVALID_OPERATION); + + + case sfSourceRelative: + case sfLooping: + case sfSourceState: + case sfSourceType: + case sfDistanceModel: + case sfDirectFilterGainHFAuto: + case sfAuxSendFilterGainAuto: + case sfAuxSendFilterGainHFAuto: + case sfDirectChannelsSOFT: + ival = (ALint)values[0]; + return SetSourceiv(Source, Context, prop, &ival); + + case sfBuffer: + case sfBuffersQueued: + case sfBuffersProcessed: + ival = (ALint)((ALuint)values[0]); + return SetSourceiv(Source, Context, prop, &ival); + } + + ERR("Unexpected property: 0x%04x\n", prop); + RETERR(AL_INVALID_ENUM); +} + +static ALenum SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values) +{ + ALCdevice *device = Context->Device; + ALbuffer *buffer = NULL; + ALfilter *filter = NULL; + ALeffectslot *slot = NULL; + ALbufferlistitem *oldlist; + ALfloat fvals[3]; + + switch(prop) + { + case AL_SOURCE_RELATIVE: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->HeadRelative = (ALboolean)*values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_LOOPING: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->Looping = (ALboolean)*values; + return AL_NO_ERROR; + + case AL_BUFFER: + CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL); + + LockContext(Context); + if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL)) + { + UnlockContext(Context); + RETERR(AL_INVALID_OPERATION); + } + + Source->BuffersInQueue = 0; + Source->BuffersPlayed = 0; + + if(buffer != NULL) + { + ALbufferlistitem *BufferListItem; + + /* Source is now Static */ + Source->SourceType = AL_STATIC; + + /* Add the selected buffer to a one-item queue */ + BufferListItem = malloc(sizeof(ALbufferlistitem)); + BufferListItem->buffer = buffer; + BufferListItem->next = NULL; + BufferListItem->prev = NULL; + IncrementRef(&buffer->ref); + + oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem); + Source->BuffersInQueue = 1; + + ReadLock(&buffer->lock); + Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + Source->SampleSize = BytesFromFmt(buffer->FmtType); + ReadUnlock(&buffer->lock); + if(buffer->FmtChannels == FmtMono) + Source->Update = CalcSourceParams; + else + Source->Update = CalcNonAttnSourceParams; + Source->NeedsUpdate = AL_TRUE; + } + else + { + /* Source is now Undetermined */ + Source->SourceType = AL_UNDETERMINED; + oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL); + } + + /* Delete all elements in the previous queue */ + while(oldlist != NULL) + { + ALbufferlistitem *temp = oldlist; + oldlist = temp->next; + + if(temp->buffer) + DecrementRef(&temp->buffer->ref); + free(temp); + } + UnlockContext(Context); + return AL_NO_ERROR; + + case siSourceState: + case siSourceType: + case siBuffersQueued: + case siBuffersProcessed: + /* Query only */ + RETERR(AL_INVALID_OPERATION); + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + CHECKVAL(*values >= 0); + + LockContext(Context); + Source->OffsetType = prop; + Source->Offset = *values; + + if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && + !Context->DeferUpdates) + { + if(ApplyOffset(Source) == AL_FALSE) + { + UnlockContext(Context); + RETERR(AL_INVALID_VALUE); + } + } + UnlockContext(Context); + return AL_NO_ERROR; + + + case siSampleRWOffsetsSOFT: + case siByteRWOffsetsSOFT: + /* Query only */ + RETERR(AL_INVALID_OPERATION); + + + case AL_DIRECT_FILTER: + CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL); + + LockContext(Context); + if(!filter) + { + Source->DirectGain = 1.0f; + Source->DirectGainHF = 1.0f; + } + else + { + Source->DirectGain = filter->Gain; + Source->DirectGainHF = filter->GainHF; + } + UnlockContext(Context); + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DryGainHFAuto = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainAuto = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->WetGainHFAuto = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_DIRECT_CHANNELS_SOFT: + CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); + + Source->DirectChannels = *values; + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + case AL_DISTANCE_MODEL: + CHECKVAL(*values == AL_NONE || + *values == AL_INVERSE_DISTANCE || + *values == AL_INVERSE_DISTANCE_CLAMPED || + *values == AL_LINEAR_DISTANCE || + *values == AL_LINEAR_DISTANCE_CLAMPED || + *values == AL_EXPONENT_DISTANCE || + *values == AL_EXPONENT_DISTANCE_CLAMPED); + + Source->DistanceModel = *values; + if(Context->SourceDistanceModel) + Source->NeedsUpdate = AL_TRUE; + return AL_NO_ERROR; + + + case AL_AUXILIARY_SEND_FILTER: + LockContext(Context); + if(!((ALuint)values[1] < device->NumAuxSends && + (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) && + (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))) + { + UnlockContext(Context); + RETERR(AL_INVALID_VALUE); + } + + /* Add refcount on the new slot, and release the previous slot */ + if(slot) IncrementRef(&slot->ref); + slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot); + if(slot) DecrementRef(&slot->ref); + + if(!filter) + { + /* Disable filter */ + Source->Send[values[1]].Gain = 1.0f; + Source->Send[values[1]].GainHF = 1.0f; + } + else + { + Source->Send[values[1]].Gain = filter->Gain; + Source->Send[values[1]].GainHF = filter->GainHF; + } + Source->NeedsUpdate = AL_TRUE; + UnlockContext(Context); + return AL_NO_ERROR; + + + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case siDopplerFactor: + fvals[0] = (ALfloat)*values; + return SetSourcefv(Source, Context, (int)prop, fvals); + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + return SetSourcefv(Source, Context, (int)prop, fvals); + + case siSampleOffsetLatencySOFT: + /* i64 only */ + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + RETERR(AL_INVALID_ENUM); +} + +static ALenum SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values) +{ + ALfloat fvals[3]; + ALint ivals[3]; + + switch(prop) + { + case siSampleRWOffsetsSOFT: + case siByteRWOffsetsSOFT: + case siSampleOffsetLatencySOFT: + /* Query only */ + RETERR(AL_INVALID_OPERATION); + + + /* 1x int */ + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BYTE_OFFSET: + case AL_SAMPLE_OFFSET: + case siSourceType: + case siBuffersQueued: + case siBuffersProcessed: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); + + ivals[0] = (ALint)*values; + return SetSourceiv(Source, Context, (int)prop, ivals); + + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + CHECKVAL(*values <= UINT_MAX && *values >= 0); + + ivals[0] = (ALuint)*values; + return SetSourceiv(Source, Context, (int)prop, ivals); + + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && + values[1] <= UINT_MAX && values[1] >= 0 && + values[2] <= UINT_MAX && values[2] >= 0); + + ivals[0] = (ALuint)values[0]; + ivals[1] = (ALuint)values[1]; + ivals[2] = (ALuint)values[2]; + return SetSourceiv(Source, Context, (int)prop, ivals); + + /* 1x float */ + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_SEC_OFFSET: + case siDopplerFactor: + fvals[0] = (ALfloat)*values; + return SetSourcefv(Source, Context, (int)prop, fvals); + + /* 3x float */ + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + return SetSourcefv(Source, Context, (int)prop, fvals); + } + + ERR("Unexpected property: 0x%04x\n", prop); + RETERR(AL_INVALID_ENUM); +} + +#undef CHECKVAL + + +static ALenum GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values) +{ + ALdouble offsets[2]; + ALdouble updateLen; + ALint ivals[3]; + ALenum err; + + switch(prop) + { + case AL_GAIN: + *values = Source->Gain; + return AL_NO_ERROR; + + case AL_PITCH: + *values = Source->Pitch; + return AL_NO_ERROR; + + case AL_MAX_DISTANCE: + *values = Source->MaxDistance; + return AL_NO_ERROR; + + case AL_ROLLOFF_FACTOR: + *values = Source->RollOffFactor; + return AL_NO_ERROR; + + case AL_REFERENCE_DISTANCE: + *values = Source->RefDistance; + return AL_NO_ERROR; + + case AL_CONE_INNER_ANGLE: + *values = Source->InnerAngle; + return AL_NO_ERROR; + + case AL_CONE_OUTER_ANGLE: + *values = Source->OuterAngle; + return AL_NO_ERROR; + + case AL_MIN_GAIN: + *values = Source->MinGain; + return AL_NO_ERROR; + + case AL_MAX_GAIN: + *values = Source->MaxGain; + return AL_NO_ERROR; + + case AL_CONE_OUTER_GAIN: + *values = Source->OuterGain; + return AL_NO_ERROR; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + LockContext(Context); + updateLen = (ALdouble)Context->Device->UpdateSize / + Context->Device->Frequency; + GetSourceOffsets(Source, prop, offsets, updateLen); + UnlockContext(Context); + *values = offsets[0]; + return AL_NO_ERROR; + + case AL_CONE_OUTER_GAINHF: + *values = Source->OuterGainHF; + return AL_NO_ERROR; + + case AL_AIR_ABSORPTION_FACTOR: + *values = Source->AirAbsorptionFactor; + return AL_NO_ERROR; + + case AL_ROOM_ROLLOFF_FACTOR: + *values = Source->RoomRolloffFactor; + return AL_NO_ERROR; + + case AL_DOPPLER_FACTOR: + *values = Source->DopplerFactor; + return AL_NO_ERROR; + + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: + LockContext(Context); + updateLen = (ALdouble)Context->Device->UpdateSize / + Context->Device->Frequency; + GetSourceOffsets(Source, prop, values, updateLen); + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_SEC_OFFSET_LATENCY_SOFT: + LockContext(Context); + values[0] = GetSourceSecOffset(Source); + values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) / + 1000000000.0; + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_POSITION: + LockContext(Context); + values[0] = Source->Position[0]; + values[1] = Source->Position[1]; + values[2] = Source->Position[2]; + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_VELOCITY: + LockContext(Context); + values[0] = Source->Velocity[0]; + values[1] = Source->Velocity[1]; + values[2] = Source->Velocity[2]; + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_DIRECTION: + LockContext(Context); + values[0] = Source->Orientation[0]; + values[1] = Source->Orientation[1]; + values[2] = Source->Orientation[2]; + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR) + *values = (ALdouble)ivals[0]; + return err; + } + + ERR("Unexpected property: 0x%04x\n", prop); + RETERR(AL_INVALID_ENUM); +} + +static ALenum GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values) +{ + ALbufferlistitem *BufferList; + ALdouble dvals[3]; + ALenum err; + + switch(prop) + { + case AL_SOURCE_RELATIVE: + *values = Source->HeadRelative; + return AL_NO_ERROR; + + case AL_LOOPING: + *values = Source->Looping; + return AL_NO_ERROR; + + case AL_BUFFER: + LockContext(Context); + BufferList = Source->queue; + if(Source->SourceType != AL_STATIC) + { + ALuint i = Source->BuffersPlayed; + while(i > 0) + { + BufferList = BufferList->next; + i--; + } + } + *values = ((BufferList && BufferList->buffer) ? + BufferList->buffer->id : 0); + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_SOURCE_STATE: + *values = Source->state; + return AL_NO_ERROR; + + case AL_BUFFERS_QUEUED: + *values = Source->BuffersInQueue; + return AL_NO_ERROR; + + case AL_BUFFERS_PROCESSED: + LockContext(Context); + if(Source->Looping || Source->SourceType != AL_STREAMING) + { + /* Buffers on a looping source are in a perpetual state of + * PENDING, so don't report any as PROCESSED */ + *values = 0; + } + else + *values = Source->BuffersPlayed; + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_SOURCE_TYPE: + *values = Source->SourceType; + return AL_NO_ERROR; + + case AL_DIRECT_FILTER_GAINHF_AUTO: + *values = Source->DryGainHFAuto; + return AL_NO_ERROR; + + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + *values = Source->WetGainAuto; + return AL_NO_ERROR; + + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + *values = Source->WetGainHFAuto; + return AL_NO_ERROR; + + case AL_DIRECT_CHANNELS_SOFT: + *values = Source->DirectChannels; + return AL_NO_ERROR; + + case AL_DISTANCE_MODEL: + *values = Source->DistanceModel; + return AL_NO_ERROR; + + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR) + *values = (ALint)dvals[0]; + return err; + + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: + if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR) + { + values[0] = (ALint)dvals[0]; + values[1] = (ALint)dvals[1]; + } + return err; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR) + { + values[0] = (ALint)dvals[0]; + values[1] = (ALint)dvals[1]; + values[2] = (ALint)dvals[2]; + } + return err; + + case siSampleOffsetLatencySOFT: + /* i64 only */ + break; + + case siDirectFilter: + case siAuxSendFilter: + /* ??? */ + break; + } + + ERR("Unexpected property: 0x%04x\n", prop); + RETERR(AL_INVALID_ENUM); +} + +static ALenum GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values) +{ + ALdouble dvals[3]; + ALint ivals[3]; + ALenum err; + + switch(prop) + { + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + LockContext(Context); + values[0] = GetSourceOffset(Source); + values[1] = ALCdevice_GetLatency(Context->Device); + UnlockContext(Context); + return AL_NO_ERROR; + + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_DOPPLER_FACTOR: + if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR) + *values = (ALint64)dvals[0]; + return err; + + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: + if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR) + { + values[0] = (ALint64)dvals[0]; + values[1] = (ALint64)dvals[1]; + } + return err; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + if((err=GetSourcedv(Source, Context, (int)prop, dvals)) == AL_NO_ERROR) + { + values[0] = (ALint64)dvals[0]; + values[1] = (ALint64)dvals[1]; + values[2] = (ALint64)dvals[2]; + } + return err; + + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR) + *values = ivals[0]; + return err; + + case siBuffer: + case siDirectFilter: + if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR) + *values = ((ALuint*)ivals)[0]; + return err; + + case siAuxSendFilter: + if((err=GetSourceiv(Source, Context, (int)prop, ivals)) == AL_NO_ERROR) + { + values[0] = ((ALuint*)ivals)[0]; + values[1] = ((ALuint*)ivals)[1]; + values[2] = ((ALuint*)ivals)[2]; + } + return err; + } + + ERR("Unexpected property: 0x%04x\n", prop); + RETERR(AL_INVALID_ENUM); +} + +#undef RETERR + + +AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) +{ + ALCcontext *Context; + ALsizei cur = 0; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALenum err; + + CHECK_VALUE(Context, n >= 0); + for(cur = 0;cur < n;cur++) + { + ALsource *source = al_calloc(16, sizeof(ALsource)); + if(!source) + al_throwerr(Context, AL_OUT_OF_MEMORY); + InitSourceParams(source); + + err = NewThunkEntry(&source->id); + if(err == AL_NO_ERROR) + err = InsertUIntMapEntry(&Context->SourceMap, source->id, source); + if(err != AL_NO_ERROR) + { + FreeThunkEntry(source->id); + memset(source, 0, sizeof(ALsource)); + al_free(source); + + al_throwerr(Context, err); + } + + sources[cur] = source->id; + } + } + al_catchany() + { + if(cur > 0) + alDeleteSources(cur, sources); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALbufferlistitem *BufferList; + ALsource *Source; + ALsizei i, j; + + CHECK_VALUE(Context, n >= 0); + + /* Check that all Sources are valid */ + for(i = 0;i < n;i++) + { + if(LookupSource(Context, sources[i]) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + } + + for(i = 0;i < n;i++) + { + ALsource **srclist, **srclistend; + + if((Source=RemoveSource(Context, sources[i])) == NULL) + continue; + FreeThunkEntry(Source->id); + + LockContext(Context); + srclist = Context->ActiveSources; + srclistend = srclist + Context->ActiveSourceCount; + while(srclist != srclistend) + { + if(*srclist == Source) + { + Context->ActiveSourceCount--; + *srclist = *(--srclistend); + break; + } + srclist++; + } + UnlockContext(Context); + + while(Source->queue != NULL) + { + BufferList = Source->queue; + Source->queue = BufferList->next; + + if(BufferList->buffer != NULL) + DecrementRef(&BufferList->buffer->ref); + free(BufferList); + } + + for(j = 0;j < MAX_SENDS;++j) + { + if(Source->Send[j].Slot) + DecrementRef(&Source->Send[j].Slot->ref); + Source->Send[j].Slot = NULL; + } + + memset(Source, 0, sizeof(*Source)); + al_free(Source); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) +{ + ALCcontext *Context; + ALboolean result; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + result = (LookupSource(Context, source) ? AL_TRUE : AL_FALSE); + + ALCcontext_DecRef(Context); + + return result; +} + + +AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(FloatValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + SetSourcefv(Source, Context, param, &value); + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(FloatValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALfloat fvals[3] = { value1, value2, value3 }; + SetSourcefv(Source, Context, param, fvals); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!(FloatValsByProp(param) > 0)) + alSetError(Context, AL_INVALID_ENUM); + else + SetSourcefv(Source, Context, param, values); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(DoubleValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALfloat fval = (ALfloat)value; + SetSourcefv(Source, Context, param, &fval); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(DoubleValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; + SetSourcefv(Source, Context, param, fvals); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) +{ + ALCcontext *Context; + ALsource *Source; + ALint count; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALfloat fvals[3]; + ALint i; + + for(i = 0;i < count;i++) + fvals[i] = (ALfloat)values[i]; + SetSourcefv(Source, Context, param, fvals); + } + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(IntValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + SetSourceiv(Source, Context, param, &value); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(IntValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALint ivals[3] = { value1, value2, value3 }; + SetSourceiv(Source, Context, param, ivals); + } + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!(IntValsByProp(param) > 0)) + alSetError(Context, AL_INVALID_ENUM); + else + SetSourceiv(Source, Context, param, values); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(Int64ValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + SetSourcei64v(Source, Context, param, &value); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(Int64ValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALint64SOFT i64vals[3] = { value1, value2, value3 }; + SetSourcei64v(Source, Context, param, i64vals); + } + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!(Int64ValsByProp(param) > 0)) + alSetError(Context, AL_INVALID_ENUM); + else + SetSourcei64v(Source, Context, param, values); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!value) + alSetError(Context, AL_INVALID_VALUE); + else if(!(FloatValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALdouble dval; + if(GetSourcedv(Source, Context, param, &dval) == AL_NO_ERROR) + *value = (ALfloat)dval; + } + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE); + else if(!(FloatValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR) + { + *value1 = (ALfloat)dvals[0]; + *value2 = (ALfloat)dvals[1]; + *value3 = (ALfloat)dvals[2]; + } + } + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) +{ + ALCcontext *Context; + ALsource *Source; + ALint count; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!((count=FloatValsByProp(param)) > 0 && count <= 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR) + { + ALint i; + for(i = 0;i < count;i++) + values[i] = (ALfloat)dvals[i]; + } + } + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!value) + alSetError(Context, AL_INVALID_VALUE); + else if(!(DoubleValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + GetSourcedv(Source, Context, param, value); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE); + else if(!(DoubleValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALdouble dvals[3]; + if(GetSourcedv(Source, Context, param, dvals) == AL_NO_ERROR) + { + *value1 = dvals[0]; + *value2 = dvals[1]; + *value3 = dvals[2]; + } + } + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!(DoubleValsByProp(param) > 0)) + alSetError(Context, AL_INVALID_ENUM); + else + GetSourcedv(Source, Context, param, values); + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!value) + alSetError(Context, AL_INVALID_VALUE); + else if(!(IntValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + GetSourceiv(Source, Context, param, value); + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE); + else if(!(IntValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALint ivals[3]; + if(GetSourceiv(Source, Context, param, ivals) == AL_NO_ERROR) + { + *value1 = ivals[0]; + *value2 = ivals[1]; + *value3 = ivals[2]; + } + } + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!(IntValsByProp(param) > 0)) + alSetError(Context, AL_INVALID_ENUM); + else + GetSourceiv(Source, Context, param, values); + + ALCcontext_DecRef(Context); +} + + +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!value) + alSetError(Context, AL_INVALID_VALUE); + else if(!(Int64ValsByProp(param) == 1)) + alSetError(Context, AL_INVALID_ENUM); + else + GetSourcei64v(Source, Context, param, value); + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!(value1 && value2 && value3)) + alSetError(Context, AL_INVALID_VALUE); + else if(!(Int64ValsByProp(param) == 3)) + alSetError(Context, AL_INVALID_ENUM); + else + { + ALint64 i64vals[3]; + if(GetSourcei64v(Source, Context, param, i64vals) == AL_NO_ERROR) + { + *value1 = i64vals[0]; + *value2 = i64vals[1]; + *value3 = i64vals[2]; + } + } + + ALCcontext_DecRef(Context); +} + +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) +{ + ALCcontext *Context; + ALsource *Source; + + Context = GetContextRef(); + if(!Context) return; + + if((Source=LookupSource(Context, source)) == NULL) + alSetError(Context, AL_INVALID_NAME); + else if(!values) + alSetError(Context, AL_INVALID_VALUE); + else if(!(Int64ValsByProp(param) > 0)) + alSetError(Context, AL_INVALID_ENUM); + else + GetSourcei64v(Source, Context, param, values); + + ALCcontext_DecRef(Context); +} + + +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; + ALsizei i; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if(!LookupSource(Context, sources[i])) + al_throwerr(Context, AL_INVALID_NAME); + } + + LockContext(Context); + 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) + { + UnlockContext(Context); + al_throwerr(Context, AL_OUT_OF_MEMORY); + } + + Context->ActiveSources = temp; + Context->MaxActiveSources = newcount; + } + + for(i = 0;i < n;i++) + { + Source = LookupSource(Context, sources[i]); + if(Context->DeferUpdates) Source->new_state = AL_PLAYING; + else SetSourceState(Source, Context, AL_PLAYING); + } + UnlockContext(Context); + } + al_endtry; + + ALCcontext_DecRef(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 = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if(!LookupSource(Context, sources[i])) + al_throwerr(Context, AL_INVALID_NAME); + } + + LockContext(Context); + for(i = 0;i < n;i++) + { + Source = LookupSource(Context, sources[i]); + if(Context->DeferUpdates) Source->new_state = AL_PAUSED; + else SetSourceState(Source, Context, AL_PAUSED); + } + UnlockContext(Context); + } + al_endtry; + + ALCcontext_DecRef(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 = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if(!LookupSource(Context, sources[i])) + al_throwerr(Context, AL_INVALID_NAME); + } + + LockContext(Context); + for(i = 0;i < n;i++) + { + Source = LookupSource(Context, sources[i]); + Source->new_state = AL_NONE; + SetSourceState(Source, Context, AL_STOPPED); + } + UnlockContext(Context); + } + al_endtry; + + ALCcontext_DecRef(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 = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, n >= 0); + for(i = 0;i < n;i++) + { + if(!LookupSource(Context, sources[i])) + al_throwerr(Context, AL_INVALID_NAME); + } + + LockContext(Context); + for(i = 0;i < n;i++) + { + Source = LookupSource(Context, sources[i]); + Source->new_state = AL_NONE; + SetSourceState(Source, Context, AL_INITIAL); + } + UnlockContext(Context); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + ALbufferlistitem *BufferListStart = NULL; + ALbufferlistitem *BufferList; + ALbuffer *BufferFmt; + + if(nb == 0) + return; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + ALCdevice *device = Context->Device; + + CHECK_VALUE(Context, nb >= 0); + + if((Source=LookupSource(Context, source)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + LockContext(Context); + if(Source->SourceType == AL_STATIC) + { + UnlockContext(Context); + /* Can't queue on a Static Source */ + al_throwerr(Context, AL_INVALID_OPERATION); + } + + BufferFmt = NULL; + + /* Check for a valid Buffer, for its frequency and format */ + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer) + { + BufferFmt = BufferList->buffer; + break; + } + BufferList = BufferList->next; + } + + for(i = 0;i < nb;i++) + { + ALbuffer *buffer = NULL; + if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) + { + UnlockContext(Context); + al_throwerr(Context, AL_INVALID_NAME); + } + + if(!BufferListStart) + { + BufferListStart = malloc(sizeof(ALbufferlistitem)); + BufferListStart->buffer = buffer; + BufferListStart->next = NULL; + BufferListStart->prev = NULL; + BufferList = BufferListStart; + } + else + { + BufferList->next = malloc(sizeof(ALbufferlistitem)); + BufferList->next->buffer = buffer; + BufferList->next->next = NULL; + BufferList->next->prev = BufferList; + BufferList = BufferList->next; + } + if(!buffer) continue; + IncrementRef(&buffer->ref); + + ReadLock(&buffer->lock); + if(BufferFmt == NULL) + { + BufferFmt = buffer; + + Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels); + Source->SampleSize = BytesFromFmt(buffer->FmtType); + 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) + { + ReadUnlock(&buffer->lock); + UnlockContext(Context); + al_throwerr(Context, AL_INVALID_OPERATION); + } + ReadUnlock(&buffer->lock); + } + + /* Source is now streaming */ + Source->SourceType = AL_STREAMING; + + if(Source->queue == NULL) + Source->queue = BufferListStart; + else + { + /* Append to the end of the queue */ + BufferList = Source->queue; + while(BufferList->next != NULL) + BufferList = BufferList->next; + + BufferListStart->prev = BufferList; + BufferList->next = BufferListStart; + } + + Source->BuffersInQueue += nb; + + UnlockContext(Context); + } + al_catchany() + { + while(BufferListStart) + { + BufferList = BufferListStart; + BufferListStart = BufferList->next; + + if(BufferList->buffer) + DecrementRef(&BufferList->buffer->ref); + free(BufferList); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + ALbufferlistitem *BufferList; + + if(nb == 0) + return; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, nb >= 0); + + if((Source=LookupSource(Context, source)) == NULL) + al_throwerr(Context, AL_INVALID_NAME); + + LockContext(Context); + if(Source->Looping || Source->SourceType != AL_STREAMING || + (ALuint)nb > Source->BuffersPlayed) + { + UnlockContext(Context); + /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */ + al_throwerr(Context, AL_INVALID_VALUE); + } + + for(i = 0;i < nb;i++) + { + BufferList = Source->queue; + Source->queue = BufferList->next; + Source->BuffersInQueue--; + Source->BuffersPlayed--; + + if(BufferList->buffer) + { + buffers[i] = BufferList->buffer->id; + DecrementRef(&BufferList->buffer->ref); + } + else + buffers[i] = 0; + + free(BufferList); + } + if(Source->queue) + Source->queue->prev = NULL; + UnlockContext(Context); + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +static ALvoid InitSourceParams(ALsource *Source) +{ + ALuint i; + + Source->InnerAngle = 360.0f; + Source->OuterAngle = 360.0f; + Source->Pitch = 1.0f; + Source->Position[0] = 0.0f; + Source->Position[1] = 0.0f; + Source->Position[2] = 0.0f; + Source->Orientation[0] = 0.0f; + Source->Orientation[1] = 0.0f; + Source->Orientation[2] = 0.0f; + Source->Velocity[0] = 0.0f; + Source->Velocity[1] = 0.0f; + Source->Velocity[2] = 0.0f; + Source->RefDistance = 1.0f; + Source->MaxDistance = FLT_MAX; + Source->RollOffFactor = 1.0f; + Source->Looping = AL_FALSE; + Source->Gain = 1.0f; + Source->MinGain = 0.0f; + Source->MaxGain = 1.0f; + Source->OuterGain = 0.0f; + Source->OuterGainHF = 1.0f; + + Source->DryGainHFAuto = AL_TRUE; + Source->WetGainAuto = AL_TRUE; + Source->WetGainHFAuto = AL_TRUE; + Source->AirAbsorptionFactor = 0.0f; + Source->RoomRolloffFactor = 0.0f; + Source->DopplerFactor = 1.0f; + Source->DirectChannels = AL_FALSE; + + Source->DistanceModel = DefaultDistanceModel; + + Source->Resampler = DefaultResampler; + + Source->state = AL_INITIAL; + Source->new_state = AL_NONE; + Source->SourceType = AL_UNDETERMINED; + Source->Offset = -1.0; + + Source->DirectGain = 1.0f; + Source->DirectGainHF = 1.0f; + for(i = 0;i < MAX_SENDS;i++) + { + Source->Send[i].Gain = 1.0f; + Source->Send[i].GainHF = 1.0f; + } + + Source->NeedsUpdate = AL_TRUE; + + Source->Hrtf.Moving = AL_FALSE; + Source->Hrtf.Counter = 0; +} + + +/* SetSourceState + * + * Sets the source's new play state given its current state. + */ +ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) +{ + if(state == AL_PLAYING) + { + ALbufferlistitem *BufferList; + ALsizei j, k; + + /* Check that there is a queue containing at least one valid, non zero + * length Buffer. */ + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer != NULL && BufferList->buffer->SampleLen) + break; + BufferList = BufferList->next; + } + + if(Source->state != AL_PLAYING) + { + for(j = 0;j < MaxChannels;j++) + { + for(k = 0;k < SRC_HISTORY_LENGTH;k++) + Source->Hrtf.History[j][k] = 0.0f; + for(k = 0;k < HRIR_LENGTH;k++) + { + Source->Hrtf.Values[j][k][0] = 0.0f; + Source->Hrtf.Values[j][k][1] = 0.0f; + } + } + } + + if(Source->state != AL_PAUSED) + { + Source->state = AL_PLAYING; + Source->position = 0; + Source->position_fraction = 0; + Source->BuffersPlayed = 0; + } + else + Source->state = AL_PLAYING; + + // Check if an Offset has been set + if(Source->Offset >= 0.0) + ApplyOffset(Source); + + /* If there's nothing to play, or device is disconnected, go right to + * stopped */ + if(!BufferList || !Context->Device->Connected) + { + SetSourceState(Source, Context, AL_STOPPED); + return; + } + + for(j = 0;j < Context->ActiveSourceCount;j++) + { + if(Context->ActiveSources[j] == Source) + break; + } + if(j == Context->ActiveSourceCount) + Context->ActiveSources[Context->ActiveSourceCount++] = Source; + } + else if(state == AL_PAUSED) + { + if(Source->state == AL_PLAYING) + { + Source->state = AL_PAUSED; + Source->Hrtf.Moving = AL_FALSE; + Source->Hrtf.Counter = 0; + } + } + else if(state == AL_STOPPED) + { + if(Source->state != AL_INITIAL) + { + Source->state = AL_STOPPED; + Source->BuffersPlayed = Source->BuffersInQueue; + Source->Hrtf.Moving = AL_FALSE; + Source->Hrtf.Counter = 0; + } + Source->Offset = -1.0; + } + else if(state == AL_INITIAL) + { + if(Source->state != AL_INITIAL) + { + Source->state = AL_INITIAL; + Source->position = 0; + Source->position_fraction = 0; + Source->BuffersPlayed = 0; + Source->Hrtf.Moving = AL_FALSE; + Source->Hrtf.Counter = 0; + } + Source->Offset = -1.0; + } +} + +/* GetSourceOffset + * + * Gets the current read offset for the given Source, in 32.32 fixed-point + * samples. The offset is relative to the start of the queue (not the start of + * the current buffer). + */ +static ALint64 GetSourceOffset(const ALsource *Source) +{ + const ALbufferlistitem *BufferList; + ALuint64 readPos; + ALuint i; + + if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) + return 0; + + /* NOTE: This is the offset into the *current* buffer, so add the length of + * any played buffers */ + readPos = (ALuint64)Source->position << 32; + readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS); + BufferList = Source->queue; + for(i = 0;i < Source->BuffersPlayed && BufferList;i++) + { + if(BufferList->buffer) + readPos += (ALuint64)BufferList->buffer->SampleLen << 32; + BufferList = BufferList->next; + } + + return (ALint64)minu64(readPos, MAKEU64(0x7fffffff,0xffffffff)); +} + +/* GetSourceSecOffset + * + * Gets the current read offset for the given Source, in seconds. The offset is + * relative to the start of the queue (not the start of the current buffer). + */ +static ALdouble GetSourceSecOffset(const ALsource *Source) +{ + const ALbufferlistitem *BufferList; + const ALbuffer *Buffer = NULL; + ALuint64 readPos; + ALuint i; + + 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) + return 0.0; + + /* NOTE: This is the offset into the *current* buffer, so add the length of + * any played buffers */ + readPos = (ALuint64)Source->position << FRACTIONBITS; + readPos |= (ALuint64)Source->position_fraction; + BufferList = Source->queue; + for(i = 0;i < Source->BuffersPlayed && BufferList;i++) + { + if(BufferList->buffer) + readPos += (ALuint64)BufferList->buffer->SampleLen << FRACTIONBITS; + BufferList = BufferList->next; + } + + return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency; +} + +/* GetSourceOffsets + * + * Gets the current read and write offsets for the given Source, in the + * appropriate format (Bytes, Samples or Seconds). The offsets are relative to + * the start of the queue (not the start of the current buffer). + */ +static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen) +{ + const ALbufferlistitem *BufferList; + const ALbuffer *Buffer = NULL; + ALuint readPos, writePos; + ALuint totalBufferLen; + ALuint i; + + // Find the first valid Buffer in the Queue + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer) + { + Buffer = BufferList->buffer; + break; + } + BufferList = BufferList->next; + } + + if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer) + { + offset[0] = 0.0; + offset[1] = 0.0; + return; + } + + if(updateLen > 0.0 && updateLen < 0.015) + updateLen = 0.015; + + /* NOTE: This is the offset into the *current* buffer, so add the length of + * any played buffers */ + readPos = Source->position; + totalBufferLen = 0; + BufferList = Source->queue; + for(i = 0;BufferList;i++) + { + if(BufferList->buffer) + { + if(i < Source->BuffersPlayed) + readPos += BufferList->buffer->SampleLen; + totalBufferLen += BufferList->buffer->SampleLen; + } + BufferList = BufferList->next; + } + if(Source->state == AL_PLAYING) + writePos = readPos + (ALuint)(updateLen*Buffer->Frequency); + else + writePos = readPos; + + if(Source->Looping) + { + readPos %= totalBufferLen; + writePos %= totalBufferLen; + } + else + { + /* Wrap positions back to 0 */ + if(readPos >= totalBufferLen) + readPos = 0; + if(writePos >= totalBufferLen) + writePos = 0; + } + + switch(name) + { + case AL_SEC_OFFSET: + offset[0] = (ALdouble)readPos / Buffer->Frequency; + offset[1] = (ALdouble)writePos / Buffer->Frequency; + break; + + case AL_SAMPLE_OFFSET: + case AL_SAMPLE_RW_OFFSETS_SOFT: + offset[0] = (ALdouble)readPos; + offset[1] = (ALdouble)writePos; + break; + + case AL_BYTE_OFFSET: + case AL_BYTE_RW_OFFSETS_SOFT: + if(Buffer->OriginalType == UserFmtIMA4) + { + ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels); + ALuint FrameBlockSize = 65; + + /* Round down to nearest ADPCM block */ + offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize); + if(Source->state != AL_PLAYING) + offset[1] = offset[0]; + else + { + /* Round up to nearest ADPCM block */ + offset[1] = (ALdouble)((writePos+FrameBlockSize-1) / + FrameBlockSize * BlockSize); + } + } + else + { + ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); + offset[0] = (ALdouble)(readPos * FrameSize); + offset[1] = (ALdouble)(writePos * FrameSize); + } + break; + } +} + + +/* ApplyOffset + * + * Apply the stored playback offset to the Source. This function will update + * the number of buffers "played" given the stored offset. + */ +ALboolean ApplyOffset(ALsource *Source) +{ + const ALbufferlistitem *BufferList; + const ALbuffer *Buffer; + ALint bufferLen, totalBufferLen; + ALint buffersPlayed; + ALint offset; + + /* Get sample frame offset */ + offset = GetSampleOffset(Source); + if(offset == -1) + return AL_FALSE; + + buffersPlayed = 0; + totalBufferLen = 0; + + BufferList = Source->queue; + while(BufferList) + { + Buffer = BufferList->buffer; + bufferLen = Buffer ? Buffer->SampleLen : 0; + + if(bufferLen <= offset-totalBufferLen) + { + /* Offset is past this buffer so increment to the next buffer */ + buffersPlayed++; + } + else if(totalBufferLen <= offset) + { + /* Offset is in this buffer */ + Source->BuffersPlayed = buffersPlayed; + + Source->position = offset - totalBufferLen; + Source->position_fraction = 0; + return AL_TRUE; + } + + totalBufferLen += bufferLen; + + BufferList = BufferList->next; + } + + /* Offset is out of range of the queue */ + return AL_FALSE; +} + + +/* GetSampleOffset + * + * Returns the sample offset into the Source's queue (from the Sample, Byte or + * Second offset supplied by the application). This takes into account the fact + * that the buffer format may have been modifed since. + */ +static ALint GetSampleOffset(ALsource *Source) +{ + const ALbuffer *Buffer = NULL; + const ALbufferlistitem *BufferList; + ALint Offset = -1; + + /* Find the first valid Buffer in the Queue */ + BufferList = Source->queue; + while(BufferList) + { + if(BufferList->buffer) + { + Buffer = BufferList->buffer; + break; + } + BufferList = BufferList->next; + } + + if(!Buffer) + { + Source->Offset = -1.0; + return -1; + } + + switch(Source->OffsetType) + { + case AL_BYTE_OFFSET: + /* Determine the ByteOffset (and ensure it is block aligned) */ + Offset = (ALint)Source->Offset; + if(Buffer->OriginalType == UserFmtIMA4) + { + Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels); + Offset *= 65; + } + else + Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); + break; + + case AL_SAMPLE_OFFSET: + Offset = (ALint)Source->Offset; + break; + + case AL_SEC_OFFSET: + Offset = (ALint)(Source->Offset * Buffer->Frequency); + break; + } + Source->Offset = -1.0; + + return Offset; +} + + +/* ReleaseALSources + * + * Destroys all sources in the source map. + */ +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; + + while(temp->queue != NULL) + { + ALbufferlistitem *BufferList = temp->queue; + temp->queue = BufferList->next; + + if(BufferList->buffer != NULL) + DecrementRef(&BufferList->buffer->ref); + free(BufferList); + } + + for(j = 0;j < MAX_SENDS;++j) + { + if(temp->Send[j].Slot) + DecrementRef(&temp->Send[j].Slot->ref); + temp->Send[j].Slot = NULL; + } + + FreeThunkEntry(temp->id); + memset(temp, 0, sizeof(*temp)); + al_free(temp); + } +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alState.c b/src/eepp/helper/android/openal-soft/OpenAL32/alState.c new file mode 100644 index 000000000..678e9e947 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alState.c @@ -0,0 +1,674 @@ +/** + * 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 "alAuxEffectSlot.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; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + Context->SourceDistanceModel = AL_TRUE; + Context->UpdateSources = AL_TRUE; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alDisable(ALenum capability) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + Context->SourceDistanceModel = AL_FALSE; + Context->UpdateSources = AL_TRUE; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability) +{ + ALCcontext *Context; + ALboolean value=AL_FALSE; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + al_try + { + switch(capability) + { + case AL_SOURCE_DISTANCE_MODEL: + value = Context->SourceDistanceModel; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); + + return value; +} + +AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname) +{ + ALCcontext *Context; + ALboolean value=AL_FALSE; + + Context = GetContextRef(); + if(!Context) return AL_FALSE; + + al_try + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + if(Context->DopplerFactor != 0.0f) + value = AL_TRUE; + break; + + case AL_DOPPLER_VELOCITY: + if(Context->DopplerVelocity != 0.0f) + value = AL_TRUE; + break; + + case AL_DISTANCE_MODEL: + if(Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) + value = AL_TRUE; + break; + + case AL_SPEED_OF_SOUND: + if(Context->SpeedOfSound != 0.0f) + value = AL_TRUE; + break; + + case AL_DEFERRED_UPDATES_SOFT: + value = Context->DeferUpdates; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); + + return value; +} + +AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) +{ + ALCcontext *Context; + ALdouble value = 0.0; + + Context = GetContextRef(); + if(!Context) return 0.0; + + al_try + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALdouble)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALdouble)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALdouble)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALdouble)Context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + value = (ALdouble)Context->DeferUpdates; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); + + return value; +} + +AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) +{ + ALCcontext *Context; + ALfloat value = 0.0f; + + Context = GetContextRef(); + if(!Context) return 0.0f; + + al_try + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALfloat)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = Context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + value = (ALfloat)Context->DeferUpdates; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); + + return value; +} + +AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) +{ + ALCcontext *Context; + ALint value = 0; + + Context = GetContextRef(); + if(!Context) return 0; + + al_try + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + value = (ALint)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALint)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALint)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALint)Context->SpeedOfSound; + break; + + case AL_DEFERRED_UPDATES_SOFT: + value = (ALint)Context->DeferUpdates; + break; + + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); + + return value; +} + +AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values) +{ + ALCcontext *Context; + + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + values[0] = alGetBoolean(pname); + return; + } + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(pname) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) +{ + ALCcontext *Context; + + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + values[0] = alGetDouble(pname); + return; + } + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(pname) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) +{ + ALCcontext *Context; + + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + values[0] = alGetFloat(pname); + return; + } + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(pname) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) +{ + ALCcontext *Context; + + if(values) + { + switch(pname) + { + case AL_DOPPLER_FACTOR: + case AL_DOPPLER_VELOCITY: + case AL_DISTANCE_MODEL: + case AL_SPEED_OF_SOUND: + case AL_DEFERRED_UPDATES_SOFT: + values[0] = alGetInteger(pname); + return; + } + } + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, values); + switch(pname) + { + default: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname) +{ + const ALchar *value; + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return NULL; + + al_try + { + switch(pname) + { + case AL_VENDOR: + value = alVendor; + break; + + case AL_VERSION: + value = alVersion; + break; + + case AL_RENDERER: + value = alRenderer; + break; + + case AL_EXTENSIONS: + value = Context->ExtensionList; + 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: + al_throwerr(Context, AL_INVALID_ENUM); + } + } + al_catchany() + { + value = NULL; + } + al_endtry; + + ALCcontext_DecRef(Context); + + return value; +} + +AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value >= 0.0f && isfinite(value)); + + Context->DopplerFactor = value; + Context->UpdateSources = AL_TRUE; + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value >= 0.0f && isfinite(value)); + + Context->DopplerVelocity = value; + Context->UpdateSources = AL_TRUE; + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value > 0.0f && isfinite(value)); + + Context->SpeedOfSound = value; + Context->UpdateSources = AL_TRUE; + } + al_endtry; + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + al_try + { + CHECK_VALUE(Context, value == AL_NONE || + value == AL_INVERSE_DISTANCE || + value == AL_INVERSE_DISTANCE_CLAMPED || + value == AL_LINEAR_DISTANCE || + value == AL_LINEAR_DISTANCE_CLAMPED || + value == AL_EXPONENT_DISTANCE || + value == AL_EXPONENT_DISTANCE_CLAMPED); + + Context->DistanceModel = value; + if(!Context->SourceDistanceModel) + Context->UpdateSources = AL_TRUE; + } + al_endtry; + + ALCcontext_DecRef(Context); +} + + +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + if(!Context->DeferUpdates) + { + ALboolean UpdateSources; + ALsource **src, **src_end; + ALeffectslot **slot, **slot_end; + FPUCtl oldMode; + + SetMixerFPUMode(&oldMode); + + LockContext(Context); + Context->DeferUpdates = AL_TRUE; + + /* Make sure all pending updates are performed */ + UpdateSources = ExchangeInt(&Context->UpdateSources, AL_FALSE); + + src = Context->ActiveSources; + src_end = src + Context->ActiveSourceCount; + while(src != src_end) + { + if((*src)->state != AL_PLAYING) + { + Context->ActiveSourceCount--; + *src = *(--src_end); + continue; + } + + if(ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) || UpdateSources) + ALsource_Update(*src, Context); + + src++; + } + + slot = Context->ActiveEffectSlots; + slot_end = slot + Context->ActiveEffectSlotCount; + while(slot != slot_end) + { + if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE)) + ALeffectState_Update((*slot)->EffectState, Context->Device, *slot); + slot++; + } + + UnlockContext(Context); + RestoreFPUMode(&oldMode); + } + + ALCcontext_DecRef(Context); +} + +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) +{ + ALCcontext *Context; + + Context = GetContextRef(); + if(!Context) return; + + if(ExchangeInt(&Context->DeferUpdates, AL_FALSE)) + { + ALsizei pos; + + LockContext(Context); + LockUIntMapRead(&Context->SourceMap); + for(pos = 0;pos < Context->SourceMap.size;pos++) + { + ALsource *Source = Context->SourceMap.array[pos].value; + ALenum new_state; + + if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && + Source->Offset >= 0.0) + ApplyOffset(Source); + + new_state = ExchangeInt(&Source->new_state, AL_NONE); + if(new_state) + SetSourceState(Source, Context, new_state); + } + UnlockUIntMapRead(&Context->SourceMap); + UnlockContext(Context); + } + + ALCcontext_DecRef(Context); +} diff --git a/src/eepp/helper/android/openal-soft/OpenAL32/alThunk.c b/src/eepp/helper/android/openal-soft/OpenAL32/alThunk.c new file mode 100644 index 000000000..c4b3b92bd --- /dev/null +++ b/src/eepp/helper/android/openal-soft/OpenAL32/alThunk.c @@ -0,0 +1,89 @@ +/** + * 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" + + +static ALenum *ThunkArray; +static ALuint ThunkArraySize; +static RWLock ThunkLock; + +void ThunkInit(void) +{ + RWLockInit(&ThunkLock); + ThunkArraySize = 1; + ThunkArray = calloc(1, ThunkArraySize * sizeof(*ThunkArray)); +} + +void ThunkExit(void) +{ + free(ThunkArray); + ThunkArray = NULL; + ThunkArraySize = 0; +} + +ALenum NewThunkEntry(ALuint *index) +{ + ALenum *NewList; + ALuint i; + + ReadLock(&ThunkLock); + for(i = 0;i < ThunkArraySize;i++) + { + if(ExchangeInt(&ThunkArray[i], AL_TRUE) == AL_FALSE) + { + ReadUnlock(&ThunkLock); + *index = i+1; + return AL_NO_ERROR; + } + } + ReadUnlock(&ThunkLock); + + WriteLock(&ThunkLock); + NewList = realloc(ThunkArray, ThunkArraySize*2 * sizeof(*ThunkArray)); + if(!NewList) + { + WriteUnlock(&ThunkLock); + ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2); + return AL_OUT_OF_MEMORY; + } + memset(&NewList[ThunkArraySize], 0, ThunkArraySize*sizeof(*ThunkArray)); + ThunkArraySize *= 2; + ThunkArray = NewList; + + ThunkArray[i] = AL_TRUE; + WriteUnlock(&ThunkLock); + + *index = i+1; + return AL_NO_ERROR; +} + +void FreeThunkEntry(ALuint index) +{ + ReadLock(&ThunkLock); + if(index > 0 && index <= ThunkArraySize) + ExchangeInt(&ThunkArray[index-1], AL_FALSE); + ReadUnlock(&ThunkLock); +} diff --git a/src/eepp/helper/android/openal-soft/README b/src/eepp/helper/android/openal-soft/README new file mode 100644 index 000000000..ebca8f915 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/README @@ -0,0 +1,53 @@ +Source Install +============== + +To install OpenAL Soft, use your favorite shell to go into the build/ +directory, and run: + +cmake .. + +Assuming configuration went well, you can then build it, typically using GNU +Make (KDevelop, MSVC, and others are possible depending on your system setup +and CMake configuration). + +Please Note: Double check that the appropriate backends were detected. Often, +complaints of no sound, crashing, and missing devices can be solved by making +sure the correct backends are being used. CMake's output will identify which +backends were enabled. + +For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio +were detected (if your target system uses them). For Windows, make sure +DirectSound was detected. + + +Utilities +========= + +The source package comes with an informational utility, openal-info, and is +built by default. It prints out information provided by the ALC and AL sub- +systems, including discovered devices, version information, and extensions. + + +Configuration +============= + +OpenAL Soft can be configured on a per-user and per-system basis. This allows +users and sysadmins to control information provided to applications, as well +as application-agnostic behavior of the library. See alsoftrc.sample for +available settings. + + +Acknowledgements +================ + +Special thanks go to: + +Creative Labs for the original source code this is based off of. + +Christopher Fitzgerald for the current reverb effect implementation, and +helping with the low-pass filter. + +Christian Borss for the 3D panning code the current implementation is heavilly +based on. + +Ben Davis for the idea behind the current click-removal code. diff --git a/src/eepp/helper/android/openal-soft/config.h b/src/eepp/helper/android/openal-soft/config.h new file mode 100644 index 000000000..60acd23e6 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/config.h @@ -0,0 +1,141 @@ +/* API declaration export attribute */ +#define AL_API __attribute__((visibility("protected"))) +#define ALC_API __attribute__((visibility("protected"))) + +/* Define to the library version */ +#define ALSOFT_VERSION "1.15.1" + +/* Define any available alignment declaration */ +#define ALIGN(x) __attribute__((aligned(x))) +#ifdef __MINGW32__ +#define align(x) aligned(x) +#endif + +/* Define to the appropriate 'restrict' keyword */ +#define RESTRICT __restrict + +/* Define if we have the C11 aligned_alloc function */ +/* #undef HAVE_ALIGNED_ALLOC */ + +/* Define if we have the posix_memalign function */ +/* #define HAVE_POSIX_MEMALIGN */ + +/* Define if we have the _aligned_malloc function */ +/* #undef HAVE__ALIGNED_MALLOC */ + +/* Define if we have SSE CPU extensions */ +/* #define HAVE_SSE */ + +/* Define if we have ARM Neon CPU extensions */ +/* #undef HAVE_NEON */ + +/* Define if we have the ALSA backend */ +/* #define HAVE_ALSA */ + +/* Define if we have the OSS backend */ +/* #define HAVE_OSS */ + +/* Define if we have the Solaris backend */ +/* #undef HAVE_SOLARIS */ + +/* Define if we have the SndIO backend */ +/* #undef HAVE_SNDIO */ + +/* Define if we have the MMDevApi backend */ +/* #undef HAVE_MMDEVAPI */ + +/* Define if we have the DSound backend */ +/* #undef HAVE_DSOUND */ + +/* Define if we have the Windows Multimedia backend */ +/* #undef HAVE_WINMM */ + +/* Define if we have the PortAudio backend */ +/* #undef HAVE_PORTAUDIO */ + +/* Define if we have the PulseAudio backend */ +/* #undef HAVE_PULSEAUDIO */ + +/* Define if we have the CoreAudio backend */ +/* #undef HAVE_COREAUDIO */ + +/* Define if we have the OpenSL backend */ +/* #undef HAVE_OPENSL */ + +/* Define if we have the Wave Writer backend */ +#define HAVE_WAVE + +/* Define if we have the stat function */ +#define HAVE_STAT + +/* Define if we have the lrintf function */ +#define HAVE_LRINTF + +/* Define if we have the strtof function */ +#define HAVE_STRTOF + +/* Define if we have the __int64 type */ +/* #undef 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 if we have GCC's destructor attribute */ +#define HAVE_GCC_DESTRUCTOR + +/* Define if we have GCC's format attribute */ +#define HAVE_GCC_FORMAT + +/* Define if we have stdint.h */ +#define HAVE_STDINT_H + +/* Define if we have windows.h */ +/* #undef HAVE_WINDOWS_H */ + +/* Define if we have dlfcn.h */ +#define HAVE_DLFCN_H + +/* Define if we have pthread_np.h */ +/* #undef HAVE_PTHREAD_NP_H */ + +/* Define if we have xmmintrin.h */ +/* #define HAVE_XMMINTRIN_H */ + +/* Define if we have arm_neon.h */ +/* #undef HAVE_ARM_NEON_H */ + +/* Define if we have malloc.h */ +#define HAVE_MALLOC_H + +/* Define if we have cpuid.h */ +#define HAVE_CPUID_H + +/* Define if we have guiddef.h */ +/* #undef HAVE_GUIDDEF_H */ + +/* Define if we have initguid.h */ +/* #undef HAVE_INITGUID_H */ + +/* Define if we have ieeefp.h */ +/* #undef HAVE_IEEEFP_H */ + +/* Define if we have float.h */ +#define HAVE_FLOAT_H + +/* Define if we have fenv.h */ +#define HAVE_FENV_H + +/* Define if we have fesetround() */ +#define HAVE_FESETROUND + +/* Define if we have _controlfp() */ +/* #undef HAVE__CONTROLFP */ + +/* Define if we have __control87_2() */ +/* #undef HAVE___CONTROL87_2 */ + +/* Define if we have pthread_setschedparam() */ +#define HAVE_PTHREAD_SETSCHEDPARAM diff --git a/src/eepp/helper/android/openal-soft/config.h.in b/src/eepp/helper/android/openal-soft/config.h.in new file mode 100644 index 000000000..06c34c813 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/config.h.in @@ -0,0 +1,141 @@ +/* API declaration export attribute */ +#define AL_API ${EXPORT_DECL} +#define ALC_API ${EXPORT_DECL} + +/* Define to the library version */ +#define ALSOFT_VERSION "${LIB_VERSION}" + +/* Define any available alignment declaration */ +#define ALIGN(x) ${ALIGN_DECL} +#ifdef __MINGW32__ +#define align(x) aligned(x) +#endif + +/* Define to the appropriate 'restrict' keyword */ +#define RESTRICT ${RESTRICT_DECL} + +/* Define if we have the C11 aligned_alloc function */ +#cmakedefine HAVE_ALIGNED_ALLOC + +/* Define if we have the posix_memalign function */ +#cmakedefine HAVE_POSIX_MEMALIGN + +/* Define if we have the _aligned_malloc function */ +#cmakedefine HAVE__ALIGNED_MALLOC + +/* Define if we have SSE CPU extensions */ +#cmakedefine HAVE_SSE + +/* Define if we have ARM Neon CPU extensions */ +#cmakedefine HAVE_NEON + +/* 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 SndIO backend */ +#cmakedefine HAVE_SNDIO + +/* Define if we have the MMDevApi backend */ +#cmakedefine HAVE_MMDEVAPI + +/* Define if we have the DSound backend */ +#cmakedefine HAVE_DSOUND + +/* Define if we have the Windows Multimedia backend */ +#cmakedefine HAVE_WINMM + +/* Define if we have the PortAudio backend */ +#cmakedefine HAVE_PORTAUDIO + +/* Define if we have the PulseAudio backend */ +#cmakedefine HAVE_PULSEAUDIO + +/* Define if we have the CoreAudio backend */ +#cmakedefine HAVE_COREAUDIO + +/* Define if we have the OpenSL backend */ +#cmakedefine HAVE_OPENSL + +/* Define if we have the Wave Writer backend */ +#cmakedefine HAVE_WAVE + +/* Define if we have the stat function */ +#cmakedefine HAVE_STAT + +/* Define if we have the lrintf function */ +#cmakedefine HAVE_LRINTF + +/* Define if we have the strtof function */ +#cmakedefine HAVE_STRTOF + +/* Define if we have the __int64 type */ +#cmakedefine HAVE___INT64 + +/* Define to the size of a long int type */ +#cmakedefine SIZEOF_LONG ${SIZEOF_LONG} + +/* Define to the size of a long long int type */ +#cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG} + +/* Define if we have GCC's destructor attribute */ +#cmakedefine HAVE_GCC_DESTRUCTOR + +/* Define if we have GCC's format attribute */ +#cmakedefine HAVE_GCC_FORMAT + +/* Define if we have stdint.h */ +#cmakedefine HAVE_STDINT_H + +/* Define if we have windows.h */ +#cmakedefine HAVE_WINDOWS_H + +/* Define if we have dlfcn.h */ +#cmakedefine HAVE_DLFCN_H + +/* Define if we have pthread_np.h */ +#cmakedefine HAVE_PTHREAD_NP_H + +/* Define if we have xmmintrin.h */ +#cmakedefine HAVE_XMMINTRIN_H + +/* Define if we have arm_neon.h */ +#cmakedefine HAVE_ARM_NEON_H + +/* Define if we have malloc.h */ +#cmakedefine HAVE_MALLOC_H + +/* Define if we have cpuid.h */ +#cmakedefine HAVE_CPUID_H + +/* Define if we have guiddef.h */ +#cmakedefine HAVE_GUIDDEF_H + +/* Define if we have initguid.h */ +#cmakedefine HAVE_INITGUID_H + +/* Define if we have ieeefp.h */ +#cmakedefine HAVE_IEEEFP_H + +/* Define if we have float.h */ +#cmakedefine HAVE_FLOAT_H + +/* Define if we have fenv.h */ +#cmakedefine HAVE_FENV_H + +/* Define if we have fesetround() */ +#cmakedefine HAVE_FESETROUND + +/* Define if we have _controlfp() */ +#cmakedefine HAVE__CONTROLFP + +/* Define if we have __control87_2() */ +#cmakedefine HAVE___CONTROL87_2 + +/* Define if we have pthread_setschedparam() */ +#cmakedefine HAVE_PTHREAD_SETSCHEDPARAM diff --git a/src/eepp/helper/android/openal-soft/include/AL/al.h b/src/eepp/helper/android/openal-soft/include/AL/al.h new file mode 100644 index 000000000..413b38331 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/include/AL/al.h @@ -0,0 +1,656 @@ +#ifndef AL_AL_H +#define AL_AL_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef AL_API + #if defined(AL_LIBTYPE_STATIC) + #define AL_API + #elif defined(_WIN32) + #define AL_API __declspec(dllimport) + #else + #define AL_API extern + #endif +#endif + +#if defined(_WIN32) + #define AL_APIENTRY __cdecl +#else + #define AL_APIENTRY +#endif + + +/** Deprecated macro. */ +#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 + +/** Supported AL version. */ +#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 + + +/** + * Relative source. + * Type: ALboolean + * Range: [AL_TRUE, AL_FALSE] + * Default: AL_FALSE + * + * Specifies if the Source has relative coordinates. + */ +#define AL_SOURCE_RELATIVE 0x202 + + +/** + * Inner cone angle, in degrees. + * Type: ALint, ALfloat + * Range: [0 - 360] + * Default: 360 + * + * The angle covered by the inner cone, where the source will not attenuate. + */ +#define AL_CONE_INNER_ANGLE 0x1001 + +/** + * Outer cone angle, in degrees. + * Range: [0 - 360] + * Default: 360 + * + * The angle covered by the outer cone, where the source will be fully + * attenuated. + */ +#define AL_CONE_OUTER_ANGLE 0x1002 + +/** + * Source pitch. + * Type: ALfloat + * Range: [0.5 - 2.0] + * Default: 1.0 + * + * A multiplier for the frequency (sample rate) of the source's buffer. + */ +#define AL_PITCH 0x1003 + +/** + * Source or listener position. + * Type: ALfloat[3], ALint[3] + * Default: {0, 0, 0} + * + * The source or listener 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. + */ +#define AL_POSITION 0x1004 + +/** + * Source direction. + * Type: ALfloat[3], ALint[3] + * Default: {0, 0, 0} + * + * Specifies the current direction in local space. + * A zero-length vector specifies an omni-directional source (cone is ignored). + */ +#define AL_DIRECTION 0x1005 + +/** + * Source or listener velocity. + * Type: ALfloat[3], ALint[3] + * Default: {0, 0, 0} + * + * Specifies the current velocity in local space. + */ +#define AL_VELOCITY 0x1006 + +/** + * Source looping. + * Type: ALboolean + * Range: [AL_TRUE, AL_FALSE] + * Default: AL_FALSE + * + * Specifies whether source is looping. + */ +#define AL_LOOPING 0x1007 + +/** + * Source buffer. + * Type: ALuint + * Range: any valid Buffer. + * + * Specifies the buffer to provide sound samples. + */ +#define AL_BUFFER 0x1009 + +/** + * Source or listener gain. + * Type: ALfloat + * Range: [0.0 - ] + * + * A value of 1.0 means unattenuated. Each division by 2 equals an attenuation + * of about -6dB. Each multiplicaton by 2 equals an amplification of about + * +6dB. + * + * A value of 0.0 is meaningless with respect to a logarithmic scale; it is + * silent. + */ +#define AL_GAIN 0x100A + +/** + * Minimum source gain. + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * The minimum gain allowed for a source, after distance and cone attenation is + * applied (if applicable). + */ +#define AL_MIN_GAIN 0x100D + +/** + * Maximum source gain. + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * The maximum gain allowed for a source, after distance and cone attenation is + * applied (if applicable). + */ +#define AL_MAX_GAIN 0x100E + +/** + * Listener orientation. + * Type: ALfloat[6] + * Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0} + * + * Effectively two three dimensional vectors. The first vector is the front (or + * "at") and the second is the top (or "up"). + * + * Both vectors are in local space. + */ +#define AL_ORIENTATION 0x100F + +/** + * Source state (query only). + * Type: ALint + * Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED] + */ +#define AL_SOURCE_STATE 0x1010 + +/** Source state value. */ +#define AL_INITIAL 0x1011 +#define AL_PLAYING 0x1012 +#define AL_PAUSED 0x1013 +#define AL_STOPPED 0x1014 + +/** + * Source Buffer Queue size (query only). + * Type: ALint + * + * The number of buffers queued using alSourceQueueBuffers, minus the buffers + * removed with alSourceUnqueueBuffers. + */ +#define AL_BUFFERS_QUEUED 0x1015 + +/** + * Source Buffer Queue processed count (query only). + * Type: ALint + * + * The number of queued buffers that have been fully processed, and can be + * removed with alSourceUnqueueBuffers. + * + * Looping sources will never fully process buffers because they will be set to + * play again for when the source loops. + */ +#define AL_BUFFERS_PROCESSED 0x1016 + +/** + * Source reference distance. + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + * + * The distance in units that no attenuation occurs. + * + * At 0.0, no distance attenuation ever occurs on non-linear attenuation models. + */ +#define AL_REFERENCE_DISTANCE 0x1020 + +/** + * Source rolloff factor. + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + * + * Multiplier to exaggerate or diminish distance attenuation. + * + * At 0.0, no distance attenuation ever occurs. + */ +#define AL_ROLLOFF_FACTOR 0x1021 + +/** + * Outer cone gain. + * Type: ALfloat + * Range: [0.0 - 1.0] + * Default: 0.0 + * + * The gain attenuation applied when the listener is outside of the source's + * outer cone. + */ +#define AL_CONE_OUTER_GAIN 0x1022 + +/** + * Source maximum distance. + * Type: ALfloat + * Range: [0.0 - ] + * Default: +inf + * + * The distance above which the source is not attenuated any further with a + * clamped distance model, or where attenuation reaches 0.0 gain for linear + * distance models with a default rolloff factor. + */ +#define AL_MAX_DISTANCE 0x1023 + +/** Source buffer position, in seconds */ +#define AL_SEC_OFFSET 0x1024 +/** Source buffer position, in sample frames */ +#define AL_SAMPLE_OFFSET 0x1025 +/** Source buffer position, in bytes */ +#define AL_BYTE_OFFSET 0x1026 + +/** + * Source type (query only). + * Type: ALint + * Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED] + * + * A Source is Static if a Buffer has been attached using AL_BUFFER. + * + * A Source is Streaming if one or more Buffers have been attached using + * alSourceQueueBuffers. + * + * A Source is Undetermined when it has the NULL buffer attached using + * AL_BUFFER. + */ +#define AL_SOURCE_TYPE 0x1027 + +/** Source type value. */ +#define AL_STATIC 0x1028 +#define AL_STREAMING 0x1029 +#define AL_UNDETERMINED 0x1030 + +/** Buffer format specifier. */ +#define AL_FORMAT_MONO8 0x1100 +#define AL_FORMAT_MONO16 0x1101 +#define AL_FORMAT_STEREO8 0x1102 +#define AL_FORMAT_STEREO16 0x1103 + +/** Buffer frequency (query only). */ +#define AL_FREQUENCY 0x2001 +/** Buffer bits per sample (query only). */ +#define AL_BITS 0x2002 +/** Buffer channel count (query only). */ +#define AL_CHANNELS 0x2003 +/** Buffer data size (query only). */ +#define AL_SIZE 0x2004 + +/** + * Buffer state. + * + * Not for public use. + */ +#define AL_UNUSED 0x2010 +#define AL_PENDING 0x2011 +#define AL_PROCESSED 0x2012 + + +/** No error. */ +#define AL_NO_ERROR 0 + +/** Invalid name paramater passed to AL call. */ +#define AL_INVALID_NAME 0xA001 + +/** Invalid enum parameter passed to AL call. */ +#define AL_INVALID_ENUM 0xA002 + +/** Invalid value parameter passed to AL call. */ +#define AL_INVALID_VALUE 0xA003 + +/** Illegal AL call. */ +#define AL_INVALID_OPERATION 0xA004 + +/** Not enough memory. */ +#define AL_OUT_OF_MEMORY 0xA005 + + +/** Context string: Vendor ID. */ +#define AL_VENDOR 0xB001 +/** Context string: Version. */ +#define AL_VERSION 0xB002 +/** Context string: Renderer ID. */ +#define AL_RENDERER 0xB003 +/** Context string: Space-separated extension list. */ +#define AL_EXTENSIONS 0xB004 + + +/** + * Doppler scale. + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + * + * Scale for source and listener velocities. + */ +#define AL_DOPPLER_FACTOR 0xC000 +AL_API void AL_APIENTRY alDopplerFactor(ALfloat value); + +/** + * Doppler velocity (deprecated). + * + * A multiplier applied to the Speed of Sound. + */ +#define AL_DOPPLER_VELOCITY 0xC001 +AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value); + +/** + * Speed of Sound, in units per second. + * Type: ALfloat + * Range: [0.0001 - ] + * Default: 343.3 + * + * The speed at which sound waves are assumed to travel, when calculating the + * doppler effect. + */ +#define AL_SPEED_OF_SOUND 0xC003 +AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value); + +/** + * Distance attenuation model. + * Type: ALint + * Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED, + * AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED, + * AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED] + * Default: AL_INVERSE_DISTANCE_CLAMPED + * + * The model by which sources attenuate with distance. + * + * None - No distance attenuation. + * Inverse - Doubling the distance halves the source gain. + * Linear - Linear gain scaling between the reference and max distances. + * Exponent - Exponential gain dropoff. + * + * Clamped variations work like the non-clamped counterparts, except the + * distance calculated is clamped between the reference and max distances. + */ +#define AL_DISTANCE_MODEL 0xD000 +AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel); + +/** Distance model value. */ +#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 *values); +AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values); +AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values); +AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values); +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 retrieval. + * + * Obtain the first error generated in the AL context since the last check. + */ +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); + + +/** 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); + + +/** 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 source); + +/** Set Source parameters. */ +AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value); +AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values); +AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value); +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values); + +/** Get Source parameters. */ +AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value); +AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values); +AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value); +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values); + + +/** Play, replay, or resume (if paused) a list of Sources */ +AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources); +/** Stop a list of Sources */ +AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources); +/** Rewind a list of Sources */ +AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources); +/** Pause a list of Sources */ +AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources); + +/** Play, replay, or resume a Source */ +AL_API void AL_APIENTRY alSourcePlay(ALuint source); +/** Stop a Source */ +AL_API void AL_APIENTRY alSourceStop(ALuint source); +/** Rewind a Source (set playback postiton to beginning) */ +AL_API void AL_APIENTRY alSourceRewind(ALuint source); +/** Pause a Source */ +AL_API void AL_APIENTRY alSourcePause(ALuint source); + +/** Queue buffers onto a source */ +AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers); +/** Unqueue processed buffers from a source */ +AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers); + + +/** 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 buffer); + +/** Specifies the data to be copied into a buffer */ +AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); + +/** Set Buffer parameters, */ +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value); +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values); +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value); +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values); + +/** Get Buffer parameters. */ +AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value); +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values); +AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value); +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values); + +/** Pointer-to-function type, 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 *values); +typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values); +typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values); +typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values); +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 source); +typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values); +typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); +typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values); +typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value); +typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values); +typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value); +typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); +typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values); +typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers); +typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers); +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 buffer); +typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); +typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values); +typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); +typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values); +typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value); +typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values); +typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value); +typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); +typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, 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(__cplusplus) +} /* extern "C" */ +#endif + +#endif /* AL_AL_H */ diff --git a/src/eepp/helper/android/openal-soft/include/AL/alc.h b/src/eepp/helper/android/openal-soft/include/AL/alc.h new file mode 100644 index 000000000..294e8b33c --- /dev/null +++ b/src/eepp/helper/android/openal-soft/include/AL/alc.h @@ -0,0 +1,237 @@ +#ifndef AL_ALC_H +#define AL_ALC_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef ALC_API + #if defined(AL_LIBTYPE_STATIC) + #define ALC_API + #elif defined(_WIN32) + #define ALC_API __declspec(dllimport) + #else + #define ALC_API extern + #endif +#endif + +#if defined(_WIN32) + #define ALC_APIENTRY __cdecl +#else + #define ALC_APIENTRY +#endif + + +/** Deprecated macro. */ +#define ALCAPI ALC_API +#define ALCAPIENTRY ALC_APIENTRY +#define ALC_INVALID 0 + +/** Supported ALC version? */ +#define ALC_VERSION_0_1 1 + +/** Opaque device handle */ +typedef struct ALCdevice_struct ALCdevice; +/** Opaque context handle */ +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 + +/** Context attribute: Hz. */ +#define ALC_FREQUENCY 0x1007 + +/** Context attribute: Hz. */ +#define ALC_REFRESH 0x1008 + +/** Context attribute: AL_TRUE or AL_FALSE. */ +#define ALC_SYNC 0x1009 + +/** Context attribute: requested Mono (3D) Sources. */ +#define ALC_MONO_SOURCES 0x1010 + +/** Context attribute: requested Stereo Sources. */ +#define ALC_STEREO_SOURCES 0x1011 + +/** No error. */ +#define ALC_NO_ERROR 0 + +/** Invalid device handle. */ +#define ALC_INVALID_DEVICE 0xA001 + +/** Invalid context handle. */ +#define ALC_INVALID_CONTEXT 0xA002 + +/** Invalid enum parameter passed to an ALC call. */ +#define ALC_INVALID_ENUM 0xA003 + +/** Invalid value parameter passed to an ALC call. */ +#define ALC_INVALID_VALUE 0xA004 + +/** Out of memory. */ +#define ALC_OUT_OF_MEMORY 0xA005 + + +/** Runtime ALC version. */ +#define ALC_MAJOR_VERSION 0x1000 +#define ALC_MINOR_VERSION 0x1001 + +/** Context attribute list properties. */ +#define ALC_ATTRIBUTES_SIZE 0x1002 +#define ALC_ALL_ATTRIBUTES 0x1003 + +/** String for the default device specifier. */ +#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 +/** + * String for the given device's specifier. + * + * If device handle is NULL, it is instead a null-char separated list of + * strings of known device specifiers (list ends with an empty string). + */ +#define ALC_DEVICE_SPECIFIER 0x1005 +/** String for space-separated list of ALC extensions. */ +#define ALC_EXTENSIONS 0x1006 + + +/** Capture extension */ +#define ALC_EXT_CAPTURE 1 +/** + * String for the given capture device's specifier. + * + * If device handle is NULL, it is instead a null-char separated list of + * strings of known capture device specifiers (list ends with an empty string). + */ +#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 +/** String for the default capture device specifier. */ +#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 +/** Number of sample frames available for capture. */ +#define ALC_CAPTURE_SAMPLES 0x312 + + +/** Enumerate All extension */ +#define ALC_ENUMERATE_ALL_EXT 1 +/** String for the default extended device specifier. */ +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 +/** + * String for the given extended device's specifier. + * + * If device handle is NULL, it is instead a null-char separated list of + * strings of known extended device specifiers (list ends with an empty string). + */ +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 + + +/** 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 Device 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 function. */ +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param); +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); + +/** Capture function. */ +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 type, 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 *values); +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(__cplusplus) +} +#endif + +#endif /* AL_ALC_H */ diff --git a/src/eepp/helper/android/openal-soft/include/AL/alext.h b/src/eepp/helper/android/openal-soft/include/AL/alext.h new file mode 100644 index 000000000..0447f2bb4 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/include/AL/alext.h @@ -0,0 +1,355 @@ +/** + * 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 +/* Define int64_t and uint64_t types */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif + +#include "alc.h" +#include "al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_LOKI_IMA_ADPCM_format +#define AL_LOKI_IMA_ADPCM_format 1 +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#endif + +#ifndef AL_LOKI_WAVE_format +#define AL_LOKI_WAVE_format 1 +#define AL_FORMAT_WAVE_EXT 0x10002 +#endif + +#ifndef AL_EXT_vorbis +#define AL_EXT_vorbis 1 +#define AL_FORMAT_VORBIS_EXT 0x10003 +#endif + +#ifndef AL_LOKI_quadriphonic +#define AL_LOKI_quadriphonic 1 +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_double +#define AL_EXT_double 1 +#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 +#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 +#endif + +#ifndef AL_EXT_MULAW +#define AL_EXT_MULAW 1 +#define AL_FORMAT_MONO_MULAW_EXT 0x10014 +#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 +#endif + +#ifndef AL_EXT_ALAW +#define AL_EXT_ALAW 1 +#define AL_FORMAT_MONO_ALAW_EXT 0x10016 +#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 +#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 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 + +#ifndef AL_EXT_FOLDBACK +#define AL_EXT_FOLDBACK 1 +#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" +#define AL_FOLDBACK_EVENT_BLOCK 0x4112 +#define AL_FOLDBACK_EVENT_START 0x4111 +#define AL_FOLDBACK_EVENT_STOP 0x4113 +#define AL_FOLDBACK_MODE_MONO 0x4101 +#define AL_FOLDBACK_MODE_STEREO 0x4102 +typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); +AL_API void AL_APIENTRY alRequestFoldbackStop(void); +#endif +#endif + +#ifndef ALC_EXT_DEDICATED +#define ALC_EXT_DEDICATED 1 +#define AL_DEDICATED_GAIN 0x0001 +#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 +#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 +#endif + +#ifndef AL_SOFT_buffer_samples +#define AL_SOFT_buffer_samples 1 +/* Channel configurations */ +#define AL_MONO_SOFT 0x1500 +#define AL_STEREO_SOFT 0x1501 +#define AL_REAR_SOFT 0x1502 +#define AL_QUAD_SOFT 0x1503 +#define AL_5POINT1_SOFT 0x1504 +#define AL_6POINT1_SOFT 0x1505 +#define AL_7POINT1_SOFT 0x1506 + +/* Sample types */ +#define AL_BYTE_SOFT 0x1400 +#define AL_UNSIGNED_BYTE_SOFT 0x1401 +#define AL_SHORT_SOFT 0x1402 +#define AL_UNSIGNED_SHORT_SOFT 0x1403 +#define AL_INT_SOFT 0x1404 +#define AL_UNSIGNED_INT_SOFT 0x1405 +#define AL_FLOAT_SOFT 0x1406 +#define AL_DOUBLE_SOFT 0x1407 +#define AL_BYTE3_SOFT 0x1408 +#define AL_UNSIGNED_BYTE3_SOFT 0x1409 + +/* Storage formats */ +#define AL_MONO8_SOFT 0x1100 +#define AL_MONO16_SOFT 0x1101 +#define AL_MONO32F_SOFT 0x10010 +#define AL_STEREO8_SOFT 0x1102 +#define AL_STEREO16_SOFT 0x1103 +#define AL_STEREO32F_SOFT 0x10011 +#define AL_QUAD8_SOFT 0x1204 +#define AL_QUAD16_SOFT 0x1205 +#define AL_QUAD32F_SOFT 0x1206 +#define AL_REAR8_SOFT 0x1207 +#define AL_REAR16_SOFT 0x1208 +#define AL_REAR32F_SOFT 0x1209 +#define AL_5POINT1_8_SOFT 0x120A +#define AL_5POINT1_16_SOFT 0x120B +#define AL_5POINT1_32F_SOFT 0x120C +#define AL_6POINT1_8_SOFT 0x120D +#define AL_6POINT1_16_SOFT 0x120E +#define AL_6POINT1_32F_SOFT 0x120F +#define AL_7POINT1_8_SOFT 0x1210 +#define AL_7POINT1_16_SOFT 0x1211 +#define AL_7POINT1_32F_SOFT 0x1212 + +/* Buffer attributes */ +#define AL_INTERNAL_FORMAT_SOFT 0x2008 +#define AL_BYTE_LENGTH_SOFT 0x2009 +#define AL_SAMPLE_LENGTH_SOFT 0x200A +#define AL_SEC_LENGTH_SOFT 0x200B + +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +#endif +#endif + +#ifndef AL_SOFT_direct_channels +#define AL_SOFT_direct_channels 1 +#define AL_DIRECT_CHANNELS_SOFT 0x1033 +#endif + +#ifndef ALC_SOFT_loopback +#define ALC_SOFT_loopback 1 +#define ALC_FORMAT_CHANNELS_SOFT 0x1990 +#define ALC_FORMAT_TYPE_SOFT 0x1991 + +/* Sample types */ +#define ALC_BYTE_SOFT 0x1400 +#define ALC_UNSIGNED_BYTE_SOFT 0x1401 +#define ALC_SHORT_SOFT 0x1402 +#define ALC_UNSIGNED_SHORT_SOFT 0x1403 +#define ALC_INT_SOFT 0x1404 +#define ALC_UNSIGNED_INT_SOFT 0x1405 +#define ALC_FLOAT_SOFT 0x1406 + +/* Channel configurations */ +#define ALC_MONO_SOFT 0x1500 +#define ALC_STEREO_SOFT 0x1501 +#define ALC_QUAD_SOFT 0x1503 +#define ALC_5POINT1_SOFT 0x1504 +#define ALC_6POINT1_SOFT 0x1505 +#define ALC_7POINT1_SOFT 0x1506 + +typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); +typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); +typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +#endif +#endif + +#ifndef AL_EXT_STEREO_ANGLES +#define AL_EXT_STEREO_ANGLES 1 +#define AL_STEREO_ANGLES 0x1030 +#endif + +#ifndef AL_EXT_SOURCE_RADIUS +#define AL_EXT_SOURCE_RADIUS 1 +#define AL_SOURCE_RADIUS 0x1031 +#endif + +#ifndef AL_SOFT_source_latency +#define AL_SOFT_source_latency 1 +#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 +#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 +typedef int64_t ALint64SOFT; +typedef uint64_t ALuint64SOFT; +typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); +AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); +AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); +AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/eepp/helper/android/openal-soft/include/AL/efx-creative.h b/src/eepp/helper/android/openal-soft/include/AL/efx-creative.h new file mode 100644 index 000000000..0a04c982e --- /dev/null +++ b/src/eepp/helper/android/openal-soft/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/src/eepp/helper/android/openal-soft/include/AL/efx-presets.h b/src/eepp/helper/android/openal-soft/include/AL/efx-presets.h new file mode 100644 index 000000000..86dcbda2f --- /dev/null +++ b/src/eepp/helper/android/openal-soft/include/AL/efx-presets.h @@ -0,0 +1,402 @@ +/* Reverb presets for EFX */ + +#ifndef EFX_PRESETS_H +#define EFX_PRESETS_H + +#ifndef EFXEAXREVERBPROPERTIES_DEFINED +#define EFXEAXREVERBPROPERTIES_DEFINED +typedef struct { + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; +} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; +#endif + +/* Default Presets */ + +#define EFX_REVERB_PRESET_GENERIC \ + { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PADDEDCELL \ + { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ROOM \ + { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_BATHROOM \ + { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_LIVINGROOM \ + { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_AUDITORIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CONCERTHALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CAVE \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_ARENA \ + { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HANGAR \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CARPETEDHALLWAY \ + { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HALLWAY \ + { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONECORRIDOR \ + { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ALLEY \ + { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FOREST \ + { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY \ + { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOUNTAINS \ + { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_QUARRY \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PLAIN \ + { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PARKINGLOT \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SEWERPIPE \ + { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_UNDERWATER \ + { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRUGGED \ + { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DIZZY \ + { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PSYCHOTIC \ + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Castle Presets */ + +#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \ + { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_HALL \ + { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \ + { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_COURTYARD \ + { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CASTLE_ALCOVE \ + { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +/* Factory Presets */ + +#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \ + { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \ + { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \ + { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_HALL \ + { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \ + { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_COURTYARD \ + { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_ALCOVE \ + { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +/* Ice Palace Presets */ + +#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \ + { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \ + { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \ + { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \ + { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_HALL \ + { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \ + { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \ + { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +/* Space Station Presets */ + +#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \ + { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \ + { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \ + { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \ + { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \ + { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_HALL \ + { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \ + { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \ + { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +/* Wooden Galleon Presets */ + +#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_HALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \ + { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_COURTYARD \ + { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_ALCOVE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +/* Sports Presets */ + +#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \ + { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \ + { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \ + { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \ + { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \ + { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Prefab Presets */ + +#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \ + { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \ + { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \ + { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \ + { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_CARAVAN \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Dome and Pipe Presets */ + +#define EFX_REVERB_PRESET_DOME_TOMB \ + { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_SMALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DOME_SAINTPAULS \ + { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_LONGTHIN \ + { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_LARGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_RESONANT \ + { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +/* Outdoors Presets */ + +#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \ + { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \ + { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \ + { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_CREEK \ + { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \ + { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +/* Mood Presets */ + +#define EFX_REVERB_PRESET_MOOD_HEAVEN \ + { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOOD_HELL \ + { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_MOOD_MEMORY \ + { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Driving Presets */ + +#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ + { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ + { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \ + { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \ + { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \ + { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_TUNNEL \ + { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 } + +/* City Presets */ + +#define EFX_REVERB_PRESET_CITY_STREETS \ + { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_SUBWAY \ + { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_MUSEUM \ + { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_LIBRARY \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_UNDERPASS \ + { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_ABANDONED \ + { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Misc. Presets */ + +#define EFX_REVERB_PRESET_DUSTYROOM \ + { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CHAPEL \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SMALLWATERROOM \ + { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#endif /* EFX_PRESETS_H */ diff --git a/src/eepp/helper/android/openal-soft/include/AL/efx.h b/src/eepp/helper/android/openal-soft/include/AL/efx.h new file mode 100644 index 000000000..57766983f --- /dev/null +++ b/src/eepp/helper/android/openal-soft/include/AL/efx.h @@ -0,0 +1,761 @@ +#ifndef AL_EFX_H +#define AL_EFX_H + + +#include "alc.h" +#include "al.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, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const 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, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const 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, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const 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, const 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, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const 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, const 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, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const 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, const 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, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const 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 AL_LOWPASS_MIN_GAIN (0.0f) +#define AL_LOWPASS_MAX_GAIN (1.0f) +#define AL_LOWPASS_DEFAULT_GAIN (1.0f) + +#define AL_LOWPASS_MIN_GAINHF (0.0f) +#define AL_LOWPASS_MAX_GAINHF (1.0f) +#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) + +/* Highpass filter */ +#define AL_HIGHPASS_MIN_GAIN (0.0f) +#define AL_HIGHPASS_MAX_GAIN (1.0f) +#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) + +#define AL_HIGHPASS_MIN_GAINLF (0.0f) +#define AL_HIGHPASS_MAX_GAINLF (1.0f) +#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) + +/* Bandpass filter */ +#define AL_BANDPASS_MIN_GAIN (0.0f) +#define AL_BANDPASS_MAX_GAIN (1.0f) +#define AL_BANDPASS_DEFAULT_GAIN (1.0f) + +#define AL_BANDPASS_MIN_GAINHF (0.0f) +#define AL_BANDPASS_MAX_GAINHF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) + +#define AL_BANDPASS_MIN_GAINLF (0.0f) +#define AL_BANDPASS_MAX_GAINLF (1.0f) +#define AL_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/src/eepp/helper/android/openal-soft/premake4.lua b/src/eepp/helper/android/openal-soft/premake4.lua new file mode 100644 index 000000000..71f309117 --- /dev/null +++ b/src/eepp/helper/android/openal-soft/premake4.lua @@ -0,0 +1,45 @@ +solution "openal-soft" + location("./make/" .. os.get() .. "/") + targetdir("./") + configurations { "debug", "release" } + objdir("obj/" .. os.get() .. "/premake4/") + + project "openal-soft-shared" + kind "SharedLib" + language "C" + targetdir("libs/" .. os.get()) + files { "Alc/*.c", "OpenAL32/*.c" } + + defines { "AL_ALEXT_PROTOTYPES" } + + if os.is("linux") then + files { "Alc/backends/alsa.c", "Alc/backends/pulseaudio.c" } + defines { "HAVE_ALSA", "HAVE_XMMINTRIN_H", "HAVE_PULSEAUDIO" } + excludes { "Alc/mixer_neon.c" } + buildoptions { "-msse" } + elseif os.is("windows") then + files { "Alc/backends/dsound.c", "Alc/backends/winmm.c" } + defines { "HAVE_DSOUND", "HAVE_WINMM" } + excludes { "Alc/mixer_neon.c" } + buildoptions { "-msse" } + elseif os.is("macosx") then + files { "Alc/backends/coreaudio.c" } + defines { "HAVE_COREAUDIO" } + excludes { "Alc/mixer_neon.c" } + buildoptions { "-msse" } + end + + includedirs { "include", "OpenAL32/Include", "./" } + + configuration "debug" + defines { "DEBUG" } + flags { "Symbols" } + buildoptions{ "-Wall" } + targetname "openal-soft-debug" + + configuration "release" + defines { "NDEBUG" } + flags { "Optimize" } + buildoptions{ "-Wall" } + targetname "openal-soft" + \ No newline at end of file diff --git a/src/eepp/system/cpackmanager.cpp b/src/eepp/system/cpackmanager.cpp index 5421de22b..639736814 100644 --- a/src/eepp/system/cpackmanager.cpp +++ b/src/eepp/system/cpackmanager.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace EE { namespace System { @@ -33,6 +34,18 @@ cPack * cPackManager::Exists( std::string& path ) { return NULL; } +cPack * cPackManager::GetPackByPath( std::string path ) { + std::list::iterator it; + + for ( it = mResources.begin(); it != mResources.end(); it++ ) { + if ( path == (*it)->GetPackPath() ) { + return (*it); + } + } + + return NULL; +} + const bool& cPackManager::FallbackToPacks() const { return mFallback; } diff --git a/src/eepp/system/cpak.cpp b/src/eepp/system/cpak.cpp index 2c4adc3c0..1679471b7 100755 --- a/src/eepp/system/cpak.cpp +++ b/src/eepp/system/cpak.cpp @@ -366,4 +366,12 @@ std::vector cPak::GetFileList() { return tmpv; } +bool cPak::IsOpen() const { + return mIsOpen; +} + +std::string cPak::GetPackPath() { + return mPak.pakPath; +} + }} diff --git a/src/eepp/system/czip.cpp b/src/eepp/system/czip.cpp index f86e65cff..9e46aa9b9 100644 --- a/src/eepp/system/czip.cpp +++ b/src/eepp/system/czip.cpp @@ -245,4 +245,9 @@ std::vector cZip::GetFileList() { return tmpv; } +/** @return The file path of the opened package */ +std::string cZip::GetPackPath() { + return mZipPath; +} + }}