diff options
Diffstat (limited to 'OpenAL32')
-rw-r--r-- | OpenAL32/Include/alBuffer.h | 32 | ||||
-rw-r--r-- | OpenAL32/Include/alError.h | 16 | ||||
-rw-r--r-- | OpenAL32/Include/alExtension.h | 33 | ||||
-rw-r--r-- | OpenAL32/Include/alListener.h | 23 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 170 | ||||
-rw-r--r-- | OpenAL32/Include/alSource.h | 71 | ||||
-rw-r--r-- | OpenAL32/Include/alState.h | 14 | ||||
-rw-r--r-- | OpenAL32/Include/alThunk.h | 42 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 26 | ||||
-rw-r--r-- | OpenAL32/OpenAL32.c | 75 | ||||
-rw-r--r-- | OpenAL32/alBuffer.c | 989 | ||||
-rw-r--r-- | OpenAL32/alError.c | 61 | ||||
-rw-r--r-- | OpenAL32/alExtension.c | 274 | ||||
-rw-r--r-- | OpenAL32/alListener.c | 513 | ||||
-rw-r--r-- | OpenAL32/alSource.c | 2108 | ||||
-rw-r--r-- | OpenAL32/alState.c | 677 | ||||
-rw-r--r-- | OpenAL32/alThunk.c | 108 |
17 files changed, 5232 insertions, 0 deletions
diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h new file mode 100644 index 00000000..06ffdea0 --- /dev/null +++ b/OpenAL32/Include/alBuffer.h @@ -0,0 +1,32 @@ +#ifndef _AL_BUFFER_H_ +#define _AL_BUFFER_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UNUSED 0 +#define PENDING 1 +#define PROCESSED 2 + +typedef struct ALbuffer_struct +{ + ALenum format; + ALenum eOriginalFormat; + ALshort *data; + ALsizei size; + ALsizei frequency; + ALenum state; + ALuint refcount; // Number of sources using this buffer (deletion can only occur when this is 0) + struct ALbuffer_struct *next; +} ALbuffer; + +ALvoid ReleaseALBuffers(ALvoid); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h new file mode 100644 index 00000000..5cee8db8 --- /dev/null +++ b/OpenAL32/Include/alError.h @@ -0,0 +1,16 @@ +#ifndef _AL_ERROR_H_ +#define _AL_ERROR_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ALvoid alSetError(ALenum errorCode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/OpenAL32/Include/alExtension.h b/OpenAL32/Include/alExtension.h new file mode 100644 index 00000000..1f33f9af --- /dev/null +++ b/OpenAL32/Include/alExtension.h @@ -0,0 +1,33 @@ +#ifndef _AL_EXTENSION_H_ +#define _AL_EXTENSION_H_ + +#include "AL/al.h" +#include "AL/alc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALextension_struct +{ + ALchar *extName; + ALvoid *address; +} ALextension; + +typedef struct ALfunction_struct +{ + ALchar *funcName; + ALvoid *address; +} ALfunction; + +typedef struct ALenum_struct +{ + ALchar *enumName; + ALenum value; +} ALenums; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h new file mode 100644 index 00000000..2075e612 --- /dev/null +++ b/OpenAL32/Include/alListener.h @@ -0,0 +1,23 @@ +#ifndef _AL_LISTENER_H_ +#define _AL_LISTENER_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALlistener_struct +{ + ALfloat Position[3]; + ALfloat Velocity[3]; + ALfloat Forward[3]; + ALfloat Up[3]; + ALfloat Gain; +} ALlistener; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h new file mode 100644 index 00000000..3d34cf38 --- /dev/null +++ b/OpenAL32/Include/alMain.h @@ -0,0 +1,170 @@ +#ifndef AL_MAIN_H +#define AL_MAIN_H + +#define AL_MAX_CHANNELS 4 +#define AL_MAX_SOURCES 32 + +#include <string.h> + +#include "alu.h" + +#ifdef _WIN32 +#include <windows.h> +//#define strcasecmp _stricmp + +#else + +#include <assert.h> +#include <pthread.h> + +#define IsBadWritePtr(a,b) (0) + +typedef pthread_mutex_t CRITICAL_SECTION; +static inline void EnterCriticalSection(CRITICAL_SECTION *cs) +{ + assert(pthread_mutex_lock(cs) == 0); +} +static inline void LeaveCriticalSection(CRITICAL_SECTION *cs) +{ + assert(pthread_mutex_unlock(cs) == 0); +} +static inline void InitializeCriticalSection(CRITICAL_SECTION *cs) +{ + pthread_mutexattr_t attrib; + + assert(pthread_mutexattr_init(&attrib) == 0); + + assert(pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(cs, &attrib) == 0); + + pthread_mutexattr_destroy(&attrib); +} + +static inline void DeleteCriticalSection(CRITICAL_SECTION *cs) +{ + assert(pthread_mutex_destroy(cs) == 0); +} + +#define min(x,y) (((x)<(y))?(x):(y)) +#define max(x,y) (((x)>(y))?(x):(y)) +#endif + +#include "alBuffer.h" +#include "alError.h" +#include "alExtension.h" +#include "alListener.h" +#include "alSource.h" +#include "alState.h" +#include "alThunk.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define AL_FORMAT_MONO_IMA4 0x1300 +#define AL_FORMAT_STEREO_IMA4 0x1301 +// These are from AL_EXT_MCFORMATS, which we don't support yet but the mixer +// can use 4-channel formats +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 + +#define SWMIXER_OUTPUT_RATE 44100 +//#define OUTPUT_BUFFER_SIZE (32768*SWMIXER_OUTPUT_RATE/22050) + +#define SPEEDOFSOUNDMETRESPERSEC (343.3f) + +typedef struct { + ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*); + void (*ClosePlayback)(ALCdevice*); + + ALCboolean (*OpenCapture)(ALCdevice*, const ALCchar*, ALCuint, ALCenum, ALCsizei); + void (*CloseCapture)(ALCdevice*); + void (*StartCapture)(ALCdevice*); + void (*StopCapture)(ALCdevice*); + void (*CaptureSamples)(ALCdevice*, void*, ALCuint); + ALCuint (*AvailableSamples)(ALCdevice*); +} BackendFuncs; + +struct ALCdevice_struct +{ + ALboolean InUse; + ALboolean IsCaptureDevice; + + ALuint Frequency; + ALuint UpdateFreq; + ALuint FrameSize; + ALuint Channels; + ALenum Format; + + ALCchar szDeviceName[256]; + + // Maximum number of sources that can be created + ALuint MaxNoOfSources; + + // Context created on this device + ALCcontext *Context; + + BackendFuncs *Funcs; + void *ExtraData; // For the backend's use +}; + +#define ALCdevice_OpenPlayback(a,b) ((a)->Funcs->OpenPlayback((a), (b))) +#define ALCdevice_ClosePlayback(a) ((a)->Funcs->ClosePlayback((a))) +#define ALCdevice_OpenCapture(a,b,c,d,e) ((a)->Funcs->OpenCapture((a), (b), (c), (d), (e))) +#define ALCdevice_CloseCapture(a) ((a)->Funcs->CloseCapture((a))) +#define ALCdevice_StartCapture(a) ((a)->Funcs->StartCapture((a))) +#define ALCdevice_StopCapture(a) ((a)->Funcs->StopCapture((a))) +#define ALCdevice_CaptureSamples(a,b,c) ((a)->Funcs->CaptureSamples((a), (b), (c))) +#define ALCdevice_AvailableSamples(a) ((a)->Funcs->AvailableSamples((a))) + +struct ALCcontext_struct +{ + ALlistener Listener; + + ALsource *Source; + ALuint SourceCount; + + ALenum LastError; + ALboolean InUse; + + ALuint Frequency; + + ALenum DistanceModel; + + ALfloat DopplerFactor; + ALfloat DopplerVelocity; + ALfloat flSpeedOfSound; + + ALint lNumMonoSources; + ALint lNumStereoSources; + + ALCdevice *Device; + ALCchar ExtensionList[1024]; + + ALCcontext *next; +}; + +ALCchar *AppendDeviceList(char *name); +ALCchar *AppendAllDeviceList(char *name); +ALCchar *AppendCaptureDeviceList(char *name); + +ALCvoid SetALCError(ALenum errorCode); + +ALCvoid SuspendContext(ALCcontext *context); +ALCvoid ProcessContext(ALCcontext *context); + +ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr); +ALuint StopThread(ALvoid *thread); + +void ReadALConfig(void); +void FreeALConfig(void); +const char *GetConfigValue(const char *blockName, const char *keyName, const char *def); +int GetConfigValueInt(const char *blockName, const char *keyName, int def); +float GetConfigValueFloat(const char *blockName, const char *keyName, float def); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h new file mode 100644 index 00000000..499ddcf4 --- /dev/null +++ b/OpenAL32/Include/alSource.h @@ -0,0 +1,71 @@ +#ifndef _AL_SOURCE_H_ +#define _AL_SOURCE_H_ + +#define AL_NUM_SOURCE_PARAMS 128 + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ALbufferlistitem +{ + ALuint buffer; + ALuint bufferstate; + ALuint flag; + struct ALbufferlistitem *next; +} ALbufferlistitem; + +typedef struct ALsource_struct +{ + ALfloat flPitch; + ALfloat flGain; + ALfloat flOuterGain; + ALfloat flMinGain; + ALfloat flMaxGain; + ALfloat flInnerAngle; + ALfloat flOuterAngle; + ALfloat flRefDistance; + ALfloat flMaxDistance; + ALfloat flRollOffFactor; + ALfloat vPosition[3]; + ALfloat vVelocity[3]; + ALfloat vOrientation[3]; + ALboolean bHeadRelative; + ALboolean bLooping; + + ALuint ulBufferID; + + ALboolean inuse; + ALboolean play; + ALenum state; + ALuint position; + ALuint position_fraction; + struct ALbufferlistitem *queue; // Linked list of buffers in queue + ALuint BuffersInQueue; // Number of buffers in queue + ALuint BuffersProcessed; // Number of buffers already processed (played) + + ALuint TotalBufferDataSize; // Total amount of data contained in the buffers queued for this source + ALuint BuffersPlayed; // Number of buffers played on this loop + ALuint BufferPosition; // Read position in audio data of current buffer + + // Index to itself + ALuint source; + + ALint lBytesPlayed; + + ALint lOffset; + ALint lOffsetType; + + // Source Type (Static, Streaming, or Undetermined) + ALint lSourceType; + + struct ALsource_struct *next; +} ALsource; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/OpenAL32/Include/alState.h b/OpenAL32/Include/alState.h new file mode 100644 index 00000000..332176b0 --- /dev/null +++ b/OpenAL32/Include/alState.h @@ -0,0 +1,14 @@ +#ifndef _AL_STATE_H_ +#define _AL_STATE_H_ + +#include "AL/al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/OpenAL32/Include/alThunk.h b/OpenAL32/Include/alThunk.h new file mode 100644 index 00000000..2ed32871 --- /dev/null +++ b/OpenAL32/Include/alThunk.h @@ -0,0 +1,42 @@ +#ifndef _AL_THUNK_H_ +#define _AL_THUNK_H_ + +#include "config.h" + +#include "AL/al.h" +#include "AL/alc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if (SIZEOF_VOIDP > SIZEOF_UINT) + +void alThunkInit(void); +void alThunkExit(void); +ALuint alThunkAddEntry(ALvoid * ptr); +void alThunkRemoveEntry(ALuint index); +ALvoid *alThunkLookupEntry(ALuint index); + +#define ALTHUNK_INIT() alThunkInit() +#define ALTHUNK_EXIT() alThunkExit() +#define ALTHUNK_ADDENTRY(p) alThunkAddEntry(p) +#define ALTHUNK_REMOVEENTRY(i) alThunkRemoveEntry(i) +#define ALTHUNK_LOOKUPENTRY(i) alThunkLookupEntry(i) + +#else + +#define ALTHUNK_INIT() +#define ALTHUNK_EXIT() +#define ALTHUNK_ADDENTRY(p) ((ALuint)p) +#define ALTHUNK_REMOVEENTRY(i) +#define ALTHUNK_LOOKUPENTRY(i) ((ALvoid*)(i)) + +#endif // (SIZEOF_VOIDP > SIZEOF_INT) + +#ifdef __cplusplus +} +#endif + +#endif //_AL_THUNK_H_ + diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h new file mode 100644 index 00000000..e4fe0dc3 --- /dev/null +++ b/OpenAL32/Include/alu.h @@ -0,0 +1,26 @@ +#ifndef _ALU_H_ +#define _ALU_H_ + +#define BUFFERSIZE 48000 +#define FRACTIONBITS 14 +#define FRACTIONMASK ((1L<<FRACTIONBITS)-1) +#define MAX_PITCH 4 +#define OUTPUTCHANNELS 4 + +#include "AL/al.h" +#include "AL/alc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +__inline ALuint aluBytesFromFormat(ALenum format); +__inline ALuint aluChannelsFromFormat(ALenum format); +ALvoid aluMixData(ALCcontext *context,ALvoid *buffer,ALsizei size,ALenum format); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/OpenAL32/OpenAL32.c b/OpenAL32/OpenAL32.c new file mode 100644 index 00000000..20ca14f9 --- /dev/null +++ b/OpenAL32/OpenAL32.c @@ -0,0 +1,75 @@ +/** + * 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 "alMain.h" +#include "alBuffer.h" +#include "alThunk.h" + +CRITICAL_SECTION g_mutex; + +#ifdef _WIN32 +BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) +{ + (void)lpReserved; + + // Perform actions based on the reason for calling. + switch(ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + InitializeCriticalSection(&g_mutex); + ALTHUNK_INIT(); + ReadALConfig(); + break; + + case DLL_PROCESS_DETACH: + ReleaseALBuffers(); + FreeALConfig(); + ALTHUNK_EXIT(); + DeleteCriticalSection(&g_mutex); + break; + } + return TRUE; +} +#else +static void my_init() __attribute__((constructor)); +static void my_init() +{ + static ALenum once = AL_FALSE; + if(once) return; + once = AL_TRUE; + + InitializeCriticalSection(&g_mutex); + ALTHUNK_INIT(); + ReadALConfig(); +} +static void my_deinit() __attribute__((destructor)); +static void my_deinit() +{ + static ALenum once = AL_FALSE; + if(once) return; + once = AL_TRUE; + + ReleaseALBuffers(); + FreeALConfig(); + ALTHUNK_EXIT(); + DeleteCriticalSection(&g_mutex); +} +#endif diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c new file mode 100644 index 00000000..53ee128a --- /dev/null +++ b/OpenAL32/alBuffer.c @@ -0,0 +1,989 @@ +/** + * 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 + */ + +#define _CRT_SECURE_NO_DEPRECATE // get rid of sprintf security warnings on VS2005 + +#include <stdlib.h> +#include <stdio.h> +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alError.h" +#include "alBuffer.h" + +#ifdef _DEBUG + char szDebug[256]; +#endif + +/* + * AL Buffer Functions + * + * AL Buffers are shared amoung Contexts, so we store the list of generated Buffers + * as a global variable in this module. (A valid context is not required to make + * AL Buffer function calls + * + */ + +/* +* Global Variables +*/ + +static ALbuffer *g_pBuffers = NULL; // Linked List of Buffers +static ALuint g_uiBufferCount = 0; // Buffer Count + +static const long g_IMAStep_size[89]={ // IMA ADPCM Stepsize table + 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 +}; + +static const long g_IMACodeword_4[16]={ // IMA4 ADPCM Codeword decode table + 1, 3, 5, 7, 9, 11, 13, 15, + -1,-3,-5,-7,-9,-11,-13,-15, +}; + +static const long g_IMAIndex_adjust_4[16]={ // IMA4 ADPCM Step index adjust decode table + -1,-1,-1,-1, 2, 4, 6, 8, + -1,-1,-1,-1, 2, 4, 6, 8 +}; + +/* +* alGenBuffers(ALsizei n, ALuint *puiBuffers) +* +* Generates n AL Buffers, and stores the Buffers Names in the array pointed to by puiBuffers +*/ +ALAPI ALvoid ALAPIENTRY alGenBuffers(ALsizei n,ALuint *puiBuffers) +{ + ALCcontext *Context; + ALsizei i=0; + + Context = alcGetCurrentContext(); + SuspendContext(Context); + + // Check that we are actually generation some Buffers + if (n > 0) + { + // Check the pointer is valid (and points to enough memory to store Buffer Names) + if (!IsBadWritePtr((void*)puiBuffers, n * sizeof(ALuint))) + { + ALbuffer **list = &g_pBuffers; + while(*list) + list = &(*list)->next; + + // Create all the new Buffers + while(i < n) + { + *list = calloc(1, sizeof(ALbuffer)); + if(*list) + { + puiBuffers[i] = (ALuint)ALTHUNK_ADDENTRY(*list); + (*list)->state = UNUSED; + g_uiBufferCount++; + i++; + + list = &(*list)->next; + } + } + + // If we didn't create all the Buffers, we must have run out of memory + if (i != n) + alSetError(AL_OUT_OF_MEMORY); + } + else + { + // Pointer does not point to enough memory to write Buffer names + alSetError(AL_INVALID_VALUE); + } + } + + ProcessContext(Context); + + return; +} + +/* +* alDeleteBuffers(ALsizei n, ALuint *puiBuffers) +* +* Deletes the n AL Buffers pointed to by puiBuffers +*/ +ALAPI ALvoid ALAPIENTRY alDeleteBuffers(ALsizei n, const ALuint *puiBuffers) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + ALsizei i; + ALboolean bFailed = AL_FALSE; + + Context = alcGetCurrentContext(); + SuspendContext(Context); + + // Check we are actually Deleting some Buffers + if (n >= 0) + { + if ((ALuint)n <= g_uiBufferCount) + { + // Check that all the buffers are valid and can actually be deleted + for (i = 0; i < n; i++) + { + // Check for valid Buffer ID (can be NULL buffer) + if (alIsBuffer(puiBuffers[i])) + { + // If not the NULL buffer, check that the reference count is 0 + ALBuf = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(puiBuffers[i])); + if (ALBuf) + { + if (ALBuf->refcount != 0) + { + // Buffer still in use, cannot be deleted + alSetError(AL_INVALID_OPERATION); + bFailed = AL_TRUE; + } + } + } + else + { + // Invalid Buffer + alSetError(AL_INVALID_NAME); + bFailed = AL_TRUE; + } + } + + // If all the Buffers were valid (and have Reference Counts of 0), then we can delete them + if (!bFailed) + { + for (i = 0; i < n; i++) + { + ALBuf=((ALbuffer *)ALTHUNK_LOOKUPENTRY(puiBuffers[i])); + if (ALBuf) + { + ALbuffer **list = &g_pBuffers; + while(*list && *list != ALBuf) + list = &(*list)->next; + + if(*list) + *list = (*list)->next; + + // Release the memory used to store audio data + free(ALBuf->data); + + // Release buffer structure + ALTHUNK_REMOVEENTRY(puiBuffers[i]); + memset(ALBuf, 0, sizeof(ALbuffer)); + g_uiBufferCount--; + free(ALBuf); + } + } + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(Context); + + return; + +} + +/* +* alIsBuffer(ALuint uiBuffer) +* +* Checks if ulBuffer is a valid Buffer Name +*/ +ALAPI ALboolean ALAPIENTRY alIsBuffer(ALuint uiBuffer) +{ + ALCcontext *Context; + ALboolean result=AL_FALSE; + ALbuffer *ALBuf; + ALbuffer *TgtALBuf; + + Context = alcGetCurrentContext(); + SuspendContext(Context); + + if (uiBuffer) + { + TgtALBuf = (ALbuffer *)ALTHUNK_LOOKUPENTRY(uiBuffer); + + // Check through list of generated buffers for uiBuffer + ALBuf = g_pBuffers; + while (ALBuf) + { + if (ALBuf == TgtALBuf) + { + result = AL_TRUE; + break; + } + + ALBuf = ALBuf->next; + } + } + else + { + result = AL_TRUE; + } + + + ProcessContext(Context); + + return result; +} + +/* +* alBufferData(ALuint buffer,ALenum format,ALvoid *data,ALsizei size,ALsizei freq) +* +* Fill buffer with audio data +*/ +ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *data,ALsizei size,ALsizei freq) +{ + ALuint *IMAData,IMACode; + ALCcontext *Context; + ALint Sample,Index; + ALint LeftSample,LeftIndex; + ALint RightSample,RightIndex; + ALuint LeftIMACode,RightIMACode; + ALbuffer *ALBuf; + ALsizei i,j,k; + + Context = alcGetCurrentContext(); + SuspendContext(Context); + + if (alIsBuffer(buffer) && (buffer != 0)) + { + ALBuf=((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + if ((ALBuf->refcount==0)&&(data)) + { + switch(format) + { + case AL_FORMAT_MONO8: + if ((size%1) == 0) + { + // 8bit Samples are converted to 16 bit here + // Allocate 8 extra samples (16 bytes) + ALBuf->data=realloc(ALBuf->data,16+(size/sizeof(ALubyte))*(1*sizeof(ALshort))); + if (ALBuf->data) + { + ALBuf->format = AL_FORMAT_MONO16; + ALBuf->eOriginalFormat = AL_FORMAT_MONO8; + for (i=0;i<(ALsizei)(size/sizeof(ALubyte));i++) + ALBuf->data[i]=(ALshort)((((ALubyte *)data)[i]-128)<<8); + memset(&(ALBuf->data[size/sizeof(ALubyte)]), 0, 16); + ALBuf->size=size/sizeof(ALubyte)*1*sizeof(ALshort); + ALBuf->frequency=freq; + } + else + alSetError(AL_OUT_OF_MEMORY); + } + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_FORMAT_MONO16: + if ((size%2) == 0) + { + // Allocate 8 extra samples (16 bytes) + ALBuf->data=realloc(ALBuf->data,16+(size/sizeof(ALshort))*(1*sizeof(ALshort))); + if (ALBuf->data) + { + ALBuf->format = AL_FORMAT_MONO16; + ALBuf->eOriginalFormat = AL_FORMAT_MONO16; + memcpy(ALBuf->data,data,size/sizeof(ALshort)*1*sizeof(ALshort)); + memset(&(ALBuf->data[size/sizeof(ALshort)]), 0, 16); + ALBuf->size=size/sizeof(ALshort)*1*sizeof(ALshort); + ALBuf->frequency=freq; + } + else + alSetError(AL_OUT_OF_MEMORY); + } + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_FORMAT_STEREO8: + if ((size%2) == 0) + { + // 8bit Samples are converted to 16 bit here + // Allocate 8 extra samples (32 bytes) + ALBuf->data=realloc(ALBuf->data,32+(size/sizeof(ALubyte))*(1*sizeof(ALshort))); + if (ALBuf->data) + { + ALBuf->format = AL_FORMAT_STEREO16; + ALBuf->eOriginalFormat = AL_FORMAT_STEREO8; + for (i=0;i<(ALsizei)(size/sizeof(ALubyte));i++) + ALBuf->data[i]=(ALshort)((((ALubyte *)data)[i]-128)<<8); + memset(&(ALBuf->data[size/sizeof(ALubyte)]), 0, 32); + ALBuf->size=size/sizeof(ALubyte)*1*sizeof(ALshort); + ALBuf->frequency=freq; + } + else + alSetError(AL_OUT_OF_MEMORY); + } + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_FORMAT_STEREO16: + if ((size%4) == 0) + { + // Allocate 8 extra samples (32 bytes) + ALBuf->data=realloc(ALBuf->data,32+(size/sizeof(ALshort))*(1*sizeof(ALshort))); + if (ALBuf->data) + { + ALBuf->format = AL_FORMAT_STEREO16; + ALBuf->eOriginalFormat = AL_FORMAT_STEREO16; + memcpy(ALBuf->data,data,size/sizeof(ALshort)*1*sizeof(ALshort)); + memset(&(ALBuf->data[size/sizeof(ALshort)]), 0, 32); + ALBuf->size=size/sizeof(ALshort)*1*sizeof(ALshort); + ALBuf->frequency=freq; + } + else + alSetError(AL_OUT_OF_MEMORY); + } + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_FORMAT_MONO_IMA4: + // Here is where things vary: + // nVidia and Apple use 64+1 samples per block => block_size=36 bytes + // Most PC sound software uses 2040+1 samples per block -> block_size=1024 bytes + if ((size%36) == 0) + { + // Allocate 8 extra samples (16 bytes) + ALBuf->data=realloc(ALBuf->data,16+(size/36)*(65*sizeof(ALshort))); + if (ALBuf->data) + { + ALBuf->format = AL_FORMAT_MONO16; + ALBuf->eOriginalFormat = AL_FORMAT_MONO_IMA4; + IMAData=(ALuint *)data; + for (i=0;i<size/36;i++) + { + Sample=((ALshort *)IMAData)[0]; + Index=((ALshort *)IMAData)[1]; + + Index=Index<0?0:Index; + Index=Index>88?88:Index; + + ALBuf->data[i*65]=(short)Sample; + + IMAData++; + + for (j=1;j<65;j+=8) + { + IMACode=*IMAData; + for (k=0;k<8;k+=2) + { + Sample+=((g_IMAStep_size[Index]*g_IMACodeword_4[IMACode&15])/8); + Index+=g_IMAIndex_adjust_4[IMACode&15]; + if (Sample<-32768) Sample=-32768; + else if (Sample>32767) Sample=32767; + if (Index<0) Index=0; + else if (Index>88) Index=88; + ALBuf->data[i*65+j+k]=(short)Sample; + IMACode>>=4; + + Sample+=((g_IMAStep_size[Index]*g_IMACodeword_4[IMACode&15])/8); + Index+=g_IMAIndex_adjust_4[IMACode&15]; + if (Sample<-32768) Sample=-32768; + else if (Sample>32767) Sample=32767; + if (Index<0) Index=0; + else if (Index>88) Index=88; + ALBuf->data[i*65+j+k+1]=(short)Sample; + IMACode>>=4; + } + IMAData++; + } + } + memset(&(ALBuf->data[(size/36*65)]), 0, 16); + ALBuf->size=size/36*65*sizeof(ALshort); + ALBuf->frequency=freq; + } + else + alSetError(AL_OUT_OF_MEMORY); + } + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_FORMAT_STEREO_IMA4: + // Here is where things vary: + // nVidia and Apple use 64+1 samples per channel per block => block_size=72 bytes + // Most PC sound software uses 2040+1 samples per channel per block -> block_size=2048 bytes + if ((size%72) == 0) + { + // Allocate 8 extra samples (32 bytes) + ALBuf->data=realloc(ALBuf->data,32+(size/72)*(2*65*sizeof(ALshort))); + if (ALBuf->data) + { + ALBuf->format = AL_FORMAT_STEREO16; + ALBuf->eOriginalFormat = AL_FORMAT_STEREO_IMA4; + IMAData=(ALuint *)data; + for (i=0;i<size/72;i++) + { + LeftSample=((ALshort *)IMAData)[0]; + LeftIndex=((ALshort *)IMAData)[1]; + + LeftIndex=LeftIndex<0?0:LeftIndex; + LeftIndex=LeftIndex>88?88:LeftIndex; + + ALBuf->data[i*2*65]=(short)LeftSample; + + IMAData++; + + RightSample=((ALshort *)IMAData)[0]; + RightIndex=((ALshort *)IMAData)[1]; + + RightIndex=RightIndex<0?0:RightIndex; + RightIndex=RightIndex>88?88:RightIndex; + + ALBuf->data[i*2*65+1]=(short)RightSample; + + IMAData++; + + for (j=2;j<130;j+=16) + { + LeftIMACode=IMAData[0]; + RightIMACode=IMAData[1]; + for (k=0;k<16;k+=4) + { + LeftSample+=((g_IMAStep_size[LeftIndex]*g_IMACodeword_4[LeftIMACode&15])/8); + LeftIndex+=g_IMAIndex_adjust_4[LeftIMACode&15]; + if (LeftSample<-32768) LeftSample=-32768; + else if (LeftSample>32767) LeftSample=32767; + if (LeftIndex<0) LeftIndex=0; + else if (LeftIndex>88) LeftIndex=88; + ALBuf->data[i*2*65+j+k]=(short)LeftSample; + LeftIMACode>>=4; + + RightSample+=((g_IMAStep_size[RightIndex]*g_IMACodeword_4[RightIMACode&15])/8); + RightIndex+=g_IMAIndex_adjust_4[RightIMACode&15]; + if (RightSample<-32768) RightSample=-32768; + else if (RightSample>32767) RightSample=32767; + if (RightIndex<0) RightIndex=0; + else if (RightIndex>88) RightIndex=88; + ALBuf->data[i*2*65+j+k+1]=(short)RightSample; + RightIMACode>>=4; + + LeftSample+=((g_IMAStep_size[LeftIndex]*g_IMACodeword_4[LeftIMACode&15])/8); + LeftIndex+=g_IMAIndex_adjust_4[LeftIMACode&15]; + if (LeftSample<-32768) LeftSample=-32768; + else if (LeftSample>32767) LeftSample=32767; + if (LeftIndex<0) LeftIndex=0; + else if (LeftIndex>88) LeftIndex=88; + ALBuf->data[i*2*65+j+k+2]=(short)LeftSample; + LeftIMACode>>=4; + + RightSample+=((g_IMAStep_size[RightIndex]*g_IMACodeword_4[RightIMACode&15])/8); + RightIndex+=g_IMAIndex_adjust_4[RightIMACode&15]; + if (RightSample<-32768) RightSample=-32768; + else if (RightSample>32767) RightSample=32767; + if (RightIndex<0) RightIndex=0; + else if (RightIndex>88) RightIndex=88; + ALBuf->data[i*2*65+j+k+3]=(short)RightSample; + RightIMACode>>=4; + } + IMAData+=2; + } + } + memset(&(ALBuf->data[(size/72*2*65)]), 0, 32); + ALBuf->size=size/72*2*65*sizeof(ALshort); + ALBuf->frequency=freq; + } + else + alSetError(AL_OUT_OF_MEMORY); + } + else + alSetError(AL_INVALID_VALUE); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + // Buffer is in use, or data is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + } + else + { + // Invalid Buffer Name + alSetError(AL_INVALID_NAME); + } + + ProcessContext(Context); +} + + +ALAPI void ALAPIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + (void)flValue; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alBuffer3f(ALuint buffer, ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + (void)flValue1; + (void)flValue2; + (void)flValue3; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alBufferfv(ALuint buffer, ALenum eParam, const ALfloat* flValues) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + (void)flValues; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alBufferi(ALuint buffer, ALenum eParam, ALint lValue) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + (void)lValue; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alBuffer3i( ALuint buffer, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + (void)lValue1; + (void)lValue2; + (void)lValue3; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alBufferiv(ALuint buffer, ALenum eParam, const ALint* plValues) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + (void)plValues; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + + ProcessContext(pContext); +} + + +ALAPI ALvoid ALAPIENTRY alGetBufferf(ALuint buffer, ALenum eParam, ALfloat *pflValue) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (pflValue) + { + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + } + else + { + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alGetBuffer3f(ALuint buffer, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if ((pflValue1) && (pflValue2) && (pflValue3)) + { + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + } + else + { + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alGetBufferfv(ALuint buffer, ALenum eParam, ALfloat* pflValues) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (pflValues) + { + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + } + else + { + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(pContext); +} + + +ALAPI ALvoid ALAPIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plValue) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (plValue) + { + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch (eParam) + { + case AL_FREQUENCY: + *plValue = pBuffer->frequency; + break; + + case AL_BITS: + *plValue= (((pBuffer->format==AL_FORMAT_MONO8)||(pBuffer->format==AL_FORMAT_STEREO8))?8:16); + break; + + case AL_CHANNELS: + *plValue = (((pBuffer->format==AL_FORMAT_MONO8)||(pBuffer->format==AL_FORMAT_MONO16))?1:2); + break; + + case AL_SIZE: + *plValue = pBuffer->size; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + } + else + { + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alGetBuffer3i(ALuint buffer, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if ((plValue1) && (plValue2) && (plValue3)) + { + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch(eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + } + else + { + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(pContext); +} + + +ALAPI void ALAPIENTRY alGetBufferiv(ALuint buffer, ALenum eParam, ALint* plValues) +{ + ALCcontext *pContext; + ALbuffer *pBuffer; + + pContext = alcGetCurrentContext(); + SuspendContext(pContext); + + if (plValues) + { + if (alIsBuffer(buffer) && (buffer != 0)) + { + pBuffer = ((ALbuffer *)ALTHUNK_LOOKUPENTRY(buffer)); + + switch (eParam) + { + case AL_FREQUENCY: + case AL_BITS: + case AL_CHANNELS: + case AL_SIZE: + alGetBufferi(buffer, eParam, plValues); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + alSetError(AL_INVALID_NAME); + } + } + else + { + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(pContext); +} + + +/* +* ReleaseALBuffers() +* +* INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist +*/ +ALvoid ReleaseALBuffers(ALvoid) +{ + ALbuffer *ALBuffer; + ALbuffer *ALBufferTemp; + +#ifdef _DEBUG + if(g_uiBufferCount > 0) + { + sprintf(szDebug, "OpenAL32 : DllMain() %d Buffer(s) NOT deleted\n", g_uiBufferCount); + OutputDebugString(szDebug); + } +#endif + + ALBuffer = g_pBuffers; + while(ALBuffer) + { + // Release sample data + free(ALBuffer->data); + + // Release Buffer structure + ALBufferTemp = ALBuffer; + ALBuffer = ALBuffer->next; + memset(ALBufferTemp, 0, sizeof(ALbuffer)); + free(ALBufferTemp); + } + g_pBuffers = NULL; + g_uiBufferCount = 0; +} diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c new file mode 100644 index 00000000..df5c16e4 --- /dev/null +++ b/OpenAL32/alError.c @@ -0,0 +1,61 @@ +/** + * 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 "alMain.h" +#include "AL/alc.h" +#include "alError.h" + +ALAPI ALenum ALAPIENTRY alGetError(ALvoid) +{ + ALCcontext *Context; + ALenum errorCode; + + Context = alcGetCurrentContext(); + SuspendContext(Context); + + if (Context) + { + errorCode = Context->LastError; + Context->LastError = AL_NO_ERROR; + } + else + { + errorCode = AL_INVALID_OPERATION; + } + + ProcessContext(Context); + + return errorCode; +} + +ALvoid alSetError(ALenum errorCode) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + SuspendContext(Context); + + if (Context) + { + Context->LastError=errorCode; + } + + ProcessContext(Context); +} diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c new file mode 100644 index 00000000..1d0928d2 --- /dev/null +++ b/OpenAL32/alExtension.c @@ -0,0 +1,274 @@ +/** + * 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 <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "alExtension.h" +#include "alError.h" +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + +static ALfunction function[]= { + { "alEnable", (ALvoid *) alEnable }, + { "alDisable", (ALvoid *) alDisable }, + { "alIsEnabled", (ALvoid *) alIsEnabled }, + { "alGetString", (ALvoid *) alGetString }, + { "alGetBooleanv", (ALvoid *) alGetBooleanv }, + { "alGetIntegerv", (ALvoid *) alGetIntegerv }, + { "alGetFloatv", (ALvoid *) alGetFloatv }, + { "alGetDoublev", (ALvoid *) alGetDoublev }, + { "alGetBoolean", (ALvoid *) alGetBoolean }, + { "alGetInteger", (ALvoid *) alGetInteger }, + { "alGetFloat", (ALvoid *) alGetFloat }, + { "alGetDouble", (ALvoid *) alGetDouble }, + { "alGetError", (ALvoid *) alGetError }, + { "alIsExtensionPresent", (ALvoid *) alIsExtensionPresent }, + { "alGetProcAddress", (ALvoid *) alGetProcAddress }, + { "alGetEnumValue", (ALvoid *) alGetEnumValue }, + { "alListenerf", (ALvoid *) alListenerf }, + { "alListener3f", (ALvoid *) alListener3f }, + { "alListenerfv", (ALvoid *) alListenerfv }, + { "alListeneri", (ALvoid *) alListeneri }, + { "alListener3i", (ALvoid *) alListener3i }, + { "alListeneriv", (ALvoid *) alListeneriv }, + { "alGetListenerf", (ALvoid *) alGetListenerf }, + { "alGetListener3f", (ALvoid *) alGetListener3f }, + { "alGetListenerfv", (ALvoid *) alGetListenerfv }, + { "alGetListeneri", (ALvoid *) alGetListeneri }, + { "alGetListener3i", (ALvoid *) alGetListener3i }, + { "alGetListeneriv", (ALvoid *) alGetListeneriv }, + { "alGenSources", (ALvoid *) alGenSources }, + { "alDeleteSources", (ALvoid *) alDeleteSources }, + { "alIsSource", (ALvoid *) alIsSource }, + { "alSourcef", (ALvoid *) alSourcef }, + { "alSource3f", (ALvoid *) alSource3f }, + { "alSourcefv", (ALvoid *) alSourcefv }, + { "alSourcei", (ALvoid *) alSourcei }, + { "alSource3i", (ALvoid *) alSource3i }, + { "alSourceiv", (ALvoid *) alSourceiv }, + { "alGetSourcef", (ALvoid *) alGetSourcef }, + { "alGetSource3f", (ALvoid *) alGetSource3f }, + { "alGetSourcefv", (ALvoid *) alGetSourcefv }, + { "alGetSourcei", (ALvoid *) alGetSourcei }, + { "alGetSource3i", (ALvoid *) alGetSource3i }, + { "alGetSourceiv", (ALvoid *) alGetSourceiv }, + { "alSourcePlayv", (ALvoid *) alSourcePlayv }, + { "alSourceStopv", (ALvoid *) alSourceStopv }, + { "alSourceRewindv", (ALvoid *) alSourceRewindv }, + { "alSourcePausev", (ALvoid *) alSourcePausev }, + { "alSourcePlay", (ALvoid *) alSourcePlay }, + { "alSourceStop", (ALvoid *) alSourceStop }, + { "alSourceRewind", (ALvoid *) alSourceRewind }, + { "alSourcePause", (ALvoid *) alSourcePause }, + { "alSourceQueueBuffers", (ALvoid *) alSourceQueueBuffers }, + { "alSourceUnqueueBuffers", (ALvoid *) alSourceUnqueueBuffers }, + { "alGenBuffers", (ALvoid *) alGenBuffers }, + { "alDeleteBuffers", (ALvoid *) alDeleteBuffers }, + { "alIsBuffer", (ALvoid *) alIsBuffer }, + { "alBufferData", (ALvoid *) alBufferData }, + { "alBufferf", (ALvoid *) alBufferf }, + { "alBuffer3f", (ALvoid *) alBuffer3f }, + { "alBufferfv", (ALvoid *) alBufferfv }, + { "alBufferi", (ALvoid *) alBufferi }, + { "alBuffer3i", (ALvoid *) alBuffer3i }, + { "alBufferiv", (ALvoid *) alBufferiv }, + { "alGetBufferf", (ALvoid *) alGetBufferf }, + { "alGetBuffer3f", (ALvoid *) alGetBuffer3f }, + { "alGetBufferfv", (ALvoid *) alGetBufferfv }, + { "alGetBufferi", (ALvoid *) alGetBufferi }, + { "alGetBuffer3i", (ALvoid *) alGetBuffer3i }, + { "alGetBufferiv", (ALvoid *) alGetBufferiv }, + { "alDopplerFactor", (ALvoid *) alDopplerFactor }, + { "alDopplerVelocity", (ALvoid *) alDopplerVelocity }, + { "alSpeedOfSound", (ALvoid *) alSpeedOfSound }, + { "alDistanceModel", (ALvoid *) alDistanceModel }, + { NULL, (ALvoid *) NULL } }; + +static ALenums enumeration[]={ + // Types + { (ALchar *)"AL_INVALID", AL_INVALID }, + { (ALchar *)"AL_NONE", AL_NONE }, + { (ALchar *)"AL_FALSE", AL_FALSE }, + { (ALchar *)"AL_TRUE", AL_TRUE }, + + // Source and Listener Properties + { (ALchar *)"AL_SOURCE_RELATIVE", AL_SOURCE_RELATIVE }, + { (ALchar *)"AL_CONE_INNER_ANGLE", AL_CONE_INNER_ANGLE }, + { (ALchar *)"AL_CONE_OUTER_ANGLE", AL_CONE_OUTER_ANGLE }, + { (ALchar *)"AL_PITCH", AL_PITCH }, + { (ALchar *)"AL_POSITION", AL_POSITION }, + { (ALchar *)"AL_DIRECTION", AL_DIRECTION }, + { (ALchar *)"AL_VELOCITY", AL_VELOCITY }, + { (ALchar *)"AL_LOOPING", AL_LOOPING }, + { (ALchar *)"AL_BUFFER", AL_BUFFER }, + { (ALchar *)"AL_GAIN", AL_GAIN }, + { (ALchar *)"AL_MIN_GAIN", AL_MIN_GAIN }, + { (ALchar *)"AL_MAX_GAIN", AL_MAX_GAIN }, + { (ALchar *)"AL_ORIENTATION", AL_ORIENTATION }, + { (ALchar *)"AL_REFERENCE_DISTANCE", AL_REFERENCE_DISTANCE }, + { (ALchar *)"AL_ROLLOFF_FACTOR", AL_ROLLOFF_FACTOR }, + { (ALchar *)"AL_CONE_OUTER_GAIN", AL_CONE_OUTER_GAIN }, + { (ALchar *)"AL_MAX_DISTANCE", AL_MAX_DISTANCE }, + { (ALchar *)"AL_SEC_OFFSET", AL_SEC_OFFSET }, + { (ALchar *)"AL_SAMPLE_OFFSET", AL_SAMPLE_OFFSET }, + { (ALchar *)"AL_BYTE_OFFSET", AL_BYTE_OFFSET }, + { (ALchar *)"AL_SOURCE_TYPE", AL_SOURCE_TYPE }, + { (ALchar *)"AL_STATIC", AL_STATIC }, + { (ALchar *)"AL_STREAMING", AL_STREAMING }, + { (ALchar *)"AL_UNDETERMINED", AL_UNDETERMINED }, + + // Source State information + { (ALchar *)"AL_SOURCE_STATE", AL_SOURCE_STATE }, + { (ALchar *)"AL_INITIAL", AL_INITIAL }, + { (ALchar *)"AL_PLAYING", AL_PLAYING }, + { (ALchar *)"AL_PAUSED", AL_PAUSED }, + { (ALchar *)"AL_STOPPED", AL_STOPPED }, + + // Queue information + { (ALchar *)"AL_BUFFERS_QUEUED", AL_BUFFERS_QUEUED }, + { (ALchar *)"AL_BUFFERS_PROCESSED", AL_BUFFERS_PROCESSED }, + + // Buffer Formats + { (ALchar *)"AL_FORMAT_MONO8", AL_FORMAT_MONO8 }, + { (ALchar *)"AL_FORMAT_MONO16", AL_FORMAT_MONO16 }, + { (ALchar *)"AL_FORMAT_STEREO8", AL_FORMAT_STEREO8 }, + { (ALchar *)"AL_FORMAT_STEREO16", AL_FORMAT_STEREO16 }, + { (ALchar *)"AL_FORMAT_MONO_IMA4", AL_FORMAT_MONO_IMA4 }, + { (ALchar *)"AL_FORMAT_STEREO_IMA4", AL_FORMAT_STEREO_IMA4 }, + { (ALchar *)"AL_FORMAT_QUAD8", AL_FORMAT_QUAD8 }, + { (ALchar *)"AL_FORMAT_QUAD16", AL_FORMAT_QUAD16 }, + + // Buffer attributes + { (ALchar *)"AL_FREQUENCY", AL_FREQUENCY }, + { (ALchar *)"AL_BITS", AL_BITS }, + { (ALchar *)"AL_CHANNELS", AL_CHANNELS }, + { (ALchar *)"AL_SIZE", AL_SIZE }, + + // Buffer States (not supported yet) + { (ALchar *)"AL_UNUSED", AL_UNUSED }, + { (ALchar *)"AL_PENDING", AL_PENDING }, + { (ALchar *)"AL_PROCESSED", AL_PROCESSED }, + + // AL Error Messages + { (ALchar *)"AL_NO_ERROR", AL_NO_ERROR }, + { (ALchar *)"AL_INVALID_NAME", AL_INVALID_NAME }, + { (ALchar *)"AL_INVALID_ENUM", AL_INVALID_ENUM }, + { (ALchar *)"AL_INVALID_VALUE", AL_INVALID_VALUE }, + { (ALchar *)"AL_INVALID_OPERATION", AL_INVALID_OPERATION }, + { (ALchar *)"AL_OUT_OF_MEMORY", AL_OUT_OF_MEMORY }, + + // Context strings + { (ALchar *)"AL_VENDOR", AL_VENDOR }, + { (ALchar *)"AL_VERSION", AL_VERSION }, + { (ALchar *)"AL_RENDERER", AL_RENDERER }, + { (ALchar *)"AL_EXTENSIONS", AL_EXTENSIONS }, + + // Global states + { (ALchar *)"AL_DOPPLER_FACTOR", AL_DOPPLER_FACTOR }, + { (ALchar *)"AL_DOPPLER_VELOCITY", AL_DOPPLER_VELOCITY }, + { (ALchar *)"AL_DISTANCE_MODEL", AL_DISTANCE_MODEL }, + { (ALchar *)"AL_SPEED_OF_SOUND", AL_SPEED_OF_SOUND }, + + // Distance Models + { (ALchar *)"AL_INVERSE_DISTANCE", AL_INVERSE_DISTANCE }, + { (ALchar *)"AL_INVERSE_DISTANCE_CLAMPED", AL_INVERSE_DISTANCE_CLAMPED }, + { (ALchar *)"AL_LINEAR_DISTANCE", AL_LINEAR_DISTANCE }, + { (ALchar *)"AL_LINEAR_DISTANCE_CLAMPED", AL_LINEAR_DISTANCE_CLAMPED }, + { (ALchar *)"AL_EXPONENT_DISTANCE", AL_EXPONENT_DISTANCE }, + { (ALchar *)"AL_EXPONENT_DISTANCE_CLAMPED", AL_EXPONENT_DISTANCE_CLAMPED }, + + // Default + { (ALchar *)NULL, (ALenum ) 0 } }; + + + +ALAPI ALboolean ALAPIENTRY alIsExtensionPresent(const ALchar *extName) +{ + ALboolean bIsSupported = AL_FALSE; + ALCcontext *pContext; + char *ptr, *ext; + + if (!extName) + { + alSetError(AL_INVALID_VALUE); + return AL_FALSE; + } + + pContext = alcGetCurrentContext(); + if(!pContext) + { + alSetError(AL_INVALID_OPERATION); + return AL_FALSE; + } + + ext = strdup(extName); + ptr = ext; + do { + *ptr = toupper(*ptr); + } while(*(ptr++)); + + SuspendContext(pContext); + + ptr = pContext->ExtensionList; + while((ptr=strstr(ptr, ext)) != NULL) + { + if(ptr == pContext->ExtensionList || ptr[-1] == ' ') + { + char e = ptr[strlen(ext)]; + if(e == ' ' || e == 0) + { + bIsSupported = AL_TRUE; + break; + } + } + ptr++; + } + + ProcessContext(pContext); + + free(ext); + return bIsSupported; +} + + +ALAPI ALvoid * ALAPIENTRY alGetProcAddress(const ALchar *funcName) +{ + ALsizei i = 0; + + while(function[i].funcName && + strcmp((char*)function[i].funcName, (char*)funcName) != 0) + i++; + + return function[i].address; +} + +/* NOTE: This function must be able to run without a context! */ +ALAPI ALenum ALAPIENTRY alGetEnumValue(const ALchar *enumName) +{ + ALsizei i = 0; + + while(enumeration[i].enumName && + strcmp(enumeration[i].enumName, enumName) != 0) + i++; + + return enumeration[i].value; +} diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c new file mode 100644 index 00000000..97fc593c --- /dev/null +++ b/OpenAL32/alListener.c @@ -0,0 +1,513 @@ +/** + * 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 "alMain.h" +#include "AL/alc.h" +#include "alError.h" +#include "alListener.h" + +ALAPI ALvoid ALAPIENTRY alListenerf(ALenum eParam, ALfloat flValue) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + switch (eParam) + { + case AL_GAIN: + if (flValue >= 0.0f) + pContext->Listener.Gain = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alListener3f(ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + switch(eParam) + { + case AL_POSITION: + pContext->Listener.Position[0] = flValue1; + pContext->Listener.Position[1] = flValue2; + pContext->Listener.Position[2] = flValue3; + break; + + case AL_VELOCITY: + pContext->Listener.Velocity[0] = flValue1; + pContext->Listener.Velocity[1] = flValue2; + pContext->Listener.Velocity[2] = flValue3; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (pflValues) + { + switch (eParam) + { + case AL_GAIN: + if (pflValues[0] >= 0.0f) + pContext->Listener.Gain = pflValues[0]; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_POSITION: + pContext->Listener.Position[0] = pflValues[0]; + pContext->Listener.Position[1] = pflValues[1]; + pContext->Listener.Position[2] = pflValues[2]; + break; + + case AL_VELOCITY: + pContext->Listener.Velocity[0] = pflValues[0]; + pContext->Listener.Velocity[1] = pflValues[1]; + pContext->Listener.Velocity[2] = pflValues[2]; + break; + + case AL_ORIENTATION: + // AT then UP + pContext->Listener.Forward[0] = pflValues[0]; + pContext->Listener.Forward[1] = pflValues[1]; + pContext->Listener.Forward[2] = pflValues[2]; + pContext->Listener.Up[0] = pflValues[3]; + pContext->Listener.Up[1] = pflValues[4]; + pContext->Listener.Up[2] = pflValues[5]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alListeneri(ALenum eParam, ALint lValue) +{ + ALCcontext *pContext; + + (void)lValue; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + switch (eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alListener3i(ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + switch(eParam) + { + case AL_POSITION: + case AL_VELOCITY: + alListener3f(eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alListeneriv( ALenum eParam, const ALint* plValues ) +{ + ALCcontext *pContext; + ALfloat flValues[6]; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (plValues) + { + switch (eParam) + { + case AL_POSITION: + case AL_VELOCITY: + flValues[0] = (ALfloat)plValues[0]; + flValues[1] = (ALfloat)plValues[1]; + flValues[2] = (ALfloat)plValues[2]; + alListenerfv(eParam, flValues); + break; + + case AL_ORIENTATION: + flValues[0] = (ALfloat)plValues[0]; + flValues[1] = (ALfloat)plValues[1]; + flValues[2] = (ALfloat)plValues[2]; + flValues[3] = (ALfloat)plValues[3]; + flValues[4] = (ALfloat)plValues[4]; + flValues[5] = (ALfloat)plValues[5]; + alListenerfv(eParam, flValues); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetListenerf(ALenum eParam, ALfloat *pflValue) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (pflValue) + { + switch (eParam) + { + case AL_GAIN: + *pflValue = pContext->Listener.Gain; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetListener3f(ALenum eParam, ALfloat *pflValue1, ALfloat *pflValue2, ALfloat *pflValue3) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if ((pflValue1) && (pflValue2) && (pflValue3)) + { + switch (eParam) + { + case AL_POSITION: + *pflValue1 = pContext->Listener.Position[0]; + *pflValue2 = pContext->Listener.Position[1]; + *pflValue3 = pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + *pflValue1 = pContext->Listener.Velocity[0]; + *pflValue2 = pContext->Listener.Velocity[1]; + *pflValue3 = pContext->Listener.Velocity[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetListenerfv(ALenum eParam, ALfloat *pflValues) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (pflValues) + { + switch (eParam) + { + case AL_GAIN: + pflValues[0] = pContext->Listener.Gain; + break; + + case AL_POSITION: + pflValues[0] = pContext->Listener.Position[0]; + pflValues[1] = pContext->Listener.Position[1]; + pflValues[2] = pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + pflValues[0] = pContext->Listener.Velocity[0]; + pflValues[1] = pContext->Listener.Velocity[1]; + pflValues[2] = pContext->Listener.Velocity[2]; + break; + + case AL_ORIENTATION: + // AT then UP + pflValues[0] = pContext->Listener.Forward[0]; + pflValues[1] = pContext->Listener.Forward[1]; + pflValues[2] = pContext->Listener.Forward[2]; + pflValues[3] = pContext->Listener.Up[0]; + pflValues[4] = pContext->Listener.Up[1]; + pflValues[5] = pContext->Listener.Up[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetListeneri(ALenum eParam, ALint *plValue) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (plValue) + { + switch (eParam) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alGetListener3i(ALenum eParam, ALint *plValue1, ALint *plValue2, ALint *plValue3) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if ((plValue1) && (plValue2) && (plValue3)) + { + switch (eParam) + { + case AL_POSITION: + *plValue1 = (ALint)pContext->Listener.Position[0]; + *plValue2 = (ALint)pContext->Listener.Position[1]; + *plValue3 = (ALint)pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + *plValue1 = (ALint)pContext->Listener.Velocity[0]; + *plValue2 = (ALint)pContext->Listener.Velocity[1]; + *plValue3 = (ALint)pContext->Listener.Velocity[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alGetListeneriv(ALenum eParam, ALint* plValues) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (plValues) + { + switch (eParam) + { + case AL_POSITION: + plValues[0] = (ALint)pContext->Listener.Position[0]; + plValues[1] = (ALint)pContext->Listener.Position[1]; + plValues[2] = (ALint)pContext->Listener.Position[2]; + break; + + case AL_VELOCITY: + plValues[0] = (ALint)pContext->Listener.Velocity[0]; + plValues[1] = (ALint)pContext->Listener.Velocity[1]; + plValues[2] = (ALint)pContext->Listener.Velocity[2]; + break; + + case AL_ORIENTATION: + // AT then UP + plValues[0] = (ALint)pContext->Listener.Forward[0]; + plValues[1] = (ALint)pContext->Listener.Forward[1]; + plValues[2] = (ALint)pContext->Listener.Forward[2]; + plValues[3] = (ALint)pContext->Listener.Up[0]; + plValues[4] = (ALint)pContext->Listener.Up[1]; + plValues[5] = (ALint)pContext->Listener.Up[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c new file mode 100644 index 00000000..90d70939 --- /dev/null +++ b/OpenAL32/alSource.c @@ -0,0 +1,2108 @@ +/** + * 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 <stdlib.h> +#include <math.h> +#include <float.h> +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" +#include "alError.h" +#include "alSource.h" + +ALvoid InitSourceParams(ALsource *pSource); +ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset); +ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext); +ALint GetByteOffset(ALsource *pSource); + +ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources) +{ + ALCcontext *Context; + ALCdevice *Device; + ALsizei i=0; + + Context = alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (n > 0) + { + Device = alcGetContextsDevice(Context); + + if (Device) + { + // Check that enough memory has been allocted in the 'sources' array for n Sources + if (!IsBadWritePtr((void*)sources, n * sizeof(ALuint))) + { + // Check that the requested number of sources can be generated + if ((Context->SourceCount + n) <= Device->MaxNoOfSources) + { + ALsource **list = &Context->Source; + while(*list) + list = &(*list)->next; + + // Add additional sources to the list (Source->next points to the location for the next Source structure) + while(i < n) + { + *list = calloc(1, sizeof(ALsource)); + if(*list) + { + sources[i]=(ALuint)ALTHUNK_ADDENTRY(*list); + (*list)->source = sources[i]; + + InitSourceParams(*list); + Context->SourceCount++; + i++; + + list = &(*list)->next; + } + } + + // If we didn't create all the Sources, we must have run out or memory + if(i != n) + alSetError(AL_OUT_OF_MEMORY); + } + else + { + // Not enough resources to create the Sources + alSetError(AL_INVALID_VALUE); + } + } + else + { + // Bad pointer + alSetError(AL_INVALID_VALUE); + } + } + else + { + // No Device created, or attached to Context + alSetError(AL_INVALID_OPERATION); + } + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + + +ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALCdevice *Device; + ALsource *ALSource; + ALsource **list; + ALsizei i; + ALbufferlistitem *ALBufferList; + ALboolean bSourcesValid = AL_TRUE; + + Context = alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (n >= 0) + { + Device = alcGetContextsDevice(Context); + + if (Device) + { + if ((ALuint)n <= Context->SourceCount) + { + // Check that all Sources are valid (and can therefore be deleted) + for (i = 0; i < n; i++) + { + if (!alIsSource(sources[i])) + { + alSetError(AL_INVALID_NAME); + bSourcesValid = AL_FALSE; + break; + } + } + + if (bSourcesValid) + { + // All Sources are valid, and can be deleted + for (i = 0; i < n; i++) + { + // Recheck that the Source is valid, because there could be duplicated Source names + if (alIsSource(sources[i])) + { + ALSource=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i])); + alSourceStop((ALuint)ALSource->source); + + // For each buffer in the source's queue, decrement its reference counter and remove it + while (ALSource->queue != NULL) + { + ALBufferList = ALSource->queue; + // Decrement buffer's reference counter + if (ALBufferList->buffer != 0) + ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--; + // Update queue to point to next element in list + ALSource->queue = ALBufferList->next; + // Release memory allocated for buffer list item + free(ALBufferList); + } + + // Decrement Source count + Context->SourceCount--; + + // Remove Source from list of Sources + list = &Context->Source; + while(*list && *list != ALSource) + list = &(*list)->next; + + if(*list) + *list = (*list)->next; + ALTHUNK_REMOVEENTRY(ALSource->source); + + memset(ALSource,0,sizeof(ALsource)); + free(ALSource); + } + } + + } + } + else + { + // Trying to delete more Sources than have been generated + alSetError(AL_INVALID_NAME); + } + } + else + { + // No Device created, or attached to Context + alSetError(AL_INVALID_OPERATION); + } + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + + +ALAPI ALboolean ALAPIENTRY alIsSource(ALuint source) +{ + ALboolean result=AL_FALSE; + ALCcontext *Context; + ALsource *Source; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + // To determine if this is a valid Source name, look through the list of generated Sources + Source = Context->Source; + while(Source) + { + if (Source == (ALsource*)ALTHUNK_LOOKUPENTRY(source)) + { + result = AL_TRUE; + break; + } + + Source = Source->next; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return result; +} + + +ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch (eParam) + { + case AL_PITCH: + if (flValue >= 0.0f) + { + pSource->flPitch = flValue; + if(pSource->flPitch < 0.001f) + pSource->flPitch = 0.001f; + } + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_CONE_INNER_ANGLE: + if ((flValue >= 0.0f) && (flValue <= 360.0f)) + pSource->flInnerAngle = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_CONE_OUTER_ANGLE: + if ((flValue >= 0.0f) && (flValue <= 360.0f)) + pSource->flOuterAngle = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_GAIN: + if (flValue >= 0.0f) + pSource->flGain = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_MAX_DISTANCE: + if (flValue >= 0.0f) + pSource->flMaxDistance = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_ROLLOFF_FACTOR: + if (flValue >= 0.0f) + pSource->flRollOffFactor = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_REFERENCE_DISTANCE: + if (flValue >= 0.0f) + pSource->flRefDistance = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_MIN_GAIN: + if ((flValue >= 0.0f) && (flValue <= 1.0f)) + pSource->flMinGain = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_MAX_GAIN: + if ((flValue >= 0.0f) && (flValue <= 1.0f)) + pSource->flMaxGain = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_CONE_OUTER_GAIN: + if ((flValue >= 0.0f) && (flValue <= 1.0f)) + pSource->flOuterGain = flValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + if (flValue >= 0.0f) + { + pSource->lOffsetType = eParam; + + // Store Offset (convert Seconds into Milliseconds) + if (eParam == AL_SEC_OFFSET) + pSource->lOffset = (ALint)(flValue * 1000.0f); + else + pSource->lOffset = (ALint)flValue; + + if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) + ApplyOffset(pSource, AL_TRUE); + } + else + alSetError(AL_INVALID_VALUE); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + // Invalid Source Name + alSetError(AL_INVALID_NAME); + } + + ProcessContext(pContext); + } + else + { + // Invalid context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + + +ALAPI ALvoid ALAPIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + switch(eParam) + { + case AL_POSITION: + pSource->vPosition[0] = flValue1; + pSource->vPosition[1] = flValue2; + pSource->vPosition[2] = flValue3; + break; + + case AL_VELOCITY: + pSource->vVelocity[0] = flValue1; + pSource->vVelocity[1] = flValue2; + pSource->vVelocity[2] = flValue3; + break; + + case AL_DIRECTION: + pSource->vOrientation[0] = flValue1; + pSource->vOrientation[1] = flValue2; + pSource->vOrientation[2] = flValue3; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + + ProcessContext(pContext); + } + else + { + alSetError(AL_INVALID_OPERATION); + } + + return; +} + + +ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (pflValues) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch (eParam) + { + case AL_PITCH: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + alSourcef(source, eParam, pflValues[0]); + break; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue) +{ + ALCcontext *pContext; + ALsource *pSource; + ALbufferlistitem *pALBufferListItem; + ALint Counter = 0; + ALint DataSize = 0; + ALint BufferSize; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch(eParam) + { + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + alSourcef(source, eParam, (ALfloat)lValue); + break; + + case AL_SOURCE_RELATIVE: + if ((lValue == AL_FALSE) || (lValue == AL_TRUE)) + pSource->bHeadRelative = (ALboolean)lValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_CONE_INNER_ANGLE: + if ((lValue >= 0) && (lValue <= 360)) + pSource->flInnerAngle = (float)lValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_CONE_OUTER_ANGLE: + if ((lValue >= 0) && (lValue <= 360)) + pSource->flOuterAngle = (float)lValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_LOOPING: + if ((lValue == AL_FALSE) || (lValue == AL_TRUE)) + pSource->bLooping = (ALboolean)lValue; + else + alSetError(AL_INVALID_VALUE); + break; + + case AL_BUFFER: + if ((pSource->state == AL_STOPPED) || (pSource->state == AL_INITIAL)) + { + if (alIsBuffer(lValue)) + { + // Remove all elements in the queue + while (pSource->queue != NULL) + { + pALBufferListItem = pSource->queue; + pSource->queue = pALBufferListItem->next; + // Decrement reference counter for buffer + if (pALBufferListItem->buffer) + ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer)))->refcount--; + // Record size of buffer + BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pALBufferListItem->buffer))->size; + DataSize += BufferSize; + // Increment the number of buffers removed from queue + Counter++; + // Release memory for buffer list item + free(pALBufferListItem); + // Decrement the number of buffers in the queue + pSource->BuffersInQueue--; + } + + // Add the buffer to the queue (as long as it is NOT the NULL buffer) + if (lValue != 0) + { + // Source is now in STATIC mode + pSource->lSourceType = AL_STATIC; + + // Add the selected buffer to the queue + pALBufferListItem = malloc(sizeof(ALbufferlistitem)); + pALBufferListItem->buffer = lValue; + pALBufferListItem->bufferstate = PENDING; + pALBufferListItem->flag = 0; + pALBufferListItem->next = NULL; + + pSource->queue = pALBufferListItem; + pSource->BuffersInQueue = 1; + + DataSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(lValue))->size; + + // Increment reference counter for buffer + ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(lValue)))->refcount++; + } + else + { + // Source is now in UNDETERMINED mode + pSource->lSourceType = AL_UNDETERMINED; + } + + // Set Buffers Processed + pSource->BuffersProcessed = 0; + + // Update AL_BUFFER parameter + pSource->ulBufferID = lValue; + } + else + alSetError(AL_INVALID_VALUE); + } + else + alSetError(AL_INVALID_OPERATION); + break; + + case AL_SOURCE_STATE: + // Query only + alSetError(AL_INVALID_OPERATION); + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + if (lValue >= 0) + { + pSource->lOffsetType = eParam; + + // Store Offset (convert Seconds into Milliseconds) + if (eParam == AL_SEC_OFFSET) + pSource->lOffset = lValue * 1000; + else + pSource->lOffset = lValue; + + if ((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) + ApplyOffset(pSource, AL_TRUE); + } + else + alSetError(AL_INVALID_VALUE); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch (eParam) + { + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (plValues) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch (eParam) + { + case AL_SOURCE_RELATIVE: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + alSourcei(source, eParam, plValues[0]); + break; + + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue) +{ + ALCcontext *pContext; + ALsource *pSource; + ALfloat flOffset; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (pflValue) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch(eParam) + { + case AL_PITCH: + *pflValue = pSource->flPitch; + break; + + case AL_GAIN: + *pflValue = pSource->flGain; + break; + + case AL_MIN_GAIN: + *pflValue = pSource->flMinGain; + break; + + case AL_MAX_GAIN: + *pflValue = pSource->flMaxGain; + break; + + case AL_MAX_DISTANCE: + *pflValue = pSource->flMaxDistance; + break; + + case AL_ROLLOFF_FACTOR: + *pflValue = pSource->flRollOffFactor; + break; + + case AL_CONE_OUTER_GAIN: + *pflValue = pSource->flOuterGain; + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + if (GetSourceOffset(pSource, eParam, &flOffset)) + *pflValue = flOffset; + else + alSetError(AL_INVALID_OPERATION); + break; + + case AL_CONE_INNER_ANGLE: + *pflValue = pSource->flInnerAngle; + break; + + case AL_CONE_OUTER_ANGLE: + *pflValue = pSource->flOuterAngle; + break; + + case AL_REFERENCE_DISTANCE: + *pflValue = pSource->flRefDistance; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if ((pflValue1) && (pflValue2) && (pflValue3)) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch(eParam) + { + case AL_POSITION: + *pflValue1 = pSource->vPosition[0]; + *pflValue2 = pSource->vPosition[1]; + *pflValue3 = pSource->vPosition[2]; + break; + + case AL_VELOCITY: + *pflValue1 = pSource->vVelocity[0]; + *pflValue2 = pSource->vVelocity[1]; + *pflValue3 = pSource->vVelocity[2]; + break; + + case AL_DIRECTION: + *pflValue1 = pSource->vOrientation[0]; + *pflValue2 = pSource->vOrientation[1]; + *pflValue3 = pSource->vOrientation[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (pflValues) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch(eParam) + { + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + alGetSourcef(source, eParam, pflValues); + break; + + case AL_POSITION: + pflValues[0] = pSource->vPosition[0]; + pflValues[1] = pSource->vPosition[1]; + pflValues[2] = pSource->vPosition[2]; + break; + + case AL_VELOCITY: + pflValues[0] = pSource->vVelocity[0]; + pflValues[1] = pSource->vVelocity[1]; + pflValues[2] = pSource->vVelocity[2]; + break; + + case AL_DIRECTION: + pflValues[0] = pSource->vOrientation[0]; + pflValues[1] = pSource->vOrientation[1]; + pflValues[2] = pSource->vOrientation[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue) +{ + ALCcontext *pContext; + ALsource *pSource; + ALfloat flOffset; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (plValue) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch(eParam) + { + case AL_MAX_DISTANCE: + *plValue = (ALint)pSource->flMaxDistance; + break; + + case AL_ROLLOFF_FACTOR: + *plValue = (ALint)pSource->flRollOffFactor; + break; + + case AL_REFERENCE_DISTANCE: + *plValue = (ALint)pSource->flRefDistance; + break; + + case AL_SOURCE_RELATIVE: + *plValue = pSource->bHeadRelative; + break; + + case AL_CONE_INNER_ANGLE: + *plValue = (ALint)pSource->flInnerAngle; + break; + + case AL_CONE_OUTER_ANGLE: + *plValue = (ALint)pSource->flOuterAngle; + break; + + case AL_LOOPING: + *plValue = pSource->bLooping; + break; + + case AL_BUFFER: + *plValue = pSource->ulBufferID; + break; + + case AL_SOURCE_STATE: + *plValue = pSource->state; + break; + + case AL_BUFFERS_QUEUED: + *plValue = pSource->BuffersInQueue; + break; + + case AL_BUFFERS_PROCESSED: + if(pSource->bLooping) + { + /* Buffers on a looping source are in a perpetual state + * of PENDING, so don't report any as PROCESSED */ + *plValue = 0; + } + else + *plValue = pSource->BuffersProcessed; + break; + + case AL_SOURCE_TYPE: + *plValue = pSource->lSourceType; + break; + + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + if (GetSourceOffset(pSource, eParam, &flOffset)) + *plValue = (ALint)flOffset; + else + alSetError(AL_INVALID_OPERATION); + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if ((plValue1) && (plValue2) && (plValue3)) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch(eParam) + { + case AL_POSITION: + *plValue1 = (ALint)pSource->vPosition[0]; + *plValue2 = (ALint)pSource->vPosition[1]; + *plValue3 = (ALint)pSource->vPosition[2]; + break; + + case AL_VELOCITY: + *plValue1 = (ALint)pSource->vVelocity[0]; + *plValue2 = (ALint)pSource->vVelocity[1]; + *plValue3 = (ALint)pSource->vVelocity[2]; + break; + + case AL_DIRECTION: + *plValue1 = (ALint)pSource->vOrientation[0]; + *plValue2 = (ALint)pSource->vOrientation[1]; + *plValue3 = (ALint)pSource->vOrientation[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI void ALAPIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues) +{ + ALCcontext *pContext; + ALsource *pSource; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (plValues) + { + if (alIsSource(source)) + { + pSource = ((ALsource *)ALTHUNK_LOOKUPENTRY(source)); + + switch (eParam) + { + case AL_SOURCE_RELATIVE: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_REFERENCE_DISTANCE: + case AL_SOURCE_TYPE: + alGetSourcei(source, eParam, plValues); + break; + + case AL_POSITION: + plValues[0] = (ALint)pSource->vPosition[0]; + plValues[1] = (ALint)pSource->vPosition[1]; + plValues[2] = (ALint)pSource->vPosition[2]; + break; + + case AL_VELOCITY: + plValues[0] = (ALint)pSource->vVelocity[0]; + plValues[1] = (ALint)pSource->vVelocity[1]; + plValues[2] = (ALint)pSource->vVelocity[2]; + break; + + case AL_DIRECTION: + plValues[0] = (ALint)pSource->vOrientation[0]; + plValues[1] = (ALint)pSource->vOrientation[1]; + plValues[2] = (ALint)pSource->vOrientation[2]; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + alSetError(AL_INVALID_NAME); + } + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + alSetError(AL_INVALID_OPERATION); + + return; +} + + +ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source) +{ + alSourcePlayv(1, &source); + return; +} + +ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList) +{ + ALCcontext *pContext; + ALsource *pSource; + ALbufferlistitem *ALBufferList; + ALboolean bSourcesValid = AL_TRUE; + ALboolean bPlay; + ALsizei i; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (pSourceList) + { + // Check that all the Sources are valid + for (i = 0; i < n; i++) + { + if (!alIsSource(pSourceList[i])) + { + alSetError(AL_INVALID_NAME); + bSourcesValid = AL_FALSE; + break; + } + } + + if (bSourcesValid) + { + for (i = 0; i < n; i++) + { + // Assume Source won't need to play + bPlay = AL_FALSE; + + pSource = ((ALsource*)ALTHUNK_LOOKUPENTRY(pSourceList[i])); + + // Check that there is a queue containing at least one non-null, non zero length AL Buffer + ALBufferList = pSource->queue; + while (ALBufferList) + { + if ((ALBufferList->buffer != 0) && (((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size)) + { + bPlay = AL_TRUE; + break; + } + ALBufferList = ALBufferList->next; + } + + if (bPlay) + { + if (pSource->state != AL_PAUSED) + { + pSource->state = AL_PLAYING; + pSource->inuse = AL_TRUE; + pSource->play = AL_TRUE; + pSource->position = 0; + pSource->position_fraction = 0; + pSource->BuffersProcessed = 0; + pSource->BuffersPlayed = 0; + pSource->BufferPosition = 0; + pSource->lBytesPlayed = 0; + + pSource->ulBufferID = pSource->queue->buffer; + + // Make sure all the Buffers in the queue are marked as PENDING + ALBufferList = pSource->queue; + while (ALBufferList) + { + ALBufferList->bufferstate = PENDING; + ALBufferList = ALBufferList->next; + } + } + else + { + pSource->state = AL_PLAYING; + pSource->inuse = AL_TRUE; + pSource->play = AL_TRUE; + } + + // Check if an Offset has been set + if (pSource->lOffset) + ApplyOffset(pSource, AL_FALSE); + } + else + { + // If there is a queue (must all be NULL or Zero length Buffers) mark them all as processed + ALBufferList = pSource->queue; + while (ALBufferList) + { + ALBufferList->bufferstate = PROCESSED; + ALBufferList = ALBufferList->next; + } + + pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue; + } + } + } + } + else + { + // sources is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(pContext); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint source) +{ + alSourcePausev(1, &source); + return; +} + +ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + ALboolean bSourcesValid = AL_TRUE; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (sources) + { + // Check all the Sources are valid + for (i=0;i<n;i++) + { + if (!alIsSource(sources[i])) + { + alSetError(AL_INVALID_NAME); + bSourcesValid = AL_FALSE; + break; + } + } + + if (bSourcesValid) + { + for (i=0;i<n;i++) + { + Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i])); + if (Source->state==AL_PLAYING) + { + Source->state=AL_PAUSED; + Source->inuse=AL_FALSE; + } + } + } + } + else + { + // sources is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint source) +{ + alSourceStopv(1, &source); + return; +} + +ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + ALbufferlistitem *ALBufferListItem; + ALboolean bSourcesValid = AL_TRUE; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (sources) + { + // Check all the Sources are valid + for (i=0;i<n;i++) + { + if (!alIsSource(sources[i])) + { + alSetError(AL_INVALID_NAME); + bSourcesValid = AL_FALSE; + break; + } + } + + if (bSourcesValid) + { + for (i=0;i<n;i++) + { + Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i])); + if (Source->state!=AL_INITIAL) + { + Source->state=AL_STOPPED; + Source->inuse=AL_FALSE; + Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue; + ALBufferListItem= Source->queue; + while (ALBufferListItem != NULL) + { + ALBufferListItem->bufferstate = PROCESSED; + ALBufferListItem = ALBufferListItem->next; + } + } + Source->lOffset = 0; + } + } + } + else + { + // sources is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint source) +{ + alSourceRewindv(1, &source); + return; +} + +ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) +{ + ALCcontext *Context; + ALsource *Source; + ALsizei i; + ALbufferlistitem *ALBufferListItem; + ALboolean bSourcesValid = AL_TRUE; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (sources) + { + // Check all the Sources are valid + for (i=0;i<n;i++) + { + if (!alIsSource(sources[i])) + { + alSetError(AL_INVALID_NAME); + bSourcesValid = AL_FALSE; + break; + } + } + + if (bSourcesValid) + { + for (i=0;i<n;i++) + { + Source=((ALsource *)ALTHUNK_LOOKUPENTRY(sources[i])); + if (Source->state!=AL_INITIAL) + { + Source->state=AL_INITIAL; + Source->inuse=AL_FALSE; + Source->position=0; + Source->position_fraction=0; + Source->BuffersProcessed = 0; + ALBufferListItem= Source->queue; + while (ALBufferListItem != NULL) + { + ALBufferListItem->bufferstate = PENDING; + ALBufferListItem = ALBufferListItem->next; + } + if (Source->queue) + Source->ulBufferID = Source->queue->buffer; + } + Source->lOffset = 0; + } + } + } + else + { + // sources is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + + +ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, const ALuint* buffers ) +{ + ALCcontext *Context; + ALsource *ALSource; + ALsizei i; + ALbufferlistitem *ALBufferList; + ALbufferlistitem *ALBufferListStart; + ALuint DataSize; + ALuint BufferSize; + ALint iFrequency; + ALint iFormat; + ALboolean bBuffersValid = AL_TRUE; + + if (n == 0) + return; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + DataSize = 0; + BufferSize = 0; + + // Check that all buffers are valid or zero and that the source is valid + + // Check that this is a valid source + if (alIsSource(source)) + { + ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source); + + // Check that this is not a STATIC Source + if (ALSource->lSourceType != AL_STATIC) + { + iFrequency = -1; + iFormat = -1; + + // Check existing Queue (if any) for a valid Buffers and get its frequency and format + ALBufferList = ALSource->queue; + while (ALBufferList) + { + if (ALBufferList->buffer) + { + iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->frequency; + iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->format; + break; + } + ALBufferList = ALBufferList->next; + } + + for (i = 0; i < n; i++) + { + if (alIsBuffer(buffers[i])) + { + if (buffers[i]) + { + if ((iFrequency == -1) && (iFormat == -1)) + { + iFrequency = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency; + iFormat = ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format; + } + else + { + if ((iFrequency != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->frequency) || + (iFormat != ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->format)) + { + alSetError(AL_INVALID_OPERATION); + bBuffersValid = AL_FALSE; + break; + } + } + } + } + else + { + alSetError(AL_INVALID_NAME); + bBuffersValid = AL_FALSE; + break; + } + } + + if (bBuffersValid) + { + // Change Source Type + ALSource->lSourceType = AL_STREAMING; + + // All buffers are valid - so add them to the list + ALBufferListStart = malloc(sizeof(ALbufferlistitem)); + ALBufferListStart->buffer = buffers[0]; + ALBufferListStart->bufferstate = PENDING; + ALBufferListStart->flag = 0; + ALBufferListStart->next = NULL; + + if (buffers[0]) + BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]))->size; + else + BufferSize = 0; + + DataSize += BufferSize; + + // Increment reference counter for buffer + if (buffers[0]) + ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[0])))->refcount++; + + ALBufferList = ALBufferListStart; + + for (i = 1; i < n; i++) + { + ALBufferList->next = malloc(sizeof(ALbufferlistitem)); + ALBufferList->next->buffer = buffers[i]; + ALBufferList->next->bufferstate = PENDING; + ALBufferList->next->flag = 0; + ALBufferList->next->next = NULL; + + if (buffers[i]) + BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]))->size; + else + BufferSize = 0; + + DataSize += BufferSize; + + // Increment reference counter for buffer + if (buffers[i]) + ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(buffers[i])))->refcount++; + + ALBufferList = ALBufferList->next; + } + + if (ALSource->queue == NULL) + { + ALSource->queue = ALBufferListStart; + // Update Current Buffer + ALSource->ulBufferID = ALBufferListStart->buffer; + } + else + { + // Find end of queue + ALBufferList = ALSource->queue; + while (ALBufferList->next != NULL) + { + ALBufferList = ALBufferList->next; + } + + ALBufferList->next = ALBufferListStart; + } + + // Update number of buffers in queue + ALSource->BuffersInQueue += n; + } + } + else + { + // Invalid Source Type (can't queue on a Static Source) + alSetError(AL_INVALID_OPERATION); + } + } + else + { + // Invalid Source Name + alSetError(AL_INVALID_NAME); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + + +// Implementation assumes that n is the number of buffers to be removed from the queue and buffers is +// an array of buffer IDs that are to be filled with the names of the buffers removed +ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers ) +{ + ALCcontext *Context; + ALsource *ALSource; + ALsizei i; + ALbufferlistitem *ALBufferList; + ALuint DataSize; + ALuint BufferSize; + ALuint BufferID; + ALboolean bBuffersProcessed; + + if (n == 0) + return; + + DataSize = 0; + BufferSize = 0; + bBuffersProcessed = AL_TRUE; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (alIsSource(source)) + { + ALSource = (ALsource*)ALTHUNK_LOOKUPENTRY(source); + + // Check that all 'n' buffers have been processed + ALBufferList = ALSource->queue; + for (i = 0; i < n; i++) + { + if ((ALBufferList != NULL) && (ALBufferList->bufferstate == PROCESSED)) + { + ALBufferList = ALBufferList->next; + } + else + { + bBuffersProcessed = AL_FALSE; + break; + } + } + + // If all 'n' buffers have been processed, remove them from the queue + if (bBuffersProcessed) + { + for (i = 0; i < n; i++) + { + ALBufferList = ALSource->queue; + + ALSource->queue = ALBufferList->next; + // Record name of buffer + buffers[i] = ALBufferList->buffer; + // Decrement buffer reference counter + if (ALBufferList->buffer) + ((ALbuffer*)(ALTHUNK_LOOKUPENTRY(ALBufferList->buffer)))->refcount--; + // Record size of buffer + if (ALBufferList->buffer) + BufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALBufferList->buffer))->size; + else + BufferSize = 0; + + DataSize += BufferSize; + // Release memory for buffer list item + free(ALBufferList); + ALSource->BuffersInQueue--; + ALSource->BuffersProcessed--; + } + + if (ALSource->state != AL_PLAYING) + { + if (ALSource->queue) + BufferID = ALSource->queue->buffer; + else + BufferID = 0; + + ALSource->ulBufferID = BufferID; + } + + if((ALuint)n > ALSource->BuffersPlayed) + { + ALSource->BuffersPlayed = 0; + ALSource->BufferPosition = 0; + } + else + ALSource->BuffersPlayed -= n; + } + else + { + // Some buffers can't be unqueue because they have not been processed + alSetError(AL_INVALID_VALUE); + } + } + else + { + // Invalid Source Name + alSetError(AL_INVALID_NAME); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + + +ALvoid InitSourceParams(ALsource *pSource) +{ + pSource->flInnerAngle = 360.0f; + pSource->flOuterAngle = 360.0f; + pSource->flPitch = 1.0f; + pSource->vPosition[0] = 0.0f; + pSource->vPosition[1] = 0.0f; + pSource->vPosition[2] = 0.0f; + pSource->vOrientation[0] = 0.0f; + pSource->vOrientation[1] = 0.0f; + pSource->vOrientation[2] = 0.0f; + pSource->vVelocity[0] = 0.0f; + pSource->vVelocity[1] = 0.0f; + pSource->vVelocity[2] = 0.0f; + pSource->flRefDistance = 1.0f; + pSource->flMaxDistance = FLT_MAX; + pSource->flRollOffFactor = 1.0f; + pSource->bLooping = AL_FALSE; + pSource->flGain = 1.0f; + pSource->flMinGain = 0.0f; + pSource->flMaxGain = 1.0f; + pSource->flOuterGain = 0.0f; + + pSource->state = AL_INITIAL; + pSource->lSourceType = AL_UNDETERMINED; + + pSource->ulBufferID= 0; +} + + +/* + GetSourceOffset + + Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds) + The offset is relative to the start of the queue (not the start of the current buffer) +*/ +ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset) +{ + ALbufferlistitem *pBufferList; + ALfloat flBufferFreq; + ALint lBufferSize, lBytesPlayed, lChannels; + ALenum eOriginalFormat; + ALboolean bReturn = AL_TRUE; + ALint lTotalBufferDataSize; + + if (((pSource->state == AL_PLAYING) || (pSource->state == AL_PAUSED)) && (pSource->ulBufferID)) + { + // Get Current Buffer Size and frequency (in milliseconds) + lBufferSize = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->size; + flBufferFreq = (ALfloat)(((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->frequency); + eOriginalFormat = ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->eOriginalFormat; + lChannels = ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pSource->ulBufferID))->format == AL_FORMAT_MONO16)?1:2); + + // Get Current BytesPlayed + lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer + // Add byte length of any processed buffers in the queue + pBufferList = pSource->queue; + while ((pBufferList) && (pBufferList->bufferstate == PROCESSED)) + { + lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size; + pBufferList = pBufferList->next; + } + + lTotalBufferDataSize = 0; + pBufferList = pSource->queue; + while (pBufferList) + { + if (pBufferList->buffer) + lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size; + pBufferList = pBufferList->next; + } + + if (pSource->bLooping) + { + if (lBytesPlayed < 0) + lBytesPlayed = 0; + else + lBytesPlayed = lBytesPlayed % lTotalBufferDataSize; + } + else + { + // Clamp BytesPlayed to within 0 and lTotalBufferDataSize + if(lBytesPlayed < 0) + lBytesPlayed = 0; + if(lBytesPlayed > lTotalBufferDataSize) + lBytesPlayed = lTotalBufferDataSize; + } + + switch (eName) + { + case AL_SEC_OFFSET: + *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq)); + break; + case AL_SAMPLE_OFFSET: + *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2)); + break; + case AL_BYTE_OFFSET: + // Take into account the original format of the Buffer + if ((eOriginalFormat == AL_FORMAT_MONO8) || (eOriginalFormat == AL_FORMAT_STEREO8)) + { + *pflOffset = (ALfloat)(lBytesPlayed >> 1); + } + else if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) || (eOriginalFormat == AL_FORMAT_STEREO_IMA4)) + { + // Compression rate of the ADPCM supported is 3.6111 to 1 + lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f); + // Round down to nearest ADPCM block + *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels); + } + else + { + *pflOffset = (ALfloat)lBytesPlayed; + } + break; + } + } + else + { + *pflOffset = 0.0f; + } + + return bReturn; +} + + +/* + ApplyOffset + + Apply a playback offset to the Source. This function will update the queue (to correctly + mark buffers as 'pending' or 'processed' depending upon the new offset. +*/ +void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext) +{ + ALbufferlistitem *pBufferList; + ALint lBufferSize, lTotalBufferSize; + ALint lByteOffset; + + // Get true byte offset + lByteOffset = GetByteOffset(pSource); + + // If this is a valid offset apply it + if (lByteOffset != -1) + { + // Sort out the queue (pending and processed states) + pBufferList = pSource->queue; + lTotalBufferSize = 0; + pSource->BuffersPlayed = 0; + pSource->BuffersProcessed = 0; + while (pBufferList) + { + lBufferSize = pBufferList->buffer ? ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size : 0; + + if ((lTotalBufferSize + lBufferSize) <= lByteOffset) + { + // Offset is past this buffer so increment BuffersPlayed and if the Source is NOT looping + // update the state to PROCESSED + pSource->BuffersPlayed++; + + if (!pSource->bLooping) + { + pBufferList->bufferstate = PROCESSED; + pSource->BuffersProcessed++; + } + } + else if (lTotalBufferSize <= lByteOffset) + { + // Offset is within this buffer + pBufferList->bufferstate = PENDING; + + // Set Current Buffer ID + pSource->ulBufferID = pBufferList->buffer; + + // Set current position in this buffer + pSource->BufferPosition = lByteOffset - lTotalBufferSize; + + // Set Total Bytes Played to Offset + pSource->lBytesPlayed = lByteOffset; + + // SW Mixer Positions are in Samples + pSource->position = pSource->BufferPosition / ((((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->format == AL_FORMAT_MONO16)?2:4); + } + else + { + // Offset is before this buffer, so mark as pending + pBufferList->bufferstate = PENDING; + } + + // Increment the TotalBufferSize + lTotalBufferSize += lBufferSize; + + // Move on to next buffer in the Queue + pBufferList = pBufferList->next; + } + } + else + { + if (bUpdateContext) + alSetError(AL_INVALID_VALUE); + } + + // Clear Offset + pSource->lOffset = 0; +} + + +/* + GetByteOffset + + Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond + offset supplied by the application). This takes into account the fact that the buffer format + may have been modifed by AL (e.g 8bit samples are converted to 16bit) +*/ +ALint GetByteOffset(ALsource *pSource) +{ + ALbuffer *pBuffer = NULL; + ALbufferlistitem *pBufferList; + ALfloat flBufferFreq; + ALint lChannels; + ALint lByteOffset = -1; + ALint lTotalBufferDataSize; + + // Find the first non-NULL Buffer in the Queue + pBufferList = pSource->queue; + while (pBufferList) + { + if (pBufferList->buffer) + { + pBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer); + break; + } + pBufferList = pBufferList->next; + } + + if (pBuffer) + { + flBufferFreq = ((ALfloat)pBuffer->frequency); + lChannels = (pBuffer->format == AL_FORMAT_MONO16)?1:2; + + // Determine the ByteOffset (and ensure it is block aligned) + switch (pSource->lOffsetType) + { + case AL_BYTE_OFFSET: + // Take into consideration the original format + if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO8) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO8)) + { + lByteOffset = pSource->lOffset * 2; + lByteOffset -= (lByteOffset % (lChannels * 2)); + } + else if ((pBuffer->eOriginalFormat == AL_FORMAT_MONO_IMA4) || (pBuffer->eOriginalFormat == AL_FORMAT_STEREO_IMA4)) + { + // Round down to nearest ADPCM block + lByteOffset = (pSource->lOffset / (36 * lChannels)) * 36 * lChannels; + // Multiply by compression rate + lByteOffset = (ALint)(3.6111f * (ALfloat)lByteOffset); + lByteOffset -= (lByteOffset % (lChannels * 2)); + } + else + { + lByteOffset = pSource->lOffset; + lByteOffset -= (lByteOffset % (lChannels * 2)); + } + break; + + case AL_SAMPLE_OFFSET: + lByteOffset = pSource->lOffset * lChannels * 2; + break; + + case AL_SEC_OFFSET: + // Note - lOffset is internally stored as Milliseconds + lByteOffset = (ALint)(pSource->lOffset * lChannels * 2.0f * flBufferFreq / 1000.0f); + lByteOffset -= (lByteOffset % (lChannels * 2)); + break; + } + + lTotalBufferDataSize = 0; + pBufferList = pSource->queue; + while (pBufferList) + { + if (pBufferList->buffer) + lTotalBufferDataSize += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size; + pBufferList = pBufferList->next; + } + + // Finally, if the ByteOffset is beyond the length of all the buffers in the queue, return -1 + if (lByteOffset >= lTotalBufferDataSize) + lByteOffset = -1; + } + + return lByteOffset; +} diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c new file mode 100644 index 00000000..06da8a88 --- /dev/null +++ b/OpenAL32/alState.c @@ -0,0 +1,677 @@ +/** + * 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 <stdlib.h> +#include "alMain.h" +#include "AL/alc.h" +#include "alError.h" +#include "alState.h" + +static const ALchar alVendor[] = "OpenAL Community"; +static const ALchar alVersion[] = "1.1"; +static const ALchar alRenderer[] = "OpenAL Sample Implementation"; + +// 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"; + +ALAPI ALvoid ALAPIENTRY alEnable(ALenum capability) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (capability) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } +} + +ALAPI ALvoid ALAPIENTRY alDisable(ALenum capability) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (capability) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } +} + +ALAPI ALboolean ALAPIENTRY alIsEnabled(ALenum capability) +{ + ALCcontext *Context; + ALboolean value=AL_FALSE; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (capability) + { + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return value; +} + +ALAPI ALboolean ALAPIENTRY alGetBoolean(ALenum pname) +{ + ALCcontext *Context; + ALboolean value=AL_FALSE; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (pname) + { + case AL_DOPPLER_FACTOR: + if (Context->DopplerFactor != 0.0f) + value = AL_TRUE; + break; + + case AL_DOPPLER_VELOCITY: + if (Context->DopplerVelocity != 0.0f) + value = AL_TRUE; + break; + + case AL_DISTANCE_MODEL: + if (Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) + value = AL_TRUE; + break; + + case AL_SPEED_OF_SOUND: + if (Context->flSpeedOfSound != 0.0f) + value = AL_TRUE; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return value; +} + +ALAPI ALdouble ALAPIENTRY alGetDouble(ALenum pname) +{ + ALCcontext *Context; + ALdouble value = 0.0; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (pname) + { + case AL_DOPPLER_FACTOR: + value = (double)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (double)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (double)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (double)Context->flSpeedOfSound; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return value; +} + +ALAPI ALfloat ALAPIENTRY alGetFloat(ALenum pname) +{ + ALCcontext *Context; + ALfloat value = 0.0f; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (pname) + { + case AL_DOPPLER_FACTOR: + value = Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (float)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = Context->flSpeedOfSound; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return value; +} + +ALAPI ALint ALAPIENTRY alGetInteger(ALenum pname) +{ + ALCcontext *Context; + ALint value = 0; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (pname) + { + case AL_DOPPLER_FACTOR: + value = (ALint)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + value = (ALint)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + value = (ALint)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + value = (ALint)Context->flSpeedOfSound; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return value; +} + +ALAPI ALvoid ALAPIENTRY alGetBooleanv(ALenum pname,ALboolean *data) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (data) + { + switch (pname) + { + case AL_DOPPLER_FACTOR: + *data = (Context->DopplerFactor != 0.0f) ? AL_TRUE : AL_FALSE; + break; + + case AL_DOPPLER_VELOCITY: + *data = (Context->DopplerVelocity != 0.0f) ? AL_TRUE : AL_FALSE; + break; + + case AL_DISTANCE_MODEL: + *data = (Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) ? AL_TRUE : AL_FALSE; + break; + + case AL_SPEED_OF_SOUND: + *data = (Context->flSpeedOfSound != 0.0f) ? AL_TRUE : AL_FALSE; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alGetDoublev(ALenum pname,ALdouble *data) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (data) + { + switch (pname) + { + case AL_DOPPLER_FACTOR: + *data = (double)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + *data = (double)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + *data = (double)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + *data = (double)Context->flSpeedOfSound; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alGetFloatv(ALenum pname,ALfloat *data) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (data) + { + switch (pname) + { + case AL_DOPPLER_FACTOR: + *data = Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + *data = Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + *data = (float)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + *data = Context->flSpeedOfSound; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alGetIntegerv(ALenum pname,ALint *data) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (data) + { + switch (pname) + { + case AL_DOPPLER_FACTOR: + *data = (ALint)Context->DopplerFactor; + break; + + case AL_DOPPLER_VELOCITY: + *data = (ALint)Context->DopplerVelocity; + break; + + case AL_DISTANCE_MODEL: + *data = (ALint)Context->DistanceModel; + break; + + case AL_SPEED_OF_SOUND: + *data = (ALint)Context->flSpeedOfSound; + break; + + default: + alSetError(AL_INVALID_ENUM); + break; + } + } + else + { + // data is a NULL pointer + alSetError(AL_INVALID_VALUE); + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI const ALchar* ALAPIENTRY alGetString(ALenum pname) +{ + const ALchar *value; + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if(!pContext) + { + alSetError(AL_INVALID_OPERATION); + return NULL; + } + + SuspendContext(pContext); + + switch(pname) + { + case AL_VENDOR: + value=alVendor; + break; + + case AL_VERSION: + value=alVersion; + break; + + case AL_RENDERER: + value=alRenderer; + break; + + case AL_EXTENSIONS: + value=pContext->ExtensionList;//alExtensions; + break; + + case AL_NO_ERROR: + value=alNoError; + break; + + case AL_INVALID_NAME: + value=alErrInvalidName; + break; + + case AL_INVALID_ENUM: + value=alErrInvalidEnum; + break; + + case AL_INVALID_VALUE: + value=alErrInvalidValue; + break; + + case AL_INVALID_OPERATION: + value=alErrInvalidOp; + break; + + case AL_OUT_OF_MEMORY: + value=alErrOutOfMemory; + break; + + default: + value=NULL; + alSetError(AL_INVALID_ENUM); + break; + } + + ProcessContext(pContext); + + return value; +} + +ALAPI ALvoid ALAPIENTRY alDopplerFactor(ALfloat value) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (value>=0.0f) + Context->DopplerFactor = value; + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alDopplerVelocity(ALfloat value) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + if (value>0.0f) + Context->DopplerVelocity=value; + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alSpeedOfSound(ALfloat flSpeedOfSound) +{ + ALCcontext *pContext; + + pContext = alcGetCurrentContext(); + if (pContext) + { + SuspendContext(pContext); + + if (flSpeedOfSound > 0.0f) + pContext->flSpeedOfSound = flSpeedOfSound; + else + alSetError(AL_INVALID_VALUE); + + ProcessContext(pContext); + } + else + { + alSetError(AL_INVALID_OPERATION); + } + + return; +} + +ALAPI ALvoid ALAPIENTRY alDistanceModel(ALenum value) +{ + ALCcontext *Context; + + Context=alcGetCurrentContext(); + if (Context) + { + SuspendContext(Context); + + switch (value) + { + case AL_NONE: + case AL_INVERSE_DISTANCE: + case AL_INVERSE_DISTANCE_CLAMPED: + case AL_LINEAR_DISTANCE: + case AL_LINEAR_DISTANCE_CLAMPED: + case AL_EXPONENT_DISTANCE: + case AL_EXPONENT_DISTANCE_CLAMPED: + Context->DistanceModel = value; + break; + + default: + alSetError(AL_INVALID_VALUE); + break; + } + + ProcessContext(Context); + } + else + { + // Invalid Context + alSetError(AL_INVALID_OPERATION); + } + + return; +} diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c new file mode 100644 index 00000000..d050d6b4 --- /dev/null +++ b/OpenAL32/alThunk.c @@ -0,0 +1,108 @@ +/** + * 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 <stdlib.h> + +#include "alMain.h" +#include "alThunk.h" + +typedef struct { + ALvoid *ptr; + ALboolean InUse; +} ThunkEntry; + +static ThunkEntry *g_ThunkArray; +static ALuint g_ThunkArraySize; + +static CRITICAL_SECTION g_ThunkLock; + +void alThunkInit(void) +{ + InitializeCriticalSection(&g_ThunkLock); + g_ThunkArraySize = 1; + g_ThunkArray = calloc(1, g_ThunkArraySize * sizeof(ThunkEntry)); +} + +void alThunkExit(void) +{ + free(g_ThunkArray); + g_ThunkArray = NULL; + g_ThunkArraySize = 0; + DeleteCriticalSection(&g_ThunkLock); +} + +ALuint alThunkAddEntry(ALvoid *ptr) +{ + ALuint index; + + EnterCriticalSection(&g_ThunkLock); + + for(index = 0;index < g_ThunkArraySize;index++) + { + if(g_ThunkArray[index].InUse == AL_FALSE) + break; + } + + if(index == g_ThunkArraySize) + { + ThunkEntry *NewList; + + NewList = realloc(g_ThunkArray, g_ThunkArraySize*2 * sizeof(ThunkEntry)); + if(!NewList) + { + LeaveCriticalSection(&g_ThunkLock); + return 0; + } + memset(&NewList[g_ThunkArraySize], 0, g_ThunkArraySize*sizeof(ThunkEntry)); + g_ThunkArraySize *= 2; + g_ThunkArray = NewList; + } + + g_ThunkArray[index].ptr = ptr; + g_ThunkArray[index].InUse = AL_TRUE; + + LeaveCriticalSection(&g_ThunkLock); + + return index+1; +} + +void alThunkRemoveEntry(ALuint index) +{ + EnterCriticalSection(&g_ThunkLock); + + if(index > 0 && index <= g_ThunkArraySize) + g_ThunkArray[index-1].InUse = AL_FALSE; + + LeaveCriticalSection(&g_ThunkLock); +} + +ALvoid *alThunkLookupEntry(ALuint index) +{ + ALvoid *ptr = NULL; + + EnterCriticalSection(&g_ThunkLock); + + if(index > 0 && index <= g_ThunkArraySize) + ptr = g_ThunkArray[index-1].ptr; + + LeaveCriticalSection(&g_ThunkLock); + + return ptr; +} |