diff options
author | Chris Robinson <[email protected]> | 2007-11-13 18:02:18 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2007-11-13 18:02:18 -0800 |
commit | ae5f4e9a742b07e004b330c04a72fac4457c9b58 (patch) | |
tree | d1d5c9fadd918d9346fb871033f60e8c91600a63 |
Initial import
42 files changed, 17641 insertions, 0 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c new file mode 100644 index 00000000..2adcbb8e --- /dev/null +++ b/Alc/ALc.c @@ -0,0 +1,1117 @@ +/** + * 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 "config.h" + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + +/////////////////////////////////////////////////////// +// DEBUG INFORMATION + +#ifdef _DEBUG + char szDebug[256]; +#endif + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// FUNCTION PROTOTYPES + +void fill_device_list(); + +void alc_alsa_init(BackendFuncs *func_list); +void alc_oss_init(BackendFuncs *func_list); +void alcDSoundInit(BackendFuncs *func_list); +void alcWinMMInit(BackendFuncs *FuncList); + +#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +struct { + const char *name; + void (*Init)(BackendFuncs*); + BackendFuncs Funcs; +} BackendList[] = { +#ifdef HAVE_ALSA + { "alsa", alc_alsa_init, EmptyFuncs }, +#endif +#ifdef HAVE_OSS + { "oss", alc_oss_init, EmptyFuncs }, +#endif +#ifdef HAVE_DSOUND + { "dsound", alcDSoundInit, EmptyFuncs }, +#endif +#ifdef HAVE_WINMM + { "winmm", alcWinMMInit, EmptyFuncs }, +#endif + + { NULL, NULL, EmptyFuncs } +}; +#undef EmptyFuncs + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// STRING and EXTENSIONS + +typedef struct ALCextension_struct +{ + ALCchar *extName; + ALvoid *address; +} ALCextension; + +typedef struct ALCfunction_struct +{ + ALCchar *funcName; + ALvoid *address; +} ALCfunction; + +static ALCextension alcExtensions[] = { + { "ALC_ENUMERATE_ALL_EXT", (ALvoid *) NULL }, + { "ALC_ENUMERATION_EXT", (ALvoid *) NULL }, + { "ALC_EXT_CAPTURE", (ALvoid *) NULL }, + { NULL, (ALvoid *) NULL } +}; + +static ALCfunction alcFunctions[] = { + { "alcCreateContext", (ALvoid *) alcCreateContext }, + { "alcMakeContextCurrent", (ALvoid *) alcMakeContextCurrent }, + { "alcProcessContext", (ALvoid *) alcProcessContext }, + { "alcSuspendContext", (ALvoid *) alcSuspendContext }, + { "alcDestroyContext", (ALvoid *) alcDestroyContext }, + { "alcGetCurrentContext", (ALvoid *) alcGetCurrentContext }, + { "alcGetContextsDevice", (ALvoid *) alcGetContextsDevice }, + { "alcOpenDevice", (ALvoid *) alcOpenDevice }, + { "alcCloseDevice", (ALvoid *) alcCloseDevice }, + { "alcGetError", (ALvoid *) alcGetError }, + { "alcIsExtensionPresent", (ALvoid *) alcIsExtensionPresent }, + { "alcGetProcAddress", (ALvoid *) alcGetProcAddress }, + { "alcGetEnumValue", (ALvoid *) alcGetEnumValue }, + { "alcGetString", (ALvoid *) alcGetString }, + { "alcGetIntegerv", (ALvoid *) alcGetIntegerv }, + { "alcCaptureOpenDevice", (ALvoid *) alcCaptureOpenDevice }, + { "alcCaptureCloseDevice", (ALvoid *) alcCaptureCloseDevice }, + { "alcCaptureStart", (ALvoid *) alcCaptureStart }, + { "alcCaptureStop", (ALvoid *) alcCaptureStop }, + { "alcCaptureSamples", (ALvoid *) alcCaptureSamples }, + { NULL, (ALvoid *) NULL } +}; + +static ALenums enumeration[]={ + // Types + { (ALchar *)"ALC_INVALID", ALC_INVALID }, + { (ALchar *)"ALC_FALSE", ALC_FALSE }, + { (ALchar *)"ALC_TRUE", ALC_TRUE }, + + // ALC Properties + { (ALchar *)"ALC_MAJOR_VERSION", ALC_MAJOR_VERSION }, + { (ALchar *)"ALC_MINOR_VERSION", ALC_MINOR_VERSION }, + { (ALchar *)"ALC_ATTRIBUTES_SIZE", ALC_ATTRIBUTES_SIZE }, + { (ALchar *)"ALC_ALL_ATTRIBUTES", ALC_ALL_ATTRIBUTES }, + { (ALchar *)"ALC_DEFAULT_DEVICE_SPECIFIER", ALC_DEFAULT_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_DEVICE_SPECIFIER", ALC_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_ALL_DEVICES_SPECIFIER", ALC_ALL_DEVICES_SPECIFIER }, + { (ALchar *)"ALC_DEFAULT_ALL_DEVICES_SPECIFIER", ALC_DEFAULT_ALL_DEVICES_SPECIFIER }, + { (ALchar *)"ALC_EXTENSIONS", ALC_EXTENSIONS }, + { (ALchar *)"ALC_FREQUENCY", ALC_FREQUENCY }, + { (ALchar *)"ALC_REFRESH", ALC_REFRESH }, + { (ALchar *)"ALC_SYNC", ALC_SYNC }, + { (ALchar *)"ALC_MONO_SOURCES", ALC_MONO_SOURCES }, + { (ALchar *)"ALC_STEREO_SOURCES", ALC_STEREO_SOURCES }, + { (ALchar *)"ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER }, + { (ALchar *)"ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES }, + + // ALC Error Message + { (ALchar *)"ALC_NO_ERROR", ALC_NO_ERROR }, + { (ALchar *)"ALC_INVALID_DEVICE", ALC_INVALID_DEVICE }, + { (ALchar *)"ALC_INVALID_CONTEXT", ALC_INVALID_CONTEXT }, + { (ALchar *)"ALC_INVALID_ENUM", ALC_INVALID_ENUM }, + { (ALchar *)"ALC_INVALID_VALUE", ALC_INVALID_VALUE }, + { (ALchar *)"ALC_OUT_OF_MEMORY", ALC_OUT_OF_MEMORY }, + { (ALchar *)NULL, (ALenum)0 } +}; +// Error strings +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; + +// Context strings +static ALCchar alcDeviceList[2048]; +static ALCchar alcAllDeviceList[2048]; +static ALCchar alcCaptureDeviceList[2048]; +// Default is always the first in the list +static ALCchar *alcDefaultDeviceSpecifier = alcDeviceList; +static ALCchar *alcDefaultAllDeviceSpecifier = alcAllDeviceList; +static ALCchar *alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList; + + +static ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE"; +static ALCint alcMajorVersion = 1; +static ALCint alcMinorVersion = 1; + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// Global Variables + +// Critical Section data +extern CRITICAL_SECTION g_mutex; + +// Context List +static ALCcontext *g_pContextList = NULL; +static ALCuint g_ulContextCount = 0; + +// Context Error +static ALCenum g_eLastContextError = ALC_NO_ERROR; + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// ALC Related helper functions + +ALCchar *AppendDeviceList(char *name) +{ + static int pos; + ALCchar *ret = alcDeviceList+pos; + pos += snprintf(alcDeviceList+pos, sizeof(alcDeviceList)-pos, "%s", name) + 1; + return ret; +} + +ALCchar *AppendAllDeviceList(char *name) +{ + static int pos; + ALCchar *ret = alcAllDeviceList+pos; + pos += snprintf(alcAllDeviceList+pos, sizeof(alcAllDeviceList)-pos, "%s", name) + 1; + return ret; +} + +ALCchar *AppendCaptureDeviceList(char *name) +{ + static int pos; + ALCchar *ret = alcCaptureDeviceList+pos; + pos += snprintf(alcCaptureDeviceList+pos, sizeof(alcCaptureDeviceList)-pos, "%s", name) + 1; + return ret; +} + +/* + IsContext + + Check pContext is a valid Context pointer +*/ +ALCboolean IsContext(ALCcontext *pContext) +{ + ALCcontext *pTempContext; + + pTempContext = g_pContextList; + while (pTempContext && pTempContext != pContext) + pTempContext = pTempContext->next; + + return (pTempContext ? ALC_TRUE : ALC_FALSE); +} + + +/* + SetALCError + + Store latest ALC Error +*/ +ALCvoid SetALCError(ALenum errorCode) +{ + g_eLastContextError = errorCode; +} + + +/* + SuspendContext + + Thread-safe entry +*/ +ALCvoid SuspendContext(ALCcontext *pContext) +{ + (void)pContext; + EnterCriticalSection(&g_mutex); +} + + +/* + ProcessContext + + Thread-safe exit +*/ +ALCvoid ProcessContext(ALCcontext *pContext) +{ + (void)pContext; + LeaveCriticalSection(&g_mutex); +} + + +/* + InitContext + + Initialize Context variables +*/ +static ALvoid InitContext(ALCcontext *pContext) +{ + //Initialise listener + pContext->Listener.Gain = 1.0f; + pContext->Listener.Position[0] = 0.0f; + pContext->Listener.Position[1] = 0.0f; + pContext->Listener.Position[2] = 0.0f; + pContext->Listener.Velocity[0] = 0.0f; + pContext->Listener.Velocity[1] = 0.0f; + pContext->Listener.Velocity[2] = 0.0f; + pContext->Listener.Forward[0] = 0.0f; + pContext->Listener.Forward[1] = 0.0f; + pContext->Listener.Forward[2] = -1.0f; + pContext->Listener.Up[0] = 0.0f; + pContext->Listener.Up[1] = 1.0f; + pContext->Listener.Up[2] = 0.0f; + + //Validate pContext + pContext->LastError = AL_NO_ERROR; + pContext->InUse = AL_FALSE; + + //Set output format + pContext->Frequency = pContext->Device->Frequency; + + //Set globals + pContext->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED; + pContext->DopplerFactor = 1.0f; + pContext->DopplerVelocity = 1.0f; + pContext->flSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; + + pContext->lNumStereoSources = 1; + pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources; + + strcpy(pContext->ExtensionList, "AL_EXT_EXPONENT_DISTANCE AL_EXT_LINEAR_DISTANCE AL_EXT_OFFSET"); +} + + +/* + ExitContext + + Clean up Context, destroy any remaining Sources +*/ +static ALCvoid ExitContext(ALCcontext *pContext) +{ + unsigned int i; + ALsource *ALSource; + ALsource *ALTempSource; + +#ifdef _DEBUG + if (pContext->SourceCount>0) + { + sprintf(szDebug,"OpenAL32 : alcDestroyContext() %d Source(s) NOT deleted\n", pContext->SourceCount); + OutputDebugString(szDebug); + } +#endif + + // Free all the Sources still remaining + ALSource = pContext->Source; + for (i = 0; i < pContext->SourceCount; i++) + { + ALTempSource = ALSource->next; + ALTHUNK_REMOVEENTRY(ALSource->source); + memset(ALSource, 0, sizeof(ALsource)); + free(ALSource); + ALSource = ALTempSource; + } + + //Invalidate context + pContext->LastError = AL_NO_ERROR; + pContext->InUse = AL_FALSE; +} + +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// ALC Functions calls + + +// This should probably move to another c file but for now ... +ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + ALCboolean DeviceFound = ALC_FALSE; + ALCdevice *pDevice = NULL; + ALCint i; + + fill_device_list(); + + pDevice = malloc(sizeof(ALCdevice)); + if (pDevice) + { + if (SampleSize > 0) + { + //Initialise device structure + memset(pDevice, 0, sizeof(ALCdevice)); + + //Validate device + pDevice->InUse = AL_TRUE; + pDevice->IsCaptureDevice = AL_TRUE; + + pDevice->Frequency = frequency; + pDevice->Format = format; + pDevice->Channels = aluChannelsFromFormat(format); + pDevice->FrameSize = aluBytesFromFormat(format) * + pDevice->Channels; + + for(i = 0;BackendList[i].Init;i++) + { + pDevice->Funcs = &BackendList[i].Funcs; + if(ALCdevice_OpenCapture(pDevice, deviceName, frequency, format, SampleSize)) + { + DeviceFound = ALC_TRUE; + break; + } + } + } + else + SetALCError(ALC_INVALID_VALUE); + + if(!DeviceFound) + { + free(pDevice); + pDevice = NULL; + } + } + else + SetALCError(ALC_OUT_OF_MEMORY); + + return pDevice; +} + +ALCAPI ALCboolean ALCAPIENTRY alcCaptureCloseDevice(ALCdevice *pDevice) +{ + ALCboolean bReturn = ALC_FALSE; + + if ((pDevice)&&(pDevice->IsCaptureDevice)) + { + ALCdevice_CloseCapture(pDevice); + free(pDevice); + + bReturn = ALC_TRUE; + } + else + SetALCError(ALC_INVALID_DEVICE); + + return bReturn; +} + +ALCAPI void ALCAPIENTRY alcCaptureStart(ALCdevice *pDevice) +{ + if ((pDevice)&&(pDevice->IsCaptureDevice)) + ALCdevice_StartCapture(pDevice); + else + SetALCError(ALC_INVALID_DEVICE); +} + +ALCAPI void ALCAPIENTRY alcCaptureStop(ALCdevice *pDevice) +{ + if ((pDevice)&&(pDevice->IsCaptureDevice)) + ALCdevice_StopCapture(pDevice); + else + SetALCError(ALC_INVALID_DEVICE); +} + +ALCAPI void ALCAPIENTRY alcCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCsizei lSamples) +{ + if ((pDevice) && (pDevice->IsCaptureDevice)) + ALCdevice_CaptureSamples(pDevice, pBuffer, lSamples); + else + SetALCError(ALC_INVALID_DEVICE); +} + +/* + alcGetError + + Return last ALC generated error code +*/ +ALCAPI ALCenum ALCAPIENTRY alcGetError(ALCdevice *device) +{ + ALCenum errorCode; + + (void)device; + + errorCode = g_eLastContextError; + g_eLastContextError = ALC_NO_ERROR; + return errorCode; +} + + +/* + alcSuspendContext + + Not functional +*/ +ALCAPI ALCvoid ALCAPIENTRY alcSuspendContext(ALCcontext *pContext) +{ + // Not a lot happens here ! + (void)pContext; +} + + +/* + alcProcessContext + + Not functional +*/ +ALCAPI ALCvoid ALCAPIENTRY alcProcessContext(ALCcontext *pContext) +{ + // Not a lot happens here ! + (void)pContext; +} + + +/* + alcGetString + + Returns information about the Device, and error strings +*/ +ALCAPI const ALCchar* ALCAPIENTRY alcGetString(ALCdevice *pDevice,ALCenum param) +{ + const ALCchar *value = NULL; + + fill_device_list(); + + switch (param) + { + case ALC_NO_ERROR: + value = alcNoError; + break; + + case ALC_INVALID_ENUM: + value = alcErrInvalidEnum; + break; + + case ALC_INVALID_VALUE: + value = alcErrInvalidValue; + break; + + case ALC_INVALID_DEVICE: + value = alcErrInvalidDevice; + break; + + case ALC_INVALID_CONTEXT: + value = alcErrInvalidContext; + break; + + case ALC_OUT_OF_MEMORY: + value = alcErrOutOfMemory; + break; + + case ALC_DEFAULT_DEVICE_SPECIFIER: + value = alcDefaultDeviceSpecifier; + break; + + case ALC_DEVICE_SPECIFIER: + if (pDevice) + value = pDevice->szDeviceName; + else + value = alcDeviceList; + break; + + case ALC_ALL_DEVICES_SPECIFIER: + value = alcAllDeviceList; + break; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + value = alcDefaultAllDeviceSpecifier; + break; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + if (pDevice) + value = pDevice->szDeviceName; + else + value = alcCaptureDeviceList; + break; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + value = alcCaptureDefaultDeviceSpecifier; + break; + + case ALC_EXTENSIONS: + value = alcExtensionList; + break; + + default: + SetALCError(ALC_INVALID_ENUM); + break; + } + + return value; +} + + +/* + alcGetIntegerv + + Returns information about the Device and the version of Open AL +*/ +ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data) +{ + fill_device_list(); + + if ((device)&&(device->IsCaptureDevice)) + { + SuspendContext(NULL); + + // Capture device + switch (param) + { + case ALC_CAPTURE_SAMPLES: + if ((size) && (data)) + *data = ALCdevice_AvailableSamples(device); + else + SetALCError(ALC_INVALID_VALUE); + break; + + default: + SetALCError(ALC_INVALID_ENUM); + break; + } + + ProcessContext(NULL); + } + else + { + if(data) + { + // Playback Device + switch (param) + { + case ALC_MAJOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcMajorVersion; + break; + + case ALC_MINOR_VERSION: + if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = alcMinorVersion; + break; + + case ALC_ATTRIBUTES_SIZE: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = 11; + break; + + case ALC_ALL_ATTRIBUTES: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if (size < 7) + SetALCError(ALC_INVALID_VALUE); + else + { + int i = 0; + + data[i++] = ALC_FREQUENCY; + data[i++] = device->Frequency; + + data[i++] = ALC_REFRESH; + data[i++] = device->UpdateFreq; + + data[i++] = ALC_SYNC; + data[i++] = ALC_FALSE; + + SuspendContext(NULL); + if(device->Context && size >= 11) + { + data[i++] = ALC_MONO_SOURCES; + data[i++] = device->Context->lNumMonoSources; + + data[i++] = ALC_STEREO_SOURCES; + data[i++] = device->Context->lNumStereoSources; + } + ProcessContext(NULL); + + data[i++] = 0; + } + break; + + case ALC_FREQUENCY: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->Frequency; + break; + + case ALC_REFRESH: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->UpdateFreq; + break; + + case ALC_SYNC: + if(!device) + SetALCError(ALC_INVALID_DEVICE); + else if(!size) + SetALCError(ALC_INVALID_VALUE); + else + *data = ALC_FALSE; + break; + + default: + SetALCError(ALC_INVALID_ENUM); + break; + } + } + else if(size) + SetALCError(ALC_INVALID_VALUE); + } + + return; +} + + +/* + alcIsExtensionPresent + + Determines if there is support for a particular extension +*/ +ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) +{ + ALCboolean bResult = ALC_FALSE; + ALsizei i = 0; + + (void)device; + + if (extName) + { + while(alcExtensions[i].extName && + strcasecmp(alcExtensions[i].extName,extName) != 0) + i++; + + if (alcExtensions[i].extName) + bResult = ALC_TRUE; + } + else + SetALCError(ALC_INVALID_VALUE); + + return bResult; +} + + +/* + alcGetProcAddress + + Retrieves the function address for a particular extension function +*/ +ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) +{ + ALCvoid *pFunction = NULL; + ALsizei i = 0; + + (void)device; + + if (funcName) + { + while(alcFunctions[i].funcName && + strcmp(alcFunctions[i].funcName,funcName) != 0) + i++; + pFunction = alcFunctions[i].address; + } + else + SetALCError(ALC_INVALID_VALUE); + + return pFunction; +} + + +/* + alcGetEnumValue + + Get the value for a particular ALC Enumerated Value +*/ +ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) +{ + ALsizei i = 0; + ALCenum val; + + (void)device; + + while ((enumeration[i].enumName)&&(strcmp(enumeration[i].enumName,enumName))) + i++; + val = enumeration[i].value; + + if(!enumeration[i].enumName) + SetALCError(ALC_INVALID_VALUE); + + return val; +} + + +/* + alcCreateContext + + Create and attach a Context to a particular Device. +*/ +ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) +{ + ALCcontext *ALContext = NULL; + ALuint ulAttributeIndex, ulRequestedStereoSources; + + if ((device)&&(!device->IsCaptureDevice)) + { + // Reset Context Last Error code + g_eLastContextError = ALC_NO_ERROR; + + // Current implementation only allows one Context per Device + if(!device->Context) + { + ALContext = calloc(1, sizeof(ALCcontext)); + if(!ALContext) + { + SetALCError(ALC_OUT_OF_MEMORY); + return NULL; + } + + ALContext->Device = device; + InitContext(ALContext); + + device->Context = ALContext; + + SuspendContext(NULL); + + ALContext->next = g_pContextList; + g_pContextList = ALContext; + g_ulContextCount++; + + ProcessContext(NULL); + + // Check for Voice Count attributes + if (attrList) + { + ulAttributeIndex = 0; + while ((ulAttributeIndex < 10) && (attrList[ulAttributeIndex])) + { + if (attrList[ulAttributeIndex] == ALC_STEREO_SOURCES) + { + ulRequestedStereoSources = attrList[ulAttributeIndex + 1]; + + if (ulRequestedStereoSources > ALContext->Device->MaxNoOfSources) + ulRequestedStereoSources = ALContext->Device->MaxNoOfSources; + + ALContext->lNumStereoSources = ulRequestedStereoSources; + ALContext->lNumMonoSources = ALContext->Device->MaxNoOfSources - ALContext->lNumStereoSources; + break; + } + + ulAttributeIndex += 2; + } + } + } + else + { + SetALCError(ALC_INVALID_VALUE); + ALContext = NULL; + } + } + else + SetALCError(ALC_INVALID_DEVICE); + + return ALContext; +} + + +/* + alcDestroyContext + + Remove a Context +*/ +ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context) +{ + ALCcontext **list; + + // Lock context list + SuspendContext(NULL); + + if (IsContext(context)) + { + // Lock context + SuspendContext(context); + + context->Device->Context = NULL; + + list = &g_pContextList; + while(*list != context) + list = &(*list)->next; + + *list = (*list)->next; + g_ulContextCount--; + + // Unlock context + ProcessContext(context); + + ExitContext(context); + + // Free memory (MUST do this after ProcessContext) + memset(context, 0, sizeof(ALCcontext)); + free(context); + } + else + SetALCError(ALC_INVALID_CONTEXT); + + ProcessContext(NULL); +} + + +/* + alcGetCurrentContext + + Returns the currently active Context +*/ +ALCAPI ALCcontext * ALCAPIENTRY alcGetCurrentContext(ALCvoid) +{ + ALCcontext *pContext = NULL; + + SuspendContext(NULL); + + pContext = g_pContextList; + while ((pContext) && (!pContext->InUse)) + pContext = pContext->next; + + ProcessContext(NULL); + + return pContext; +} + + +/* + alcGetContextsDevice + + Returns the Device that a particular Context is attached to +*/ +ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *pContext) +{ + ALCdevice *pDevice = NULL; + + SuspendContext(NULL); + if (IsContext(pContext)) + pDevice = pContext->Device; + else + SetALCError(ALC_INVALID_CONTEXT); + ProcessContext(NULL); + + return pDevice; +} + + +/* + alcMakeContextCurrent + + Makes the given Context the active Context +*/ +ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + ALCcontext *ALContext; + ALboolean bReturn = AL_TRUE; + + SuspendContext(NULL); + + // context must be a valid Context or NULL + if ((IsContext(context)) || (context == NULL)) + { + if ((ALContext=alcGetCurrentContext())) + { + SuspendContext(ALContext); + ALContext->InUse=AL_FALSE; + ProcessContext(ALContext); + } + + if ((ALContext=context) && (ALContext->Device)) + { + SuspendContext(ALContext); + ALContext->InUse=AL_TRUE; + ProcessContext(ALContext); + } + } + else + { + SetALCError(ALC_INVALID_CONTEXT); + bReturn = AL_FALSE; + } + + ProcessContext(NULL); + + return bReturn; +} + + +/* + alcOpenDevice + + Open the Device specified. +*/ +ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName) +{ + ALboolean bDeviceFound = AL_FALSE; + ALCdevice *device; + ALint i; + + fill_device_list(); + + device = malloc(sizeof(ALCdevice)); + if (device) + { + const char *fmt; + + //Initialise device structure + memset(device, 0, sizeof(ALCdevice)); + + //Validate device + device->InUse = AL_TRUE; + device->IsCaptureDevice = AL_FALSE; + + //Set output format + device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE); + if((ALint)device->Frequency <= 0) + device->Frequency = SWMIXER_OUTPUT_RATE; + + fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16"); + if(fmt[0]) + device->Format = alGetEnumValue(fmt); + switch(device->Format) + { + case AL_FORMAT_MONO8: + device->Channels = 1; + device->FrameSize = 1; + break; + case AL_FORMAT_STEREO8: + device->Channels = 2; + device->FrameSize = 2; + break; + case AL_FORMAT_QUAD8: + device->Channels = 4; + device->FrameSize = 4; + break; + case AL_FORMAT_MONO16: + device->Channels = 1; + device->FrameSize = 2; + break; + case AL_FORMAT_STEREO16: + device->Channels = 2; + device->FrameSize = 4; + break; + case AL_FORMAT_QUAD16: + device->Channels = 4; + device->FrameSize = 8; + break; + default: + device->Format = AL_FORMAT_STEREO16; + device->Channels = 2; + device->FrameSize = 4; + break; + } + + device->UpdateFreq = GetConfigValueInt(NULL, "refresh", 0); + if((ALint)device->UpdateFreq <= 0) + device->UpdateFreq = 8192 * device->Frequency / 22050; + + // Find a playback device to open + for(i = 0;BackendList[i].Init;i++) + { + device->Funcs = &BackendList[i].Funcs; + if(ALCdevice_OpenPlayback(device, deviceName)) + { + bDeviceFound = AL_TRUE; + break; + } + } + + if (!bDeviceFound) + { + // No suitable output device found + free(device); + device = NULL; + } + } + + return device; +} + + +/* + alcCloseDevice + + Close the specified Device +*/ +ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice(ALCdevice *pDevice) +{ + ALCboolean bReturn = ALC_FALSE; + + if ((pDevice)&&(!pDevice->IsCaptureDevice)) + { + ALCdevice_ClosePlayback(pDevice); + + //Release device structure + memset(pDevice, 0, sizeof(ALCdevice)); + free(pDevice); + + bReturn = ALC_TRUE; + } + else + SetALCError(ALC_INVALID_DEVICE); + + return bReturn; +} +/////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////// +// ALC Device Specific Functions + +void fill_device_list() +{ + static int done = 0; + if(!done) + { + int i; + for(i = 0;BackendList[i].Init;i++) + BackendList[i].Init(&BackendList[i].Funcs); + done = 1; + } +} diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c new file mode 100644 index 00000000..f20b5e4f --- /dev/null +++ b/Alc/alcConfig.c @@ -0,0 +1,283 @@ +/** + * 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 <stdio.h> +#include <ctype.h> +#include <string.h> + +typedef struct ConfigEntry { + char *key; + char *value; +} ConfigEntry; + +typedef struct ConfigBlock { + char *name; + ConfigEntry *entries; + size_t entryCount; +} ConfigBlock; + +static ConfigBlock *cfgBlocks; +static size_t cfgCount; + +static char buffer[1024]; + +static void LoadConfigFromFile(FILE *f) +{ + ConfigBlock *curBlock = cfgBlocks; + ConfigEntry *ent; + + while(fgets(buffer, sizeof(buffer), f)) + { + size_t i = 0; + + while(isspace(buffer[i])) + i++; + if(!buffer[i] || buffer[i] == '#') + continue; + + memmove(buffer, buffer+i, strlen(buffer+i)+1); + + if(buffer[0] == '[') + { + ConfigBlock *nextBlock; + + i = 1; + while(buffer[i] && buffer[i] != ']') + i++; + + if(!buffer[i]) + { + fprintf(stderr, "openal: config parse error: bad line \"%s\"\n", buffer); + continue; + } + buffer[i] = 0; + + do { + i++; + if(buffer[i] && !isspace(buffer[i])) + { + if(buffer[i] != '#') + fprintf(stderr, "openal: config warning: extra data after block: \"%s\"\n", buffer+i); + break; + } + } while(buffer[i]); + + nextBlock = NULL; + for(i = 0;i < cfgCount;i++) + { + if(strcasecmp(cfgBlocks[i].name, buffer+1) == 0) + { + nextBlock = cfgBlocks+i; +// printf("found block '%s'\n", nextBlock->name); + break; + } + } + + if(!nextBlock) + { + nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock)); + if(!nextBlock) + { + fprintf(stderr, "openal: config parse error: error reallocating config blocks\n"); + continue; + } + cfgBlocks = nextBlock; + nextBlock = cfgBlocks+cfgCount; + cfgCount++; + + nextBlock->name = strdup(buffer+1); + nextBlock->entries = NULL; + nextBlock->entryCount = 0; + +// printf("found new block '%s'\n", nextBlock->name); + } + curBlock = nextBlock; + continue; + } + + /* Look for the option name */ + i = 0; + while(buffer[i] && buffer[i] != '#' && buffer[i] != '=' && + !isspace(buffer[i])) + i++; + + if(!buffer[i] || buffer[i] == '#' || i == 0) + { + fprintf(stderr, "openal: config parse error: malformed option line: \"%s\"\n", buffer); + continue; + } + + /* Seperate the option */ + if(buffer[i] != '=') + { + buffer[i++] = 0; + + while(isspace(buffer[i])) + i++; + if(buffer[i] != '=') + { + fprintf(stderr, "openal: config parse error: option without a value: \"%s\"\n", buffer); + continue; + } + } + /* Find the start of the value */ + buffer[i++] = 0; + while(isspace(buffer[i])) + i++; + + /* Check if we already have this option set */ + ent = curBlock->entries; + while((size_t)(ent-curBlock->entries) < curBlock->entryCount) + { + if(strcasecmp(ent->key, buffer) == 0) + break; + ent++; + } + + if((size_t)(ent-curBlock->entries) >= curBlock->entryCount) + { + /* Allocate a new option entry */ + ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry)); + if(!ent) + { + fprintf(stderr, "openal: config parse error: error reallocating config entries\n"); + continue; + } + curBlock->entries = ent; + ent = curBlock->entries + curBlock->entryCount; + curBlock->entryCount++; + + ent->key = strdup(buffer); + ent->value = NULL; + } + + /* Look for the end of the line (Null term, new-line, or #-symbol) and + eat up the trailing whitespace */ + memmove(buffer, buffer+i, strlen(buffer+i)+1); + + i = 0; + while(buffer[i] && buffer[i] != '#' && buffer[i] != '\n') + i++; + do { + i--; + } while(isspace(buffer[i])); + buffer[++i] = 0; + + free(ent->value); + ent->value = strdup(buffer); + +// printf("found '%s' = '%s'\n", ent->key, ent->value); + } +} + +void ReadALConfig(void) +{ + FILE *f; + + cfgBlocks = calloc(1, sizeof(ConfigBlock)); + cfgBlocks->name = strdup("general"); + cfgCount = 1; + +#ifdef _WIN32 +#else + f = fopen("/etc/openal/config", "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + if(getenv("HOME") && *(getenv("HOME"))) + { + snprintf(buffer, sizeof(buffer), "%s/.openalrc", getenv("HOME")); + f = fopen(buffer, "r"); + if(f) + { + LoadConfigFromFile(f); + fclose(f); + } + } +#endif +} + +void FreeALConfig(void) +{ + size_t i; + + for(i = 0;i < cfgCount;i++) + { + size_t j; + for(j = 0;j < cfgBlocks[i].entryCount;j++) + { + free(cfgBlocks[i].entries[j].key); + free(cfgBlocks[i].entries[j].value); + } + free(cfgBlocks[i].entries); + free(cfgBlocks[i].name); + } + free(cfgBlocks); + cfgBlocks = NULL; + cfgCount = 0; +} + +const char *GetConfigValue(const char *blockName, const char *keyName, const char *def) +{ + size_t i, j; + + if(keyName) + { + if(!blockName) + blockName = "general"; + + for(i = 0;i < cfgCount;i++) + { + if(strcasecmp(cfgBlocks[i].name, blockName) != 0) + continue; + + for(j = 0;j < cfgBlocks[i].entryCount;j++) + { + if(strcasecmp(cfgBlocks[i].entries[j].key, keyName) == 0) + return cfgBlocks[i].entries[j].value; + } + } + } + + return def; +} + +int GetConfigValueInt(const char *blockName, const char *keyName, int def) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + + if(!val[0]) return def; + return strtol(val, NULL, 0); +} + +float GetConfigValueFloat(const char *blockName, const char *keyName, float def) +{ + const char *val = GetConfigValue(blockName, keyName, ""); + + if(!val[0]) return def; +#ifdef HAVE_STRTOF + return strtof(val, NULL); +#else + return (float)strtod(val, NULL); +#endif +} diff --git a/Alc/alcThread.c b/Alc/alcThread.c new file mode 100644 index 00000000..6752f702 --- /dev/null +++ b/Alc/alcThread.c @@ -0,0 +1,125 @@ +/** + * 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" + + +#ifdef _WIN32 + +#include <windows.h> + +typedef struct { + ALuint (*func)(ALvoid*); + ALvoid *ptr; + HANDLE thread; +} ThreadInfo; + +static DWORD CALLBACK StarterFunc(void *ptr) +{ + ThreadInfo *inf = (ThreadInfo*)ptr; + ALint ret; + + ret = inf->func(inf->ptr); + ExitThread((DWORD)ret); + + return (DWORD)ret; +} + +ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr) +{ + ThreadInfo *inf = malloc(sizeof(ThreadInfo)); + if(!inf) return 0; + + inf->func = func; + inf->ptr = ptr; + + inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, NULL); + if(!inf->thread) + { + free(inf); + return NULL; + } + + return inf; +} + +ALuint StopThread(ALvoid *thread) +{ + ThreadInfo *inf = thread; + DWORD ret = 0; + + WaitForSingleObject(inf->thread, INFINITE); + GetExitCodeThread(inf->thread, &ret); + + free(inf); + + return (ALuint)ret; +} + +#else + +#include <pthread.h> + +typedef struct { + ALuint (*func)(ALvoid*); + ALvoid *ptr; + pthread_t thread; +} ThreadInfo; + +static void *StarterFunc(void *ptr) +{ + ThreadInfo *inf = (ThreadInfo*)ptr; + ALint ret; + + ret = inf->func(inf->ptr); + return (void*)ret; +} + +ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr) +{ + ThreadInfo *inf = malloc(sizeof(ThreadInfo)); + if(!inf) return 0; + + inf->func = func; + inf->ptr = ptr; + if(pthread_create(&inf->thread, NULL, StarterFunc, inf) != 0) + { + free(inf); + return NULL; + } + + return inf; +} + +ALuint StopThread(ALvoid *thread) +{ + ThreadInfo *inf = thread; + void *ret; + + pthread_join(inf->thread, &ret); + free(inf); + + return (ALuint)ret; +} + +#endif diff --git a/Alc/alsa.c b/Alc/alsa.c new file mode 100644 index 00000000..df866a66 --- /dev/null +++ b/Alc/alsa.c @@ -0,0 +1,828 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + +#include <alsa/asoundlib.h> + + +typedef struct { + snd_pcm_t *pcmHandle; + snd_pcm_format_t format; + int killNow; + ALvoid *thread; +} alsa_data; + +typedef struct { + ALCchar *name; + int card, dev; +} DevMap; + +static void *alsa_handle; +#define MAKE_FUNC(f) static typeof(f) * p##f +MAKE_FUNC(snd_strerror); +MAKE_FUNC(snd_pcm_open); +MAKE_FUNC(snd_pcm_close); +MAKE_FUNC(snd_pcm_nonblock); +MAKE_FUNC(snd_pcm_frames_to_bytes); +MAKE_FUNC(snd_pcm_hw_params_malloc); +MAKE_FUNC(snd_pcm_hw_params_free); +MAKE_FUNC(snd_pcm_hw_params_any); +MAKE_FUNC(snd_pcm_hw_params_set_access); +MAKE_FUNC(snd_pcm_hw_params_set_format); +MAKE_FUNC(snd_pcm_hw_params_set_channels); +MAKE_FUNC(snd_pcm_hw_params_set_periods_near); +MAKE_FUNC(snd_pcm_hw_params_set_rate_near); +MAKE_FUNC(snd_pcm_hw_params_set_rate); +MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near); +MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min); +MAKE_FUNC(snd_pcm_hw_params); +MAKE_FUNC(snd_pcm_prepare); +MAKE_FUNC(snd_pcm_start); +MAKE_FUNC(snd_pcm_resume); +MAKE_FUNC(snd_pcm_state); +MAKE_FUNC(snd_pcm_avail_update); +MAKE_FUNC(snd_pcm_areas_silence); +MAKE_FUNC(snd_pcm_mmap_begin); +MAKE_FUNC(snd_pcm_mmap_commit); +MAKE_FUNC(snd_pcm_drain); +MAKE_FUNC(snd_pcm_info_malloc); +MAKE_FUNC(snd_pcm_info_free); +MAKE_FUNC(snd_pcm_info_set_device); +MAKE_FUNC(snd_pcm_info_set_subdevice); +MAKE_FUNC(snd_pcm_info_set_stream); +MAKE_FUNC(snd_pcm_info_get_name); +MAKE_FUNC(snd_ctl_pcm_next_device); +MAKE_FUNC(snd_ctl_pcm_info); +MAKE_FUNC(snd_ctl_open); +MAKE_FUNC(snd_ctl_close); +MAKE_FUNC(snd_ctl_card_info_malloc); +MAKE_FUNC(snd_ctl_card_info_free); +MAKE_FUNC(snd_ctl_card_info); +MAKE_FUNC(snd_ctl_card_info_get_name); +MAKE_FUNC(snd_card_next); +#undef MAKE_FUNC + +#define MAX_DEVICES 16 +#define MAX_ALL_DEVICES 32 + +static DevMap allDevNameMap[MAX_ALL_DEVICES]; +static ALCchar *alsaDeviceList[MAX_DEVICES]; +static ALCchar *alsaCaptureDeviceList[MAX_DEVICES]; + +static int xrun_recovery(snd_pcm_t *handle, int err) +{ + if (err == -EPIPE) + { /* under-run */ + err = psnd_pcm_prepare(handle); + if(err >= 0) + err = psnd_pcm_start(handle); + if (err < 0) + printf("Can't recover from underrun, prepare failed: %s\n", psnd_strerror(err)); + } + else if (err == -ESTRPIPE) + { + while ((err = psnd_pcm_resume(handle)) == -EAGAIN) + usleep(1); /* wait until the suspend flag is released */ + if (err < 0) + { + err = psnd_pcm_prepare(handle); + if(err >= 0) + err = psnd_pcm_start(handle); + if (err < 0) + printf("Can't recover from suspend, prepare failed: %s\n", psnd_strerror(err)); + } + } + return err; +} + + +static ALuint ALSAProc(ALvoid *ptr) +{ + ALCdevice *pDevice = (ALCdevice*)ptr; + alsa_data *data = (alsa_data*)pDevice->ExtraData; + const snd_pcm_channel_area_t *areas = NULL; + snd_pcm_sframes_t avail, commitres; + snd_pcm_uframes_t offset, frames; + char *WritePtr; + int WriteCnt; + int err; + + while(!data->killNow) + { + snd_pcm_state_t state = psnd_pcm_state(data->pcmHandle); + if(state == SND_PCM_STATE_XRUN) + { + err = xrun_recovery(data->pcmHandle, -EPIPE); + if (err < 0) + { + fprintf(stderr, "XRUN recovery failed: %s\n", psnd_strerror(err)); + break; + } + } + else if (state == SND_PCM_STATE_SUSPENDED) + { + err = xrun_recovery(data->pcmHandle, -ESTRPIPE); + if (err < 0) + { + fprintf(stderr, "SUSPEND recovery failed: %s\n", psnd_strerror(err)); + break; + } + } + + avail = psnd_pcm_avail_update(data->pcmHandle); + if(avail < 0) + { + err = xrun_recovery(data->pcmHandle, avail); + if (err < 0) + { + fprintf(stderr, "available update failed: %s\n", psnd_strerror(err)); + break; + } + } + + // make sure there's frames to process + if(avail == 0) + { + usleep(1000); + continue; + } + + // it is possible that contiguous areas are smaller, thus we use a loop + while (avail > 0) + { + frames = avail; + + err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames); + if (err < 0) + { + err = xrun_recovery(data->pcmHandle, err); + if (err < 0) + fprintf(stderr, "mmap begin error: %s\n", psnd_strerror(err)); + break; + } + + SuspendContext(NULL); + if(pDevice->Context) + { + // If we have an active context, mix data directly into output + // buffer + WritePtr = (char*)areas->addr + (offset * areas->step / 8); + WriteCnt = psnd_pcm_frames_to_bytes(data->pcmHandle, frames); + + aluMixData(pDevice->Context, WritePtr, WriteCnt, pDevice->Format); + } + else + psnd_pcm_areas_silence(areas, offset, pDevice->Channels, frames, data->format); + ProcessContext(NULL); + + commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames); + if (commitres < 0 || (commitres-frames) != 0) + { + fprintf(stderr, "mmap commit error: %s\n", + psnd_strerror(commitres >= 0 ? -EPIPE : commitres)); + break; + } + + avail -= frames; + } + } + + return 0; +} + +static void fill_silence(snd_pcm_t *pcmHandle, snd_pcm_format_t alsaFormat, int channels) +{ + const snd_pcm_channel_area_t *areas = NULL; + snd_pcm_sframes_t avail, commitres; + snd_pcm_uframes_t offset, frames; + int err; + + avail = psnd_pcm_avail_update(pcmHandle); + if(avail < 0) + { + err = xrun_recovery(pcmHandle, avail); + if (err < 0) + { + fprintf(stderr, "available update failed: %s\n", psnd_strerror(err)); + return; + } + } + + // it is possible that contiguous areas are smaller, thus we use a loop + while (avail > 0) + { + frames = avail; + + err = psnd_pcm_mmap_begin(pcmHandle, &areas, &offset, &frames); + if (err < 0) + { + err = xrun_recovery(pcmHandle, err); + if (err < 0) + { + fprintf(stderr, "mmap begin error: %s\n", psnd_strerror(err)); + break; + } + continue; + } + + psnd_pcm_areas_silence(areas, offset, channels, frames, alsaFormat); + + commitres = psnd_pcm_mmap_commit(pcmHandle, offset, frames); + if (commitres < 0 || (commitres-frames) != 0) + { + fprintf(stderr, "mmap commit error: %s\n", + psnd_strerror(commitres >= 0 ? -EPIPE : commitres)); + break; + } + + avail -= frames; + } +} + +static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + snd_pcm_uframes_t bufferSizeInFrames; + snd_pcm_hw_params_t *p = NULL; + unsigned int periods; + alsa_data *data; + char driver[64]; + int i; + + strncpy(driver, GetConfigValue("alsa", "default", "default"), sizeof(driver)-1); + driver[sizeof(driver)-1] = 0; + if(deviceName) + { + size_t idx; + + for(idx = 0;idx < MAX_ALL_DEVICES;idx++) + { + if(allDevNameMap[idx].name && + strcmp(deviceName, allDevNameMap[idx].name) == 0) + { + if(idx > 0) + sprintf(driver, "hw:%d,%d", allDevNameMap[idx].card, allDevNameMap[idx].dev); + goto open_alsa; + } + } + for(idx = 0;idx < MAX_DEVICES;idx++) + { + if(alsaDeviceList[idx] && + strcmp(deviceName, alsaDeviceList[idx]) == 0) + { + if(idx > 0) + sprintf(driver, "hw:%d,0", idx-1); + goto open_alsa; + } + } + return ALC_FALSE; + } + + if(deviceName) + strcpy(device->szDeviceName, deviceName); + else + strcpy(device->szDeviceName, alsaDeviceList[0]); + +open_alsa: + data = (alsa_data*)calloc(1, sizeof(alsa_data)); + + i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + if(i < 0) + { + usleep(200000); + i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + } + if(i >= 0) + { + i = psnd_pcm_nonblock(data->pcmHandle, 0); + if(i < 0) + psnd_pcm_close(data->pcmHandle); + } + if(i < 0) + { + free(data); + return ALC_FALSE; + } + + switch(device->Format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_STEREO8: + case AL_FORMAT_QUAD8: + data->format = SND_PCM_FORMAT_U8; + break; + case AL_FORMAT_MONO16: + case AL_FORMAT_STEREO16: + case AL_FORMAT_QUAD16: + data->format = SND_PCM_FORMAT_S16; + break; + default: + data->format = SND_PCM_FORMAT_UNKNOWN; + fprintf(stderr, "Unknown format?! %x\n", device->Format); + } + + periods = GetConfigValueInt("alsa", "periods", 4); + if((int)periods <= 0) + periods = 4; + bufferSizeInFrames = device->UpdateFreq; + + psnd_pcm_hw_params_malloc(&p); +#define ok(func, str) (i=(func),((i<0)?fprintf(stderr,"%s failed: %s\n", str, psnd_strerror(i)),0:1)) + /* start with the largest configuration space possible */ + if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") && + /* set interleaved access */ + ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set access") && + /* set format (implicitly sets sample bits) */ + ok(psnd_pcm_hw_params_set_format(data->pcmHandle, p, data->format), "set format") && + /* set channels (implicitly sets frame bits) */ + ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, device->Channels), "set channels") && + /* set periods (implicitly constrains period/buffer parameters) */ + ok(psnd_pcm_hw_params_set_periods_near(data->pcmHandle, p, &periods, NULL), "set periods near") && + /* set rate (implicitly constrains period/buffer parameters) */ + ok(psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &device->Frequency, NULL), "set rate near") && + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + ok(psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames), "set buffer size near") && + /* install and prepare hardware configuration */ + ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params"))) + { + psnd_pcm_hw_params_free(p); + psnd_pcm_close(data->pcmHandle); + free(data); + return ALC_FALSE; + } +#undef ok + psnd_pcm_hw_params_free(p); + + device->MaxNoOfSources = 256; + device->UpdateFreq = bufferSizeInFrames; + + i = psnd_pcm_prepare(data->pcmHandle); + if(i < 0) + { + fprintf(stderr, "prepare error: %s\n", psnd_strerror(i)); + psnd_pcm_close(data->pcmHandle); + free(data); + return ALC_FALSE; + } + + fill_silence(data->pcmHandle, data->format, device->Channels); + i = psnd_pcm_start(data->pcmHandle); + if(i < 0) + { + fprintf(stderr, "start error: %s\n", psnd_strerror(i)); + psnd_pcm_close(data->pcmHandle); + free(data); + return ALC_FALSE; + } + + device->ExtraData = data; + data->thread = StartThread(ALSAProc, device); + if(data->thread == NULL) + { + psnd_pcm_close(data->pcmHandle); + device->ExtraData = NULL; + free(data); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void alsa_close_playback(ALCdevice *device) +{ + alsa_data *data = (alsa_data*)device->ExtraData; + data->killNow = 1; + StopThread(data->thread); + psnd_pcm_close(data->pcmHandle); + + free(data); + device->ExtraData = NULL; +} + + +static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + snd_pcm_format_t alsaFormat; + snd_pcm_hw_params_t *p; + unsigned int periods = 4; + snd_pcm_uframes_t bufferSizeInFrames = SampleSize; + alsa_data *data; + char driver[64]; + int i; + + strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1); + driver[sizeof(driver)-1] = 0; + if(deviceName) + { + size_t idx; + + for(idx = 0;idx < MAX_DEVICES;idx++) + { + if(alsaCaptureDeviceList[idx] && + strcmp(deviceName, alsaCaptureDeviceList[idx]) == 0) + { + if(idx > 0) + sprintf(driver, "hw:%d,0", idx-1); + goto open_alsa; + } + } + return ALC_FALSE; + } + + if(deviceName) + strcpy(pDevice->szDeviceName, deviceName); + else + strcpy(pDevice->szDeviceName, alsaCaptureDeviceList[0]); + +open_alsa: + data = (alsa_data*)calloc(1, sizeof(alsa_data)); + + i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); + if(i < 0) + { + usleep(200000); + i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); + } + if(i >= 0) + { + i = psnd_pcm_nonblock(data->pcmHandle, 0); + if(i < 0) + psnd_pcm_close(data->pcmHandle); + } + if(i < 0) + { + free(data); + return ALC_FALSE; + } + + switch(aluBytesFromFormat(format)) + { + case 1: + alsaFormat = SND_PCM_FORMAT_U8; + break; + case 2: + alsaFormat = SND_PCM_FORMAT_S16; + break; + default: + alsaFormat = SND_PCM_FORMAT_UNKNOWN; + fprintf(stderr, "Unknown format?! %x\n", format); + } + + psnd_pcm_hw_params_malloc(&p); +#define ok(func, str) (i=(func),((i<0)?fprintf(stderr,"%s failed\n", str),0:1)) + /* start with the largest configuration space possible */ + if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") && + /* set interleaved access */ + ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set access") && + /* set format (implicitly sets sample bits) */ + ok(psnd_pcm_hw_params_set_format(data->pcmHandle, p, alsaFormat), "set format") && + /* set channels (implicitly sets frame bits) */ + ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, pDevice->Channels), "set channels") && + /* set periods (implicitly constrains period/buffer parameters) */ + ok(psnd_pcm_hw_params_set_periods_near(data->pcmHandle, p, &periods, NULL), "set periods near") && + /* set rate (implicitly constrains period/buffer parameters) */ + ok(psnd_pcm_hw_params_set_rate(data->pcmHandle, p, frequency, 0), "set rate") && + /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */ + ok(psnd_pcm_hw_params_set_buffer_size_min(data->pcmHandle, p, &bufferSizeInFrames), "set buffer size min") && + /* install and prepare hardware configuration */ + ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params"))) + { + psnd_pcm_hw_params_free(p); + psnd_pcm_close(data->pcmHandle); + free(data); + return ALC_FALSE; + } +#undef ok + psnd_pcm_hw_params_free(p); + + i = psnd_pcm_prepare(data->pcmHandle); + if(i < 0) + { + fprintf(stderr, "prepare error: %s\n", psnd_strerror(i)); + psnd_pcm_close(data->pcmHandle); + free(data); + return ALC_FALSE; + } + + pDevice->ExtraData = data; + return ALC_TRUE; +} + +static void alsa_close_capture(ALCdevice *pDevice) +{ + alsa_data *data = (alsa_data*)pDevice->ExtraData; + psnd_pcm_close(data->pcmHandle); + + free(data); + pDevice->ExtraData = NULL; +} + +static void alsa_start_capture(ALCdevice *pDevice) +{ + alsa_data *data = (alsa_data*)pDevice->ExtraData; + psnd_pcm_start(data->pcmHandle); +} + +static void alsa_stop_capture(ALCdevice *pDevice) +{ + alsa_data *data = (alsa_data*)pDevice->ExtraData; + psnd_pcm_drain(data->pcmHandle); +} + +static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + alsa_data *data = (alsa_data*)pDevice->ExtraData; + const snd_pcm_channel_area_t *areas = NULL; + snd_pcm_sframes_t frames, commitres; + snd_pcm_uframes_t size, offset; + int err; + + frames = psnd_pcm_avail_update(data->pcmHandle); + if(frames < 0) + { + err = xrun_recovery(data->pcmHandle, frames); + if (err < 0) + fprintf(stderr, "available update failed: %s\n", psnd_strerror(err)); + else + frames = psnd_pcm_avail_update(data->pcmHandle); + } + if (frames < (snd_pcm_sframes_t)lSamples) + { + SetALCError(ALC_INVALID_VALUE); + return; + } + + // it is possible that contiguous areas are smaller, thus we use a loop + while (lSamples > 0) + { + char *Pointer; + int Count; + + size = lSamples; + err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &size); + if (err < 0) + { + err = xrun_recovery(data->pcmHandle, err); + if (err < 0) + { + fprintf(stderr, "mmap begin error: %s\n", psnd_strerror(err)); + break; + } + continue; + } + + Pointer = (char*)areas->addr + (offset * areas->step / 8); + Count = size * pDevice->FrameSize; + + memcpy(pBuffer, Pointer, Count); + pBuffer = (char*)pBuffer + Count; + + commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, size); + if (commitres < 0 || (commitres-size) != 0) + { + fprintf(stderr, "mmap commit error: %s\n", + psnd_strerror(commitres >= 0 ? -EPIPE : commitres)); + break; + } + + lSamples -= size; + } +} + +static ALCuint alsa_available_samples(ALCdevice *pDevice) +{ + alsa_data *data = (alsa_data*)pDevice->ExtraData; + snd_pcm_sframes_t frames = psnd_pcm_avail_update(data->pcmHandle); + if(frames < 0) + { + int err = xrun_recovery(data->pcmHandle, frames); + if (err < 0) + fprintf(stderr, "available update failed: %s\n", psnd_strerror(err)); + else + frames = psnd_pcm_avail_update(data->pcmHandle); + if(frames < 0) /* ew.. */ + SetALCError(ALC_INVALID_DEVICE); + } + return max(frames, 0); +} + + +BackendFuncs alsa_funcs = { + alsa_open_playback, + alsa_close_playback, + alsa_open_capture, + alsa_close_capture, + alsa_start_capture, + alsa_stop_capture, + alsa_capture_samples, + alsa_available_samples +}; + +void alc_alsa_init(BackendFuncs *func_list) +{ +#define error(...) do { \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +}while(0) + snd_ctl_t *handle; + int card, err, dev, idx = 1; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; + char name[128]; + char *str; + + *func_list = alsa_funcs; + +#ifdef HAVE_DLFCN_H + alsa_handle = dlopen("libasound.so.2", RTLD_NOW); + if(!alsa_handle) + return; + dlerror(); + +#define LOAD_FUNC(f) do { \ + p##f = (typeof(f)*)dlsym(alsa_handle, #f); \ + if((str=dlerror()) != NULL) \ + { \ + dlclose(alsa_handle); \ + alsa_handle = NULL; \ + error("Could not load %s from libasound.so.2: %s", #f, str); \ + return; \ + } \ +} while(0) +#else + str = NULL; + alsa_handle = NULL; +#define LOAD_FUNC(f) p##f = f +#endif + +LOAD_FUNC(snd_strerror); +LOAD_FUNC(snd_pcm_open); +LOAD_FUNC(snd_pcm_close); +LOAD_FUNC(snd_pcm_nonblock); +LOAD_FUNC(snd_pcm_frames_to_bytes); +LOAD_FUNC(snd_pcm_hw_params_malloc); +LOAD_FUNC(snd_pcm_hw_params_free); +LOAD_FUNC(snd_pcm_hw_params_any); +LOAD_FUNC(snd_pcm_hw_params_set_access); +LOAD_FUNC(snd_pcm_hw_params_set_format); +LOAD_FUNC(snd_pcm_hw_params_set_channels); +LOAD_FUNC(snd_pcm_hw_params_set_periods_near); +LOAD_FUNC(snd_pcm_hw_params_set_rate_near); +LOAD_FUNC(snd_pcm_hw_params_set_rate); +LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); +LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); +LOAD_FUNC(snd_pcm_hw_params); +LOAD_FUNC(snd_pcm_prepare); +LOAD_FUNC(snd_pcm_start); +LOAD_FUNC(snd_pcm_resume); +LOAD_FUNC(snd_pcm_state); +LOAD_FUNC(snd_pcm_avail_update); +LOAD_FUNC(snd_pcm_areas_silence); +LOAD_FUNC(snd_pcm_mmap_begin); +LOAD_FUNC(snd_pcm_mmap_commit); +LOAD_FUNC(snd_pcm_drain); + +LOAD_FUNC(snd_pcm_info_malloc); +LOAD_FUNC(snd_pcm_info_free); +LOAD_FUNC(snd_pcm_info_set_device); +LOAD_FUNC(snd_pcm_info_set_subdevice); +LOAD_FUNC(snd_pcm_info_set_stream); +LOAD_FUNC(snd_pcm_info_get_name); +LOAD_FUNC(snd_ctl_pcm_next_device); +LOAD_FUNC(snd_ctl_pcm_info); +LOAD_FUNC(snd_ctl_open); +LOAD_FUNC(snd_ctl_close); +LOAD_FUNC(snd_ctl_card_info_malloc); +LOAD_FUNC(snd_ctl_card_info_free); +LOAD_FUNC(snd_ctl_card_info); +LOAD_FUNC(snd_ctl_card_info_get_name); +LOAD_FUNC(snd_card_next); + +#undef LOAD_FUNC + + psnd_ctl_card_info_malloc(&info); + psnd_pcm_info_malloc(&pcminfo); + + card = -1; + if(psnd_card_next(&card) < 0 || card < 0) + error("no playback cards found..."); + else + { + alsaDeviceList[0] = AppendDeviceList("ALSA Software on default"); + allDevNameMap[0].name = AppendAllDeviceList("ALSA Software on default"); + } + + while (card >= 0) { + sprintf(name, "hw:%d", card); + if ((err = psnd_ctl_open(&handle, name, 0)) < 0) { + error("control open (%i): %s", card, psnd_strerror(err)); + goto next_card; + } + if ((err = psnd_ctl_card_info(handle, info)) < 0) { + error("control hardware info (%i): %s", card, psnd_strerror(err)); + psnd_ctl_close(handle); + goto next_card; + } + if(card < MAX_DEVICES-1) { + snprintf(name, sizeof(name), "ALSA Software on %s", + psnd_ctl_card_info_get_name(info)); + alsaDeviceList[card+1] = AppendDeviceList(name); + } + + dev = -1; + while (idx < MAX_ALL_DEVICES) { + if (psnd_ctl_pcm_next_device(handle, &dev)<0) + error("snd_ctl_pcm_next_device"); + if (dev < 0) + break; + psnd_pcm_info_set_device(pcminfo, dev); + psnd_pcm_info_set_subdevice(pcminfo, 0); + psnd_pcm_info_set_stream(pcminfo, stream); + if ((err = psnd_ctl_pcm_info(handle, pcminfo)) < 0) { + if (err != -ENOENT) + error("control digital audio info (%i): %s", card, psnd_strerror(err)); + continue; + } + snprintf(name, sizeof(name), "ALSA Software on %s [%s]", + psnd_ctl_card_info_get_name(info), + psnd_pcm_info_get_name(pcminfo)); + allDevNameMap[idx].name = AppendAllDeviceList(name); + allDevNameMap[idx].card = card; + allDevNameMap[idx].dev = dev; + idx++; + } + psnd_ctl_close(handle); +next_card: + if(psnd_card_next(&card) < 0) { + error("snd_card_next"); + break; + } + } + + + stream = SND_PCM_STREAM_CAPTURE; + + card = -1; + if(psnd_card_next(&card) < 0 || card < 0) { + error("no capture cards found..."); + psnd_pcm_info_free(pcminfo); + psnd_ctl_card_info_free(info); + return; + } + + alsaCaptureDeviceList[0] = AppendCaptureDeviceList("ALSA Capture on default"); + + while (card >= 0) { + sprintf(name, "hw:%d", card); + handle = NULL; + if ((err = psnd_ctl_open(&handle, name, 0)) < 0) { + error("control open (%i): %s", card, psnd_strerror(err)); + } + if (err >= 0 && (err = psnd_ctl_card_info(handle, info)) < 0) { + error("control hardware info (%i): %s", card, psnd_strerror(err)); + psnd_ctl_close(handle); + } + else if (err >= 0 && card < MAX_DEVICES-1) + { + snprintf(name, sizeof(name), "ALSA Capture on %s", + psnd_ctl_card_info_get_name(info)); + alsaCaptureDeviceList[card+1] = AppendCaptureDeviceList(name); + } + if(handle) psnd_ctl_close(handle); + if(psnd_card_next(&card) < 0) { + error("snd_card_next"); + break; + } + } + psnd_pcm_info_free(pcminfo); + psnd_ctl_card_info_free(info); +#undef error +} diff --git a/Alc/dsound.c b/Alc/dsound.c new file mode 100644 index 00000000..5d688567 --- /dev/null +++ b/Alc/dsound.c @@ -0,0 +1,294 @@ +/** + * 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 <stdio.h> +#include <memory.h> + +#include <windows.h> +#include <mmsystem.h> +#include <dsound.h> + +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + + +typedef struct { + // DirectSound Playback Device + LPDIRECTSOUND lpDS; + LPDIRECTSOUNDBUFFER DSpbuffer; + LPDIRECTSOUNDBUFFER DSsbuffer; + MMRESULT ulDSTimerID; +} DSoundData; + + +static ALCchar *DeviceList[16]; + +static void CALLBACK DirectSoundProc(UINT uID,UINT uReserved,DWORD_PTR dwUser,DWORD_PTR dwReserved1,DWORD_PTR dwReserved2) +{ + static DWORD OldWriteCursor=0; + + ALCdevice *pDevice = (ALCdevice *)dwUser; + DSoundData *pData = pDevice->ExtraData; + DWORD PlayCursor,WriteCursor; + BYTE *WritePtr1,*WritePtr2; + DWORD WriteCnt1,WriteCnt2; + WAVEFORMATEX OutputType; + DWORD BytesPlayed; + DWORD BufSize; + HRESULT DSRes; + + (void)uID; + (void)uReserved; + (void)dwReserved1; + (void)dwReserved2; + + BufSize = pDevice->UpdateFreq * pDevice->FrameSize; + + // Get current play and write cursors + IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer,&PlayCursor,&WriteCursor); + if (!OldWriteCursor) OldWriteCursor=WriteCursor-PlayCursor; + + // Get the output format and figure the number of bytes played (block aligned) + IDirectSoundBuffer_GetFormat(pData->DSsbuffer,&OutputType,sizeof(WAVEFORMATEX),NULL); + BytesPlayed=((((WriteCursor<OldWriteCursor)?(BufSize+WriteCursor-OldWriteCursor):(WriteCursor-OldWriteCursor))/OutputType.nBlockAlign)*OutputType.nBlockAlign); + + // Lock output buffer started at 40msec in front of the old write cursor (15msec in front of the actual write cursor) + DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0); + + // If the buffer is lost, restore it, play and lock + if (DSRes==DSERR_BUFFERLOST) + { + IDirectSoundBuffer_Restore(pData->DSsbuffer); + IDirectSoundBuffer_Play(pData->DSsbuffer,0,0,DSBPLAY_LOOPING); + DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0); + } + + // Successfully locked the output buffer + if (DSRes==DS_OK) + { + // If we have an active context, mix data directly into output buffer otherwise fill with silence + SuspendContext(NULL); + if(pDevice->Context) + { + if (WritePtr1) + aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format); + if (WritePtr2) + aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format); + } + else + { + if (WritePtr1) memset(WritePtr1, 0, WriteCnt1); + if (WritePtr2) memset(WritePtr2, 0, WriteCnt2); + } + ProcessContext(NULL); + + // Unlock output buffer only when successfully locked + IDirectSoundBuffer_Unlock(pData->DSsbuffer,WritePtr1,WriteCnt1,WritePtr2,WriteCnt2); + } + + // Update old write cursor location + OldWriteCursor=((OldWriteCursor+BytesPlayed)%BufSize); +} + + +static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) +{ + DSBUFFERDESC DSBDescription; + DSoundData *pData = NULL; + WAVEFORMATEX OutputType; + HRESULT hr; + + if(deviceName) + { + int i; + for(i = 0;DeviceList[i];i++) + { + if(strcmp(deviceName, DeviceList[i]) == 0) + break; + } + if(!DeviceList[i]) + return ALC_FALSE; + } + + //Platform specific + memset(&OutputType, 0, sizeof(WAVEFORMATEX)); + OutputType.wFormatTag = WAVE_FORMAT_PCM; + OutputType.nChannels = device->Channels; + OutputType.wBitsPerSample = (((device->Format==AL_FORMAT_MONO16)||(device->Format==AL_FORMAT_STEREO16)||(device->Format==AL_FORMAT_QUAD16))?16:8); + OutputType.nBlockAlign = OutputType.nChannels*OutputType.wBitsPerSample/8; + OutputType.nSamplesPerSec = device->Frequency; + OutputType.nAvgBytesPerSec = OutputType.nSamplesPerSec*OutputType.nBlockAlign; + OutputType.cbSize = 0; + + //Initialise requested device + + pData = calloc(1, sizeof(DSoundData)); + if(!pData) + { + SetALCError(ALC_OUT_OF_MEMORY); + return ALC_FALSE; + } + + //Init COM + CoInitialize(NULL); + + //DirectSound Init code + hr = CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectSound, (LPVOID*)&pData->lpDS); + if(SUCCEEDED(hr)) + hr = IDirectSound_Initialize(pData->lpDS, NULL); + if(SUCCEEDED(hr)) + hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY); + + if(SUCCEEDED(hr)) + { + memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); + DSBDescription.dwSize=sizeof(DSBUFFERDESC); + DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; + hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL); + } + if(SUCCEEDED(hr)) + hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType); + + if(SUCCEEDED(hr)) + { + memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); + DSBDescription.dwSize=sizeof(DSBUFFERDESC); + DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2; + DSBDescription.dwBufferBytes=device->UpdateFreq * device->FrameSize; + DSBDescription.lpwfxFormat=&OutputType; + hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL); + } + + if(SUCCEEDED(hr)) + hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); + + if(FAILED(hr)) + { + if (pData->DSsbuffer) + IDirectSoundBuffer_Release(pData->DSsbuffer); + if (pData->DSpbuffer) + IDirectSoundBuffer_Release(pData->DSpbuffer); + if (pData->lpDS) + IDirectSound_Release(pData->lpDS); + + free(pData); + return ALC_FALSE; + } + + pData->ulDSTimerID = timeSetEvent(25, 0, (LPTIMECALLBACK)DirectSoundProc, (DWORD)device, (UINT)TIME_CALLBACK_FUNCTION|TIME_PERIODIC); + device->MaxNoOfSources = 256; + + if(deviceName) + strcpy(device->szDeviceName, deviceName); + else + strcpy(device->szDeviceName, DeviceList[0]); + + device->ExtraData = pData; + return ALC_TRUE; +} + +static void DSoundClosePlayback(ALCdevice *device) +{ + DSoundData *pData = device->ExtraData; + + // Stop and release the DS timer + if (pData->ulDSTimerID) + timeKillEvent(pData->ulDSTimerID); + + // Wait ... just in case any timer events happen + Sleep(100); + + SuspendContext(NULL); + + if (pData->DSsbuffer) + IDirectSoundBuffer_Release(pData->DSsbuffer); + if (pData->DSpbuffer) + IDirectSoundBuffer_Release(pData->DSpbuffer); + IDirectSound_Release(pData->lpDS); + + //Deinit COM + CoUninitialize(); + + ProcessContext(NULL); + + free(pData); + device->ExtraData = NULL; +} + + +static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + (void)pDevice; + (void)deviceName; + (void)frequency; + (void)format; + (void)SampleSize; + return ALC_FALSE; +} + +static void DSoundCloseCapture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void DSoundStartCapture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void DSoundStopCapture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + (void)pDevice; + (void)pBuffer; + (void)lSamples; +} + +static ALCuint DSoundAvailableSamples(ALCdevice *pDevice) +{ + (void)pDevice; + return 0; +} + + +BackendFuncs DSoundFuncs = { + DSoundOpenPlayback, + DSoundClosePlayback, + DSoundOpenCapture, + DSoundCloseCapture, + DSoundStartCapture, + DSoundStopCapture, + DSoundCaptureSamples, + DSoundAvailableSamples +}; + +void alcDSoundInit(BackendFuncs *FuncList) +{ + *FuncList = DSoundFuncs; + + DeviceList[0] = AppendDeviceList("DirectSound Software"); + AppendAllDeviceList(DeviceList[0]); +} diff --git a/Alc/oss.c b/Alc/oss.c new file mode 100644 index 00000000..5874a88c --- /dev/null +++ b/Alc/oss.c @@ -0,0 +1,328 @@ +/** + * 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 <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include <unistd.h> +#include <errno.h> +#include <math.h> +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + +#include <sys/soundcard.h> + +/* + * The OSS documentation talks about SOUND_MIXER_READ, but the header + * only contains MIXER_READ. Play safe. Same for WRITE. + */ +#ifndef SOUND_MIXER_READ +#define SOUND_MIXER_READ MIXER_READ +#endif +#ifndef SOUND_MIXER_WRITE +#define SOUND_MIXER_WRITE MIXER_WRITE +#endif + +static char *oss_device; + +typedef struct { + int fd; + int killNow; + ALvoid *thread; + + void *mix_data; + int data_size; + int silence; +} oss_data; + + +static int log2i(ALCuint x) +{ + int y = 0; + while (x > 1) + { + x >>= 1; + y++; + } + return y; +} + + +static ALuint OSSProc(ALvoid *ptr) +{ + ALCdevice *pDevice = (ALCdevice*)ptr; + oss_data *data = (oss_data*)pDevice->ExtraData; + int remaining; + int wrote; + + while(!data->killNow) + { + SuspendContext(NULL); + if(pDevice->Context) + aluMixData(pDevice->Context,data->mix_data,data->data_size,pDevice->Format); + else + memset(data->mix_data,data->silence,data->data_size); + ProcessContext(NULL); + + remaining = data->data_size; + while(remaining > 0) + { + wrote = write(data->fd, data->mix_data+data->data_size-remaining, remaining); + if(wrote < 0) + { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + break; + } + if(wrote == 0) + { + usleep(1000); + continue; + } + remaining -= wrote; + } + } + + return 0; +} + +static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + int numFragmentsLogSize; + int log2FragmentSize; + unsigned int periods; + audio_buf_info info; + char driver[64]; + int numChannels; + oss_data *data; + int ossFormat; + int ossSpeed; + int i; + + strncpy(driver, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver)-1); + driver[sizeof(driver)-1] = 0; + if(deviceName) + { + if(strcmp(deviceName, oss_device)) + return ALC_FALSE; + } + + if(deviceName) + strcpy(device->szDeviceName, deviceName); + else + strcpy(device->szDeviceName, oss_device); + + data = (oss_data*)calloc(1, sizeof(oss_data)); + data->killNow = 0; + + data->fd = open(driver, O_WRONLY); + if(data->fd == -1) + { + free(data); + return ALC_FALSE; + } + + switch(device->Format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_STEREO8: + case AL_FORMAT_QUAD8: + data->silence = 0x80; + ossFormat = AFMT_U8; + break; + case AL_FORMAT_MONO16: + case AL_FORMAT_STEREO16: + case AL_FORMAT_QUAD16: + data->silence = 0; + ossFormat = AFMT_S16_NE; + break; + default: + ossFormat = -1; + fprintf(stderr, "Unknown format?! %x\n", device->Format); + } + + periods = GetConfigValueInt("oss", "periods", 4); + if((int)periods < 0) + periods = 4; + numChannels = device->Channels; + ossSpeed = device->Frequency; + log2FragmentSize = log2i(device->UpdateFreq * device->FrameSize / periods); + + /* according to the OSS spec, 16 bytes are the minimum */ + if (log2FragmentSize < 4) + log2FragmentSize = 4; + numFragmentsLogSize = (periods << 16) | log2FragmentSize; + +#define ok(func, str) (i=(func),((i<0)?fprintf(stderr,"%s failed\n", str),0:1)) + if (!(ok(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize), "set fragment") && + ok(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat), "set format") && + ok(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels), "set channels") && + ok(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed), "set speed") && + ok(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info), "get space"))) + { + close(data->fd); + free(data); + return ALC_FALSE; + } +#undef ok + + device->Channels = numChannels; + device->Frequency = ossSpeed; + device->Format = 0; + if(ossFormat == AFMT_U8) + { + if(device->Channels == 1) + { + device->Format = AL_FORMAT_MONO8; + device->FrameSize = 1; + } + else if(device->Channels == 2) + { + device->Format = AL_FORMAT_STEREO8; + device->FrameSize = 2; + } + else if(device->Channels == 4) + { + device->Format = AL_FORMAT_QUAD8; + device->FrameSize = 4; + } + } + else if(ossFormat == AFMT_S16_NE) + { + if(device->Channels == 1) + { + device->Format = AL_FORMAT_MONO16; + device->FrameSize = 2; + } + else if(device->Channels == 2) + { + device->Format = AL_FORMAT_STEREO16; + device->FrameSize = 4; + } + else if(device->Channels == 4) + { + device->Format = AL_FORMAT_QUAD16; + device->FrameSize = 8; + } + } + + if(!device->Format) + { + fprintf(stderr, "Unknown returned format/channel %#x/%d!\n", ossFormat, numChannels); + close(data->fd); + free(data); + return ALC_FALSE; + } + + device->UpdateFreq = info.fragsize / device->FrameSize; + + data->data_size = device->UpdateFreq * device->FrameSize; + data->mix_data = calloc(1, data->data_size); + + device->MaxNoOfSources = 256; + + device->ExtraData = data; + data->thread = StartThread(OSSProc, device); + if(data->thread == NULL) + { + device->ExtraData = NULL; + free(data->mix_data); + free(data); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void oss_close_playback(ALCdevice *device) +{ + oss_data *data = (oss_data*)device->ExtraData; + data->killNow = 1; + StopThread(data->thread); + + close(data->fd); + + free(data->mix_data); + free(data); + device->ExtraData = NULL; +} + + +static ALCboolean oss_open_capture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + (void)pDevice; + (void)deviceName; + (void)frequency; + (void)format; + (void)SampleSize; + return ALC_FALSE; +} + +static void oss_close_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void oss_start_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void oss_stop_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + (void)pDevice; + (void)pBuffer; + (void)lSamples; +} + +static ALCuint oss_available_samples(ALCdevice *pDevice) +{ + (void)pDevice; + return 0; +} + + +BackendFuncs oss_funcs = { + oss_open_playback, + oss_close_playback, + oss_open_capture, + oss_close_capture, + oss_start_capture, + oss_stop_capture, + oss_capture_samples, + oss_available_samples +}; + +void alc_oss_init(BackendFuncs *func_list) +{ + *func_list = oss_funcs; + + oss_device = AppendDeviceList("OSS Software"); + AppendAllDeviceList(oss_device); +} diff --git a/Alc/winmm.c b/Alc/winmm.c new file mode 100644 index 00000000..26f40db2 --- /dev/null +++ b/Alc/winmm.c @@ -0,0 +1,421 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> + +#include <windows.h> +#include <mmsystem.h> + +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + + +typedef struct { + // MMSYSTEM Capture Device + ALboolean bWaveInShutdown; + HANDLE hWaveInHdrEvent; + HANDLE hWaveInThreadEvent; + HANDLE hWaveInThread; + DWORD ulWaveInThreadID; + ALint lWaveInBuffersCommitted; + HWAVEIN hWaveInHandle; + WAVEHDR WaveInBuffer[4]; + ALCchar *pCapturedSampleData; + ALuint ulCapturedDataSize; + ALuint ulReadCapturedDataPos; + ALuint ulWriteCapturedDataPos; +} WinMMData; + + +static ALCchar *CaptureDeviceList[16]; + +/* + WaveInProc + + Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and + returns to the application (with more data) +*/ +static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2) +{ + ALCdevice *pDevice = (ALCdevice *)dwInstance; + WinMMData *pData = pDevice->ExtraData; + + (void)hDevice; + (void)dwParam2; + + if ((uMsg==WIM_DATA) && (pDevice)) + { + // Decrement number of buffers in use + pData->lWaveInBuffersCommitted--; + + if (pData->bWaveInShutdown == AL_FALSE) + { + // Notify Wave Processor Thread that a Wave Header has returned + PostThreadMessage(pData->ulWaveInThreadID,uMsg,0,dwParam1); + } + else + { + if (pData->lWaveInBuffersCommitted == 0) + { + // Signal Wave Buffers Returned event + if (pData->hWaveInHdrEvent) + SetEvent(pData->hWaveInHdrEvent); + + // Post 'Quit' Message to WaveIn Processor Thread + PostThreadMessage(pData->ulWaveInThreadID,WM_QUIT,0,0); + } + } + } +} + +/* + CaptureThreadProc + + Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new + audio data. +*/ +DWORD WINAPI CaptureThreadProc(LPVOID lpParameter) +{ + ALCdevice *pDevice = (ALCdevice*)lpParameter; + WinMMData *pData = pDevice->ExtraData; + ALuint ulOffset, ulMaxSize, ulSection; + LPWAVEHDR pWaveHdr; + MSG msg; + + while (GetMessage(&msg, NULL, 0, 0)) + { + if ((msg.message==WIM_DATA)&&(!pData->bWaveInShutdown)) + { + SuspendContext(NULL); + + pWaveHdr = ((LPWAVEHDR)msg.lParam); + + // Calculate offset in local buffer to write data to + ulOffset = pData->ulWriteCapturedDataPos % pData->ulCapturedDataSize; + + if ((ulOffset + pWaveHdr->dwBytesRecorded) > pData->ulCapturedDataSize) + { + ulSection = pData->ulCapturedDataSize - ulOffset; + memcpy(pData->pCapturedSampleData + ulOffset, pWaveHdr->lpData, ulSection); + memcpy(pData->pCapturedSampleData, pWaveHdr->lpData + ulSection, pWaveHdr->dwBytesRecorded - ulSection); + } + else + { + memcpy(pData->pCapturedSampleData + ulOffset, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded); + } + + pData->ulWriteCapturedDataPos += pWaveHdr->dwBytesRecorded; + + if (pData->ulWriteCapturedDataPos > (pData->ulReadCapturedDataPos + pData->ulCapturedDataSize)) + { + // Application has not read enough audio data from the capture buffer so data has been + // overwritten. Reset ReadPosition. + pData->ulReadCapturedDataPos = pData->ulWriteCapturedDataPos - pData->ulCapturedDataSize; + } + + // To prevent an over-flow prevent the offset values from getting too large + ulMaxSize = pData->ulCapturedDataSize << 4; + if ((pData->ulReadCapturedDataPos > ulMaxSize) && (pData->ulWriteCapturedDataPos > ulMaxSize)) + { + pData->ulReadCapturedDataPos -= ulMaxSize; + pData->ulWriteCapturedDataPos -= ulMaxSize; + } + + // Send buffer back to capture more data + waveInAddBuffer(pData->hWaveInHandle,pWaveHdr,sizeof(WAVEHDR)); + pData->lWaveInBuffersCommitted++; + + ProcessContext(NULL); + } + } + + // Signal Wave Thread completed event + if (pData->hWaveInThreadEvent) + SetEvent(pData->hWaveInThreadEvent); + + ExitThread(0); + + return 0; +} + + +static ALCboolean WinMMOpenPlayback(ALCdevice *device, const ALCchar *deviceName) +{ + (void)device; + (void)deviceName; + return ALC_FALSE; +} + +static void WinMMClosePlayback(ALCdevice *device) +{ + (void)device; +} + + +static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + WAVEFORMATEX wfexCaptureFormat; + WinMMData *pData = NULL; + ALint lDeviceID = 0; + ALint lBufferSize; + ALint i; + + (void)format; + + // Find the Device ID matching the deviceName if valid + if (deviceName) + { + for(i = 0;CaptureDeviceList[i];i++) + { + if (!strcmp(deviceName, CaptureDeviceList[i])) + { + lDeviceID = i; + break; + } + } + if(!CaptureDeviceList[i]) + return ALC_FALSE; + } + + pData = calloc(1, sizeof(*pData)); + if(!pData) + { + SetALCError(ALC_OUT_OF_MEMORY); + return ALC_FALSE; + } + + memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX)); + wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM; + wfexCaptureFormat.nChannels = pDevice->Channels; + wfexCaptureFormat.wBitsPerSample = pDevice->FrameSize / pDevice->Channels * 8; + wfexCaptureFormat.nBlockAlign = pDevice->FrameSize; + wfexCaptureFormat.nSamplesPerSec = frequency; + wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec * + pDevice->FrameSize; + wfexCaptureFormat.cbSize = 0; + + if (waveInOpen(&pData->hWaveInHandle, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + goto failure; + + pData->hWaveInHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInAllHeadersReturned"); + if (pData->hWaveInHdrEvent == NULL) + goto failure; + + pData->hWaveInThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInThreadDestroyed"); + if (pData->hWaveInThreadEvent == NULL) + goto failure; + + pData->hWaveInThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveInThreadID); + if (pData->hWaveInThread == NULL) + goto failure; + + // Allocate circular memory buffer for the captured audio + pData->ulCapturedDataSize = SampleSize * wfexCaptureFormat.nBlockAlign; + + // Make sure circular buffer is at least 100ms in size (and an exact multiple of + // the block alignment + if (pData->ulCapturedDataSize < (wfexCaptureFormat.nAvgBytesPerSec / 10)) + { + pData->ulCapturedDataSize = wfexCaptureFormat.nAvgBytesPerSec / 10; + pData->ulCapturedDataSize -= (pData->ulCapturedDataSize % wfexCaptureFormat.nBlockAlign); + } + + pData->pCapturedSampleData = (ALCchar*)malloc(pData->ulCapturedDataSize); + pData->lWaveInBuffersCommitted=0; + + // Create 4 Buffers of 50ms each + lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20; + lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign); + + for (i=0;i<4;i++) + { + memset(&pData->WaveInBuffer[i], 0, sizeof(WAVEHDR)); + pData->WaveInBuffer[i].dwBufferLength = lBufferSize; + pData->WaveInBuffer[i].lpData = calloc(1,pData->WaveInBuffer[i].dwBufferLength); + pData->WaveInBuffer[i].dwFlags = 0; + pData->WaveInBuffer[i].dwLoops = 0; + waveInPrepareHeader(pData->hWaveInHandle, &pData->WaveInBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(pData->hWaveInHandle, &pData->WaveInBuffer[i], sizeof(WAVEHDR)); + pData->lWaveInBuffersCommitted++; + } + + pData->ulReadCapturedDataPos = 0; + pData->ulWriteCapturedDataPos = 0; + + strcpy(pDevice->szDeviceName, CaptureDeviceList[lDeviceID]); + + pDevice->ExtraData = pData; + return ALC_TRUE; + +failure: + if (pData->hWaveInThreadEvent) + CloseHandle(pData->hWaveInThreadEvent); + if (pData->hWaveInHdrEvent) + CloseHandle(pData->hWaveInHdrEvent); + if (pData->hWaveInHandle) + waveInClose(pData->hWaveInHandle); + + free(pData); + return ALC_FALSE; +} + +static void WinMMCloseCapture(ALCdevice *pDevice) +{ + WinMMData *pData = (WinMMData*)pDevice->ExtraData; + int i; + + // Call waveOutReset to shutdown wave device + pData->bWaveInShutdown = AL_TRUE; + waveInReset(pData->hWaveInHandle); + + // Wait for signal that all Wave Buffers have returned + WaitForSingleObjectEx(pData->hWaveInHdrEvent, 5000, FALSE); + + // Wait for signal that Wave Thread has been destroyed + WaitForSingleObjectEx(pData->hWaveInThreadEvent, 5000, FALSE); + + // Release the wave buffers + for (i=0;i<4;i++) + { + waveInUnprepareHeader(pData->hWaveInHandle, &pData->WaveInBuffer[i], sizeof(WAVEHDR)); + free(pData->WaveInBuffer[i].lpData); + } + + // Free Audio Buffer data + free(pData->pCapturedSampleData); + pData->pCapturedSampleData = NULL; + + // Close the Wave device + waveInClose(pData->hWaveInHandle); + pData->hWaveInHandle = 0; + + CloseHandle(pData->hWaveInThread); + pData->hWaveInThread = 0; + + if (pData->hWaveInHdrEvent) + { + CloseHandle(pData->hWaveInHdrEvent); + pData->hWaveInHdrEvent = 0; + } + + if (pData->hWaveInThreadEvent) + { + CloseHandle(pData->hWaveInThreadEvent); + pData->hWaveInThreadEvent = 0; + } + + free(pData); + pDevice->ExtraData = NULL; +} + +static void WinMMStartCapture(ALCdevice *pDevice) +{ + WinMMData *pData = (WinMMData*)pDevice->ExtraData; + waveInStart(pData->hWaveInHandle); +} + +static void WinMMStopCapture(ALCdevice *pDevice) +{ + WinMMData *pData = (WinMMData*)pDevice->ExtraData; + waveInStop(pData->hWaveInHandle); +} + +static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + WinMMData *pData = (WinMMData*)pDevice->ExtraData; + ALuint ulSamples = (unsigned long)lSamples; + ALuint ulBytes, ulBytesToCopy; + ALuint ulCapturedSamples; + ALuint ulReadOffset; + + // Check that we have the requested numbers of Samples + ulCapturedSamples = (pData->ulWriteCapturedDataPos - pData->ulReadCapturedDataPos) / pDevice->FrameSize; + if(ulSamples > ulCapturedSamples) + { + SetALCError(ALC_INVALID_VALUE); + return; + } + + ulBytes = ulSamples * pDevice->FrameSize; + + // Get Read Offset + ulReadOffset = (pData->ulReadCapturedDataPos % pData->ulCapturedDataSize); + + // Check for wrap-around condition + if ((ulReadOffset + ulBytes) > pData->ulCapturedDataSize) + { + // Copy data from last Read position to end of data + ulBytesToCopy = pData->ulCapturedDataSize - ulReadOffset; + memcpy(pBuffer, pData->pCapturedSampleData + ulReadOffset, ulBytesToCopy); + + // Copy rest of the data from the start of the captured data + memcpy(((char *)pBuffer) + ulBytesToCopy, pData->pCapturedSampleData, ulBytes - ulBytesToCopy); + } + else + { + // Copy data from the read position in the captured data + memcpy(pBuffer, pData->pCapturedSampleData + ulReadOffset, ulBytes); + } + + // Update Read Position + pData->ulReadCapturedDataPos += ulBytes; +} + +static ALCuint WinMMAvailableSamples(ALCdevice *pDevice) +{ + WinMMData *pData = (WinMMData*)pDevice->ExtraData; + ALCuint lCapturedBytes = (pData->ulWriteCapturedDataPos - pData->ulReadCapturedDataPos); + return lCapturedBytes / pDevice->FrameSize; +} + + +BackendFuncs WinMMFuncs = { + WinMMOpenPlayback, + WinMMClosePlayback, + WinMMOpenCapture, + WinMMCloseCapture, + WinMMStartCapture, + WinMMStopCapture, + WinMMCaptureSamples, + WinMMAvailableSamples +}; + +void alcWinMMInit(BackendFuncs *FuncList) +{ + ALint lNumDevs; + ALint lLoop; + + *FuncList = WinMMFuncs; + + lNumDevs = waveInGetNumDevs(); + for (lLoop = 0; lLoop < lNumDevs; lLoop++) + { + WAVEINCAPS WaveInCaps; + if(waveInGetDevCaps(lLoop, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) + { + char name[128]; + snprintf(name, sizeof(name), "WaveIn on %s", WaveInCaps.szPname); + CaptureDeviceList[lLoop] = AppendCaptureDeviceList(name); + } + } +} diff --git a/Alu/ALu.c b/Alu/ALu.c new file mode 100644 index 00000000..1b9fbce9 --- /dev/null +++ b/Alu/ALu.c @@ -0,0 +1,677 @@ +/** + * 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 "config.h" + +#include <math.h> +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + +#if defined(HAVE_STDINT_H) +#include <stdint.h> +typedef int64_t ALint64; +#elif defined(HAVE___INT64) +typedef __int64 ALint64; +#elif (SIZEOF_LONG == 8) +typedef long ALint64; +#elif (SIZEOF_LONG_LONG == 8) +typedef long long ALint64; +#endif + +#ifdef HAVE_SQRTF +#define aluSqrt(x) ((ALfloat)sqrtf((float)(x))) +#else +#define aluSqrt(x) ((ALfloat)sqrt((double)(x))) +#endif + +// fixes for mingw32. +#if defined(max) && !defined(__max) +#define __max max +#endif +#if defined(min) && !defined(__min) +#define __min min +#endif + +__inline ALuint aluBytesFromFormat(ALenum format) +{ + switch(format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_STEREO8: + case AL_FORMAT_QUAD8: + return 1; + + case AL_FORMAT_MONO16: + case AL_FORMAT_STEREO16: + case AL_FORMAT_QUAD16: + return 2; + + default: + return 0; + } +} + +__inline ALuint aluChannelsFromFormat(ALenum format) +{ + switch(format) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + return 1; + + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + return 2; + + case AL_FORMAT_QUAD8: + case AL_FORMAT_QUAD16: + return 4; + + default: + return 0; + } +} + +static __inline ALint aluF2L(ALfloat Value) +{ + if(sizeof(ALint) == 4 && sizeof(double) == 8) + { + double temp; + temp = Value + (((65536.0*65536.0*16.0)+(65536.0*65536.0*8.0))*65536.0); + return *((ALint*)&temp); + } + return (ALint)Value; +} + +static __inline ALshort aluF2S(ALfloat Value) +{ + ALint i; + + i = aluF2L(Value); + i = __min( 32767, i); + i = __max(-32768, i); + return ((ALshort)i); +} + +static __inline ALvoid aluCrossproduct(ALfloat *inVector1,ALfloat *inVector2,ALfloat *outVector) +{ + outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; + outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; + outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; +} + +static __inline ALfloat aluDotproduct(ALfloat *inVector1,ALfloat *inVector2) +{ + return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] + + inVector1[2]*inVector2[2]; +} + +static __inline ALvoid aluNormalize(ALfloat *inVector) +{ + ALfloat length, inverse_length; + + length = (ALfloat)aluSqrt(aluDotproduct(inVector, inVector)); + if(length != 0) + { + inverse_length = 1.0f/length; + inVector[0] *= inverse_length; + inVector[1] *= inverse_length; + inVector[2] *= inverse_length; + } +} + +static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3]) +{ + ALfloat result[3]; + + result[0] = vector[0]*matrix[0][0] + vector[1]*matrix[1][0] + vector[2]*matrix[2][0]; + result[1] = vector[0]*matrix[0][1] + vector[1]*matrix[1][1] + vector[2]*matrix[2][1]; + result[2] = vector[0]*matrix[0][2] + vector[1]*matrix[1][2] + vector[2]*matrix[2][2]; + memcpy(vector, result, sizeof(result)); +} + +static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource, + ALenum isMono, ALenum OutputFormat, + ALfloat *drysend, ALfloat *wetsend, + ALfloat *pitch) +{ + ALfloat ListenerOrientation[6],ListenerPosition[3],ListenerVelocity[3]; + ALfloat InnerAngle,OuterAngle,OuterGain,Angle,Distance,DryMix,WetMix; + ALfloat Direction[3],Position[3],Velocity[3],SourceToListener[3]; + ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; + ALfloat Pitch,ConeVolume,SourceVolume,PanningFB,PanningLR,ListenerGain; + ALfloat U[3],V[3],N[3]; + ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound, flMaxVelocity; + ALfloat flVSS, flVLS; + ALint DistanceModel; + ALfloat Matrix[3][3]; + ALint HeadRelative; + ALfloat flAttenuation; + + //Get context properties + DopplerFactor = ALContext->DopplerFactor; + DistanceModel = ALContext->DistanceModel; + DopplerVelocity = ALContext->DopplerVelocity; + flSpeedOfSound = ALContext->flSpeedOfSound; + + //Get listener properties + ListenerGain = ALContext->Listener.Gain; + memcpy(ListenerPosition, ALContext->Listener.Position, sizeof(ALContext->Listener.Position)); + memcpy(ListenerVelocity, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity)); + memcpy(&ListenerOrientation[0], ALContext->Listener.Forward, sizeof(ALContext->Listener.Forward)); + memcpy(&ListenerOrientation[3], ALContext->Listener.Up, sizeof(ALContext->Listener.Up)); + + //Get source properties + Pitch = ALSource->flPitch; + SourceVolume = ALSource->flGain; + memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition)); + memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity)); + memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation)); + MinVolume = ALSource->flMinGain; + MaxVolume = ALSource->flMaxGain; + MinDist = ALSource->flRefDistance; + MaxDist = ALSource->flMaxDistance; + Rolloff = ALSource->flRollOffFactor; + OuterGain = ALSource->flOuterGain; + InnerAngle = ALSource->flInnerAngle; + OuterAngle = ALSource->flOuterAngle; + HeadRelative = ALSource->bHeadRelative; + + //Set working variables + DryMix = (ALfloat)(1.0f); + WetMix = (ALfloat)(0.0f); + + //Only apply 3D calculations for mono buffers + if(isMono != AL_FALSE) + { + //1. Translate Listener to origin (convert to head relative) + if(HeadRelative==AL_FALSE) + { + Position[0] -= ListenerPosition[0]; + Position[1] -= ListenerPosition[1]; + Position[2] -= ListenerPosition[2]; + } + + //2. Calculate distance attenuation + Distance = aluSqrt(aluDotproduct(Position, Position)); + + flAttenuation = 1.0f; + switch (DistanceModel) + { + case AL_INVERSE_DISTANCE_CLAMPED: + Distance=__max(Distance,MinDist); + Distance=__min(Distance,MaxDist); + if (MaxDist < MinDist) + break; + //fall-through + case AL_INVERSE_DISTANCE: + if (MinDist > 0.0f) + { + if ((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f) + flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist))); + } + break; + + case AL_LINEAR_DISTANCE_CLAMPED: + Distance=__max(Distance,MinDist); + Distance=__min(Distance,MaxDist); + if (MaxDist < MinDist) + break; + //fall-through + case AL_LINEAR_DISTANCE: + Distance=__min(Distance,MaxDist); + if (MaxDist != MinDist) + flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist)); + break; + + case AL_EXPONENT_DISTANCE_CLAMPED: + Distance=__max(Distance,MinDist); + Distance=__min(Distance,MaxDist); + if (MaxDist < MinDist) + break; + //fall-through + case AL_EXPONENT_DISTANCE: + if ((Distance > 0.0f) && (MinDist > 0.0f)) + flAttenuation = (ALfloat)pow(Distance/MinDist, -Rolloff); + break; + + case AL_NONE: + default: + flAttenuation = 1.0f; + break; + } + + // Source Gain + Attenuation + DryMix = SourceVolume * flAttenuation; + + // Clamp to Min/Max Gain + DryMix = __min(DryMix,MaxVolume); + DryMix = __max(DryMix,MinVolume); + WetMix = __min(WetMix,MaxVolume); + WetMix = __max(WetMix,MinVolume); + //3. Apply directional soundcones + SourceToListener[0] = -Position[0]; + SourceToListener[1] = -Position[1]; + SourceToListener[2] = -Position[2]; + aluNormalize(Direction); + aluNormalize(SourceToListener); + Angle = (ALfloat)(180.0*acos(aluDotproduct(Direction,SourceToListener))/3.141592654f); + if(Angle >= InnerAngle && Angle <= OuterAngle) + ConeVolume = (1.0f+(OuterGain-1.0f)*(Angle-InnerAngle)/(OuterAngle-InnerAngle)); + else if(Angle > OuterAngle) + ConeVolume = (1.0f+(OuterGain-1.0f) ); + else + ConeVolume = 1.0f; + + //4. Calculate Velocity + if(DopplerFactor != 0.0f) + { + flVLS = aluDotproduct(ListenerVelocity, SourceToListener); + flVSS = aluDotproduct(Velocity, SourceToListener); + + flMaxVelocity = (DopplerVelocity * flSpeedOfSound) / DopplerFactor; + + if (flVSS >= flMaxVelocity) + flVSS = (flMaxVelocity - 1.0f); + else if (flVSS <= -flMaxVelocity) + flVSS = -flMaxVelocity + 1.0f; + + if (flVLS >= flMaxVelocity) + flVLS = (flMaxVelocity - 1.0f); + else if (flVLS <= -flMaxVelocity) + flVLS = -flMaxVelocity + 1.0f; + + pitch[0] = Pitch * ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) / + ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS)); + } + else + pitch[0] = Pitch; + + //5. Align coordinate system axes + aluCrossproduct(&ListenerOrientation[0], &ListenerOrientation[3], U); // Right-vector + aluNormalize(U); // Normalized Right-vector + memcpy(V, &ListenerOrientation[3], sizeof(V)); // Up-vector + aluNormalize(V); // Normalized Up-vector + memcpy(N, &ListenerOrientation[0], sizeof(N)); // At-vector + aluNormalize(N); // Normalized At-vector + Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; + Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; + Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; + aluMatrixVector(Position, Matrix); + + //6. Convert normalized position into left/right front/back pannings + if(Distance != 0.0f) + { + aluNormalize(Position); + PanningLR = 0.5f + 0.5f*Position[0]; + PanningFB = 0.5f + 0.5f*Position[2]; + } + else + { + PanningLR = 0.5f; + PanningFB = 0.5f; + } + + //7. Convert pannings into channel volumes + switch(OutputFormat) + { + case AL_FORMAT_MONO8: + case AL_FORMAT_MONO16: + drysend[0] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f); //Direct + drysend[1] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f); //Direct + wetsend[0] = ListenerGain * WetMix * aluSqrt(1.0f); //Room + wetsend[1] = ListenerGain * WetMix * aluSqrt(1.0f); //Room + break; + case AL_FORMAT_STEREO8: + case AL_FORMAT_STEREO16: + drysend[0] = ConeVolume * ListenerGain * DryMix * aluSqrt(1.0f-PanningLR); //L Direct + drysend[1] = ConeVolume * ListenerGain * DryMix * aluSqrt( PanningLR); //R Direct + wetsend[0] = ListenerGain * WetMix * aluSqrt(1.0f-PanningLR); //L Room + wetsend[1] = ListenerGain * WetMix * aluSqrt( PanningLR); //R Room + break; + case AL_FORMAT_QUAD8: + case AL_FORMAT_QUAD16: + drysend[0] = ConeVolume * ListenerGain * DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); //FL Direct + drysend[1] = ConeVolume * ListenerGain * DryMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); //FR Direct + drysend[2] = ConeVolume * ListenerGain * DryMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); //BL Direct + drysend[3] = ConeVolume * ListenerGain * DryMix * aluSqrt(( PanningLR)*( PanningFB)); //BR Direct + wetsend[0] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB)); //FL Room + wetsend[1] = ListenerGain * WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB)); //FR Room + wetsend[2] = ListenerGain * WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB)); //BL Room + wetsend[3] = ListenerGain * WetMix * aluSqrt(( PanningLR)*( PanningFB)); //BR Room + break; + default: + break; + } + } + else + { + //1. Multi-channel buffers always play "normal" + drysend[0] = SourceVolume * 1.0f * ListenerGain; + drysend[1] = SourceVolume * 1.0f * ListenerGain; + drysend[2] = SourceVolume * 1.0f * ListenerGain; + drysend[3] = SourceVolume * 1.0f * ListenerGain; + wetsend[0] = SourceVolume * 0.0f * ListenerGain; + wetsend[1] = SourceVolume * 0.0f * ListenerGain; + wetsend[2] = SourceVolume * 0.0f * ListenerGain; + wetsend[3] = SourceVolume * 0.0f * ListenerGain; + + pitch[0] = Pitch; + } +} + +ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum format) +{ + static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS]; + static float WetBuffer[BUFFERSIZE][OUTPUTCHANNELS]; + ALfloat DrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f }; + ALfloat WetSend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f }; + ALuint BlockAlign,BufferSize; + ALuint DataSize=0,DataPosInt=0,DataPosFrac=0; + ALuint Channels,Bits,Frequency,ulExtraSamples; + ALfloat Pitch; + ALint Looping,increment,State; + ALuint Buffer,fraction; + ALuint SamplesToDo; + ALsource *ALSource; + ALbuffer *ALBuffer; + ALfloat value; + ALshort *Data; + ALuint i,j,k; + ALbufferlistitem *BufferListItem; + ALuint loop; + ALint64 DataSize64,DataPos64; + + SuspendContext(ALContext); + + if(buffer) + { + //Figure output format variables + BlockAlign = aluChannelsFromFormat(format) * + aluBytesFromFormat(format); + + size /= BlockAlign; + while(size > 0) + { + //Setup variables + ALSource = ALContext->Source; + SamplesToDo = min(size, BUFFERSIZE); + + //Clear mixing buffer + memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat)); + memset(WetBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat)); + + //Actual mixing loop + while(ALSource) + { + j = 0; + State = ALSource->state; + while(State == AL_PLAYING && j < SamplesToDo) + { + DataSize = 0; + DataPosInt = 0; + DataPosFrac = 0; + + //Get buffer info + if((Buffer = ALSource->ulBufferID)) + { + ALBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(Buffer); + + Data = ALBuffer->data; + Bits = aluBytesFromFormat(ALBuffer->format) * 8; + Channels = aluChannelsFromFormat(ALBuffer->format); + DataSize = ALBuffer->size; + Frequency = ALBuffer->frequency; + + CalcSourceParams(ALContext, ALSource, + (Channels==1) ? AL_TRUE : AL_FALSE, + format, DrySend, WetSend, &Pitch); + + + Pitch = (Pitch*Frequency) / ALContext->Frequency; + DataSize = DataSize / (Bits*Channels/8); + + //Get source info + DataPosInt = ALSource->position; + DataPosFrac = ALSource->position_fraction; + + //Compute 18.14 fixed point step + increment = aluF2L(Pitch*(1L<<FRACTIONBITS)); + if(increment > (MAX_PITCH<<FRACTIONBITS)) + increment = (MAX_PITCH<<FRACTIONBITS); + + //Figure out how many samples we can mix. + //Pitch must be <= 4 (the number below !) + DataSize64 = DataSize+MAX_PITCH; + DataSize64 <<= FRACTIONBITS; + DataPos64 = DataPosInt; + DataPos64 <<= FRACTIONBITS; + DataPos64 += DataPosFrac; + BufferSize = (ALuint)((DataSize64-DataPos64) / increment); + BufferListItem = ALSource->queue; + for(loop = 0; loop < ALSource->BuffersPlayed; loop++) + { + if(BufferListItem) + BufferListItem = BufferListItem->next; + } + if (BufferListItem) + { + if (BufferListItem->next) + { + if(BufferListItem->next->buffer && + ((ALbuffer*)ALTHUNK_LOOKUPENTRY(BufferListItem->next->buffer))->data) + { + ulExtraSamples = min(((ALbuffer*)ALTHUNK_LOOKUPENTRY(BufferListItem->next->buffer))->size, (ALint)(16*Channels)); + memcpy(&Data[DataSize*Channels], ((ALbuffer*)ALTHUNK_LOOKUPENTRY(BufferListItem->next->buffer))->data, ulExtraSamples); + } + } + else if (ALSource->bLooping) + { + if (ALSource->queue->buffer) + { + if(((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALSource->queue->buffer))->data) + { + ulExtraSamples = min(((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALSource->queue->buffer))->size, (ALint)(16*Channels)); + memcpy(&Data[DataSize*Channels], ((ALbuffer*)ALTHUNK_LOOKUPENTRY(ALSource->queue->buffer))->data, ulExtraSamples); + } + } + } + } + BufferSize = min(BufferSize, (SamplesToDo-j)); + + //Actual sample mixing loop + Data += DataPosInt*Channels; + while(BufferSize--) + { + k = DataPosFrac>>FRACTIONBITS; + fraction = DataPosFrac&FRACTIONMASK; + if(Channels==1) + { + //First order interpolator + value = (ALfloat)((ALshort)(((Data[k]*((1L<<FRACTIONBITS)-fraction))+(Data[k+1]*(fraction)))>>FRACTIONBITS)); + //Direct path final mix buffer and panning + DryBuffer[j][0] += value*DrySend[0]; + DryBuffer[j][1] += value*DrySend[1]; + DryBuffer[j][2] += value*DrySend[2]; + DryBuffer[j][3] += value*DrySend[3]; + //Room path final mix buffer and panning + WetBuffer[j][0] += value*WetSend[0]; + WetBuffer[j][1] += value*WetSend[1]; + WetBuffer[j][2] += value*WetSend[2]; + WetBuffer[j][3] += value*WetSend[3]; + } + else + { + //First order interpolator (left) + value = (ALfloat)((ALshort)(((Data[k*2 ]*((1L<<FRACTIONBITS)-fraction))+(Data[k*2+2]*(fraction)))>>FRACTIONBITS)); + //Direct path final mix buffer and panning (left) + DryBuffer[j][0] += value*DrySend[0]; + //Room path final mix buffer and panning (left) + WetBuffer[j][0] += value*WetSend[0]; + //First order interpolator (right) + value = (ALfloat)((ALshort)(((Data[k*2+1]*((1L<<FRACTIONBITS)-fraction))+(Data[k*2+3]*(fraction)))>>FRACTIONBITS)); + //Direct path final mix buffer and panning (right) + DryBuffer[j][1] += value*DrySend[1]; + //Room path final mix buffer and panning (right) + WetBuffer[j][1] += value*WetSend[1]; + } + DataPosFrac += increment; + j++; + } + DataPosInt += (DataPosFrac>>FRACTIONBITS); + DataPosFrac = (DataPosFrac&FRACTIONMASK); + + //Update source info + ALSource->position = DataPosInt; + ALSource->position_fraction = DataPosFrac; + } + + //Handle looping sources + if(!Buffer || DataPosInt >= DataSize) + { + //queueing + if(ALSource->queue) + { + Looping = ALSource->bLooping; + if(ALSource->BuffersPlayed < (ALSource->BuffersInQueue-1)) + { + BufferListItem = ALSource->queue; + for(loop = 0; loop <= ALSource->BuffersPlayed; loop++) + { + if(BufferListItem) + { + if(!Looping) + BufferListItem->bufferstate = PROCESSED; + BufferListItem = BufferListItem->next; + } + } + if(!Looping) + ALSource->BuffersProcessed++; + if(BufferListItem) + ALSource->ulBufferID = BufferListItem->buffer; + ALSource->position = DataPosInt-DataSize; + ALSource->position_fraction = DataPosFrac; + ALSource->BuffersPlayed++; + } + else + { + if(!Looping) + { + /* alSourceStop */ + ALSource->state = AL_STOPPED; + ALSource->inuse = AL_FALSE; + ALSource->BuffersPlayed = ALSource->BuffersProcessed = ALSource->BuffersInQueue; + BufferListItem = ALSource->queue; + while(BufferListItem != NULL) + { + BufferListItem->bufferstate = PROCESSED; + BufferListItem = BufferListItem->next; + } + } + else + { + /* alSourceRewind */ + /* alSourcePlay */ + ALSource->state = AL_PLAYING; + ALSource->inuse = AL_TRUE; + ALSource->play = AL_TRUE; + ALSource->BuffersPlayed = 0; + ALSource->BufferPosition = 0; + ALSource->lBytesPlayed = 0; + ALSource->BuffersProcessed = 0; + BufferListItem = ALSource->queue; + while(BufferListItem != NULL) + { + BufferListItem->bufferstate = PENDING; + BufferListItem = BufferListItem->next; + } + ALSource->ulBufferID = ALSource->queue->buffer; + + ALSource->position = DataPosInt-DataSize; + ALSource->position_fraction = DataPosFrac; + } + } + } + } + + //Get source state + State = ALSource->state; + } + + ALSource = ALSource->next; + } + + //Post processing loop + switch(format) + { + case AL_FORMAT_MONO8: + for(i = 0;i < SamplesToDo;i++) + { + *((ALubyte*)buffer) = (aluF2S(DryBuffer[i][0]+DryBuffer[i][1]+WetBuffer[i][0]+WetBuffer[i][1])>>8)+128; + buffer = ((ALubyte*)buffer) + 1; + } + break; + case AL_FORMAT_STEREO8: + for(i = 0;i < SamplesToDo*2;i++) + { + *((ALubyte*)buffer) = (aluF2S(DryBuffer[i>>1][i&1]+WetBuffer[i>>1][i&1])>>8)+128; + buffer = ((ALubyte*)buffer) + 1; + } + break; + case AL_FORMAT_QUAD8: + for(i = 0;i < SamplesToDo*4;i++) + { + *((ALubyte*)buffer) = (aluF2S(DryBuffer[i>>2][i&3]+WetBuffer[i>>2][i&3])>>8)+128; + buffer = ((ALubyte*)buffer) + 1; + } + break; + case AL_FORMAT_MONO16: + for(i = 0;i < SamplesToDo;i++) + { + *((ALshort*)buffer) = aluF2S(DryBuffer[i][0]+DryBuffer[i][1]+WetBuffer[i][0]+WetBuffer[i][1]); + buffer = ((ALshort*)buffer) + 1; + } + break; + case AL_FORMAT_STEREO16: + default: + for(i = 0;i < SamplesToDo*2;i++) + { + *((ALshort*)buffer) = aluF2S(DryBuffer[i>>1][i&1]+WetBuffer[i>>1][i&1]); + buffer = ((ALshort*)buffer) + 1; + } + break; + case AL_FORMAT_QUAD16: + for(i = 0;i < SamplesToDo*4;i++) + { + *((ALshort*)buffer) = aluF2S(DryBuffer[i>>2][i&3]+WetBuffer[i>>2][i&3]); + buffer = ((ALshort*)buffer) + 1; + } + break; + } + + size -= SamplesToDo; + } + } + + ProcessContext(ALContext); +} diff --git a/CMakeConf/.empty b/CMakeConf/.empty new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/CMakeConf/.empty diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..a414c493 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,256 @@ +# CMake build file list for OpenAL + +INCLUDE(CheckLibraryExists) +INCLUDE(CheckIncludeFile) +INCLUDE(CheckCCompilerFlag) +INCLUDE(CheckCSourceCompiles) +INCLUDE(CheckTypeSize) + + +PROJECT(OpenAL) + + +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE) + + +OPTION(ALSA "ALSA backend" ON) +OPTION(OSS "OSS backend" ON) +OPTION(DSOUND "DirectSound backend" ON) + +OPTION(DLOPEN "Use the dlopen API for loading optional libs" ON) + +OPTION(DEBUG "Build lib in debug mode" OFF) +OPTION(NODEBUG "Disable all debug info for optimizations" OFF) +OPTION(WERROR "Treat compile warnings as errors" OFF) + + +SET(LIB_MAJOR_VERSION "1") +SET(LIB_MINOR_VERSION "0") +SET(LIB_BUILD_VERSION "0") +SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_BUILD_VERSION}") + + +IF("${WIN32}") + SET(LIBNAME openal32) +ELSE() + SET(LIBNAME openal) +ENDIF() + + +CHECK_TYPE_SIZE("long" SIZEOF_LONG) +CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) +CHECK_TYPE_SIZE("unsigned int" SIZEOF_UINT) +CHECK_TYPE_SIZE("void*" SIZEOF_VOIDP) + + +# Add definitions, compiler switches, etc. +INCLUDE_DIRECTORIES(OpenAL32/Include include "${OpenAL_BINARY_DIR}") +SET(EXTRA_LIBS m ${EXTRA_LIBS}) + +IF("${MSVC}") + # ??? +ELSE() + ADD_DEFINITIONS(-W -Wall) + IF(WERROR) + ADD_DEFINITIONS(-Werror) + ENDIF() + IF(DEBUG) + ADD_DEFINITIONS(-g3) + ELSEIF(NODEBUG) + ADD_DEFINITIONS(-O2 -funroll-loops -fomit-frame-pointer) + ELSE() + ADD_DEFINITIONS(-g -O2 -funroll-loops) + ENDIF() + + # The mixer doesn't like GCC's strict aliasing optimizations. Make sure + # it's turned off + CHECK_C_COMPILER_FLAG(-fstrict-aliasing HAVE_STRICT_ALIASING) + IF("${HAVE_STRICT_ALIASING}") + ADD_DEFINITIONS(-fno-strict-aliasing) + ENDIF() + + # Set visibility options if available + IF(NOT "${WIN32}") + CHECK_C_SOURCE_COMPILES("int foo() __attribute__((visibility(\"default\"))); + int main() {return 0;}" HAVE_GCC_VISIBILITY) + IF("${HAVE_GCC_VISIBILITY}") + ADD_DEFINITIONS(-fvisibility=hidden -DHAVE_GCC_VISIBILITY) + ENDIF() + ENDIF() +ENDIF() + +CHECK_LIBRARY_EXISTS(m sqrtf "" HAVE_SQRTF) +CHECK_LIBRARY_EXISTS("" strtof "" HAVE_STRTOF) + +CHECK_LIBRARY_EXISTS("" strcasecmp "" HAVE_STRCASECMP) +IF(NOT "${HAVE_STRCASECMP}") + CHECK_LIBRARY_EXISTS("" _stricmp "" HAVE__STRICMP) + IF(NOT "${HAVE__STRICMP}") + MESSAGE(FATAL_ERROR "No case-insensitive compare function found, please report!") + ENDIF() + + ADD_DEFINITIONS(-Dstrcasecmp=_stricmp) +ENDIF() + +# Check for the dlopen API (for dynamicly loading backend libs) +IF(DLOPEN) + CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H) + IF("${HAVE_DLFCN_H}") + CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL) + IF("${HAVE_LIBDL}") + SET(EXTRA_LIBS dl ${EXTRA_LIBS}) + ENDIF() + ENDIF() +ENDIF() + +# Check if we have Windows headers +CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H) +IF(NOT "${HAVE_WINDOWS_H}") + # We need pthreads outside of Windows + CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H) + IF(NOT "${HAVE_PTHREAD_H}") + MESSAGE(FATAL_ERROR "PThreads is required for non-Windows builds!") + ENDIF() + + # _GNU_SOURCE is needed on some systems for extra attributes, and + # _REENTRANT is needed for libc thread-safety + ADD_DEFINITIONS(-D_GNU_SOURCE=1 -D_REENTRANT) + CHECK_LIBRARY_EXISTS(pthread pthread_create "" HAVE_LIBPTHREAD) + IF("${HAVE_LIBPTHREAD}") + SET(EXTRA_LIBS pthread ${EXTRA_LIBS}) + ENDIF() +ENDIF() + +# Check for a 64-bit type +CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H) +IF(NOT "${HAVE_STDINT_H}") + IF("${HAVE_WINDOWS_H}") + CHECK_C_SOURCE_COMPILES("\#include <windows.h> + __int64 foo; + int main() {return 0;}" HAVE___INT64) + ENDIF() + IF(NOT "${HAVE___INT64}") + IF(NOT "${SIZEOF_LONG}" MATCHES "8") + IF(NOT "${SIZEOF_LONG_LONG}" MATCHES "8") + MESSAGE(FATAL_ERROR "No 64-bit types found, please report!") + ENDIF() + ENDIF() + ENDIF() +ENDIF() + + +SET(OPENAL_OBJS OpenAL32/alBuffer.c + OpenAL32/alError.c + OpenAL32/alExtension.c + OpenAL32/alListener.c + OpenAL32/alSource.c + OpenAL32/alState.c + OpenAL32/alThunk.c + OpenAL32/OpenAL32.c +) +SET(ALU_OBJS Alu/ALu.c) +SET(ALC_OBJS Alc/ALc.c + Alc/alcConfig.c + Alc/alcThread.c +) + +SET(BACKENDS "") + +# Check ALSA backend +IF(ALSA) + CHECK_INCLUDE_FILE(alsa/asoundlib.h HAVE_ALSA_ASOUNDLIB_H) + IF("${HAVE_ALSA_ASOUNDLIB_H}") + CHECK_LIBRARY_EXISTS(asound snd_pcm_open "" HAVE_LIBASOUND) + IF("${HAVE_DLFCN_H}" OR "${HAVE_LIBASOUND}") + SET(HAVE_ALSA 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/alsa.c) + IF("${HAVE_DLFCN_H}") + SET(BACKENDS ${BACKENDS} ALSA) + ELSE() + SET(BACKENDS ${BACKENDS} ALSA\(linked\)) + SET(EXTRA_LIBS asound ${EXTRA_LIBS}) + ENDIF() + ENDIF() + ENDIF() +ENDIF() + +# Check OSS backend +IF(OSS) + CHECK_INCLUDE_FILE(sys/soundcard.h HAVE_SYS_SOUNDCARD_H) + IF("${HAVE_SYS_SOUNDCARD_H}") + SET(HAVE_OSS 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/oss.c) + SET(BACKENDS ${BACKENDS} OSS) + ENDIF() +ENDIF() + +# Check DSound/MMSystem backend +IF(DSOUND) + IF("${HAVE_WINDOWS_H}") + SET(CMAKE_REQUIRED_LIBRARIES ole32) + CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBOLE32) + SET(CMAKE_REQUIRED_LIBRARIES "") +# CHECK_LIBRARY_EXISTS(ole32 CoInitialize "" HAVE_LIBOLE32) + IF("${HAVE_LIBOLE32}") + SET(EXTRA_LIBS ole32 ${EXTRA_LIBS}) + ENDIF() + + CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H) + IF("${HAVE_DSOUND_H}") + SET(HAVE_DSOUND 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c) + SET(BACKENDS ${BACKENDS} DirectSound) + + CHECK_LIBRARY_EXISTS(dxguid IID_IDirectSound "" HAVE_LIBDXGUID) + IF("${HAVE_LIBDXGUID}") + SET(EXTRA_LIBS dxguid ${EXTRA_LIBS}) + ENDIF() + ENDIF() + + CHECK_C_SOURCE_COMPILES("\#include <windows.h> + \#include <mmsystem.h> + int main() {return 0;}" HAVE_MMSYSTEM_H) + IF("${HAVE_MMSYSTEM_H}") + SET(HAVE_WINMM 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/winmm.c) + SET(BACKENDS ${BACKENDS} WinMM) + + SET(CMAKE_REQUIRED_LIBRARIES winmm) + CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBWINMM) + SET(CMAKE_REQUIRED_LIBRARIES "") +# CHECK_LIBRARY_EXISTS(winmm waveInOpen "" HAVE_LIBWINMM) + IF("${HAVE_LIBWINMM}") + SET(EXTRA_LIBS winmm ${EXTRA_LIBS}) + ENDIF() + ENDIF() + ENDIF() +ENDIF() + +# End configuration +CONFIGURE_FILE( + "${OpenAL_SOURCE_DIR}/config.h.in" + "${OpenAL_BINARY_DIR}/config.h") + +ADD_DEFINITIONS(-DAL_BUILD_LIBRARY) + +# Build a shared library +ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALU_OBJS} ${ALC_OBJS}) +SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION}) + +TARGET_LINK_LIBRARIES(${LIBNAME} ${EXTRA_LIBS}) + +# Add an install target here +INSTALL(TARGETS ${LIBNAME} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) +INSTALL(FILES include/AL/al.h + include/AL/alc.h + DESTINATION include/AL +) + +MESSAGE(STATUS "") +MESSAGE(STATUS "Building OpenAL with support for the following backends:") +MESSAGE(STATUS " ${BACKENDS}") +MESSAGE(STATUS "") diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..d0c89786 --- /dev/null +++ b/COPYING @@ -0,0 +1,484 @@ + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + 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; +} diff --git a/Router/OpenAL32.cpp b/Router/OpenAL32.cpp new file mode 100644 index 00000000..8c84148b --- /dev/null +++ b/Router/OpenAL32.cpp @@ -0,0 +1,135 @@ +/** + * 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 <windows.h> +#include "OpenAL32.h" + + +void CleanDeviceEnumeration(); +void CleanDeviceList(ALDEVICE *pDeviceList); + +//***************************************************************************** +// DllMain +//***************************************************************************** +// +BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID reserved) +{ + BOOL result = TRUE; + + // Perform actions based on the reason for calling. + switch(reason) + { + case DLL_PROCESS_ATTACH: + // Create the context list lock so I can safely add/remove contexts. + result = alListCreate(&alContextList); + break; + + case DLL_THREAD_ATTACH: + // Do thread-specific initialization. + break; + + case DLL_THREAD_DETACH: + // Do thread-specific cleanup. + break; + + case DLL_PROCESS_DETACH: + // Perform any necessary cleanup. + CleanDeviceEnumeration(); + alListFree(alContextList); + alContextList = 0; + break; + } + + return TRUE; +} + + +void CleanDeviceEnumeration() +{ + if (pszDefaultDeviceSpecifier) + { + free(pszDefaultDeviceSpecifier); + pszDefaultDeviceSpecifier = NULL; + } + + if (pszDeviceSpecifierList) + { + free(pszDeviceSpecifierList); + pszDeviceSpecifierList = NULL; + } + + if (pszDefaultCaptureDeviceSpecifier) + { + free(pszDefaultCaptureDeviceSpecifier); + pszDefaultCaptureDeviceSpecifier = NULL; + } + + if (pszCaptureDeviceSpecifierList) + { + free(pszCaptureDeviceSpecifierList); + pszCaptureDeviceSpecifierList = NULL; + } + + if (pszDefaultAllDevicesSpecifier) + { + free(pszDefaultAllDevicesSpecifier); + pszDefaultAllDevicesSpecifier = NULL; + } + + if (pszAllDevicesSpecifierList) + { + free(pszAllDevicesSpecifierList); + pszAllDevicesSpecifierList = NULL; + } + + CleanDeviceList(g_pDeviceList); + g_pDeviceList = NULL; + + CleanDeviceList(g_pCaptureDeviceList); + g_pCaptureDeviceList = NULL; + + CleanDeviceList(g_pAllDevicesList); + g_pAllDevicesList = NULL; +} + +void CleanDeviceList(ALDEVICE *pDeviceList) +{ + ALDEVICE *pDevice, *pNextDevice; + + pDevice = pDeviceList; + + while (pDevice) + { + pNextDevice = pDevice->pNextDevice; + + if (pDevice->pszHostDLLFilename) + free(pDevice->pszHostDLLFilename); + + if (pDevice->pszDeviceName) + free(pDevice->pszDeviceName); + + free(pDevice); + + pDevice = pNextDevice; + } +}
\ No newline at end of file diff --git a/Router/OpenAL32.h b/Router/OpenAL32.h new file mode 100644 index 00000000..a291a5a8 --- /dev/null +++ b/Router/OpenAL32.h @@ -0,0 +1,341 @@ +/** + * 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 + */ + + + + +#ifndef _OPENAL32_H_ +#define _OPENAL32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AL_BUILD_LIBRARY + +#include "al\al.h" + +// ALAPI +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_ENABLE)(ALenum capability); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_DISABLE)(ALenum capability); +typedef ALAPI ALboolean (ALAPIENTRY *ALAPI_IS_ENABLED)(ALenum capability); + +typedef ALAPI const ALchar* (ALAPIENTRY *ALAPI_GET_STRING)(ALenum param); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_BOOLEANV)(ALenum param, ALboolean* data); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_INTEGERV)(ALenum param, ALint* data); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_FLOATV)(ALenum param, ALfloat* data); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_DOUBLEV)(ALenum param, ALdouble* data); +typedef ALAPI ALboolean (ALAPIENTRY *ALAPI_GET_BOOLEAN)(ALenum param); +typedef ALAPI ALint (ALAPIENTRY *ALAPI_GET_INTEGER)(ALenum param); +typedef ALAPI ALfloat (ALAPIENTRY *ALAPI_GET_FLOAT)(ALenum param); +typedef ALAPI ALdouble (ALAPIENTRY *ALAPI_GET_DOUBLE)(ALenum param); + +typedef ALAPI ALenum (ALAPIENTRY *ALAPI_GET_ERROR)(ALvoid); + +typedef ALAPI ALboolean (ALAPIENTRY *ALAPI_IS_EXTENSION_PRESENT)(const ALchar* ename); +typedef ALAPI ALvoid* (ALAPIENTRY *ALAPI_GET_PROC_ADDRESS)(const ALchar* fname); +typedef ALAPI ALenum (ALAPIENTRY *ALAPI_GET_ENUM_VALUE)(const ALchar* ename); + +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_LISTENERF)(ALenum param, ALfloat value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_LISTENER3F)(ALenum param, ALfloat v1, ALfloat v2, ALfloat v3); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_LISTENERFV)(ALenum param, const ALfloat* values); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_LISTENERI)(ALenum param, ALint value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_LISTENER3I)( ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_LISTENERIV)( ALenum param, const ALint* values ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_LISTENERF)(ALenum param, ALfloat* value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_LISTENER3F)(ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_LISTENERFV)(ALenum param, ALfloat* values); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_LISTENERI)(ALenum param, ALint* value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_LISTENER3I)( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_LISTENERIV)( ALenum param, ALint* values ); + +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GEN_SOURCES)(ALsizei n, ALuint* sourceNames); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_DELETE_SOURCES)(ALsizei n, const ALuint* sourceNames); +typedef ALAPI ALboolean (ALAPIENTRY *ALAPI_IS_SOURCE)(ALuint id); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCEF)(ALuint sourceName, ALenum param, ALfloat value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE3F)(ALuint sourceName, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCEFV)(ALuint sourceName, ALenum param, const ALfloat* values); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCEI)(ALuint sourceName, ALenum param, ALint value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE3I)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCEIV)( ALuint sid, ALenum param, const ALint* values ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_SOURCEF)(ALuint sourceName, ALenum param, ALfloat* value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_SOURCE3F)(ALuint sourceName, ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_SOURCEFV)(ALuint sourceName, ALenum param, const ALfloat* values); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_SOURCEI)(ALuint sourceName, ALenum param, ALint* value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_SOURCE3I)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_SOURCEIV)( ALuint sid, ALenum param, ALint* values ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_PLAYV)(ALsizei n, const ALuint* sources); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_STOPV)(ALsizei n, const ALuint* sources); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_REWINDV)(ALsizei n, const ALuint* sources); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_PAUSEV)(ALsizei n, const ALuint* sources); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_PLAY)(ALuint sourceName); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_STOP)(ALuint sourceName); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_REWIND)(ALuint sourceName); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_PAUSE)(ALuint sourceName); + +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_QUEUE_BUFFERS)(ALuint sourceName, ALsizei n, const ALuint* bufferNames); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SOURCE_UNQUEUE_BUFFERS)(ALuint sourceName, ALsizei n, ALuint* bufferNames); + +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GEN_BUFFERS)(ALsizei n, ALuint* bufferNames); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_DELETE_BUFFERS)(ALsizei n, const ALuint* bufferNames); +typedef ALAPI ALboolean (ALAPIENTRY *ALAPI_IS_BUFFER)(ALuint bufferName); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_BUFFER_DATA)(ALuint bufferName, ALenum format, const ALvoid* data, ALsizei size, ALuint freq); + +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_BUFFERF)( ALuint bid, ALenum param, ALfloat value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_BUFFER3F)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_BUFFERFV)( ALuint bid, ALenum param, const ALfloat* values ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_BUFFERI)( ALuint bid, ALenum param, ALint value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_BUFFER3I)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_BUFFERIV)( ALuint bid, ALenum param, const ALint* values ); + +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_BUFFERF)( ALuint bid, ALenum param, ALfloat* value ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_BUFFER3F)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_BUFFERFV)( ALuint bid, ALenum param, ALfloat* values ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_BUFFERI)( ALuint bid, ALenum param, ALint* value ); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_BUFFER3I)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_GET_BUFFERIV)( ALuint bid, ALenum param, ALint* values ); + +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_DOPPLER_FACTOR)(ALfloat value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_DOPPLER_VELOCITY)(ALfloat value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_SPEED_OF_SOUND)(ALfloat value); +typedef ALAPI ALvoid (ALAPIENTRY *ALAPI_DISTANCE_MODEL)(ALenum value); + +typedef struct ALAPI_FXN_TABLE_STRUCT +{ + ALAPI_ENABLE alEnable; + ALAPI_DISABLE alDisable; + ALAPI_IS_ENABLED alIsEnabled; + + ALAPI_GET_STRING alGetString; + ALAPI_GET_BOOLEANV alGetBooleanv; + ALAPI_GET_INTEGERV alGetIntegerv; + ALAPI_GET_FLOATV alGetFloatv; + ALAPI_GET_DOUBLEV alGetDoublev; + ALAPI_GET_BOOLEAN alGetBoolean; + ALAPI_GET_INTEGER alGetInteger; + ALAPI_GET_FLOAT alGetFloat; + ALAPI_GET_DOUBLE alGetDouble; + + ALAPI_GET_ERROR alGetError; + + ALAPI_IS_EXTENSION_PRESENT alIsExtensionPresent; + ALAPI_GET_PROC_ADDRESS alGetProcAddress; + ALAPI_GET_ENUM_VALUE alGetEnumValue; + + ALAPI_LISTENERF alListenerf; + ALAPI_LISTENER3F alListener3f; + ALAPI_LISTENERFV alListenerfv; + ALAPI_LISTENERI alListeneri; + ALAPI_LISTENER3I alListener3i; + ALAPI_LISTENERIV alListeneriv; + + ALAPI_GET_LISTENERF alGetListenerf; + ALAPI_GET_LISTENER3F alGetListener3f; + ALAPI_GET_LISTENERFV alGetListenerfv; + ALAPI_GET_LISTENERI alGetListeneri; + ALAPI_GET_LISTENER3I alGetListener3i; + ALAPI_GET_LISTENERIV alGetListeneriv; + + ALAPI_GEN_SOURCES alGenSources; + ALAPI_DELETE_SOURCES alDeleteSources; + ALAPI_IS_SOURCE alIsSource; + ALAPI_SOURCEF alSourcef; + ALAPI_SOURCE3F alSource3f; + ALAPI_SOURCEFV alSourcefv; + ALAPI_SOURCEI alSourcei; + ALAPI_SOURCE3I alSource3i; + ALAPI_SOURCEIV alSourceiv; + ALAPI_GET_SOURCEF alGetSourcef; + ALAPI_GET_SOURCE3F alGetSource3f; + ALAPI_GET_SOURCEFV alGetSourcefv; + ALAPI_GET_SOURCEI alGetSourcei; + ALAPI_GET_SOURCE3I alGetSource3i; + ALAPI_GET_SOURCEIV alGetSourceiv; + ALAPI_SOURCE_PLAYV alSourcePlayv; + ALAPI_SOURCE_STOPV alSourceStopv; + ALAPI_SOURCE_REWINDV alSourceRewindv; + ALAPI_SOURCE_PAUSEV alSourcePausev; + ALAPI_SOURCE_PLAY alSourcePlay; + ALAPI_SOURCE_STOP alSourceStop; + ALAPI_SOURCE_REWIND alSourceRewind; + ALAPI_SOURCE_PAUSE alSourcePause; + + ALAPI_SOURCE_QUEUE_BUFFERS alSourceQueueBuffers; + ALAPI_SOURCE_UNQUEUE_BUFFERS alSourceUnqueueBuffers; + + ALAPI_GEN_BUFFERS alGenBuffers; + ALAPI_DELETE_BUFFERS alDeleteBuffers; + ALAPI_IS_BUFFER alIsBuffer; + ALAPI_BUFFER_DATA alBufferData; + ALAPI_BUFFERF alBufferf; + ALAPI_BUFFER3F alBuffer3f; + ALAPI_BUFFERFV alBufferfv; + ALAPI_BUFFERI alBufferi; + ALAPI_BUFFER3I alBuffer3i; + ALAPI_BUFFERIV alBufferiv; + ALAPI_GET_BUFFERF alGetBufferf; + ALAPI_GET_BUFFER3F alGetBuffer3f; + ALAPI_GET_BUFFERFV alGetBufferfv; + ALAPI_GET_BUFFERI alGetBufferi; + ALAPI_GET_BUFFER3I alGetBuffer3i; + ALAPI_GET_BUFFERIV alGetBufferiv; + + ALAPI_DOPPLER_FACTOR alDopplerFactor; + ALAPI_DOPPLER_VELOCITY alDopplerVelocity; + ALAPI_SPEED_OF_SOUND alSpeedOfSound; + ALAPI_DISTANCE_MODEL alDistanceModel; + +} ALAPI_FXN_TABLE; + +#include "al\alc.h" + +// ALCAPI +typedef struct ALCdevice_struct ALCdevice; +typedef struct ALCcontext_struct ALCcontext; + +typedef ALCAPI ALCcontext* (ALCAPIENTRY *ALCAPI_CREATE_CONTEXT)(ALCdevice* device, const ALint* attrList); +typedef ALCAPI ALboolean (ALCAPIENTRY *ALCAPI_MAKE_CONTEXT_CURRENT)(ALCcontext* context); +typedef ALCAPI ALvoid (ALCAPIENTRY *ALCAPI_PROCESS_CONTEXT)(ALCcontext* context); +typedef ALCAPI ALCvoid (ALCAPIENTRY *ALCAPI_SUSPEND_CONTEXT)(ALCcontext* context); +typedef ALCAPI ALvoid (ALCAPIENTRY *ALCAPI_DESTROY_CONTEXT)(ALCcontext* context); +typedef ALCAPI ALCcontext* (ALCAPIENTRY *ALCAPI_GET_CURRENT_CONTEXT)(ALvoid); +typedef ALCAPI ALCdevice* (ALCAPIENTRY *ALCAPI_GET_CONTEXTS_DEVICE)(ALCcontext* context); + +typedef ALCAPI ALCdevice* (ALCAPIENTRY *ALCAPI_OPEN_DEVICE)(const ALCchar* deviceName); +typedef ALCAPI ALCboolean (ALCAPIENTRY *ALCAPI_CLOSE_DEVICE)(ALCdevice* device); + +typedef ALCAPI ALenum (ALCAPIENTRY *ALCAPI_GET_ERROR)(ALCdevice* device); + +typedef ALCAPI ALboolean (ALCAPIENTRY *ALCAPI_IS_EXTENSION_PRESENT)(ALCdevice* device, const ALCchar* eName); +typedef ALCAPI ALvoid* (ALCAPIENTRY *ALCAPI_GET_PROC_ADDRESS)(ALCdevice* device, const ALCchar* fName); +typedef ALCAPI ALenum (ALCAPIENTRY *ALCAPI_GET_ENUM_VALUE)(ALCdevice* device, const ALCchar* eName); + +typedef ALCAPI const ALCchar* (ALCAPIENTRY *ALCAPI_GET_STRING)(ALCdevice* device, ALenum param); +typedef ALCAPI ALvoid (ALCAPIENTRY *ALCAPI_GET_INTEGERV)(ALCdevice* device, ALenum param, ALsizei size, ALint* data); + +typedef ALCAPI ALCdevice * (ALCAPIENTRY *ALCAPI_CAPTURE_OPEN_DEVICE)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); +typedef ALCAPI ALCboolean (ALCAPIENTRY *ALCAPI_CAPTURE_CLOSE_DEVICE)( ALCdevice *device ); +typedef ALCAPI void (ALCAPIENTRY *ALCAPI_CAPTURE_START)( ALCdevice *device ); +typedef ALCAPI void (ALCAPIENTRY *ALCAPI_CAPTURE_STOP)( ALCdevice *device ); +typedef ALCAPI void (ALCAPIENTRY *ALCAPI_CAPTURE_SAMPLES)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + +typedef struct ALCAPI_FXN_TABLE_STRUCT +{ + ALCAPI_CREATE_CONTEXT alcCreateContext; + ALCAPI_MAKE_CONTEXT_CURRENT alcMakeContextCurrent; + ALCAPI_PROCESS_CONTEXT alcProcessContext; + ALCAPI_SUSPEND_CONTEXT alcSuspendContext; + ALCAPI_DESTROY_CONTEXT alcDestroyContext; + ALCAPI_GET_CURRENT_CONTEXT alcGetCurrentContext; + ALCAPI_GET_CONTEXTS_DEVICE alcGetContextsDevice; + + ALCAPI_OPEN_DEVICE alcOpenDevice; + ALCAPI_CLOSE_DEVICE alcCloseDevice; + + ALCAPI_GET_ERROR alcGetError; + + ALCAPI_IS_EXTENSION_PRESENT alcIsExtensionPresent; + ALCAPI_GET_PROC_ADDRESS alcGetProcAddress; + ALCAPI_GET_ENUM_VALUE alcGetEnumValue; + + ALCAPI_GET_STRING alcGetString; + ALCAPI_GET_INTEGERV alcGetIntegerv; + + ALCAPI_CAPTURE_OPEN_DEVICE alcCaptureOpenDevice; + ALCAPI_CAPTURE_CLOSE_DEVICE alcCaptureCloseDevice; + ALCAPI_CAPTURE_START alcCaptureStart; + ALCAPI_CAPTURE_STOP alcCaptureStop; + ALCAPI_CAPTURE_SAMPLES alcCaptureSamples; + +} ALCAPI_FXN_TABLE; + +#include "windows.h" +#include "alList.h" + + +//***************************************************************************** +// Additional Defines +//***************************************************************************** + +typedef struct ALCdevice_struct +{ + // + // These variables must always be initialized. + // + ALenum LastError; + ALint InUse; + + // + // Support for 3rd party OpenAL implementations. + // + HINSTANCE Dll; + ALCAPI_FXN_TABLE AlcApi; + + // Capture Device + ALCdevice* CaptureDevice; + + struct ALCdevice_struct* DllDevice; + +} ALCdevice; + +typedef struct ALCcontext_struct +{ + // + // These variables are always initialized. + // + ALlistEntry ListEntry; + ALboolean Suspended; + ALenum LastError; + ALCdevice* Device; + ALAPI_FXN_TABLE AlApi; + CRITICAL_SECTION Lock; + struct ALCcontext_struct* DllContext; + +} ALCcontext; + + +extern ALlist* alContextList; +extern ALCcontext* alCurrentContext; + +// Device Enumeration structures, strings and variables +typedef struct _ALDEVICE +{ + ALchar *pszDeviceName; + TCHAR *pszHostDLLFilename; + struct _ALDEVICE *pNextDevice; +} ALDEVICE; + +extern ALchar *pszDefaultDeviceSpecifier; +extern ALchar *pszDeviceSpecifierList; +extern ALchar *pszDefaultCaptureDeviceSpecifier; +extern ALchar *pszCaptureDeviceSpecifierList; +extern ALchar *pszDefaultAllDevicesSpecifier; +extern ALchar *pszAllDevicesSpecifierList; + +extern ALDEVICE *g_pDeviceList; +extern ALDEVICE *g_pCaptureDeviceList; +extern ALDEVICE *g_pAllDevicesList; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Router/OpenAL32.rc b/Router/OpenAL32.rc new file mode 100644 index 00000000..5ddbb5b9 --- /dev/null +++ b/Router/OpenAL32.rc @@ -0,0 +1,101 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 6,14,357,23 + PRODUCTVERSION 6,14,357,23 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Portions (C) Creative Labs Inc. and NVIDIA Corp." + VALUE "FileDescription", "Standard OpenAL(TM) Implementation" + VALUE "FileVersion", "6.14.0357.23" + VALUE "LegalCopyright", "Copyright (C) 2000-2006" + VALUE "OriginalFilename", "OpenAL32.dll" + VALUE "ProductName", "Standard OpenAL(TM) Library" + VALUE "ProductVersion", "6.14.0357.23" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Router/al.cpp b/Router/al.cpp new file mode 100644 index 00000000..81e11461 --- /dev/null +++ b/Router/al.cpp @@ -0,0 +1,981 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2003 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 <al\alc.h> +#include "OpenAL32.h" + +typedef struct ALfunction_struct +{ + ALchar *funcName; + ALvoid *address; +} ALfunction; + +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 } }; + + +//***************************************************************************** +//***************************************************************************** +// +// Defines +// +//***************************************************************************** +//***************************************************************************** + + +#ifdef __MINGW32__ +// fix for Mingw32. +#define AL_VOID_FXN(fxn) \ + ALCcontext* context; \ + \ + alListAcquireLock(alContextList); \ + if(!alCurrentContext) \ + { \ + alListReleaseLock(alContextList); \ + return; \ + } \ + \ + context = alCurrentContext; \ + EnterCriticalSection(&context->Lock); \ + alListReleaseLock(alContextList); \ + \ + context->AlApi.fxn; \ + LeaveCriticalSection(&context->Lock); \ + return +#define AL_RESULT_FXN(fxn, resultType, resultDefVal) \ + resultType result = resultDefVal; \ + ALCcontext* context; \ + \ + alListAcquireLock(alContextList); \ + if(!alCurrentContext) \ + { \ + alListReleaseLock(alContextList); \ + return result; \ + } \ + \ + context = alCurrentContext; \ + EnterCriticalSection(&context->Lock); \ + alListReleaseLock(alContextList); \ + \ + result = context->AlApi.fxn; \ + LeaveCriticalSection(&context->Lock); \ + return result + +#else +#define AL_RESULT_FXN(fxn, resultType, resultDefVal) \ + resultType result = resultDefVal; \ + ALCcontext* context; \ + \ + alListAcquireLock(alContextList); \ + if(!alCurrentContext) \ + { \ + alListReleaseLock(alContextList); \ + return result; \ + } \ + \ + context = alCurrentContext; \ + EnterCriticalSection(&context->Lock); \ + alListReleaseLock(alContextList); \ + \ + result = context->AlApi.##fxn; \ + LeaveCriticalSection(&context->Lock); \ + return result + +#define AL_VOID_FXN(fxn) \ + ALCcontext* context; \ + \ + alListAcquireLock(alContextList); \ + if(!alCurrentContext) \ + { \ + alListReleaseLock(alContextList); \ + return; \ + } \ + \ + context = alCurrentContext; \ + EnterCriticalSection(&context->Lock); \ + alListReleaseLock(alContextList); \ + \ + context->AlApi.##fxn; \ + LeaveCriticalSection(&context->Lock); \ + return +#endif + + +//***************************************************************************** +//***************************************************************************** +// +// AL API Buffer Entry Points +// +//***************************************************************************** +//***************************************************************************** + +//***************************************************************************** +// alGenBuffers +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGenBuffers(ALsizei n, ALuint* bufferNames) +{ + AL_VOID_FXN(alGenBuffers(n, bufferNames)); +} + + +//***************************************************************************** +// alDeleteBuffers +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alDeleteBuffers(ALsizei n, const ALuint* bufferNames) +{ + AL_VOID_FXN(alDeleteBuffers(n, bufferNames)); +} + + +//***************************************************************************** +// alIsBuffer +//***************************************************************************** +// +ALAPI ALboolean ALAPIENTRY alIsBuffer(ALuint bufferName) +{ + AL_RESULT_FXN(alIsBuffer(bufferName), ALboolean, AL_FALSE); +} + +//***************************************************************************** +// alBuffer3f +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alBuffer3f(ALuint bufferName, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3) +{ + AL_VOID_FXN(alBuffer3f(bufferName, param, v1, v2, v3)); +} + +//***************************************************************************** +// alBuffer3i +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alBuffer3i(ALuint bufferName, ALenum param, ALint v1, ALint v2, ALint v3) +{ + AL_VOID_FXN(alBuffer3i(bufferName, param, v1, v2, v3)); +} + + +//***************************************************************************** +// alBufferData +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alBufferData(ALuint bufferName, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq) +{ + AL_VOID_FXN(alBufferData(bufferName, format, data, size, freq)); +} + + +//***************************************************************************** +// alBufferf +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alBufferf(ALuint bufferName, ALenum param, ALfloat value) +{ + AL_VOID_FXN(alBufferf(bufferName, param, value)); +} + + +//***************************************************************************** +// alBufferfv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alBufferfv(ALuint bufferName, ALenum param, const ALfloat* values) +{ + AL_VOID_FXN(alBufferfv(bufferName, param, values)); +} + + +//***************************************************************************** +// alBufferi +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alBufferi(ALuint bufferName, ALenum param, ALint value) +{ + AL_VOID_FXN(alBufferi(bufferName, param, value)); +} + + +//***************************************************************************** +// alBufferiv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alBufferiv(ALuint bufferName, ALenum param, const ALint* values) +{ + AL_VOID_FXN(alBufferiv(bufferName, param, values)); +} + +//***************************************************************************** +// alGetBuffer3f +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetBuffer3f(ALuint bufferName, ALenum param, ALfloat *v1, ALfloat *v2, ALfloat *v3) +{ + AL_VOID_FXN(alGetBuffer3f(bufferName, param, v1, v2, v3)); +} + +//***************************************************************************** +// alGetBuffer3i +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetBuffer3i(ALuint bufferName, ALenum param, ALint *v1, ALint *v2, ALint *v3) +{ + AL_VOID_FXN(alGetBuffer3i(bufferName, param, v1, v2, v3)); +} + +//***************************************************************************** +// alGetBufferf +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetBufferf(ALuint bufferName, ALenum param, ALfloat* value) +{ + AL_VOID_FXN(alGetBufferf(bufferName, param, value)); +} + +//***************************************************************************** +// alGetBufferfv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetBufferfv(ALuint bufferName, ALenum param, ALfloat* values) +{ + AL_VOID_FXN(alGetBufferfv(bufferName, param, values)); +} + + +//***************************************************************************** +// alGetBufferi +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetBufferi(ALuint bufferName, ALenum param, ALint* value) +{ + AL_VOID_FXN(alGetBufferi(bufferName, param, value)); +} + +//***************************************************************************** +// alGetBufferiv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetBufferiv(ALuint bufferName, ALenum param, ALint* values) +{ + AL_VOID_FXN(alGetBufferiv(bufferName, param, values)); +} + + +//***************************************************************************** +//***************************************************************************** +// +// AL API Generic Entry Points +// +//***************************************************************************** +//***************************************************************************** + +//***************************************************************************** +// alEnable +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alEnable(ALenum capability) +{ + AL_VOID_FXN(alEnable(capability)); +} + + +//***************************************************************************** +// alDisable +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alDisable(ALenum capability) +{ + AL_VOID_FXN(alDisable(capability)); +} + + +//***************************************************************************** +// alDopplerFactor +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alDopplerFactor(ALfloat value) +{ + AL_VOID_FXN(alDopplerFactor(value)); +} + + +//***************************************************************************** +// alDopplerVelocity +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alDopplerVelocity(ALfloat value) +{ + AL_VOID_FXN(alDopplerVelocity(value)); +} + + +//***************************************************************************** +// alSpeedOfSound +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSpeedOfSound(ALfloat value) +{ + ALCcontext* context; + + alListAcquireLock(alContextList); + if(!alCurrentContext) + { + alListReleaseLock(alContextList); + return; + } + + context = alCurrentContext; + EnterCriticalSection(&context->Lock); + alListReleaseLock(alContextList); + + if (context->AlApi.alSpeedOfSound) { // protect against talking to a 1.0 lib + context->AlApi.alSpeedOfSound(value); + } + LeaveCriticalSection(&context->Lock); + return; +} + + +//***************************************************************************** +// alDistanceModel +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alDistanceModel(ALenum value) +{ + AL_VOID_FXN(alDistanceModel(value)); +} + + +//***************************************************************************** +// alGetBoolean +//***************************************************************************** +// +ALAPI ALboolean ALAPIENTRY alGetBoolean(ALenum param) +{ + AL_RESULT_FXN(alGetBoolean(param), ALboolean, AL_FALSE); +} + + +//***************************************************************************** +// alGetBooleanv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetBooleanv(ALenum param, ALboolean* data) +{ + AL_VOID_FXN(alGetBooleanv(param, data)); +} + + +//***************************************************************************** +// alGetDouble +//***************************************************************************** +// +ALAPI ALdouble ALAPIENTRY alGetDouble(ALenum param) +{ + AL_RESULT_FXN(alGetDouble(param), ALdouble, 0.0); +} + + +//***************************************************************************** +// alGetDoublev +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetDoublev(ALenum param, ALdouble* data) +{ + AL_VOID_FXN(alGetDoublev(param, data)); +} + +//***************************************************************************** +// alGetFloat +//***************************************************************************** +// +ALAPI ALfloat ALAPIENTRY alGetFloat(ALenum param) +{ + AL_RESULT_FXN(alGetFloat(param), ALfloat, 0.0f); +} + + +//***************************************************************************** +// alGetFloatv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetFloatv(ALenum param, ALfloat* data) +{ + AL_VOID_FXN(alGetFloatv(param, data)); +} + + +//***************************************************************************** +// alGetInteger +//***************************************************************************** +// +ALAPI ALint ALAPIENTRY alGetInteger(ALenum param) +{ + AL_RESULT_FXN(alGetInteger(param), ALint, 0); +} + + +//***************************************************************************** +// alGetIntegerv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetIntegerv(ALenum param, ALint* data) +{ + AL_VOID_FXN(alGetIntegerv(param, data)); +} + + +//***************************************************************************** +// alGetEnumValue +//***************************************************************************** +// +ALAPI ALenum ALAPIENTRY alGetEnumValue(const ALCchar* ename) +{ + AL_RESULT_FXN(alGetEnumValue(ename), ALenum, AL_INVALID_ENUM); +} + + +//***************************************************************************** +// alGetError +//***************************************************************************** +// +ALAPI ALenum ALAPIENTRY alGetError(ALvoid) +{ + AL_RESULT_FXN(alGetError(), ALenum, AL_NO_ERROR); +} + + +//***************************************************************************** +// alGetProcAddress +//***************************************************************************** +// +ALAPI ALvoid* ALAPIENTRY alGetProcAddress(const ALCchar* fname) +{ + // return router's address if available + ALsizei i=0; + ALvoid *pAddress; + + while ((function[i].funcName)&&(strcmp((char *)function[i].funcName,(char *)fname))) + i++; + pAddress = function[i].address; + + if (pAddress != NULL) { + return pAddress; + } + + // router doesn't have this entry point, so go to the device... + AL_RESULT_FXN(alGetProcAddress(fname), ALvoid*, 0); + + return pAddress; +} + + +//***************************************************************************** +// alGetString +//***************************************************************************** +// +ALAPI const ALCchar* ALAPIENTRY alGetString(ALenum param) +{ + AL_RESULT_FXN(alGetString(param), const ALCchar*, 0); +} + + +//***************************************************************************** +// alIsExtensionPresent +//***************************************************************************** +// +ALAPI ALboolean ALAPIENTRY alIsExtensionPresent(const ALCchar* ename) +{ + AL_RESULT_FXN(alIsExtensionPresent(ename), ALboolean, AL_FALSE); +} + + +//***************************************************************************** +// alIsEnabled +//***************************************************************************** +// +ALAPI ALboolean ALAPIENTRY alIsEnabled(ALenum capability) +{ + AL_RESULT_FXN(alIsEnabled(capability), ALboolean, AL_FALSE); +} + + + +//***************************************************************************** +//***************************************************************************** +// +// AL API Listener Entry Points +// +//***************************************************************************** +//***************************************************************************** + +//***************************************************************************** +// alListenerf +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alListenerf(ALenum param, ALfloat value) +{ + AL_VOID_FXN(alListenerf(param, value)); +} + + +//***************************************************************************** +// alListener3f +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alListener3f(ALenum param, ALfloat v1, ALfloat v2, ALfloat v3) +{ + AL_VOID_FXN(alListener3f(param, v1, v2, v3)); +} + + +//***************************************************************************** +// alListener3i +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alListener3i(ALenum param, ALint v1, ALint v2, ALint v3) +{ + AL_VOID_FXN(alListener3i(param, v1, v2, v3)); +} + + +//***************************************************************************** +// alListenerfv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alListenerfv(ALenum param, const ALfloat* values) +{ + AL_VOID_FXN(alListenerfv(param, values)); +} + + +//***************************************************************************** +// alListeneri +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alListeneri(ALenum param, ALint value) +{ + AL_VOID_FXN(alListeneri(param, value)); +} + + +//***************************************************************************** +// alListeneriv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alListeneriv(ALenum param, const ALint *values) +{ + AL_VOID_FXN(alListeneriv(param, values)); +} + + +//***************************************************************************** +// alGetListenerf +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetListenerf(ALenum param, ALfloat* value) +{ + AL_VOID_FXN(alGetListenerf(param, value)); +} + + +//***************************************************************************** +// alGetListener3f +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetListener3f(ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3) +{ + AL_VOID_FXN(alGetListener3f(param, v1, v2, v3)); +} + + +//***************************************************************************** +// alGetListener3i +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetListener3i(ALenum param, ALint* v1, ALint* v2, ALint* v3) +{ + AL_VOID_FXN(alGetListener3i(param, v1, v2, v3)); +} + + +//***************************************************************************** +// alGetListenerfv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetListenerfv(ALenum param, ALfloat* values) +{ + AL_VOID_FXN(alGetListenerfv(param, values)); +} + + +//***************************************************************************** +// alGetListeneri +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetListeneri(ALenum param, ALint* value) +{ + AL_VOID_FXN(alGetListeneri(param, value)); +} + + +//***************************************************************************** +// alGetListeneriv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetListeneriv(ALenum param, ALint* values) +{ + AL_VOID_FXN(alGetListeneriv(param, values)); +} + + +//***************************************************************************** +//***************************************************************************** +// +// AL API Source Entry Points +// +//***************************************************************************** +//***************************************************************************** + + +//***************************************************************************** +// alGenSources +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n, ALuint* sourceNames) +{ + AL_VOID_FXN(alGenSources(n, sourceNames)); +} + + +//***************************************************************************** +// alDeleteSources +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alDeleteSources(ALsizei n, const ALuint* sourceNames) +{ + AL_VOID_FXN(alDeleteSources(n, sourceNames)); +} + + +//***************************************************************************** +// alIsSource +//***************************************************************************** +// +ALAPI ALboolean ALAPIENTRY alIsSource(ALuint sourceName) +{ + AL_RESULT_FXN(alIsSource(sourceName), ALboolean, AL_FALSE); +} + + +//***************************************************************************** +// alSourcef +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourcef(ALuint sourceName, ALenum param, ALfloat value) +{ + AL_VOID_FXN(alSourcef(sourceName, param, value)); +} + + +//***************************************************************************** +// alSourcefv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourcefv(ALuint sourceName, ALenum param, const ALfloat* values) +{ + AL_VOID_FXN(alSourcefv(sourceName, param, values)); +} + + +//***************************************************************************** +// alSource3f +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSource3f(ALuint sourceName, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3) +{ + AL_VOID_FXN(alSource3f(sourceName, param, v1, v2, v3)); +} + + +//***************************************************************************** +// alSource3i +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSource3i(ALuint sourceName, ALenum param, ALint v1, ALint v2, ALint v3) +{ + AL_VOID_FXN(alSource3i(sourceName, param, v1, v2, v3)); +} + + +//***************************************************************************** +// alSourcei +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourcei(ALuint sourceName, ALenum param, ALint value) +{ + AL_VOID_FXN(alSourcei(sourceName, param, value)); +} + +//***************************************************************************** +// alSourceiv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourceiv(ALuint sourceName, ALenum param, const ALint* values) +{ + AL_VOID_FXN(alSourceiv(sourceName, param, values)); +} + + +//***************************************************************************** +// alGetSourcef +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint sourceName, ALenum param, ALfloat* value) +{ + AL_VOID_FXN(alGetSourcef(sourceName, param, value)); +} + +//***************************************************************************** +// alGetSource3f +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetSource3f(ALuint sourceName, ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3) +{ + AL_VOID_FXN(alGetSource3f(sourceName, param, v1, v2, v3)); +} + + +//***************************************************************************** +// alGetSource3i +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetSource3i(ALuint sourceName, ALenum param, ALint* v1, ALint* v2, ALint* v3) +{ + AL_VOID_FXN(alGetSource3i(sourceName, param, v1, v2, v3)); +} + + +//***************************************************************************** +// alGetSourcefv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetSourcefv(ALuint sourceName, ALenum param, ALfloat* values) +{ + AL_VOID_FXN(alGetSourcefv(sourceName, param, values)); +} + + +//***************************************************************************** +// alGetSourcei +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint sourceName, ALenum param, ALint* value) +{ + AL_VOID_FXN(alGetSourcei(sourceName, param, value)); +} + + +//***************************************************************************** +// alGetSourceiv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alGetSourceiv(ALuint sourceName, ALenum param, ALint* values) +{ + AL_VOID_FXN(alGetSourceiv(sourceName, param, values)); +} + + +//***************************************************************************** +// alSourcePlay +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint sourceName) +{ + AL_VOID_FXN(alSourcePlay(sourceName)); +} + + +//***************************************************************************** +// alSourcePlayv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint* sourceNames) +{ + AL_VOID_FXN(alSourcePlayv(n, sourceNames)); +} + + +//***************************************************************************** +// alSourcePause +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourcePause(ALuint sourceName) +{ + AL_VOID_FXN(alSourcePause(sourceName)); +} + + +//***************************************************************************** +// alSourcePausev +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, const ALuint* sourceNames) +{ + AL_VOID_FXN(alSourcePausev(n, sourceNames)); +} + + +//***************************************************************************** +// alSourceStop +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourceStop(ALuint sourceName) +{ + AL_VOID_FXN(alSourceStop(sourceName)); +} + + +//***************************************************************************** +// alSourceStopv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint* sourceNames) +{ + AL_VOID_FXN(alSourceStopv(n, sourceNames)); +} + + +//***************************************************************************** +// alSourceRewind +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourceRewind(ALuint sourceName) +{ + AL_VOID_FXN(alSourceRewind(sourceName)); +} + + +//***************************************************************************** +// alSourceRewindv +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint* sourceNames) +{ + AL_VOID_FXN(alSourceRewindv(n, sourceNames)); +} + + +//***************************************************************************** +// alSourceQueueBuffers +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers(ALuint sourceName, ALsizei n, const ALuint* buffers) +{ + AL_VOID_FXN(alSourceQueueBuffers(sourceName, n, buffers)); +} + + +//***************************************************************************** +// alSourceUnqueueBuffers +//***************************************************************************** +// +ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers(ALuint sourceName, ALsizei n, ALuint* buffers) +{ + AL_VOID_FXN(alSourceUnqueueBuffers(sourceName, n, buffers)); +} + diff --git a/Router/alList.cpp b/Router/alList.cpp new file mode 100644 index 00000000..2c884c56 --- /dev/null +++ b/Router/alList.cpp @@ -0,0 +1,1029 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2003 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 "alList.h" +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> + + +//**************************************************************************** +//**************************************************************************** +// +// Defines +// +//**************************************************************************** +//**************************************************************************** + +// +// Some occasionally useful debugging stuff. +// +#if(DBG) + #ifndef ASSERT + static ALint alListDebugAssertsEnabled = 1; + #define ASSERT(exp) \ + { \ + if(!(exp) && alListDebugAssertsEnabled) \ + { \ + char tempStr[256]; \ + OutputDebugString("\n"); \ + sprintf(tempStr, "Assert failed in file %s, line %d!\n", \ + __FILE__, __LINE__); \ + OutputDebugString(tempStr); \ + OutputDebugString("\n"); \ + if(alListDebugAssertsEnabled) \ + { \ + DebugBreak(); \ + } \ + } \ + } + + #endif +#else + #ifndef ASSERT + #define ASSERT(exp) + #endif +#endif + + + +//**************************************************************************** +//**************************************************************************** +// +// List Functions +// +//**************************************************************************** +//**************************************************************************** + +//***************************************************************************** +// alListAddEntry +//***************************************************************************** +// Adds an entry to the tail of the list. Each entry must be unique. +// +ALvoid alListAddEntry +( + IN ALlist* pList, + IN ALlistEntry* pEntry +) +{ +#if(DBG) + ALlistEntry* pCurrent = 0; +#endif + + ASSERT(pList); + ASSERT(pEntry); + ASSERT(pList->Locked); + ASSERT(!pEntry->Next); + ASSERT(!pEntry->Previous); + + // + // Verify the entry doesn't already exist. + // +#if(DBG) + pCurrent = pList->Head; + while(pCurrent) + { + if(pCurrent == pEntry) + { + break; + } + + pCurrent = pCurrent->Next; + } + + if(pCurrent) + { + // Duplicate entries are not supported. + ASSERT(0); + return; + } +#endif + + + // + // Add the item to the tail of the list. + // + if(pList->Tail) + { + pList->Tail->Next = pEntry; + } + + pEntry->Previous = pList->Tail; + pList->Tail = pEntry; + + // + // Check if this is the first entry. + // + if(!pList->Head) + { + pList->Head = pEntry; + pList->Current = pEntry; + } + + pList->NumberOfEntries++; +} + + +//***************************************************************************** +// alListAddEntryToHead +//***************************************************************************** +// Adds an entry to the head of the list. Each entry must be unique. +// +ALvoid alListAddEntryToHead +( + IN ALlist* pList, + IN ALlistEntry* pEntry +) +{ +#if(DBG) + ALlistEntry* pCurrent = 0; +#endif + ASSERT(pList); + ASSERT(pEntry); + ASSERT(pList->Locked); + ASSERT(!pEntry->Next); + ASSERT(!pEntry->Previous); + + // + // Verify the entry doesn't already exist. + // +#if(DBG) + pCurrent = pList->Head; + while(pCurrent) + { + if(pCurrent == pEntry) + { + break; + } + + pCurrent = pCurrent->Next; + } + + if(pCurrent) + { + // Duplicate entries are not supported. + ASSERT(0); + return; + } +#endif + + + // + // Add the item to the head of the list. + // + if(pList->Head) + { + pList->Head->Previous = pEntry; + } + + pEntry->Next = pList->Head; + pList->Head = pEntry; + + // + // Check if this is the first entry. + // + if(!pList->Tail) + { + pList->Tail = pEntry; + pList->Current = pEntry; + } + + pList->NumberOfEntries++; +} + + +//***************************************************************************** +// alListAcquireLock +//***************************************************************************** +// This is called to aquire the list lock for operations that span multiple +// list calls like iterating over the list. +// +ALvoid alListAcquireLock +( + IN ALlist* pList +) +{ + ASSERT(pList); + + EnterCriticalSection(&pList->Lock); +#if(DBG) + pList->Locked++; +#endif + + // + // Check that only one person has the lock. + // + ASSERT(pList->Locked == 1); +} + + +//***************************************************************************** +// alListCreate +//***************************************************************************** +// Creates and initializes a list. +// +ALboolean alListCreate +( + OUT ALlist** ppList +) +{ + ALlist* pList = 0; + + ASSERT(ppList); + + // + // Allocate and initialize the list context. + // + *ppList = 0; + pList = (ALlist*)malloc(sizeof(ALlist)); + if(!pList) + { + // Failed to allocate the list! + ASSERT(0); + return FALSE; + } + + memset(pList, 0, sizeof(ALlist)); + InitializeCriticalSection(&pList->Lock); + pList->NumberOfEntries = 0; + *ppList = pList; + return TRUE; +} + + +//***************************************************************************** +// alListFree +//***************************************************************************** +// Destroys the list. +// +ALvoid alListFree +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(!pList->Head); + + // + // Free the resources allocated during the creation. + // + if(pList) + { + DeleteCriticalSection(&pList->Lock); + free(pList); + } + + return; +} + + +//***************************************************************************** +// alListGetData +//***************************************************************************** +// Returns the data from the list entry. +// +ALvoid* alListGetData +( + IN ALlistEntry* pEntry +) +{ + ASSERT(pEntry); + + return pEntry->Data; +} + + +//***************************************************************************** +// alListGetEntryAt +//***************************************************************************** +// Returns the entry in the list at the specified index of the list. +// +ALlistEntry* alListGetEntryAt +( + IN ALlist* pList, + IN ALint Index +) +{ + ALlistEntry* pEntry = 0; + ALint i; + + ASSERT(pList); + ASSERT(pList->Locked); + ASSERT(Index < pList->NumberOfEntries); + + pEntry = pList->Head; + for(i = 0; i < Index && pEntry; i++) + { + pEntry = pEntry->Next; + } + + return pEntry; +} + + +//***************************************************************************** +// alListGetEntryCount +//***************************************************************************** +// Returns the number of items stored in the list. +// +ALint alListGetEntryCount +( + IN ALlist* pList +) +{ + ASSERT(pList->Locked); + return pList->NumberOfEntries; +} + + +//***************************************************************************** +// alListGetHead +//***************************************************************************** +// Returns the first entry in the list. +// +ALlistEntry* alListGetHead +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + return pList->Head; +} + + +//***************************************************************************** +// alListGetNext +//***************************************************************************** +// Returns the entry after to the entry pointed to by the iterator. If +// the iterator is at the last entry (or has finished iterating over the +// list), the returned entry will be 0. +// +ALlistEntry* alListGetNext +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + if(!pList->Current) + { + return 0; + } + + return pList->Current->Next; +} + + +//***************************************************************************** +// alListGetPrevious +//***************************************************************************** +// Returns the entry previous to the entry pointed to by the iterator. If +// the iterator is at the first entry, the returned entry will be 0. +// +ALlistEntry* alListGetPrevious +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + if(!pList->Current) + { + return 0; + } + + return pList->Current->Previous; +} + + +//***************************************************************************** +// alListGetTail +//***************************************************************************** +// Returns the last entry in the list. +// +ALlistEntry* alListGetTail +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + return pList->Tail; +} + + +//***************************************************************************** +// alListInitializeEntry +//***************************************************************************** +// Initializes a preallocated list entry. +// +ALvoid alListInitializeEntry +( + ALlistEntry* pEntry, + ALvoid* pData +) +{ + ASSERT(pEntry); + + pEntry->Data = pData; + pEntry->Next = 0; + pEntry->Previous = 0; +} + + +//***************************************************************************** +// alListIsEmpty +//***************************************************************************** +// Returns the TRUE if the list is empty. +// +ALboolean alListIsEmpty +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + return (pList->Head == 0); +} + + +//***************************************************************************** +// alListIteratorGet +//***************************************************************************** +// Returns the entry pointed to by the iterator. +// +ALlistEntry* alListIteratorGet +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + return pList->Current; +} + + +//***************************************************************************** +// alListIteratorFindData +//***************************************************************************** +// Searches the list for the matching item and return the pointer to the +// entry. If the match is not found, the return will be 0. +// +ALlistEntry* alListIteratorFindData +( + IN ALlist* pList, + IN ALvoid* pData +) +{ + ALlistEntry* pCurrent = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + + // + // Find the item. + // + pCurrent = pList->Head; + while(pCurrent) + { + if(pCurrent->Data == pData) + { + break; + } + + pCurrent = pCurrent->Next; + } + + pList->Current = pCurrent; + return pCurrent; +} + + +//***************************************************************************** +// alListIteratorNext +//***************************************************************************** +// This is called to advance the list iterator to the next entry in the list +// and return that entry. +// +ALlistEntry* alListIteratorNext +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + if(!pList->Current) + { + return 0; + } + + pList->Current = pList->Current->Next; + return pList->Current; +} + + +//***************************************************************************** +// alListIteratorPrevious +//***************************************************************************** +// This is called to advance the list iterator to the previous entry in the +// list and return that entry. +// +ALlistEntry* alListIteratorPrevious +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + if(!pList->Current) + { + return 0; + } + + pList->Current = pList->Current->Previous; + return pList->Current; +} + + +//***************************************************************************** +// alListIteratorRemove +//***************************************************************************** +// Removes the current item from the list and returns it. The iterator will +// equal the next item in the list. +// +ALlistEntry* alListIteratorRemove +( + IN ALlist* pList +) +{ + ALlistEntry* pEntry = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + + // + // Make sure we aren't at the end of the list. + // + if(!pList->Current) + { + return 0; + } + + // + // Remove the item from the list. + // + pEntry = pList->Current; + + // + // Fix up the next item in the list. + // + if(pEntry->Next) + { + pEntry->Next->Previous = pEntry->Previous; + } + + // + // Fix up the previous item in the list. + // + if(pEntry->Previous) + { + pEntry->Previous->Next = pEntry->Next; + } + + // + // Fix up the current pointer. + // + pList->Current = pEntry->Next; + + // + // Check the head pointer. + // + if(pList->Head == pEntry) + { + pList->Head = pEntry->Next; + } + + // + // Check the tail pointer. + // + if(pList->Tail == pEntry) + { + pList->Tail = pEntry->Previous; + } + + // + // Set the entry pointers. + // + pEntry->Next = 0; + pEntry->Previous = 0; + pList->NumberOfEntries--; + ASSERT(0 <= pList->NumberOfEntries); + return pEntry; +} + + +//***************************************************************************** +// alListIteratorReset +//***************************************************************************** +// Returns the list iterator to the head of the list. +// +ALlistEntry* alListIteratorReset +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + + pList->Current = pList->Head; + return pList->Current; +} + + +//***************************************************************************** +// alListIteratorSet +//***************************************************************************** +// Sets the current entry pointer to the entry passed in. If the entry is not +// found, the current entry will be 0. +// +ALlistEntry* alListIteratorSet +( + IN ALlist* pList, + IN ALlistEntry* pEntry +) +{ + ALlistEntry* pCurrent = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + + pCurrent = pList->Head; + while(pCurrent) + { + if(pCurrent == pEntry) + { + break; + } + + pCurrent = pCurrent->Next; + } + + pList->Current = pCurrent; + return pList->Current; +} + + +//***************************************************************************** +// alListMatchEntry +//***************************************************************************** +// Matches the entry to an item in the list and returns the data in that +// entry. If the match is not found, the return will be 0. +// +ALvoid* alListMatchEntry +( + IN ALlist* pList, + IN ALlistEntry* pEntry +) +{ + ALlistEntry* pCurrent = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + + // + // Find the item. + // + pCurrent = pList->Head; + while(pCurrent) + { + if(pCurrent == pEntry) + { + break; + } + + pCurrent = pCurrent->Next; + } + + if(!pCurrent) + { + return 0; + } + + return pCurrent->Data; +} + + +//***************************************************************************** +// alListMatchData +//***************************************************************************** +// Searches the list for the first matching item and returns the pointer to +// the entry. If the match is not found, the return will be 0. +// +ALlistEntry* alListMatchData +( + IN ALlist* pList, + IN ALvoid* pData +) +{ + ALlistEntry* pCurrent = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + + // + // Find the item. + // + pCurrent = pList->Head; + while(pCurrent) + { + if(pCurrent->Data == pData) + { + break; + } + + pCurrent = pCurrent->Next; + } + + return pCurrent; +} + + +//***************************************************************************** +// alListReleaseLock +//***************************************************************************** +// This is called to release the list lock. +// +ALvoid alListReleaseLock +( + IN ALlist* pList +) +{ + ASSERT(pList); + ASSERT(pList->Locked); + +#if(DBG) + pList->Locked--; + ASSERT(pList->Locked == 0); +#endif + + LeaveCriticalSection(&pList->Lock); +} + + +//***************************************************************************** +// alListRemoveEntry +//***************************************************************************** +// Removes the item from the list and returns the data from the item. If +// this is the current item, the current item will equal the next item in the +// list. +// +ALvoid* alListRemoveEntry +( + IN ALlist* pList, + IN ALlistEntry* pEntry +) +{ + ALlistEntry* pCurrent = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + ASSERT(pEntry); + + // + // Release the item from the list. + // + pCurrent = pList->Head; + while(pCurrent) + { + if(pCurrent == pEntry) + { + break; + } + + pCurrent = pCurrent->Next; + } + + if(!pCurrent) + { + return 0; + } + + // + // Fix up the next item in the list. + // + if(pEntry->Next) + { + pEntry->Next->Previous = pEntry->Previous; + } + + // + // Fix up the previous item in the list. + // + if(pEntry->Previous) + { + pEntry->Previous->Next = pEntry->Next; + } + + // + // Fix up the current pointer. + // + if(pCurrent == pList->Current) + { + pList->Current = pEntry->Next; + } + + // + // Check the head pointer. + // + if(pList->Head == pEntry) + { + pList->Head = pEntry->Next; + } + + // + // Check the tail pointer. + // + if(pList->Tail == pEntry) + { + pList->Tail = pEntry->Previous; + } + + // + // Set the entry pointers. + // + pEntry->Next = 0; + pEntry->Previous = 0; + pList->NumberOfEntries--; + ASSERT(0 <= pList->NumberOfEntries); + return pEntry->Data; +} + + +//***************************************************************************** +// alListRemoveHead +//***************************************************************************** +// Removes the list entry at the head of the list. If this is the current +// item, the current item will equal the next item in the list. +// +ALlistEntry* alListRemoveHead +( + IN ALlist* pList +) +{ + ALlistEntry* pCurrent = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + + // + // Release the item from the list. + // + pCurrent = pList->Head; + if(!pCurrent) + { + return 0; + } + + // + // Fix up the next item in the list. + // + if(pCurrent->Next) + { + pCurrent->Next->Previous = 0; + } + + // + // Fix up the previous item in the list. + // + ASSERT(!pCurrent->Previous) + + // + // Fix up the current pointer. + // + if(pCurrent == pList->Current) + { + pList->Current = pCurrent->Next; + } + + // + // Check the head pointer. + // + pList->Head = pCurrent->Next; + + // + // Check the tail pointer. + // + if(pList->Tail == pCurrent) + { + pList->Tail = 0; + } + + // + // Set the entry pointers. + // + pCurrent->Next = 0; + pCurrent->Previous = 0; + pList->NumberOfEntries--; + ASSERT(0 <= pList->NumberOfEntries); + return pCurrent; +} + + +//***************************************************************************** +// alListRemoveTail +//***************************************************************************** +// Removes the list entry at the tail of the list. If this is the current +// item, the current item will be null. +// +ALlistEntry* alListRemoveTail +( + IN ALlist* pList +) +{ + ALlistEntry* pCurrent = 0; + + ASSERT(pList); + ASSERT(pList->Locked); + + // + // Release the item from the list. + // + pCurrent = pList->Tail; + if(!pCurrent) + { + return 0; + } + + // + // Fix up the next item in the list. + // + ASSERT(!pCurrent->Next) + + // + // Fix up the previous item in the list. + // + if(pCurrent->Previous) + { + pCurrent->Previous->Next = 0; + } + + // + // Fix up the current pointer. + // + if(pCurrent == pList->Current) + { + pList->Current = 0; + } + + // + // Check the head pointer. + // + if(pList->Head == pCurrent) + { + pList->Head = 0; + } + + // + // Check the tail pointer. + // + pList->Tail = pCurrent->Previous; + + // + // Set the entry pointers. + // + pCurrent->Next = 0; + pCurrent->Previous = 0; + pList->NumberOfEntries--; + ASSERT(0 <= pList->NumberOfEntries); + return pCurrent; +} + diff --git a/Router/alList.h b/Router/alList.h new file mode 100644 index 00000000..71dc43c5 --- /dev/null +++ b/Router/alList.h @@ -0,0 +1,433 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2003 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + + + + +#ifndef _AL_LIST_H_ +#define _AL_LIST_H_ + +#include <al/al.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include <windows.h> + + + +//***************************************************************************** +//***************************************************************************** +// +// Defines +// +//***************************************************************************** +//***************************************************************************** + +// +// Some useful things to track parameters. +// +#ifndef IN +#define IN +#endif + +#ifndef OPTIONAL +#define OPTIONAL +#endif + +#ifndef OUT +#define OUT +#endif + +// +// The list entry. This should not be modified outside the list routines. +// +typedef struct ALlistEntry_Struct +{ + // + // The previous list entry. + // + struct ALlistEntry_Struct* Previous; + + // + // The next list entry. + // + struct ALlistEntry_Struct* Next; + + // + // The data for the current entry. + // + ALvoid* Data; + +} ALlistEntry; + + +// +// This is the context to pass to all the list calls. It must be initialized +// before any list calls are made. +// +typedef struct //ALlist_Struct +{ + // + // This is the pointer to the first item in the list. + // + ALlistEntry* Head; + + // + // This is the pointer to the last item in the list. + // + ALlistEntry* Tail; + + // + // This is the list iterator. + // + ALlistEntry* Current; + + // + // This is the list lock to prevent simultaneous addition and removal + // of entries. + // + CRITICAL_SECTION Lock; + + // + // This maintains a count of the number of entries in the list. + // + ALint NumberOfEntries; + + // + // This is set if the list is locked. For debug use only. + // +#if(DBG) + ALint Locked; +#endif + +} ALlist; + + + +//***************************************************************************** +//***************************************************************************** +// +// List Functions +// +//***************************************************************************** +//***************************************************************************** + +//***************************************************************************** +// alListAddEntry +//***************************************************************************** +// Adds an entry to the tail of the list. Each entry must be unique. +// +ALvoid alListAddEntry +( + IN ALlist* pList, + IN ALlistEntry* pEntry +); + +//***************************************************************************** +// alListAddEntryToHead +//***************************************************************************** +// Adds an entry to the head of the list. Each entry must be unique. +// +ALvoid alListAddEntryToHead +( + IN ALlist* pList, + IN ALlistEntry* pEntry +); + +//***************************************************************************** +// alListAcquireLock +//***************************************************************************** +// This is called to acquire the list lock for operations that span multiple +// list calls like iterating over the list. +// +ALvoid alListAcquireLock +( + IN ALlist* pList +); + +//***************************************************************************** +// alListCreate +//***************************************************************************** +// Creates and initializes a list. +// +ALboolean alListCreate +( + OUT ALlist** ppList +); + +//***************************************************************************** +// alListFree +//***************************************************************************** +// Destroys the list. Dynamically allocated entries are not freed. +// +ALvoid alListFree +( + IN ALlist* pList +); + +//***************************************************************************** +// alListGetData +//***************************************************************************** +// Returns the data from the list entry. +// +ALvoid* alListGetData +( + IN ALlistEntry* pEntry +); + +//***************************************************************************** +// alListGetEntryAt +//***************************************************************************** +// Returns the entry in the list at the specified index of the list. +// +ALlistEntry* alListGetEntryAt +( + IN ALlist* pList, + IN ALint Index +); + +//***************************************************************************** +// alListGetEntryCount +//***************************************************************************** +// Returns the number of items stored in the list. +// +ALint alListGetEntryCount +( + IN ALlist* pList +); + +//***************************************************************************** +// alListGetHead +//***************************************************************************** +// Returns the first entry in the list. +// +ALlistEntry* alListGetHead +( + IN ALlist* pList +); + +//***************************************************************************** +// alListGetNext +//***************************************************************************** +// Returns the entry after to the entry pointed to by the iterator. If +// the iterator is at the last entry (or has finished iterating over the +// list), the returned entry will be 0. +// +ALlistEntry* alListGetNext +( + IN ALlist* pList +); + +//***************************************************************************** +// alListGetPrevious +//***************************************************************************** +// Returns the entry previous to the entry pointed to by the iterator. If +// the iterator is at the first entry, the returned entry will be 0. +// +ALlistEntry* alListGetPrevious +( + IN ALlist* pList +); + +//***************************************************************************** +// alListGetTail +//***************************************************************************** +// Returns the last entry in the list. +// +ALlistEntry* alListGetTail +( + IN ALlist* pList +); + +//***************************************************************************** +// alListInitializeEntry +//***************************************************************************** +// Initializes a preallocated list entry. +// +ALvoid alListInitializeEntry +( + IN ALlistEntry* pListEntry, + IN ALvoid* pData +); + +//***************************************************************************** +// alListIsEmpty +//***************************************************************************** +// Returns the TRUE if the list is empty. +// +ALboolean alListIsEmpty +( + IN ALlist* pList +); + +//***************************************************************************** +// alListIteratorGet +//***************************************************************************** +// Returns the entry pointed to by the iterator. +// +ALlistEntry* alListIteratorGet +( + IN ALlist* pList +); + +//***************************************************************************** +// alListIteratorFindData +//***************************************************************************** +// Searches the list for the matching item and return the pointer to the +// entry. If the match is not found, the return will be 0. +// +ALlistEntry* alListIteratorFindData +( + IN ALlist* pList, + IN ALvoid* pData +); + +//***************************************************************************** +// alListIteratorNext +//***************************************************************************** +// This is called to advance the list iterator to the next entry in the list +// and return that entry. +// +ALlistEntry* alListIteratorNext +( + IN ALlist* pList +); + +//***************************************************************************** +// alListIteratorPrevious +//***************************************************************************** +// This is called to advance the list iterator to the previous entry in the +// list and return that entry. +// +ALlistEntry* alListIteratorPrevious +( + IN ALlist* pList +); + +//***************************************************************************** +// alListIteratorReset +//***************************************************************************** +// Returns the list iterator to the head of the list and returns the head +// entry. +// +ALlistEntry* alListIteratorReset +( + IN ALlist* pList +); + +//***************************************************************************** +// alListIteratorRemove +//***************************************************************************** +// Removes the current item from the list and returns it. The iterator will +// equal the next item in the list. +// +ALlistEntry* alListIteratorRemove +( + IN ALlist* pList +); + +//***************************************************************************** +// alListIteratorSet +//***************************************************************************** +// Sets the current entry pointer to the entry passed in. If the entry is not +// found, the current entry will be 0. +// +ALlistEntry* alListIteratorSet +( + IN ALlist* pList, + IN ALlistEntry* pEntry +); + +//***************************************************************************** +// alListMatchEntry +//***************************************************************************** +// Matches the entry to an item in the list and returns the data in that +// entry. If the match is not found, the return will be 0. +// +ALvoid* alListMatchEntry +( + IN ALlist* pList, + IN ALlistEntry* pEntry +); + +//***************************************************************************** +// alListMatchData +//***************************************************************************** +// Searches the list for the matching item and return the pointer to the +// entry. If the match is not found, the return will be 0. +// +ALlistEntry* alListMatchData +( + IN ALlist* pList, + IN ALvoid* pData +); + +//***************************************************************************** +// alListReleaseLock +//***************************************************************************** +// This is called to release the list lock. +// +ALvoid alListReleaseLock +( + IN ALlist* pList +); + +//***************************************************************************** +// alListRemoveEntry +//***************************************************************************** +// Removes the item from the list and returns the data from the item. If +// this is the current item, the current item will equal the next item in the +// list. +// +ALvoid* alListRemoveEntry +( + IN ALlist* pList, + IN ALlistEntry* pEntry +); + +//***************************************************************************** +// alListRemoveHead +//***************************************************************************** +// Removes the list entry at the head of the list. If this is the current +// item, the current item will equal the next item in the list. +// +ALlistEntry* alListRemoveHead +( + IN ALlist* pList +); + +//***************************************************************************** +// alListRemoveTail +//***************************************************************************** +// Removes the list entry at the tail of the list. If this is the current +// item, the current item will be null. +// +ALlistEntry* alListRemoveTail +( + IN ALlist* pList +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Router/alc.cpp b/Router/alc.cpp new file mode 100644 index 00000000..c4abff8c --- /dev/null +++ b/Router/alc.cpp @@ -0,0 +1,2332 @@ +/** + * 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 + */ + +#ifndef __MINGW32__ +#define _CRT_SECURE_NO_DEPRECATE // get rid of sprintf security warnings on VS2005 +#endif + +#include <stdlib.h> +#include <memory.h> +#define AL_BUILD_LIBRARY +#include <al/alc.h> +#include <stdio.h> +#include <tchar.h> +#include <assert.h> + +#include <stddef.h> +#include <windows.h> +#if defined(_MSC_VER) +#include <crtdbg.h> +#else +#define _malloc_dbg(s,x,f,l) malloc(s) +#define _realloc_dbg(p,s,x,f,l) realloc(p,s) +#endif +#include <objbase.h> +#ifndef __MINGW32__ +#include <atlconv.h> +#else +#define T2A(x) x +#endif +#include <mmsystem.h> + +#include "OpenAL32.h" + + +//***************************************************************************** +//***************************************************************************** +// +// Defines +// +//***************************************************************************** +//***************************************************************************** + +typedef struct ALCextension_struct +{ + + const char* ename; + +} ALCextension; + +typedef struct +{ + const char* ename; + ALenum value; + +} ALCRouterEnum; + +typedef struct ALCfunction_struct +{ + + const char* fname; + ALvoid* address; + +} ALCfunction; + + + +//***************************************************************************** +//***************************************************************************** +// +// Global Vars +// +//***************************************************************************** +//***************************************************************************** + +ALlist* alContextList = 0; +ALCcontext* alCurrentContext = 0; + +ALCdevice* g_CaptureDevice = NULL; + +//***************************************************************************** +//***************************************************************************** +// +// Local Vars +// +//***************************************************************************** +//***************************************************************************** + +// +// The values of the enums supported by OpenAL. +// +static ALCRouterEnum alcEnums[] = +{ + // Types + {"ALC_INVALID", ALC_INVALID}, + {"ALC_FALSE", ALC_FALSE}, + {"ALC_TRUE", ALC_TRUE}, + + // ALC Properties + {"ALC_MAJOR_VERSION", ALC_MAJOR_VERSION}, + {"ALC_MINOR_VERSION", ALC_MINOR_VERSION}, + {"ALC_ATTRIBUTES_SIZE", ALC_ATTRIBUTES_SIZE}, + {"ALC_ALL_ATTRIBUTES", ALC_ALL_ATTRIBUTES}, + {"ALC_DEFAULT_DEVICE_SPECIFIER", ALC_DEFAULT_DEVICE_SPECIFIER}, + {"ALC_DEVICE_SPECIFIER", ALC_DEVICE_SPECIFIER}, + {"ALC_EXTENSIONS", ALC_EXTENSIONS}, + {"ALC_FREQUENCY", ALC_FREQUENCY}, + {"ALC_REFRESH", ALC_REFRESH}, + {"ALC_SYNC", ALC_SYNC}, + {"ALC_MONO_SOURCES", ALC_MONO_SOURCES}, + {"ALC_STEREO_SOURCES", ALC_STEREO_SOURCES}, + {"ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER}, + {"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER}, + {"ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES}, + + // New Enumeration extension + {"ALC_DEFAULT_ALL_DEVICES_SPECIFIER", ALC_DEFAULT_ALL_DEVICES_SPECIFIER}, + {"ALC_ALL_DEVICES_SPECIFIER", ALC_ALL_DEVICES_SPECIFIER}, + + // ALC Error Message + {"ALC_NO_ERROR", ALC_NO_ERROR}, + {"ALC_INVALID_DEVICE", ALC_INVALID_DEVICE}, + {"ALC_INVALID_CONTEXT", ALC_INVALID_CONTEXT}, + {"ALC_INVALID_ENUM", ALC_INVALID_ENUM}, + {"ALC_INVALID_VALUE", ALC_INVALID_VALUE}, + {"ALC_OUT_OF_MEMORY", ALC_OUT_OF_MEMORY}, + + // Default + {0, (ALenum)0} +}; + +// +// Our function pointers. +// +static ALCfunction alcFunctions[] = +{ + {"alcCreateContext", (ALvoid*)alcCreateContext}, + {"alcMakeContextCurrent", (ALvoid*)alcMakeContextCurrent}, + {"alcProcessContext", (ALvoid*)alcProcessContext}, + {"alcSuspendContext", (ALvoid*)alcSuspendContext}, + {"alcDestroyContext", (ALvoid*)alcDestroyContext}, + {"alcGetCurrentContext", (ALvoid*)alcGetCurrentContext}, + {"alcGetContextsDevice", (ALvoid*)alcGetContextsDevice}, + {"alcOpenDevice", (ALvoid*)alcOpenDevice}, + {"alcCloseDevice", (ALvoid*)alcCloseDevice}, + {"alcGetError", (ALvoid*)alcGetError}, + {"alcIsExtensionPresent", (ALvoid*)alcIsExtensionPresent}, + {"alcGetProcAddress", (ALvoid*)alcGetProcAddress}, + {"alcGetEnumValue", (ALvoid*)alcGetEnumValue}, + {"alcGetString", (ALvoid*)alcGetString}, + {"alcGetIntegerv", (ALvoid*)alcGetIntegerv}, + {"alcCaptureOpenDevice", (ALvoid*)alcCaptureOpenDevice}, + {"alcCaptureCloseDevice", (ALvoid*)alcCaptureCloseDevice}, + {"alcCaptureStart", (ALvoid*)alcCaptureStart}, + {"alcCaptureStop", (ALvoid*)alcCaptureStop}, + {"alcCaptureSamples", (ALvoid*)alcCaptureSamples}, + {0, (ALvoid*)0} +}; + +// +// Our extensions. +// +static ALCextension alcExtensions[] = +{ + "ALC_ENUMERATION_EXT", + "ALC_ENUMERATE_ALL_EXT", + "ALC_EXT_CAPTURE", + 0 +}; + + +// Error strings +static ALenum LastError = ALC_NO_ERROR; +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; + +static ALint alcMajorVersion = 1; +static ALint alcMinorVersion = 1; + +// Enumeration stuff +ALDEVICE *g_pDeviceList = NULL; // ALC_ENUMERATION_EXT Device List +ALDEVICE *g_pCaptureDeviceList = NULL; // ALC_ENUMERATION_EXT Capture Device List +ALDEVICE *g_pAllDevicesList = NULL; // ALC_ENUMERATE_ALL_EXT Device List + +ALchar *pszDefaultDeviceSpecifier = NULL; +ALchar *pszDeviceSpecifierList = NULL; +ALchar *pszDefaultCaptureDeviceSpecifier = NULL; +ALchar *pszCaptureDeviceSpecifierList = NULL; +ALchar *pszDefaultAllDevicesSpecifier = NULL; +ALchar *pszAllDevicesSpecifierList = NULL; +ALchar szEmptyString[] = ""; + +typedef BOOL (CALLBACK *LPDSENUMCALLBACKA)(LPGUID, LPCSTR, LPCSTR, LPVOID); +typedef HRESULT (WINAPI *LPDIRECTSOUNDENUMERATEA)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); +typedef HRESULT (WINAPI *LPDIRECTSOUNDCAPTUREENUMERATEA)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext); + +BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext); +bool GetDefaultPlaybackDeviceName(char **pszName); +bool GetDefaultCaptureDeviceName(char **pszName); +bool FindDevice(ALDEVICE *pDeviceList, char *szDeviceName, bool bExactMatch, char **ppszDefaultName); +bool HasDLLAlreadyBeenUsed(ALDEVICE *pDeviceList, TCHAR *szDLLName); +//bool ValidCaptureDevice(const char *szCaptureDeviceName); + +//***************************************************************************** +//***************************************************************************** +// +// Logging Options +// +//***************************************************************************** +//***************************************************************************** + +// NOTE : LOG macro below requires a compiler newer than Visual Studio 6 + +//#define _LOGCALLS + +#ifdef _LOGCALLS + void OutputMessage(const char *szTest,...); + #define LOG(x, ...) OutputMessage(x, ##__VA_ARGS__) + #define LOGFILENAME "OpenALCalls.txt" +#endif + +//***************************************************************************** +//***************************************************************************** +// +// Local Functions +// +//***************************************************************************** +//***************************************************************************** + +//***************************************************************************** +// GetLoadedModuleDirectory +//***************************************************************************** +BOOL GetLoadedModuleDirectory(LPCTSTR moduleName, + LPTSTR directoryContainingModule, + DWORD directoryContainingModuleLength) { + // Attempts to find the given module in the address space of this + // process and return the directory containing the module. A NULL + // moduleName means to look up the directory containing the + // application rather than any given loaded module. There is no + // trailing backslash ('\') on the returned path. If the named + // module was found in the address space of this process, returns + // TRUE, otherwise returns FALSE. directoryContainingModule may be + // mutated regardless. + HMODULE module = NULL; + TCHAR fileDrive[MAX_PATH + 1]; + TCHAR fileDir[MAX_PATH + 1]; + TCHAR fileName[MAX_PATH + 1]; + TCHAR fileExt[MAX_PATH + 1]; + DWORD numChars; + + if (moduleName != NULL) { + module = GetModuleHandle(moduleName); + if (module == NULL) + return FALSE; + } + + numChars = GetModuleFileName(module, + directoryContainingModule, + directoryContainingModuleLength); + if (numChars == 0) + return FALSE; + + _splitpath(directoryContainingModule, fileDrive, fileDir, fileName, fileExt); + _tcscpy(directoryContainingModule, fileDrive); + _tcscat(directoryContainingModule, fileDir); + return TRUE; +} + + + + +//***************************************************************************** +// AddDevice +//***************************************************************************** +void AddDevice(const char *pszDeviceName, TCHAR *pszHostDLLFilename, ALDEVICE **ppDeviceList) +{ + // Adds pszDeviceName nad pszHostDLLFilename to the given Device List *IF* pszDeviceName has + // not already been added. + ALDEVICE *pNewDevice, *pTempDevice; + + // Check if unique + for (pTempDevice = *ppDeviceList; pTempDevice; pTempDevice = pTempDevice->pNextDevice) + { + if (strcmp(pTempDevice->pszDeviceName, pszDeviceName) == 0) + break; + } + + if (pTempDevice) + return; + + pNewDevice = (ALDEVICE*)malloc(sizeof(ALDEVICE)); + if (pNewDevice) + { + pNewDevice->pszDeviceName = (char*)malloc((strlen(pszDeviceName)+1)*sizeof(char)); + if (pNewDevice->pszDeviceName) + strcpy(pNewDevice->pszDeviceName, pszDeviceName); + + pNewDevice->pszHostDLLFilename = (TCHAR*)malloc((_tcslen(pszHostDLLFilename)+1)*sizeof(TCHAR)); + if (pNewDevice->pszHostDLLFilename) + _tcscpy(pNewDevice->pszHostDLLFilename, pszHostDLLFilename); + + pNewDevice->pNextDevice = NULL; + + if (*ppDeviceList) + { + pTempDevice = *ppDeviceList; + while (pTempDevice->pNextDevice) + pTempDevice = pTempDevice->pNextDevice; + pTempDevice->pNextDevice = pNewDevice; + } + else + { + *ppDeviceList = pNewDevice; + } + } +} + + + + +//***************************************************************************** +// BuildDeviceList +//***************************************************************************** +ALvoid BuildDeviceList() +{ + // This function will scan several directories (details below) looking for + // OpenAL DLLs. Each OpenAL DLL found will be opened and queried for it's + // list of playback and capture devices. All the information is stored + // in various lists: - + // + // g_pDevicesList : List of Playback Devices + // g_pCaptureDeviceList : List of Capture devices + // g_pAllDevicesList : List of *all* possible Playback devices (ALC_ENUMERATE_ALL_EXT support) + // + // In addition this function allocates memory for the strings that will + // be returned to the application in response to alcGetString queries. + // + // pszDefaultDeviceSpecifier : Default Playback Device + // pszDeviceSpecifierList : List of Playback Devices + // pszDefaultCaptureDeviceSpecifier : Default Capture Device + // pszCaptureDeviceSpecifierList : List of Capture Devices + // pszDefaultAllDevicesSpecifier : Default *all* Playback Device (ALC_ENUMERATE_ALL_EXT support) + // pszAllDevicesSpecifierList : List of *all* Playback Devices (ALC_ENUMERATE_ALL_EXT support) + WIN32_FIND_DATA findData; + HANDLE searchHandle = INVALID_HANDLE_VALUE; + TCHAR searchName[MAX_PATH + 1]; + BOOL found = FALSE; + const ALCchar* specifier = 0; + ALuint specifierSize = 0; + ALCdevice *device; + void *context; + bool bUsedWrapper = false; + ALDEVICE *pDevice = NULL; + + // Only build the list once ... + if (((g_pDeviceList == NULL) && (waveOutGetNumDevs())) || + ((g_pCaptureDeviceList == NULL) && (waveInGetNumDevs()))) + { + // + // Directory[0] is the directory containing OpenAL32.dll + // Directory[1] is the current directory. + // Directory[2] is the current app directory + // Directory[3] is the system directory + // + TCHAR dir[4][MAX_PATH + 1] = { 0 }; + int numDirs = 0; + int i; + HINSTANCE dll = 0; + ALCAPI_GET_STRING alcGetStringFxn = 0; + ALCAPI_IS_EXTENSION_PRESENT alcIsExtensionPresentFxn = 0; + ALCAPI_OPEN_DEVICE alcOpenDeviceFxn = 0; + ALCAPI_CREATE_CONTEXT alcCreateContextFxn = 0; + ALCAPI_MAKE_CONTEXT_CURRENT alcMakeContextCurrentFxn = 0; + ALCAPI_DESTROY_CONTEXT alcDestroyContextFxn = 0; + ALCAPI_CLOSE_DEVICE alcCloseDeviceFxn = 0; + + // + // Construct our search paths + // + if (GetLoadedModuleDirectory("OpenAL32.dll", dir[0], MAX_PATH)) { + ++numDirs; + } + + GetCurrentDirectory(MAX_PATH, dir[1]); + _tcscat(dir[1], _T("\\")); + ++numDirs; + + GetLoadedModuleDirectory(NULL, dir[2], MAX_PATH); + ++numDirs; + + GetSystemDirectory(dir[3], MAX_PATH); + _tcscat(dir[3], _T("\\")); + ++numDirs; + + // + // Begin searching for additional OpenAL implementations. + // + for(i = 0; i < numDirs; i++) + { + if ((i == 0) && (strcmp(dir[0], dir[3]) == 0)) // if searching router dir and router dir is sys dir, skip search + continue; + + if ((i == 2) && (strcmp(dir[2], dir[1]) == 0)) // if searching app dir and app dir is current dir, skip search + continue; + + if ((i == 3) && ((strcmp(dir[3], dir[2]) == 0) || (strcmp(dir[3], dir[1]) == 0))) // if searching sys dir and sys dir is either current or app directory, skip search + continue; + + _tcscpy(searchName, dir[i]); + _tcscat(searchName, _T("*oal.dll")); + searchHandle = FindFirstFile(searchName, &findData); + if(searchHandle != INVALID_HANDLE_VALUE) + { + while(TRUE) + { + // + // if this is an OpenAL32.dll, skip it -- it's probably a router and shouldn't be enumerated regardless + // + _tcscpy(searchName, dir[i]); + _tcscat(searchName, findData.cFileName); + TCHAR cmpName[MAX_PATH]; + _tcscpy(cmpName, searchName); + _tcsupr(cmpName); + if (_tcsstr(cmpName, _T("OPENAL32.DLL")) == 0) + { + boolean skipSearch = false; + + // don't search the same DLL twice + TCHAR *szDLLName = _tcsrchr(searchName, _T('\\')); + if (szDLLName) + szDLLName++; // Skip over the '\' + else + szDLLName = searchName; + + skipSearch = HasDLLAlreadyBeenUsed(g_pDeviceList, szDLLName); + if (!skipSearch) + skipSearch = HasDLLAlreadyBeenUsed(g_pCaptureDeviceList, szDLLName); + if (!skipSearch) + skipSearch = HasDLLAlreadyBeenUsed(g_pAllDevicesList, szDLLName); + + if (skipSearch == false) { + dll = LoadLibrary(searchName); + if(dll) + { + alcOpenDeviceFxn = (ALCAPI_OPEN_DEVICE)GetProcAddress(dll, "alcOpenDevice"); + alcCreateContextFxn = (ALCAPI_CREATE_CONTEXT)GetProcAddress(dll, "alcCreateContext"); + alcMakeContextCurrentFxn = (ALCAPI_MAKE_CONTEXT_CURRENT)GetProcAddress(dll, "alcMakeContextCurrent"); + alcGetStringFxn = (ALCAPI_GET_STRING)GetProcAddress(dll, "alcGetString"); + alcDestroyContextFxn = (ALCAPI_DESTROY_CONTEXT)GetProcAddress(dll, "alcDestroyContext"); + alcCloseDeviceFxn = (ALCAPI_CLOSE_DEVICE)GetProcAddress(dll, "alcCloseDevice"); + alcIsExtensionPresentFxn = (ALCAPI_IS_EXTENSION_PRESENT)GetProcAddress(dll, "alcIsExtensionPresent"); + + if ((alcOpenDeviceFxn != 0) && + (alcCreateContextFxn != 0) && + (alcMakeContextCurrentFxn != 0) && + (alcGetStringFxn != 0) && + (alcDestroyContextFxn != 0) && + (alcCloseDeviceFxn != 0) && + (alcIsExtensionPresentFxn != 0)) { + + bool bAddToAllDevicesList = false; + + if (alcIsExtensionPresentFxn(NULL, "ALC_ENUMERATE_ALL_EXT")) { + // this DLL can enumerate *all* devices -- so add complete list of devices + specifier = alcGetStringFxn(0, ALC_ALL_DEVICES_SPECIFIER); + if ((specifier) && strlen(specifier)) + { + do { + AddDevice(specifier, searchName, &g_pAllDevicesList); + specifier += strlen((char *)specifier) + 1; + } while (strlen((char *)specifier) > 0); + } + } else { + bAddToAllDevicesList = true; + } + + if (alcIsExtensionPresentFxn(NULL, "ALC_ENUMERATION_EXT")) { + // this DLL can enumerate devices -- so add complete list of devices + specifier = alcGetStringFxn(0, ALC_DEVICE_SPECIFIER); + if ((specifier) && strlen(specifier)) + { + do { + AddDevice(specifier, searchName, &g_pDeviceList); + if (bAddToAllDevicesList) + AddDevice(specifier, searchName, &g_pAllDevicesList); + specifier += strlen((char *)specifier) + 1; + } while (strlen((char *)specifier) > 0); + } + } else { + // no enumeration ability, -- so just add default device to the list + device = alcOpenDeviceFxn(NULL); + if (device != NULL) { + context = alcCreateContextFxn(device, NULL); + alcMakeContextCurrentFxn((ALCcontext *)context); + if (context != NULL) { + specifier = alcGetStringFxn(device, ALC_DEVICE_SPECIFIER); + if ((specifier) && strlen(specifier)) + { + AddDevice(specifier, searchName, &g_pDeviceList); + if (bAddToAllDevicesList) + AddDevice(specifier, searchName, &g_pAllDevicesList); + } + alcMakeContextCurrentFxn((ALCcontext *)NULL); + alcDestroyContextFxn((ALCcontext *)context); + alcCloseDeviceFxn(device); + } + } + } + + // add to capture device list + if (_tcsstr(cmpName, _T("CT_OAL.DLL")) == 0) { + // Skip native AL component (will contain same Capture List as the wrap_oal component) + if (alcIsExtensionPresentFxn(NULL, "ALC_EXT_CAPTURE")) { + // this DLL supports capture -- so add complete list of capture devices + specifier = alcGetStringFxn(0, ALC_CAPTURE_DEVICE_SPECIFIER); + if ((specifier) && strlen(specifier)) + { + do { + AddDevice(specifier, searchName, &g_pCaptureDeviceList); + specifier += strlen((char *)specifier) + 1; + } while (strlen((char *)specifier) > 0); + } + } + } + } + + FreeLibrary(dll); + dll = 0; + } + } + } + + if(!FindNextFile(searchHandle, &findData)) + { + if(GetLastError() == ERROR_NO_MORE_FILES) + { + break; + } + } + } + + FindClose(searchHandle); + searchHandle = INVALID_HANDLE_VALUE; + } + } + + // We now have a list of all the Device Names and their associated DLLs. + // Put the names in the appropriate strings + ALuint uiLength; + ALchar *pszTemp; + char *pszDefaultName = NULL; + bool bFound = false; + + if (g_pDeviceList) + { + uiLength = 0; + for (pDevice = g_pDeviceList; pDevice; pDevice = pDevice->pNextDevice) + uiLength += (strlen(pDevice->pszDeviceName) + 1); + + pszDeviceSpecifierList = (ALchar*)malloc((uiLength + 1) * sizeof(ALchar)); + if (pszTemp = pszDeviceSpecifierList) + { + memset(pszDeviceSpecifierList, 0, (uiLength + 1) * sizeof(ALchar)); + for (pDevice = g_pDeviceList; pDevice; pDevice = pDevice->pNextDevice) + { + strcpy(pszTemp, pDevice->pszDeviceName); + pszTemp += (strlen(pDevice->pszDeviceName) + 1); + } + } + + // Determine what the Default Device should be + if (GetDefaultPlaybackDeviceName(&pszDefaultName)) + { + bFound = false; + + // Search for an exact match first + bFound = FindDevice(g_pDeviceList, pszDefaultName, true, &pszDefaultDeviceSpecifier); + + // If we haven't found a match ... search for a partial match if name contains 'X-Fi' + if ((!bFound) && (strstr(pszDefaultName, "X-Fi"))) + bFound = FindDevice(g_pDeviceList, "X-Fi", false, &pszDefaultDeviceSpecifier); + + // If we haven't found a match ... search for a partial match if name contains 'Audigy' + if ((!bFound) && (strstr(pszDefaultName, "Audigy"))) + bFound = FindDevice(g_pDeviceList, "Audigy", false, &pszDefaultDeviceSpecifier); + + // If we haven't found a match ... search for a partial match with 'Generic Hardware' + if (!bFound) + bFound = FindDevice(g_pDeviceList, "Generic Hardware", false, &pszDefaultDeviceSpecifier); + + // If we haven't found a match ... search for a partial match with 'Generic Software' + if (!bFound) + bFound = FindDevice(g_pDeviceList, "Generic Software", false, &pszDefaultDeviceSpecifier); + + // If we STILL haven't found a match ... pick the 1st device! + if (!bFound) + { + pszDefaultDeviceSpecifier = (char*)malloc((strlen(g_pDeviceList->pszDeviceName) + 1) * sizeof(char)); + if (pszDefaultDeviceSpecifier) + strcpy(pszDefaultDeviceSpecifier, g_pDeviceList->pszDeviceName); + } + + free(pszDefaultName); + pszDefaultName = NULL; + } + } + + if (g_pCaptureDeviceList) + { + uiLength = 0; + for (pDevice = g_pCaptureDeviceList; pDevice; pDevice = pDevice->pNextDevice) + uiLength += (strlen(pDevice->pszDeviceName) + 1); + + pszCaptureDeviceSpecifierList = (ALchar*)malloc((uiLength + 1) * sizeof(ALchar)); + if (pszTemp = pszCaptureDeviceSpecifierList) + { + memset(pszCaptureDeviceSpecifierList, 0, (uiLength + 1) * sizeof(ALchar)); + for (pDevice = g_pCaptureDeviceList; pDevice; pDevice = pDevice->pNextDevice) + { + strcpy(pszTemp, pDevice->pszDeviceName); + pszTemp += (strlen(pDevice->pszDeviceName) + 1); + } + } + + if (GetDefaultCaptureDeviceName(&pszDefaultName)) + { + bFound = false; + + // Search for an exact match first + bFound = FindDevice(g_pCaptureDeviceList, pszDefaultName, true, &pszDefaultCaptureDeviceSpecifier); + + // If we haven't found a match, truncate the default name to 32 characters (MMSYSTEM limitation) + if ((!bFound) && (strlen(pszDefaultName) > 31)) + { + pszDefaultName[31] = '\0'; + bFound = FindDevice(g_pCaptureDeviceList, pszDefaultName, true, &pszDefaultCaptureDeviceSpecifier); + } + + // If we haven't found a match ... pick the 1st device! + if (!bFound) + { + pszDefaultCaptureDeviceSpecifier = (char*)malloc((strlen(g_pCaptureDeviceList->pszDeviceName) + 1) * sizeof(char)); + if (pszDefaultCaptureDeviceSpecifier) + strcpy(pszDefaultCaptureDeviceSpecifier, g_pCaptureDeviceList->pszDeviceName); + } + + free(pszDefaultName); + pszDefaultName = NULL; + } + } + + if (g_pAllDevicesList) + { + uiLength = 0; + for (pDevice = g_pAllDevicesList; pDevice; pDevice = pDevice->pNextDevice) + uiLength += (strlen(pDevice->pszDeviceName) + 1); + + pszAllDevicesSpecifierList = (ALchar*)malloc((uiLength + 1) * sizeof(ALchar)); + if (pszTemp = pszAllDevicesSpecifierList) + { + memset(pszAllDevicesSpecifierList, 0, (uiLength + 1) * sizeof(ALchar)); + for (pDevice = g_pAllDevicesList; pDevice; pDevice = pDevice->pNextDevice) + { + strcpy(pszTemp, pDevice->pszDeviceName); + pszTemp += (strlen(pDevice->pszDeviceName) + 1); + } + } + + // Determine what the Default Device should be + if (GetDefaultPlaybackDeviceName(&pszDefaultName)) + { + bFound = false; + + // If the (regular) default Playback device exists in this list ... use that + bFound = FindDevice(g_pAllDevicesList, pszDefaultDeviceSpecifier, true, &pszDefaultAllDevicesSpecifier); + + // If we haven't found a match ... pick a partial match with the Default Device Name + if (!bFound) + bFound = FindDevice(g_pAllDevicesList, pszDefaultName, false, &pszDefaultAllDevicesSpecifier); + + // If we STILL haven't found a match ... pick the 1st device! + if (!bFound) + { + pszDefaultAllDevicesSpecifier = (char*)malloc((strlen(g_pAllDevicesList->pszDeviceName) + 1) * sizeof(char)); + if (pszDefaultAllDevicesSpecifier) + strcpy(pszDefaultAllDevicesSpecifier, g_pAllDevicesList->pszDeviceName); + } + + free(pszDefaultName); + pszDefaultName = NULL; + } + } + } + + return; +} + + + + +//***************************************************************************** +// HasDLLAlreadyBeenUsed +//***************************************************************************** +bool HasDLLAlreadyBeenUsed(ALDEVICE *pDeviceList, TCHAR *szDLLName) +{ + // Checks if an OpenAL DLL has already been enumerated + ALDEVICE *pDevice = NULL; + TCHAR *szHostDLLName; + bool bReturn = false; + + for (pDevice = pDeviceList; pDevice; pDevice = pDevice->pNextDevice) + { + szHostDLLName = _tcsrchr(pDevice->pszHostDLLFilename, _T('\\')); + if (szHostDLLName) + szHostDLLName++; // Skip over the '\' + else + szHostDLLName = pDevice->pszHostDLLFilename; + + if (_tcscmp(szHostDLLName, szDLLName) == 0) + { + bReturn = true; + break; + } + } + + return bReturn; +} + + + + +//***************************************************************************** +// ValidCaptureDevice +//***************************************************************************** +/* +bool ValidCaptureDevice(const char *szCaptureDeviceName) +{ + // Microsoft changed the behaviour of Input devices on Windows Vista such that *each* input + // on each soundcard is reported as a separate device. Unfortunately, even though you can + // enumerate each input there are restrictions on what devices can be opened (e.g. you can only + // open the soundcard's default input). There is no API call to change the default input, so + // there is little point enumerating input devices that cannot be used, so we filter them out here. + WAVEFORMATEX wfex = { WAVE_FORMAT_PCM, 1, 22050, 44100, 2, 16, 0 }; // 16bit Mono 22050Hz + WAVEINCAPS WaveInCaps; + HWAVEIN hWaveIn; + bool bValid = false; + + // Find the device ID from the device name + long lNumCaptureDevs = waveInGetNumDevs(); + long lDeviceID = -1; + for (long lLoop = 0; lLoop < lNumCaptureDevs; lLoop++) + { + if (waveInGetDevCaps(lLoop, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) + { + if (!strcmp(szCaptureDeviceName, WaveInCaps.szPname)) + { + lDeviceID = lLoop; + break; + } + } + } + + if (lDeviceID != -1) + { + if (waveInOpen(&hWaveIn, lDeviceID, &wfex, NULL, NULL, WAVE_MAPPED) == MMSYSERR_NOERROR) + { + waveInClose(hWaveIn); + bValid = true; + } + } + + return bValid; +} +*/ + + + +//***************************************************************************** +// GetDefaultPlaybackDeviceName +//***************************************************************************** +bool GetDefaultPlaybackDeviceName(char **pszName) +{ + // Try to use DirectSound to get the name of the 'Preferred Audio Device / Endpoint" + // If that fails use MMSYSTEM (name will be limited to 32 characters in length) + TCHAR szPath[_MAX_PATH]; + HINSTANCE hDSoundDLL; + + if (!pszName) + return false; + + *pszName = NULL; + + // Load dsound.dll from the System Directory and use the DirectSoundEnumerateA function to + // get the list of playback devices + if (GetSystemDirectory(szPath, _MAX_PATH)) + { + _tcscat(szPath, "\\dsound.dll"); + hDSoundDLL = LoadLibrary(szPath); + if (hDSoundDLL) + { + LPDIRECTSOUNDENUMERATEA pfnDirectSoundEnumerateA = (LPDIRECTSOUNDENUMERATEA)GetProcAddress(hDSoundDLL, "DirectSoundEnumerateA"); + if (pfnDirectSoundEnumerateA) + pfnDirectSoundEnumerateA(&DSEnumCallback, pszName); + FreeLibrary(hDSoundDLL); + } + } + + // Falling back to MMSYSTEM + if (*pszName == NULL) + { + UINT uDeviceID=0; + DWORD dwFlags=1; + WAVEOUTCAPS outputInfo; + + #if !defined(_WIN64) + #ifdef __GNUC__ + __asm__ ("pusha;"); + #else + __asm pusha; // workaround for register destruction caused by these wavOutMessage calls (weird but true) + #endif + #endif // !defined(_WIN64) + waveOutMessage((HWAVEOUT)(UINT_PTR)WAVE_MAPPER,0x2000+0x0015,(LPARAM)&uDeviceID,(WPARAM)&dwFlags); + waveOutGetDevCaps(uDeviceID,&outputInfo,sizeof(outputInfo)); + #if !defined(_WIN64) + #ifdef __GNUC__ + __asm__ ("popa;"); + #else + __asm popa; + #endif + #endif // !defined(_WIN64) + + *pszName = (char*)malloc((strlen(outputInfo.szPname) + 1) * sizeof(char)); + if (*pszName) + strcpy(*pszName, outputInfo.szPname); + } + + return (*pszName) ? true : false; +} + + + + +//***************************************************************************** +// GetDefaultCaptureDeviceName +//***************************************************************************** +bool GetDefaultCaptureDeviceName(char **pszName) +{ + // Try to use DirectSound to get the name of the 'Preferred Audio Device / Endpoint" for recording. + // If that fails use MMSYSTEM (name will be limited to 32 characters in length) + TCHAR szPath[_MAX_PATH]; + HINSTANCE hDSoundDLL; + + if (!pszName) + return false; + + *pszName = NULL; + + // Load dsound.dll from the System Directory and use the DirectSoundCaptureEnumerateA function to + // get the list of capture devices + if (GetSystemDirectory(szPath, _MAX_PATH)) + { + _tcscat(szPath, "\\dsound.dll"); + hDSoundDLL = LoadLibrary(szPath); + if (hDSoundDLL) + { + LPDIRECTSOUNDCAPTUREENUMERATEA pfnDirectSoundCaptureEnumerateA = (LPDIRECTSOUNDCAPTUREENUMERATEA)GetProcAddress(hDSoundDLL, "DirectSoundCaptureEnumerateA"); + if (pfnDirectSoundCaptureEnumerateA) + pfnDirectSoundCaptureEnumerateA(&DSEnumCallback, pszName); + FreeLibrary(hDSoundDLL); + } + } + + // Falling back to MMSYSTEM + if (*pszName == NULL) + { + UINT uDeviceID=0; + DWORD dwFlags=1; + WAVEINCAPS inputInfo; + + #if !defined(_WIN64) + #ifdef __GNUC__ + __asm__ ("pusha;"); + #else + __asm pusha; // workaround for register destruction caused by these wavOutMessage calls (weird but true) + #endif + #endif // !defined(_WIN64) + waveInMessage((HWAVEIN)(UINT_PTR)WAVE_MAPPER,0x2000+0x0015,(LPARAM)&uDeviceID,(WPARAM)&dwFlags); + waveInGetDevCaps(uDeviceID, &inputInfo, sizeof(inputInfo)); + #if !defined(_WIN64) + #ifdef __GNUC__ + __asm__ ("popa;"); + #else + __asm popa; + #endif + #endif // !defined(_WIN64) + + *pszName = (char*)malloc((strlen(inputInfo.szPname) + 1) * sizeof(char)); + if (*pszName) + strcpy(*pszName, inputInfo.szPname); + } + + return (*pszName) ? true : false; +} + + + + +//***************************************************************************** +// DSEnumCallback +//***************************************************************************** +BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) +{ + // DirectSound Enumeration callback will be called for each device found. + // The first device returned with a non-NULL GUID is the 'preferred device' + + // Skip over the device without a GUID + if (lpGuid) + { + char **pszName = (char**)lpContext; + *pszName = (char*)malloc((strlen(lpcstrDescription)+1) * sizeof(char)); + if (*pszName) + { + strcpy(*pszName, lpcstrDescription); + return FALSE; + } + } + + return TRUE; +} + + + +//***************************************************************************** +// FindDevice +//***************************************************************************** +bool FindDevice(ALDEVICE *pDeviceList, char *szDeviceName, bool bExactMatch, char **ppszDefaultName) +{ + // Search through pDeviceList for szDeviceName using an exact match if bExactMatch is true, or using + // a sub-string search otherwise. + // If found, allocate memory for *ppszDefaultName and copy the device name over + ALDEVICE *pDevice = NULL; + bool bFound = false; + + if (!pDeviceList || !szDeviceName || !ppszDefaultName) + return false; + + for (pDevice = pDeviceList; pDevice; pDevice = pDevice->pNextDevice) + { + if (bExactMatch) + bFound = (strcmp(pDevice->pszDeviceName, szDeviceName) == 0) ? true : false; + else + bFound = (strstr(pDevice->pszDeviceName, szDeviceName)) ? true : false; + + if (bFound) + { + *ppszDefaultName = (char*)malloc((strlen(pDevice->pszDeviceName) + 1) * sizeof(char)); + if (*ppszDefaultName) + { + strcpy(*ppszDefaultName, pDevice->pszDeviceName); + break; + } + } + } + + return *ppszDefaultName ? true : false; +} + + + + +//***************************************************************************** +// LoadDevicesDLL +//***************************************************************************** +HINSTANCE LoadDevicesDLL(ALDEVICE *pDeviceList, const ALchar *szDeviceName) +{ + // Search pDeviceList for szDeviceName, and when found load the OpenAL DLL + // that contains that Device name. + HINSTANCE hDLL = NULL; + ALDEVICE *pDevice; + + for (pDevice = pDeviceList; pDevice; pDevice = pDevice->pNextDevice) + { + if (strcmp(pDevice->pszDeviceName, szDeviceName) == 0) + { + hDLL = LoadLibrary(pDevice->pszHostDLLFilename); + break; + } + } + + return hDLL; +} + + + + +//***************************************************************************** +// FillOutAlcFunctions +//***************************************************************************** +ALboolean FillOutAlcFunctions(ALCdevice* device) +{ + ALboolean alcFxns = FALSE; + ALCAPI_FXN_TABLE* alcApi = &device->AlcApi; + + memset(alcApi, 0, sizeof(ALCAPI_FXN_TABLE)); + + // + // Get the OpenAL 1.0 Entry points. + // + alcApi->alcCreateContext = (ALCAPI_CREATE_CONTEXT)GetProcAddress(device->Dll, "alcCreateContext"); + alcApi->alcMakeContextCurrent = (ALCAPI_MAKE_CONTEXT_CURRENT)GetProcAddress(device->Dll, "alcMakeContextCurrent"); + alcApi->alcProcessContext = (ALCAPI_PROCESS_CONTEXT)GetProcAddress(device->Dll, "alcProcessContext"); + alcApi->alcSuspendContext = (ALCAPI_SUSPEND_CONTEXT)GetProcAddress(device->Dll, "alcSuspendContext"); + alcApi->alcDestroyContext = (ALCAPI_DESTROY_CONTEXT)GetProcAddress(device->Dll, "alcDestroyContext"); + alcApi->alcGetCurrentContext = (ALCAPI_GET_CURRENT_CONTEXT)GetProcAddress(device->Dll, "alcGetCurrentContext"); + alcApi->alcGetContextsDevice = (ALCAPI_GET_CONTEXTS_DEVICE)GetProcAddress(device->Dll, "alcGetContextsDevice"); + + alcApi->alcOpenDevice = (ALCAPI_OPEN_DEVICE)GetProcAddress(device->Dll, "alcOpenDevice"); + alcApi->alcCloseDevice = (ALCAPI_CLOSE_DEVICE)GetProcAddress(device->Dll, "alcCloseDevice"); + + alcApi->alcGetError = (ALCAPI_GET_ERROR)GetProcAddress(device->Dll, "alcGetError"); + + alcApi->alcIsExtensionPresent = (ALCAPI_IS_EXTENSION_PRESENT)GetProcAddress(device->Dll, "alcIsExtensionPresent"); + alcApi->alcGetProcAddress = (ALCAPI_GET_PROC_ADDRESS)GetProcAddress(device->Dll, "alcGetProcAddress"); + alcApi->alcGetEnumValue = (ALCAPI_GET_ENUM_VALUE)GetProcAddress(device->Dll, "alcGetEnumValue"); + + alcApi->alcGetString = (ALCAPI_GET_STRING)GetProcAddress(device->Dll, "alcGetString"); + alcApi->alcGetIntegerv = (ALCAPI_GET_INTEGERV)GetProcAddress(device->Dll, "alcGetIntegerv"); + + // + // Get the OpenAL 1.1 Entry points. + // + alcApi->alcCaptureOpenDevice = (ALCAPI_CAPTURE_OPEN_DEVICE)GetProcAddress(device->Dll, "alcCaptureOpenDevice"); + alcApi->alcCaptureCloseDevice = (ALCAPI_CAPTURE_CLOSE_DEVICE)GetProcAddress(device->Dll, "alcCaptureCloseDevice"); + alcApi->alcCaptureStart = (ALCAPI_CAPTURE_START)GetProcAddress(device->Dll, "alcCaptureStart"); + alcApi->alcCaptureStop = (ALCAPI_CAPTURE_STOP)GetProcAddress(device->Dll, "alcCaptureStop"); + alcApi->alcCaptureSamples = (ALCAPI_CAPTURE_SAMPLES)GetProcAddress(device->Dll, "alcCaptureSamples"); + + // handle legacy issue with old Creative DLLs which may not have alcGetProcAddress, alcIsExtensionPresent, alcGetEnumValue + if (alcApi->alcGetProcAddress == NULL) { + alcApi->alcGetProcAddress = (ALCAPI_GET_PROC_ADDRESS)alcGetProcAddress; + } + if (alcApi->alcIsExtensionPresent == NULL) { + alcApi->alcIsExtensionPresent = (ALCAPI_IS_EXTENSION_PRESENT)alcIsExtensionPresent; + } + if (alcApi->alcGetEnumValue == NULL) { + alcApi->alcGetEnumValue = (ALCAPI_GET_ENUM_VALUE)alcGetEnumValue; + } + + + alcFxns = (alcApi->alcCreateContext && + alcApi->alcMakeContextCurrent && + alcApi->alcProcessContext && + alcApi->alcSuspendContext && + alcApi->alcDestroyContext && + alcApi->alcGetCurrentContext && + alcApi->alcGetContextsDevice && + alcApi->alcOpenDevice && + alcApi->alcCloseDevice && + alcApi->alcGetError && + alcApi->alcIsExtensionPresent && + alcApi->alcGetProcAddress && + alcApi->alcGetEnumValue && + alcApi->alcGetString && + alcApi->alcGetIntegerv); + + return alcFxns; +} + + + + +//***************************************************************************** +// FillOutAlFunctions +//***************************************************************************** +ALboolean FillOutAlFunctions(ALCcontext* context) +{ + ALboolean alFxns = FALSE; + ALAPI_FXN_TABLE* alApi = &context->AlApi; + + memset(alApi, 0, sizeof(ALAPI_FXN_TABLE)); + + // + // Get the OpenAL 1.0 & 1.1 Entry points. + // + alApi->alEnable = (ALAPI_ENABLE)GetProcAddress(context->Device->Dll, "alEnable"); + alApi->alDisable = (ALAPI_DISABLE)GetProcAddress(context->Device->Dll, "alDisable"); + alApi->alIsEnabled = (ALAPI_IS_ENABLED)GetProcAddress(context->Device->Dll, "alIsEnabled"); + + alApi->alGetString = (ALAPI_GET_STRING)GetProcAddress(context->Device->Dll, "alGetString"); + alApi->alGetBooleanv = (ALAPI_GET_BOOLEANV)GetProcAddress(context->Device->Dll, "alGetBooleanv"); + alApi->alGetIntegerv = (ALAPI_GET_INTEGERV)GetProcAddress(context->Device->Dll, "alGetIntegerv"); + alApi->alGetFloatv = (ALAPI_GET_FLOATV)GetProcAddress(context->Device->Dll, "alGetFloatv"); + alApi->alGetDoublev = (ALAPI_GET_DOUBLEV)GetProcAddress(context->Device->Dll, "alGetDoublev"); + alApi->alGetBoolean = (ALAPI_GET_BOOLEAN)GetProcAddress(context->Device->Dll, "alGetBoolean"); + alApi->alGetInteger = (ALAPI_GET_INTEGER)GetProcAddress(context->Device->Dll, "alGetInteger"); + alApi->alGetFloat = (ALAPI_GET_FLOAT)GetProcAddress(context->Device->Dll, "alGetFloat"); + alApi->alGetDouble = (ALAPI_GET_DOUBLE)GetProcAddress(context->Device->Dll, "alGetDouble"); + alApi->alGetError = (ALAPI_GET_ERROR)GetProcAddress(context->Device->Dll, "alGetError"); + alApi->alIsExtensionPresent = (ALAPI_IS_EXTENSION_PRESENT)GetProcAddress(context->Device->Dll, "alIsExtensionPresent"); + alApi->alGetProcAddress = (ALAPI_GET_PROC_ADDRESS)GetProcAddress(context->Device->Dll, "alGetProcAddress"); + alApi->alGetEnumValue = (ALAPI_GET_ENUM_VALUE)GetProcAddress(context->Device->Dll, "alGetEnumValue"); + + alApi->alListenerf = (ALAPI_LISTENERF)GetProcAddress(context->Device->Dll, "alListenerf"); + alApi->alListener3f = (ALAPI_LISTENER3F)GetProcAddress(context->Device->Dll, "alListener3f"); + alApi->alListenerfv = (ALAPI_LISTENERFV)GetProcAddress(context->Device->Dll, "alListenerfv"); + alApi->alListeneri = (ALAPI_LISTENERI)GetProcAddress(context->Device->Dll, "alListeneri"); + alApi->alListener3i = (ALAPI_LISTENER3I)GetProcAddress(context->Device->Dll, "alListener3i"); + alApi->alListeneriv = (ALAPI_LISTENERIV)GetProcAddress(context->Device->Dll, "alListeneriv"); + alApi->alGetListenerf = (ALAPI_GET_LISTENERF)GetProcAddress(context->Device->Dll, "alGetListenerf"); + alApi->alGetListener3f = (ALAPI_GET_LISTENER3F)GetProcAddress(context->Device->Dll, "alGetListener3f"); + alApi->alGetListenerfv = (ALAPI_GET_LISTENERFV)GetProcAddress(context->Device->Dll, "alGetListenerfv"); + alApi->alGetListeneri = (ALAPI_GET_LISTENERI)GetProcAddress(context->Device->Dll, "alGetListeneri"); + alApi->alGetListener3i = (ALAPI_GET_LISTENER3I)GetProcAddress(context->Device->Dll, "alGetListener3i"); + alApi->alGetListeneriv = (ALAPI_GET_LISTENERIV)GetProcAddress(context->Device->Dll, "alGetListeneriv"); + + alApi->alGenSources = (ALAPI_GEN_SOURCES)GetProcAddress(context->Device->Dll, "alGenSources"); + alApi->alDeleteSources = (ALAPI_DELETE_SOURCES)GetProcAddress(context->Device->Dll, "alDeleteSources"); + alApi->alIsSource = (ALAPI_IS_SOURCE)GetProcAddress(context->Device->Dll, "alIsSource"); + alApi->alSourcef = (ALAPI_SOURCEF)GetProcAddress(context->Device->Dll, "alSourcef"); + alApi->alSource3f = (ALAPI_SOURCE3F)GetProcAddress(context->Device->Dll, "alSource3f"); + alApi->alSourcefv = (ALAPI_SOURCEFV)GetProcAddress(context->Device->Dll, "alSourcefv"); + alApi->alSourcei = (ALAPI_SOURCEI)GetProcAddress(context->Device->Dll, "alSourcei"); + alApi->alSource3i = (ALAPI_SOURCE3I)GetProcAddress(context->Device->Dll, "alSource3i"); + alApi->alSourceiv = (ALAPI_SOURCEIV)GetProcAddress(context->Device->Dll, "alSourceiv"); + alApi->alGetSourcef = (ALAPI_GET_SOURCEF)GetProcAddress(context->Device->Dll, "alGetSourcef"); + alApi->alGetSource3f = (ALAPI_GET_SOURCE3F)GetProcAddress(context->Device->Dll, "alGetSource3f"); + alApi->alGetSourcefv = (ALAPI_GET_SOURCEFV)GetProcAddress(context->Device->Dll, "alGetSourcefv"); + alApi->alGetSourcei = (ALAPI_GET_SOURCEI)GetProcAddress(context->Device->Dll, "alGetSourcei"); + alApi->alGetSource3i = (ALAPI_GET_SOURCE3I)GetProcAddress(context->Device->Dll, "alGetSource3i"); + alApi->alGetSourceiv = (ALAPI_GET_SOURCEIV)GetProcAddress(context->Device->Dll, "alGetSourceiv"); + alApi->alSourcePlayv = (ALAPI_SOURCE_PLAYV)GetProcAddress(context->Device->Dll, "alSourcePlayv"); + alApi->alSourceStopv = (ALAPI_SOURCE_STOPV)GetProcAddress(context->Device->Dll, "alSourceStopv"); + alApi->alSourceRewindv = (ALAPI_SOURCE_REWINDV)GetProcAddress(context->Device->Dll, "alSourceRewindv"); + alApi->alSourcePausev = (ALAPI_SOURCE_PAUSEV)GetProcAddress(context->Device->Dll, "alSourcePausev"); + alApi->alSourcePlay = (ALAPI_SOURCE_PLAY)GetProcAddress(context->Device->Dll, "alSourcePlay"); + alApi->alSourceStop = (ALAPI_SOURCE_STOP)GetProcAddress(context->Device->Dll, "alSourceStop"); + alApi->alSourceRewind = (ALAPI_SOURCE_STOP)GetProcAddress(context->Device->Dll, "alSourceRewind"); + alApi->alSourcePause = (ALAPI_SOURCE_PAUSE)GetProcAddress(context->Device->Dll, "alSourcePause"); + + alApi->alSourceQueueBuffers = (ALAPI_SOURCE_QUEUE_BUFFERS)GetProcAddress(context->Device->Dll, "alSourceQueueBuffers"); + alApi->alSourceUnqueueBuffers = (ALAPI_SOURCE_UNQUEUE_BUFFERS)GetProcAddress(context->Device->Dll, "alSourceUnqueueBuffers"); + + alApi->alGenBuffers = (ALAPI_GEN_BUFFERS)GetProcAddress(context->Device->Dll, "alGenBuffers"); + alApi->alDeleteBuffers = (ALAPI_DELETE_BUFFERS)GetProcAddress(context->Device->Dll, "alDeleteBuffers"); + alApi->alIsBuffer = (ALAPI_IS_BUFFER)GetProcAddress(context->Device->Dll, "alIsBuffer"); + alApi->alBufferData = (ALAPI_BUFFER_DATA)GetProcAddress(context->Device->Dll, "alBufferData"); + alApi->alBufferf = (ALAPI_BUFFERF)GetProcAddress(context->Device->Dll, "alBufferf"); + alApi->alBuffer3f = (ALAPI_BUFFER3F)GetProcAddress(context->Device->Dll, "alBuffer3f"); + alApi->alBufferfv = (ALAPI_BUFFERFV)GetProcAddress(context->Device->Dll, "alBufferfv"); + alApi->alBufferi = (ALAPI_BUFFERI)GetProcAddress(context->Device->Dll, "alBufferi"); + alApi->alBuffer3i = (ALAPI_BUFFER3I)GetProcAddress(context->Device->Dll, "alBuffer3i"); + alApi->alBufferiv = (ALAPI_BUFFERIV)GetProcAddress(context->Device->Dll, "alBufferiv"); + alApi->alGetBufferf = (ALAPI_GET_BUFFERF)GetProcAddress(context->Device->Dll, "alGetBufferf"); + alApi->alGetBuffer3f = (ALAPI_GET_BUFFER3F)GetProcAddress(context->Device->Dll, "alGetBuffer3f"); + alApi->alGetBufferfv = (ALAPI_GET_BUFFERFV)GetProcAddress(context->Device->Dll, "alGetBufferfv"); + alApi->alGetBufferi = (ALAPI_GET_BUFFERI)GetProcAddress(context->Device->Dll, "alGetBufferi"); + alApi->alGetBuffer3i = (ALAPI_GET_BUFFER3I)GetProcAddress(context->Device->Dll, "alGetBuffer3i"); + alApi->alGetBufferiv = (ALAPI_GET_BUFFERIV)GetProcAddress(context->Device->Dll, "alGetBufferiv"); + + alApi->alDopplerFactor = (ALAPI_DOPPLER_FACTOR)GetProcAddress(context->Device->Dll, "alDopplerFactor"); + alApi->alDopplerVelocity = (ALAPI_DOPPLER_VELOCITY)GetProcAddress(context->Device->Dll, "alDopplerVelocity"); + alApi->alSpeedOfSound = (ALAPI_SPEED_OF_SOUND)GetProcAddress(context->Device->Dll, "alSpeedOfSound"); + alApi->alDistanceModel = (ALAPI_DISTANCE_MODEL)GetProcAddress(context->Device->Dll, "alDistanceModel"); + + alFxns = (alApi->alEnable && + alApi->alDisable && + alApi->alIsEnabled && + + alApi->alGetString && + alApi->alGetBooleanv && + alApi->alGetIntegerv && + alApi->alGetFloatv && + alApi->alGetDoublev && + alApi->alGetBoolean && + alApi->alGetInteger && + alApi->alGetFloat && + alApi->alGetDouble && + + alApi->alGetError && + + alApi->alIsExtensionPresent && + alApi->alGetProcAddress && + alApi->alGetEnumValue && + + alApi->alListenerf && + alApi->alListener3f && + alApi->alListenerfv && + alApi->alListeneri && + alApi->alGetListenerf && + alApi->alGetListener3f && + alApi->alGetListenerfv && + alApi->alGetListeneri && + + alApi->alGenSources && + alApi->alDeleteSources && + alApi->alIsSource && + alApi->alSourcef && + alApi->alSource3f && + alApi->alSourcefv && + alApi->alSourcei && + alApi->alGetSourcef && + alApi->alGetSource3f && + alApi->alGetSourcefv && + alApi->alGetSourcei && + alApi->alSourcePlayv && + alApi->alSourceStopv && + alApi->alSourceRewindv && + alApi->alSourcePausev && + alApi->alSourcePlay && + alApi->alSourceStop && + alApi->alSourceRewind && + alApi->alSourcePause && + + alApi->alSourceQueueBuffers && + alApi->alSourceUnqueueBuffers && + + alApi->alGenBuffers && + alApi->alDeleteBuffers && + alApi->alIsBuffer && + alApi->alBufferData && + alApi->alGetBufferf && + alApi->alGetBufferi && + + alApi->alDopplerFactor && + alApi->alDopplerVelocity && + alApi->alDistanceModel); + + return alFxns; +} + + + + +//***************************************************************************** +//***************************************************************************** +// +// ALC API Entry Points +// +//*****************************************************************************ALC_ +//***************************************************************************** + +//***************************************************************************** +// alcCloseDevice +//***************************************************************************** +// +ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice(ALCdevice* device) +{ +#ifdef _LOGCALLS + LOG("alcCloseDevice device %p\n", device); +#endif + if(!device) + { + return ALC_FALSE; + } + + if (device == g_CaptureDevice) + return g_CaptureDevice->AlcApi.alcCloseDevice(g_CaptureDevice->CaptureDevice); + + // + // Check if its linked to a context. + // + if(device->InUse) + { + ALCcontext* context = 0; + ALlistEntry* entry = 0; + + // + // Not all of the contexts using the device have been destroyed. + // + assert(0); + + // + // Loop through the context list and free and contexts linked to the device. + // Go back to the beginning each time in case some one changed the context + // list iterator. + // + alListAcquireLock(alContextList); + entry = alListIteratorReset(alContextList); + while(entry) + { + context = (ALCcontext*)alListGetData(entry); + if(context->Device == device) + { + alListReleaseLock(alContextList); + alcDestroyContext((ALCcontext *)context); + alListAcquireLock(alContextList); + entry = alListIteratorReset(alContextList); + } + + else + { + entry = alListIteratorNext(alContextList); + } + } + + alListReleaseLock(alContextList); + assert(!device->InUse); + } + + device->AlcApi.alcCloseDevice(device->DllDevice); + FreeLibrary(device->Dll); + free(device); + + return ALC_TRUE; +} + + + + +//***************************************************************************** +// alcCreateContext +//***************************************************************************** +ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice* device, const ALint* attrList) +{ +#ifdef _LOGCALLS + LOG("alcCreateContext device %p ", device); + if (attrList) + { + unsigned long ulIndex = 0; + while ((ulIndex < 16) && (attrList[ulIndex])) + { + switch(attrList[ulIndex]) + { + case ALC_FREQUENCY: + LOG("ALC_FREQUENCY %d ", attrList[ulIndex + 1]); + break; + + case ALC_REFRESH: + LOG("ALC_REFRESH %d ", attrList[ulIndex + 1]); + break; + + case ALC_SYNC: + LOG("ALC_SYNC %d ", attrList[ulIndex + 1]); + break; + + case ALC_MONO_SOURCES: + LOG("ALC_MONO_SOURCES %d ", attrList[ulIndex + 1]); + break; + + case ALC_STEREO_SOURCES: + LOG("ALC_STEREO_SOURCES %d ", attrList[ulIndex + 1]); + break; + + case 0x20003/*ALC_MAX_AUXILIARY_SENDS*/: + LOG("ALC_MAX_AUXILIARY_SENDS %d", attrList[ulIndex + 1]); + break; + } + ulIndex += 2; + } + } + LOG("\n"); +#endif + + ALCcontext* context = 0; + + if(!device) + { + LastError = ALC_INVALID_DEVICE; + return 0; + } + + if (device == g_CaptureDevice) + return g_CaptureDevice->AlcApi.alcCreateContext(g_CaptureDevice->CaptureDevice, attrList); + + // + // Allocate the context. + // + context = (ALCcontext*)malloc(sizeof(ALCcontext)); + if(!context) + { + return 0; + } + + memset(context, 0, sizeof(ALCcontext)); + context->Device = device; + context->Suspended = FALSE; + context->LastError = ALC_NO_ERROR; + InitializeCriticalSection(&context->Lock); + + // + // We don't fill out the AL functions in case they are context specific. + // + + context->DllContext = device->AlcApi.alcCreateContext(device->DllDevice, attrList); + if(!context->DllContext) + { + DeleteCriticalSection(&context->Lock); + free(context); + context = 0; + return 0; + } + + device->InUse++; + + // + // Add it to the context list. + // + alListInitializeEntry(&context->ListEntry, context); + alListAcquireLock(alContextList); + alListAddEntry(alContextList, &context->ListEntry); + alListReleaseLock(alContextList); + return context; +} + + + + +//***************************************************************************** +// alcDestroyContext +//***************************************************************************** +ALCAPI ALvoid ALCAPIENTRY alcDestroyContext(ALCcontext* context) +{ +#ifdef _LOGCALLS + LOG("alcDestroyContext context %p\n", context); +#endif + ALCcontext* listData = 0; + + if(!context) + { + return; + } + + // + // Remove the entry from the context list. + // + alListAcquireLock(alContextList); + listData = (ALCcontext*)alListRemoveEntry(alContextList, &context->ListEntry); + if(!listData) + { + alListReleaseLock(alContextList); + return; + } + + if(context == alCurrentContext) + { + alCurrentContext = 0; + } + + EnterCriticalSection(&context->Lock); + alListReleaseLock(alContextList); + + context->Device->InUse--; + + // Clean up the context. + if(context->DllContext) + { + context->Device->AlcApi.alcDestroyContext(context->DllContext); + } + + LeaveCriticalSection(&context->Lock); + DeleteCriticalSection(&context->Lock); + free(context); +} + + + + +//***************************************************************************** +// alcGetContextsDevice +//***************************************************************************** +ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext* context) +{ +#ifdef _LOGCALLS + LOG("alcGetContextsDevice context %p\n", context); +#endif + ALCdevice* ALCdevice = 0; + + alListAcquireLock(alContextList); + if(alListMatchData(alContextList, context)) + { + ALCdevice = context->Device; + } + + alListReleaseLock(alContextList); + + return ALCdevice; +} + + + + +//***************************************************************************** +// alcGetCurrentContext +//***************************************************************************** +ALCAPI ALCcontext* ALCAPIENTRY alcGetCurrentContext(ALvoid) +{ +#ifdef _LOGCALLS + LOG("alcGetCurrentContext\n"); +#endif + return (ALCcontext *)alCurrentContext; +} + + + + +//***************************************************************************** +// alcGetEnumValue +//***************************************************************************** +ALCAPI ALenum ALCAPIENTRY alcGetEnumValue(ALCdevice* device, const ALCchar* ename) +{ +#ifdef _LOGCALLS + LOG("alcGetEnumValue device %p enum name '%s'\n", device, ename ? ename : "<NULL>"); +#endif + // + // Always return the router version of the ALC enum if it exists. + // + ALsizei i = 0; + while(alcEnums[i].ename && strcmp((char*)alcEnums[i].ename, (char*)ename)) + { + i++; + } + + if(alcEnums[i].ename) + { + return alcEnums[i].value; + } + + if(device) + { + if (device == g_CaptureDevice) + return g_CaptureDevice->AlcApi.alcGetEnumValue(g_CaptureDevice->CaptureDevice, ename); + + return device->AlcApi.alcGetEnumValue(device->DllDevice, ename); + } + + LastError = ALC_INVALID_ENUM; + return 0; +} + + + + +//***************************************************************************** +// alcGetError +//***************************************************************************** +ALCAPI ALenum ALCAPIENTRY alcGetError(ALCdevice* device) +{ +#ifdef _LOGCALLS + LOG("alcGetError device %p\n", device); +#endif + ALenum errorCode = ALC_NO_ERROR; + + // Try to get a valid device. + if(!device) + { + if (g_CaptureDevice == device) + return + errorCode = LastError; + LastError = ALC_NO_ERROR; + return errorCode; + } + + // + // Check if its a 3rd party device. + // + if (device == g_CaptureDevice) + errorCode = g_CaptureDevice->AlcApi.alcGetError(g_CaptureDevice->CaptureDevice); + else + errorCode = device->AlcApi.alcGetError(device->DllDevice); + + return errorCode; +} + + + + +//***************************************************************************** +// alcGetIntegerv +//***************************************************************************** +ALCAPI ALvoid ALCAPIENTRY alcGetIntegerv(ALCdevice* device, ALenum param, ALsizei size, ALint* data) +{ +#ifdef _LOGCALLS + LOG("alcGetIntegerv device %p enum ", device); + switch (param) + { + case ALC_ATTRIBUTES_SIZE: + LOG("ALC_ATTRIBUTES_SIZE\n"); + break; + case ALC_ALL_ATTRIBUTES: + LOG("ALC_ALL_ATTRIBUTES\n"); + break; + case ALC_MAJOR_VERSION: + LOG("ALC_MAJOR_VERSION\n"); + break; + case ALC_MINOR_VERSION: + LOG("ALC_MINOR_VERSION\n"); + break; + case ALC_CAPTURE_SAMPLES: + LOG("ALC_CAPTURE_SAMPLES\n"); + break; + case ALC_FREQUENCY: + LOG("ALC_FREQUENCY\n"); + break; + case ALC_REFRESH: + LOG("ALC_REFRESH\n"); + break; + case ALC_SYNC: + LOG("ALC_SYNC\n"); + break; + case ALC_MONO_SOURCES: + LOG("ALC_MONO_SOURCES\n"); + break; + case ALC_STEREO_SOURCES: + LOG("ALC_STEREO_SOURCES\n"); + break; + case 0x20003: // ALC_MAX_AUXILIARY_SENDS + LOG("ALC_MAX_AUXILIARY_SENDS\n"); + break; + case 0x20001: // ALC_EFX_MAJOR_VERSION + LOG("ALC_EFX_MAJOR_VERSION\n"); + break; + case 0x20002: // ALC_EFX_MINOR_VERSION + LOG("ALC_EFX_MINOR_VERSION\n"); + break; + default: + LOG("<Unknown>\n"); + break; + } +#endif + + if(device) + { + if (device == g_CaptureDevice) + { + g_CaptureDevice->AlcApi.alcGetIntegerv(g_CaptureDevice->CaptureDevice, param, size, data); + return; + } + + device->AlcApi.alcGetIntegerv(device->DllDevice, param, size, data); + return; + } + + switch(param) + { + case ALC_MAJOR_VERSION: + { + if((size < sizeof(ALint)) || (data == 0)) + { + LastError = ALC_INVALID; + return; + } + + *data = alcMajorVersion; + } + break; + + case ALC_MINOR_VERSION: + { + if((size < sizeof(ALint)) || (data == 0)) + { + LastError = ALC_INVALID; + return; + } + + *data = alcMinorVersion; + } + break; + + default: + { + device->LastError = ALC_INVALID_ENUM; + } + break; + } +} + + + + +//***************************************************************************** +// alcGetProcAddress +//***************************************************************************** +ALCAPI ALvoid* ALCAPIENTRY alcGetProcAddress(ALCdevice* device, const ALCchar* fname) +{ +#ifdef _LOGCALLS + LOG("alcGetProcAddress device %p function name '%s'\n", device, fname ? fname : "<NULL>"); +#endif + + // + // Always return the router version of the ALC function if it exists. + // + ALsizei i = 0; + while(alcFunctions[i].fname && strcmp((char*)alcFunctions[i].fname, (char*)fname)) + { + i++; + } + + if(alcFunctions[i].fname) + { + return alcFunctions[i].address; + } + + if(device) + { + if (device == g_CaptureDevice) + return g_CaptureDevice->AlcApi.alcGetProcAddress(g_CaptureDevice->CaptureDevice, fname); + + return device->AlcApi.alcGetProcAddress(device->DllDevice, fname); + } + + LastError = ALC_INVALID_ENUM; + return 0; +} + + + + +//***************************************************************************** +// alcIsExtensionPresent +//***************************************************************************** +ALCAPI ALboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice* device, const ALCchar* ename) +{ +#ifdef _LOGCALLS + LOG("alcIsExtensionPresent device %p extension name '%s'\n", device, ename ? ename : "<NULL>"); +#endif + // + // Check if its a router supported extension first as its a good idea to have + // ALC calls go through the router if possible. + // + ALsizei i = 0; + while(alcExtensions[i].ename && _stricmp((char*)alcExtensions[i].ename, (char*)ename)) + { + i++; + } + + if(alcExtensions[i].ename) + { + return ALC_TRUE; + } + + // + // Check the device passed in to see if the extension is supported. + // + if(device) + { + if (device == g_CaptureDevice) + return g_CaptureDevice->AlcApi.alcIsExtensionPresent(g_CaptureDevice->CaptureDevice, ename); + + return device->AlcApi.alcIsExtensionPresent(device->DllDevice, ename); + } + + LastError = ALC_INVALID_ENUM; + return ALC_FALSE; +} + + + + +//***************************************************************************** +// alcMakeContextCurrent +//***************************************************************************** +ALCAPI ALboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext* context) +{ +#ifdef _LOGCALLS + LOG("alcMakeContextCurrent context %p\n", context); +#endif + ALboolean contextSwitched = AL_TRUE; + + // + // Context must be a valid context or 0 + // + alListAcquireLock(alContextList); + if(!alListMatchData(alContextList, context) && context != 0) + { + alListReleaseLock(alContextList); + return ALC_FALSE; + } + + // + // Try the new context. + // + if(context) + { + contextSwitched = context->Device->AlcApi.alcMakeContextCurrent(context->DllContext); + + // + // If this is the first time the context has been made the current context, fill in the context + // function pointers. + // + if(contextSwitched && !context->AlApi.alGetProcAddress) + { + // + // Don't fill out the functions here in case they are context specific pointers in the device. + // + if(!FillOutAlFunctions(context)) + { + LastError = ALC_INVALID_CONTEXT; + contextSwitched = AL_FALSE; + + // + // Something went wrong, restore the old context. + // + if(alCurrentContext) + { + alCurrentContext->Device->AlcApi.alcMakeContextCurrent(alCurrentContext->DllContext); + } + + else + { + alCurrentContext->Device->AlcApi.alcMakeContextCurrent(0); + } + } + } + } else { + if ((alCurrentContext) && (alCurrentContext->Device) && (alCurrentContext->Device->AlcApi.alcMakeContextCurrent)) { + contextSwitched = alCurrentContext->Device->AlcApi.alcMakeContextCurrent(0); + } + } + + // + // Set the context states if the switch was successful. + // + if(contextSwitched) + { + alCurrentContext = context; + } + + alListReleaseLock(alContextList); + return contextSwitched; +} + + + + +//***************************************************************************** +// alcOpenDevice +//***************************************************************************** +ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar* deviceName) +{ +#ifdef _LOGCALLS + LOG("alcOpenDevice device name '%s'\n", deviceName ? deviceName : "<NULL>"); +#endif + HINSTANCE dll = 0; + ALCdevice* device = 0; + const ALchar *pszDeviceName = NULL; + + BuildDeviceList(); + + if (g_pDeviceList) + { + if ((!deviceName) || (strlen(deviceName)==0) || (strcmp(deviceName, "DirectSound3D")==0)) + pszDeviceName = pszDefaultDeviceSpecifier; + else + pszDeviceName = deviceName; + + // Search for device in Playback Device List + dll = LoadDevicesDLL(g_pDeviceList, pszDeviceName); + + if (!dll) + { + // If NOT found, and the requested name is one of these ... + // "Generic Hardware" (no longer available on Windows Vista) + // "DirectSound" (legacy name for OpenAL Software mixer device) + // "MMSYSTEM" (legacy name for OpenAL Software mixer using MMSYSTEM instead of DirectSound) + // try to open the "Generic Software" device instead + if ((strcmp(pszDeviceName, "Generic Hardware") == 0) || + (strcmp(pszDeviceName, "DirectSound") == 0) || + (strcmp(pszDeviceName, "MMSYSTEM") == 0)) + { + dll = LoadDevicesDLL(g_pDeviceList, "Generic Software"); + } + } + + if (!dll) + dll = LoadDevicesDLL(g_pAllDevicesList, pszDeviceName); + + if (dll) + { + device = (ALCdevice*)malloc(sizeof(ALCdevice)); + if (device) + { + memset(device, 0, sizeof(ALCdevice)); + device->LastError = ALC_NO_ERROR; + device->InUse = 0; + device->Dll = dll; + if (FillOutAlcFunctions(device)) + device->DllDevice = device->AlcApi.alcOpenDevice(pszDeviceName); + + if (!device->DllDevice) + { + FreeLibrary(dll); + free(device); + device = 0; + } + } + } + } + + if (!device) + LastError = ALC_INVALID_DEVICE; + + return device; +} + + + + +//***************************************************************************** +// alcProcessContext +//***************************************************************************** +ALCAPI ALvoid ALCAPIENTRY alcProcessContext(ALCcontext* context) +{ +#ifdef _LOGCALLS + LOG("alcProcessContext context %p\n", context); +#endif + alListAcquireLock(alContextList); + if(!context && !alCurrentContext) + { + alListReleaseLock(alContextList); + return; + } + + if(!context) + { + context = alCurrentContext; + } + + EnterCriticalSection(&context->Lock); + alListReleaseLock(alContextList); + + if(context->DllContext) + { + context->Device->AlcApi.alcProcessContext(context->DllContext); + } + + context->Suspended = FALSE; + + LeaveCriticalSection(&context->Lock); + return; +} + + + + +//***************************************************************************** +// alcSuspendContext +//***************************************************************************** +ALCAPI ALCvoid ALCAPIENTRY alcSuspendContext(ALCcontext* context) +{ +#ifdef _LOGCALLS + LOG("alcSuspendContext context %p\n", context); +#endif + alListAcquireLock(alContextList); + if(!context && !alCurrentContext) + { + alListReleaseLock(alContextList); + return; + } + + if(!context) + { + context = (ALCcontext *)alCurrentContext; + } + + EnterCriticalSection(&context->Lock); + alListReleaseLock(alContextList); + + context->Suspended = TRUE; + + if(context->DllContext) + { + context->Device->AlcApi.alcSuspendContext(context->DllContext); + } + + LeaveCriticalSection(&context->Lock); + return; +} + + + + +//***************************************************************************** +// alcGetString +//***************************************************************************** +ALCAPI const ALCchar* ALCAPIENTRY alcGetString(ALCdevice* device, ALenum param) +{ +#ifdef _LOGCALLS + LOG("alcGetString device %p enum ", device); + switch (param) + { + case ALC_NO_ERROR: + LOG("ALC_NO_ERROR\n"); + break; + case ALC_INVALID_ENUM: + LOG("ALC_INVALID_ENUM\n"); + break; + case ALC_INVALID_VALUE: + LOG("ALC_INVALID_VALUE\n"); + break; + case ALC_INVALID_DEVICE: + LOG("ALC_INVALID_DEVICE\n"); + break; + case ALC_INVALID_CONTEXT: + LOG("ALC_INVALID_CONTEXT\n"); + break; + case ALC_DEFAULT_DEVICE_SPECIFIER: + LOG("ALC_DEFAULT_DEVICE_SPECIFIER\n"); + break; + case ALC_DEVICE_SPECIFIER: + LOG("ALC_DEVICE_SPECIFIER\n"); + break; + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + LOG("ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER\n"); + break; + case ALC_CAPTURE_DEVICE_SPECIFIER: + LOG("ALC_CAPTURE_DEVICE_SPECIFIER\n"); + break; + case ALC_ALL_DEVICES_SPECIFIER: + LOG("ALC_ALL_DEVICES_SPECIFIER\n"); + break; + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + LOG("ALC_DEFAULT_ALL_DEVICES_SPECIFIER\n"); + break; + case ALC_EXTENSIONS: + LOG("ALC_EXTENSIONS\n"); + break; + default: + LOG("<Unknown>\n"); + break; + } +#endif + + const ALCchar* value = 0; + + if ((param != ALC_DEFAULT_DEVICE_SPECIFIER) && (param != ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)) { + if(device) + { + if (device == g_CaptureDevice) + return g_CaptureDevice->AlcApi.alcGetString(g_CaptureDevice->CaptureDevice, param); + + return device->AlcApi.alcGetString(device->DllDevice, param); + } + } + + switch(param) + { + case ALC_NO_ERROR: + { + value = alcNoError; + } + break; + + case ALC_INVALID_ENUM: + { + value = alcErrInvalidEnum; + } + break; + + case ALC_INVALID_VALUE: + { + value = alcErrInvalidValue; + } + break; + + case ALC_INVALID_DEVICE: + { + value = alcErrInvalidDevice; + } + break; + + case ALC_INVALID_CONTEXT: + { + value = alcErrInvalidContext; + } + break; + + case ALC_DEFAULT_DEVICE_SPECIFIER: + BuildDeviceList(); + if (pszDefaultDeviceSpecifier) + value = pszDefaultDeviceSpecifier; + else + value = szEmptyString; + break; + + case ALC_DEVICE_SPECIFIER: + BuildDeviceList(); + if (pszDeviceSpecifierList) + value = pszDeviceSpecifierList; + else + value = szEmptyString; + break; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + BuildDeviceList(); + if (pszDefaultCaptureDeviceSpecifier) + value = pszDefaultCaptureDeviceSpecifier; + else + value = szEmptyString; + break; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + BuildDeviceList(); + if (pszCaptureDeviceSpecifierList) + value = pszCaptureDeviceSpecifierList; + else + value = szEmptyString; + break; + + case ALC_ALL_DEVICES_SPECIFIER: + BuildDeviceList(); + if (pszAllDevicesSpecifierList) + value = pszAllDevicesSpecifierList; + else + value = szEmptyString; + break; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + BuildDeviceList(); + if (pszDefaultAllDevicesSpecifier) + value = pszDefaultAllDevicesSpecifier; + else + value = szEmptyString; + break; + + default: + LastError = ALC_INVALID_ENUM; + break; + } + + return value; +} + + + + +//***************************************************************************** +// alcCaptureOpenDevice +//***************************************************************************** +ALCAPI ALCdevice * ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei buffersize) +{ +#ifdef _LOGCALLS + LOG("alcCaptureOpenDevice device name '%s' frequency %d format %d buffersize %d\n", deviceName ? deviceName : "<NULL>", frequency, format, buffersize); +#endif + const ALchar *pszDeviceName = NULL; + + BuildDeviceList(); + + if (!g_pCaptureDeviceList) + return NULL; + + if (!g_CaptureDevice) { + g_CaptureDevice = (ALCdevice*)malloc(sizeof(ALCdevice)); + + if (g_CaptureDevice) + { + // clear + memset(g_CaptureDevice, 0, sizeof(ALCdevice)); + + // make sure we have a device name + if ((!deviceName) || (strlen(deviceName) == 0)) + pszDeviceName = pszDefaultCaptureDeviceSpecifier; + else + pszDeviceName = deviceName; + + g_CaptureDevice->Dll = LoadDevicesDLL(g_pCaptureDeviceList, pszDeviceName); + + if (g_CaptureDevice->Dll) { + if(FillOutAlcFunctions(g_CaptureDevice)) { + if (g_CaptureDevice->AlcApi.alcCaptureOpenDevice) { + g_CaptureDevice->CaptureDevice = g_CaptureDevice->AlcApi.alcCaptureOpenDevice(pszDeviceName, frequency, format, buffersize); + g_CaptureDevice->LastError = ALC_NO_ERROR; + g_CaptureDevice->InUse = 0; + } else { + g_CaptureDevice->LastError = ALC_INVALID_DEVICE; + } + } + } + } + } else { + // already open + g_CaptureDevice->LastError = ALC_INVALID_VALUE; + } + + if (g_CaptureDevice != NULL) { + if (g_CaptureDevice->CaptureDevice) { + return g_CaptureDevice; + } else { + free(g_CaptureDevice); + g_CaptureDevice = NULL; + return NULL; + } + } else { + return NULL; + } +} + + + + +//***************************************************************************** +// alcCaptureCloseDevice +//***************************************************************************** +ALCAPI ALCboolean ALCAPIENTRY alcCaptureCloseDevice(ALCdevice *device) +{ +#ifdef _LOGCALLS + LOG("alcCaptureCloseDevice device %p\n", device); +#endif + ALCboolean bReturn = ALC_FALSE; + + if (device == g_CaptureDevice) + { + if (g_CaptureDevice != NULL) { + if (g_CaptureDevice->AlcApi.alcCaptureCloseDevice) { + bReturn = g_CaptureDevice->AlcApi.alcCaptureCloseDevice(g_CaptureDevice->CaptureDevice); + delete g_CaptureDevice; + g_CaptureDevice = NULL; + } else { + g_CaptureDevice->LastError = ALC_INVALID_DEVICE; + } + } + } + + return bReturn; +} + + + + +//***************************************************************************** +// alcCaptureStart +//***************************************************************************** +ALCAPI ALCvoid ALCAPIENTRY alcCaptureStart(ALCdevice *device) +{ +#ifdef _LOGCALLS + LOG("alcCaptureStart device %p\n", device); +#endif + if (device == g_CaptureDevice) + { + if (g_CaptureDevice != NULL) { + if (g_CaptureDevice->AlcApi.alcCaptureStart) { + g_CaptureDevice->AlcApi.alcCaptureStart(g_CaptureDevice->CaptureDevice); + } else { + g_CaptureDevice->LastError = ALC_INVALID_DEVICE; + } + } + } + + return; +} + + + + +//***************************************************************************** +// alcCaptureStop +//***************************************************************************** +ALCAPI ALCvoid ALCAPIENTRY alcCaptureStop(ALCdevice *device) +{ +#ifdef _LOGCALLS + LOG("alcCaptureStop device %p\n", device); +#endif + if (device == g_CaptureDevice) + { + if (g_CaptureDevice != NULL) { + if (g_CaptureDevice->AlcApi.alcCaptureStop) { + g_CaptureDevice->AlcApi.alcCaptureStop(g_CaptureDevice->CaptureDevice); + } else { + g_CaptureDevice->LastError = ALC_INVALID_DEVICE; + } + } + } + + return; +} + + + + +//***************************************************************************** +// alcCaptureSamples +//***************************************************************************** +ALCAPI ALCvoid ALCAPIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ +#ifdef _LOGCALLS + LOG("alcCaptureSamples device %p buffer %p samples %d\n", device, buffer, samples); +#endif + if (device == g_CaptureDevice) + { + if (g_CaptureDevice != NULL) { + if (g_CaptureDevice->AlcApi.alcCaptureSamples) { + g_CaptureDevice->AlcApi.alcCaptureSamples(g_CaptureDevice->CaptureDevice, buffer, samples); + } else { + g_CaptureDevice->LastError = ALC_INVALID_DEVICE; + } + } + } + + return; +} + +#ifdef _LOGCALLS +void OutputMessage(const char *szDebug,...) +{ + static FILE *pFile = NULL; + SYSTEMTIME sysTime; + va_list args; + + va_start(args, szDebug); + + if (!pFile) + { + pFile = fopen(LOGFILENAME, "w"); + GetLocalTime(&sysTime); + fprintf(pFile, "OpenAL Router\n\nLog Time : %d/%d/%d at %d:%s%d:%s%d\n\n", sysTime.wDay, sysTime.wMonth, sysTime.wYear, + sysTime.wHour, (sysTime.wMinute < 10) ? "0" : "", sysTime.wMinute, (sysTime.wSecond < 10) ? "0" : "", sysTime.wSecond); + } + + vfprintf(pFile, szDebug, args); + fflush(pFile); + + va_end(args); +} +#endif
\ No newline at end of file diff --git a/Router/resource.h b/Router/resource.h new file mode 100644 index 00000000..bdff6160 --- /dev/null +++ b/Router/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by openal32.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/RouterTest/main.cpp b/RouterTest/main.cpp new file mode 100644 index 00000000..961c3ecb --- /dev/null +++ b/RouterTest/main.cpp @@ -0,0 +1,647 @@ +#include <al.h>
+#include <alc.h>
+#include <stdio.h>
+#include <conio.h>
+#include <string.h>
+#include <windows.h>
+#include <mmsystem.h>
+
+int main(int argc, char* argv[])
+{
+ const ALchar *szNames = NULL;
+ long lErrorCount = 0;
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Enumerate the playback devices
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING ALC_ENUMERATION_EXT EXTENSION\n\n");
+ if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE)
+ {
+ printf("ALC_ENUMERATION_EXT Device List:-\n\n");
+
+ szNames = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+ if (strlen(szNames) == 0)
+ printf("NO DEVICES FOUND\n");
+ else
+ {
+ while (szNames && *szNames)
+ {
+ printf("%s ", szNames);
+ // Try opening each device
+ ALCdevice *pDevice = alcOpenDevice(szNames);
+ if (pDevice)
+ {
+ printf("- Opened Successfully\n");
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ printf("- FAILED to open\n");
+ lErrorCount++;
+ }
+ szNames += (strlen(szNames) + 1);
+ }
+ }
+ }
+ else
+ {
+ printf("!!!ERROR!!! : ALC_ENUMERATION_EXT NOT FOUND!\n");
+ lErrorCount++;
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Get Default Playback Device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING GET DEFAULT PLAYBACK DEVICE\n\n");
+ szNames = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+ if (szNames && strlen(szNames))
+ {
+ printf("\nDEFAULT DEVICE is %s\n", szNames);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("\n!!!ERROR!!! DEFAULT DEVICE NOT FOUND!\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("\nDEFAULT DEVICE NOT FOUND!\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Enumerate all the capture devices
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING CAPTURE ENUMERATION EXTENSION\n\n");
+ if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE)
+ {
+ printf("ALC_ENUMERATION_EXT Capture Device List:-\n\n");
+
+ szNames = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
+ if (strlen(szNames) == 0)
+ printf("NO DEVICES FOUND\n");
+ else
+ {
+ while (szNames && *szNames)
+ {
+ printf("%s ", szNames);
+ // Try opening each device
+ ALCdevice *pDevice = alcCaptureOpenDevice(szNames, 11025, AL_FORMAT_STEREO16, 8192);
+ if (pDevice)
+ {
+ printf("- Opened Successfully\n");
+ alcCaptureCloseDevice(pDevice);
+ }
+ else
+ {
+ printf("- FAILED to open\n");
+ lErrorCount++;
+ }
+ szNames += (strlen(szNames) + 1);
+ }
+ }
+ }
+ else
+ {
+ printf("!!!ERROR!!! : ALC_ENUMERATION_EXT NOT FOUND!\n");
+ lErrorCount++;
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Get Default Capture Device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING DEFAULT CAPTURE DEVICE\n\n");
+ szNames = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
+ if (szNames && strlen(szNames))
+ {
+ printf("\nDEFAULT CAPTURE DEVICE IS %s\n", szNames);
+ }
+ else
+ {
+ if (waveInGetNumDevs())
+ {
+ printf("\n!!!ERROR!!! DEFAULT CAPTURE DEVICE NOT FOUND!\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("\nDEFAULT CAPTURE DEVICE NOT FOUND!\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Enumerate *all* the playback devices
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING PLAYBACK ENUMERATE ALL EXTENSION\n\n");
+ if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") == AL_TRUE)
+ {
+ printf("ALC_ENUMERATE_ALL_EXT DEVICE LIST:-\n\n");
+
+ szNames = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
+ if (strlen(szNames) == 0)
+ printf("NO DEVICES FOUND\n");
+ else
+ {
+ while (szNames && *szNames)
+ {
+ printf("%s ", szNames);
+
+ // Try opening each device
+ ALCdevice *pDevice = alcOpenDevice(szNames);
+ if (pDevice)
+ {
+ printf("- Opened Successfully\n");
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ printf("- FAILED to open\n");
+ lErrorCount++;
+ }
+
+ szNames += (strlen(szNames) + 1);
+ }
+ }
+ }
+ else
+ {
+ printf("!!!ERROR!!! : ALC_ENUMERATE_ALL_EXT NOT FOUND!\n");
+ lErrorCount++;
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Get Default *All* Playback Device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING DEFAULT ALL PLAYBACK DEVICE\n\n");
+ szNames = alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
+ if (szNames && strlen(szNames))
+ {
+ printf("\nDEFAULT ALL DEVICES IS %s\n", szNames);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("\n!!!ERROR!!! DEFAULT ALL DEVICE NOT FOUND!\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("\nDEFAULT ALL DEVICES NOT FOUND!\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open 'Generic Hardware' device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING 'Generic Hardware' DEVICE\n\n");
+ ALCdevice *pDevice = alcOpenDevice("Generic Hardware");
+ if (pDevice)
+ {
+ printf("OPENED 'Generic Hardware' DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN 'Generic Hardware' DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN 'Generic Hardware' DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open 'Generic Software' device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING 'Generic Software' DEVICE\n\n");
+ pDevice = alcOpenDevice("Generic Software");
+ if (pDevice)
+ {
+ printf("OPENED 'Generic Software' DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN 'Generic Software' DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN 'Generic Software' DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open legacy 'DirectSound3D' device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING LEGACY 'DirectSound3D' DEVICE\n\n");
+ pDevice = alcOpenDevice("DirectSound3D");
+ if (pDevice)
+ {
+ printf("OPENED 'DirectSound3D' DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN 'DirectSound3D' DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN 'DirectSound3D' DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open legacy 'DirectSound' device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING LEGACY 'DirectSound' DEVICE\n\n");
+ pDevice = alcOpenDevice("DirectSound");
+ if (pDevice)
+ {
+ printf("OPENED 'DirectSound' DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN 'DirectSound' DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN 'DirectSound' DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open legacy 'MMSYSTEM' device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING LEGACY 'MMSYSTEM' DEVICE\n\n");
+ pDevice = alcOpenDevice("MMSYSTEM");
+ if (pDevice)
+ {
+ printf("OPENED 'MMSYSTEM' DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN 'MMSYSTEM' DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN 'MMSYSTEM' DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open NULL device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING NULL DEVICE\n\n");
+ pDevice = alcOpenDevice(NULL);
+ if (pDevice)
+ {
+ printf("OPENED NULL DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN NULL DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN NULL DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open "" device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING EMPTY DEVICE\n\n");
+ pDevice = alcOpenDevice("");
+ if (pDevice)
+ {
+ printf("OPENED \"\" DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveOutGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN EMPTY DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN EMPTY DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open "A Random Name" device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING 'A Random Name' DEVICE\n\n");
+ pDevice = alcOpenDevice("A Random Name");
+ if (pDevice)
+ {
+ printf("!!!ERROR!!! : OPENED 'A Random Name' DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_DEVICE_SPECIFIER));
+ lErrorCount++;
+ alcCloseDevice(pDevice);
+ }
+ else
+ {
+ printf("FAILED TO OPEN 'A Random Name' DEVICE\n");
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open NULL Capture device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING NULL CAPTURE DEVICE\n\n");
+ pDevice = alcCaptureOpenDevice(NULL, 22500, AL_FORMAT_MONO16, 4096);
+ if (pDevice)
+ {
+ printf("OPENED NULL CAPTURE DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_CAPTURE_DEVICE_SPECIFIER));
+ alcCaptureCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveInGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN NULL CAPTURE DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN NULL CAPTURE DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open "" capture device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING EMPTY CAPTURE DEVICE\n\n");
+ pDevice = alcCaptureOpenDevice("", 22500, AL_FORMAT_MONO16, 4096);
+ if (pDevice)
+ {
+ printf("OPENED \"\" CAPTURE DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_CAPTURE_DEVICE_SPECIFIER));
+ alcCaptureCloseDevice(pDevice);
+ }
+ else
+ {
+ if (waveInGetNumDevs())
+ {
+ printf("!!!ERROR!!! : FAILED TO OPEN EMPTY CAPTURE DEVICE\n");
+ lErrorCount++;
+ }
+ else
+ {
+ printf("FAILED TO OPEN EMPTY CAPTURE DEVICE\n");
+ }
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////////
+ // TEST : Open "A Random Name" capture device
+ //
+ printf("--------------------------------------\n");
+ printf("TESTING 'A Random Name' CAPTURE DEVICE\n\n");
+ pDevice = alcCaptureOpenDevice("A Random Name", 22500, AL_FORMAT_MONO16, 4096);
+ if (pDevice)
+ {
+ printf("!!!ERROR!!! : OPENED 'A Random Name' CAPTURE DEVICE ... GOT %s\n", alcGetString(pDevice, ALC_CAPTURE_DEVICE_SPECIFIER));
+ lErrorCount++;
+ alcCaptureCloseDevice(pDevice);
+ }
+ else
+ {
+ printf("FAILED TO OPEN 'A Random Name' CAPTURE DEVICE\n");
+ }
+ printf("--------------------------------------\n\n");
+ ///////////////////////////////////////////////////////////////////
+
+ printf("\nFOUND %d ERRORS\n", lErrorCount);
+
+ printf("\nPress a key to quit\n");
+ char ch = _getch();
+
+ return 0;
+}
+
+
+/*
+ALboolean InitOpenAL(ALCdevice **ppDevice, ALCcontext **ppContext)
+{
+ ALchar szDeviceNames[10][1024];
+ ALchar *szNames;
+ ALint lNumDevices;
+ ALint lLoop;
+ ALint lLength;
+ ALbyte ch;
+ ALboolean bInit;
+
+ bInit = AL_FALSE;
+ memset(szDeviceNames, 0, sizeof(ALchar) * 10 * 1024);
+ lNumDevices = 0;
+
+
+
+ if (!szNames)
+ {
+ szNames = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+ if (szNames && *szNames && (strlen(szNames) < 1024))
+ strcpy(szDeviceNames[lNumDevices++], szNames);
+ }
+
+ for (lLoop = 0; lLoop < lNumDevices; lLoop++)
+ printf("Press %d for '%s' Device\n", lLoop+1, szDeviceNames[lLoop]);
+ printf("Press Q to quit\n");
+
+ do
+ {
+ ch = _getch();
+ if (ch == 'q' || ch == 'Q')
+ exit(0);
+ else if ((ch >= '1') && (ch < ('1' + lNumDevices)))
+ break;
+ } while (1);
+
+ *ppDevice = alcOpenDevice(szDeviceNames[ch - '1']);
+ if (*ppDevice)
+ {
+ *ppContext = alcCreateContext(*ppDevice,NULL);
+ if (*ppContext)
+ {
+ alcGetError(*ppDevice);
+ alcMakeContextCurrent(*ppContext);
+ if (alcGetError(*ppDevice) == ALC_NO_ERROR)
+ bInit = AL_TRUE;
+ }
+ else
+ {
+ alcCloseDevice(*ppDevice);
+ }
+ }
+
+ return bInit;
+}
+
+
+ALboolean InitOpenALEx(ALCdevice **ppDevice, ALCcontext **ppContext)
+{
+ ALchar szDeviceNames[32][1024];
+ const ALchar *szNames;
+ const ALchar *szDefaultName = NULL;
+ const ALchar *szDefaultAllName = NULL;
+ ALint lNumDevices = 0;
+ ALint lLoop;
+ ALint lLength;
+ ALbyte ch;
+ ALboolean bInit;
+
+ bInit = AL_FALSE;
+ memset(szDeviceNames, 0, sizeof(ALchar) * 32 * 1024);
+
+ // Get legacy enumeration list and Default Device
+ if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE)
+ {
+ szNames = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+
+ while (szNames && *szNames)
+ {
+ if ((lLength = strlen(szNames)) < 1024)
+ strcpy(szDeviceNames[lNumDevices++], szNames);
+ szNames += lLength + 1;
+ }
+
+ szDefaultName = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+ }
+
+ // Get new uber enumeration list and Default Device
+ if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") == AL_TRUE)
+ {
+ szNames = alcGetString(NULL, alcGetEnumValue(NULL, "ALC_ALL_DEVICES_SPECIFIER"));
+
+ while (szNames && *szNames)
+ {
+ if ((lLength = strlen(szNames)) < 1024)
+ strcpy(szDeviceNames[lNumDevices++], szNames);
+ szNames += lLength + 1;
+ }
+
+ szDefaultAllName = alcGetString(NULL, alcGetEnumValue(NULL, "ALC_DEFAULT_ALL_DEVICES_SPECIFIER"));
+ }
+
+
+ for (lLoop = 0; lLoop < lNumDevices; lLoop++)
+ printf("Press %d for '%s' Device %s\n", lLoop+1, szDeviceNames[lLoop],
+ (strcmp(szDeviceNames[lLoop], szDefaultName?szDefaultName:"") == 0) ? "*" : (strcmp(szDeviceNames[lLoop], szDefaultAllName?szDefaultAllName:"") == 0) ? "**" : "");
+ printf("Press Q to quit\n");
+
+ do
+ {
+ ch = _getch();
+ if (ch == 'q' || ch == 'Q')
+ exit(0);
+ else if ((ch >= '1') && (ch < ('1' + lNumDevices)))
+ break;
+ } while (1);
+
+ *ppDevice = alcOpenDevice(szDeviceNames[ch - '1']);
+ if (*ppDevice)
+ {
+ *ppContext = alcCreateContext(*ppDevice,NULL);
+ if (*ppContext)
+ {
+ alcGetError(*ppDevice);
+ alcMakeContextCurrent(*ppContext);
+ if (alcGetError(*ppDevice) == ALC_NO_ERROR)
+ bInit = AL_TRUE;
+ }
+ else
+ {
+ alcCloseDevice(*ppDevice);
+ }
+ }
+
+ return bInit;
+}
+*/
\ No newline at end of file diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000..d8c26def --- /dev/null +++ b/config.h.in @@ -0,0 +1,43 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* Define if we have the ALSA backend */ +#cmakedefine HAVE_ALSA + +/* Define if we have the OSS backend */ +#cmakedefine HAVE_OSS + +/* Define if we have the DSound backend */ +#cmakedefine HAVE_DSOUND + +/* Define if we have the Windows Multimedia backend */ +#cmakedefine HAVE_WINMM + +/* Define if we have dlfcn.h */ +#cmakedefine HAVE_DLFCN_H + +/* Define if we have the sqrtf function */ +#cmakedefine HAVE_SQRTF + +/* Define if we have the strtof function */ +#cmakedefine HAVE_STRTOF + +/* Define if we have stdint.h */ +#cmakedefine HAVE_STDINT_H + +/* Define if we have the __int64 type */ +#cmakedefine HAVE___INT64 + +/* Define to the size of a long int type */ +#cmakedefine SIZEOF_LONG ${SIZEOF_LONG} + +/* Define to the size of a long long int type */ +#cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG} + +/* Define to the size of an unsigned int type */ +#cmakedefine SIZEOF_UINT ${SIZEOF_UINT} + +/* Define to the size of a void pointer type */ +#cmakedefine SIZEOF_VOIDP ${SIZEOF_VOIDP} + +#endif diff --git a/include/AL/al.h b/include/AL/al.h new file mode 100644 index 00000000..630b6ad5 --- /dev/null +++ b/include/AL/al.h @@ -0,0 +1,724 @@ +#ifndef AL_AL_H +#define AL_AL_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(_WIN32) && !defined(_XBOX) + /* _OPENAL32LIB is deprecated */ + #if defined(AL_BUILD_LIBRARY) || defined (_OPENAL32LIB) + #define AL_API __declspec(dllexport) + #else + #define AL_API __declspec(dllimport) + #endif +#else + #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) + #define AL_API __attribute__((visibility("default"))) + #else + #define AL_API extern + #endif +#endif + +#if defined(_WIN32) + #define AL_APIENTRY __cdecl +#else + #define AL_APIENTRY +#endif + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export on +#endif + +/* + * The OPENAL, ALAPI, ALAPIENTRY, AL_INVALID, AL_ILLEGAL_ENUM, and + * AL_ILLEGAL_COMMAND macros are deprecated, but are included for + * applications porting code from AL 1.0 + */ +#define OPENAL +#define ALAPI AL_API +#define ALAPIENTRY AL_APIENTRY +#define AL_INVALID (-1) +#define AL_ILLEGAL_ENUM AL_INVALID_ENUM +#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION + +#define AL_VERSION_1_0 +#define AL_VERSION_1_1 + + +/** 8-bit boolean */ +typedef char ALboolean; + +/** character */ +typedef char ALchar; + +/** signed 8-bit 2's complement integer */ +typedef char ALbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALsizei; + +/** enumerated 32-bit value */ +typedef int ALenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALdouble; + +/** void type (for opaque pointers only) */ +typedef void ALvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/* "no distance model" or "no buffer" */ +#define AL_NONE 0 + +/* Boolean False. */ +#define AL_FALSE 0 + +/** Boolean True. */ +#define AL_TRUE 1 + +/** Indicate Source has relative coordinates. */ +#define AL_SOURCE_RELATIVE 0x202 + + + +/** + * Directional source, inner cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_INNER_ANGLE 0x1001 + +/** + * Directional source, outer cone angle, in degrees. + * Range: [0-360] + * Default: 360 + */ +#define AL_CONE_OUTER_ANGLE 0x1002 + +/** + * Specify the pitch to be applied, either at source, + * or on mixer results, at listener. + * Range: [0.5-2.0] + * Default: 1.0 + */ +#define AL_PITCH 0x1003 + +/** + * Specify the current location in three dimensional space. + * OpenAL, like OpenGL, uses a right handed coordinate system, + * where in a frontal default view X (thumb) points right, + * Y points up (index finger), and Z points towards the + * viewer/camera (middle finger). + * To switch from a left handed coordinate system, flip the + * sign on the Z coordinate. + * Listener position is always in the world coordinate system. + */ +#define AL_POSITION 0x1004 + +/** Specify the current direction. */ +#define AL_DIRECTION 0x1005 + +/** Specify the current velocity in three dimensional space. */ +#define AL_VELOCITY 0x1006 + +/** + * Indicate whether source is looping. + * Type: ALboolean? + * Range: [AL_TRUE, AL_FALSE] + * Default: FALSE. + */ +#define AL_LOOPING 0x1007 + +/** + * Indicate the buffer to provide sound samples. + * Type: ALuint. + * Range: any valid Buffer id. + */ +#define AL_BUFFER 0x1009 + +/** + * Indicate the gain (volume amplification) applied. + * Type: ALfloat. + * Range: ]0.0- ] + * A value of 1.0 means un-attenuated/unchanged. + * Each division by 2 equals an attenuation of -6dB. + * Each multiplicaton with 2 equals an amplification of +6dB. + * A value of 0.0 is meaningless with respect to a logarithmic + * scale; it is interpreted as zero volume - the channel + * is effectively disabled. + */ +#define AL_GAIN 0x100A + +/* + * Indicate minimum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ +#define AL_MIN_GAIN 0x100D + +/** + * Indicate maximum source attenuation + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * Logarthmic + */ +#define AL_MAX_GAIN 0x100E + +/** + * Indicate listener orientation. + * + * at/up + */ +#define AL_ORIENTATION 0x100F + +/** + * Source state information. + */ +#define AL_SOURCE_STATE 0x1010 +#define AL_INITIAL 0x1011 +#define AL_PLAYING 0x1012 +#define AL_PAUSED 0x1013 +#define AL_STOPPED 0x1014 + +/** + * Buffer Queue params + */ +#define AL_BUFFERS_QUEUED 0x1015 +#define AL_BUFFERS_PROCESSED 0x1016 + +/** + * Source buffer position information + */ +#define AL_SEC_OFFSET 0x1024 +#define AL_SAMPLE_OFFSET 0x1025 +#define AL_BYTE_OFFSET 0x1026 + +/* + * Source type (Static, Streaming or undetermined) + * Source is Static if a Buffer has been attached using AL_BUFFER + * Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers + * Source is undetermined when it has the NULL buffer attached + */ +#define AL_SOURCE_TYPE 0x1027 +#define AL_STATIC 0x1028 +#define AL_STREAMING 0x1029 +#define AL_UNDETERMINED 0x1030 + +/** Sound samples: format specifier. */ +#define AL_FORMAT_MONO8 0x1100 +#define AL_FORMAT_MONO16 0x1101 +#define AL_FORMAT_STEREO8 0x1102 +#define AL_FORMAT_STEREO16 0x1103 + +/** + * source specific reference distance + * Type: ALfloat + * Range: 0.0 - +inf + * + * At 0.0, no distance attenuation occurs. Default is + * 1.0. + */ +#define AL_REFERENCE_DISTANCE 0x1020 + +/** + * source specific rolloff factor + * Type: ALfloat + * Range: 0.0 - +inf + * + */ +#define AL_ROLLOFF_FACTOR 0x1021 + +/** + * Directional source, outer cone gain. + * + * Default: 0.0 + * Range: [0.0 - 1.0] + * Logarithmic + */ +#define AL_CONE_OUTER_GAIN 0x1022 + +/** + * Indicate distance above which sources are not + * attenuated using the inverse clamped distance model. + * + * Default: +inf + * Type: ALfloat + * Range: 0.0 - +inf + */ +#define AL_MAX_DISTANCE 0x1023 + +/** + * Sound samples: frequency, in units of Hertz [Hz]. + * This is the number of samples per second. Half of the + * sample frequency marks the maximum significant + * frequency component. + */ +#define AL_FREQUENCY 0x2001 +#define AL_BITS 0x2002 +#define AL_CHANNELS 0x2003 +#define AL_SIZE 0x2004 + +/** + * Buffer state. + * + * Not supported for public use (yet). + */ +#define AL_UNUSED 0x2010 +#define AL_PENDING 0x2011 +#define AL_PROCESSED 0x2012 + + +/** Errors: No Error. */ +#define AL_NO_ERROR AL_FALSE + +/** + * Invalid Name paramater passed to AL call. + */ +#define AL_INVALID_NAME 0xA001 + +/** + * Invalid parameter passed to AL call. + */ +#define AL_INVALID_ENUM 0xA002 + +/** + * Invalid enum parameter value. + */ +#define AL_INVALID_VALUE 0xA003 + +/** + * Illegal call. + */ +#define AL_INVALID_OPERATION 0xA004 + + +/** + * No mojo. + */ +#define AL_OUT_OF_MEMORY 0xA005 + + +/** Context strings: Vendor Name. */ +#define AL_VENDOR 0xB001 +#define AL_VERSION 0xB002 +#define AL_RENDERER 0xB003 +#define AL_EXTENSIONS 0xB004 + +/** Global tweakage. */ + +/** + * Doppler scale. Default 1.0 + */ +#define AL_DOPPLER_FACTOR 0xC000 + +/** + * Tweaks speed of propagation. + */ +#define AL_DOPPLER_VELOCITY 0xC001 + +/** + * Speed of Sound in units per second + */ +#define AL_SPEED_OF_SOUND 0xC003 + +/** + * Distance models + * + * used in conjunction with DistanceModel + * + * implicit: NONE, which disances distance attenuation. + */ +#define AL_DISTANCE_MODEL 0xD000 +#define AL_INVERSE_DISTANCE 0xD001 +#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 +#define AL_LINEAR_DISTANCE 0xD003 +#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 +#define AL_EXPONENT_DISTANCE 0xD005 +#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 + +/* + * Renderer State management + */ +AL_API void AL_APIENTRY alEnable( ALenum capability ); + +AL_API void AL_APIENTRY alDisable( ALenum capability ); + +AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability ); + + +/* + * State retrieval + */ +AL_API const ALchar* AL_APIENTRY alGetString( ALenum param ); + +AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* data ); + +AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* data ); + +AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* data ); + +AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* data ); + +AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param ); + +AL_API ALint AL_APIENTRY alGetInteger( ALenum param ); + +AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param ); + +AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param ); + + +/* + * Error support. + * Obtain the most recent error generated in the AL state machine. + */ +AL_API ALenum AL_APIENTRY alGetError( void ); + + +/* + * Extension support. + * Query for the presence of an extension, and obtain any appropriate + * function pointers and enum values. + */ +AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname ); + +AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname ); + +AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename ); + + +/* + * LISTENER + * Listener represents the location and orientation of the + * 'user' in 3D-space. + * + * Properties include: - + * + * Gain AL_GAIN ALfloat + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Orientation AL_ORIENTATION ALfloat[6] (Forward then Up vectors) +*/ + +/* + * Set Listener parameters + */ +AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value ); + +AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values ); + +/* + * Get Listener parameters + */ +AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); + +AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); + +AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values ); + + +/** + * SOURCE + * Sources represent individual sound objects in 3D-space. + * Sources take the PCM data provided in the specified Buffer, + * apply Source-specific modifications, and then + * submit them to be mixed according to spatial arrangement etc. + * + * Properties include: - + * + * Gain AL_GAIN ALfloat + * Min Gain AL_MIN_GAIN ALfloat + * Max Gain AL_MAX_GAIN ALfloat + * Position AL_POSITION ALfloat[3] + * Velocity AL_VELOCITY ALfloat[3] + * Direction AL_DIRECTION ALfloat[3] + * Head Relative Mode AL_SOURCE_RELATIVE ALint (AL_TRUE or AL_FALSE) + * Reference Distance AL_REFERENCE_DISTANCE ALfloat + * Max Distance AL_MAX_DISTANCE ALfloat + * RollOff Factor AL_ROLLOFF_FACTOR ALfloat + * Inner Angle AL_CONE_INNER_ANGLE ALint or ALfloat + * Outer Angle AL_CONE_OUTER_ANGLE ALint or ALfloat + * Cone Outer Gain AL_CONE_OUTER_GAIN ALint or ALfloat + * Pitch AL_PITCH ALfloat + * Looping AL_LOOPING ALint (AL_TRUE or AL_FALSE) + * MS Offset AL_MSEC_OFFSET ALint or ALfloat + * Byte Offset AL_BYTE_OFFSET ALint or ALfloat + * Sample Offset AL_SAMPLE_OFFSET ALint or ALfloat + * Attached Buffer AL_BUFFER ALint + * State (Query only) AL_SOURCE_STATE ALint + * Buffers Queued (Query only) AL_BUFFERS_QUEUED ALint + * Buffers Processed (Query only) AL_BUFFERS_PROCESSED ALint + */ + +/* Create Source objects */ +AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* sources ); + +/* Delete Source objects */ +AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* sources ); + +/* Verify a handle is a valid Source */ +AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid ); + +/* + * Set Source parameters + */ +AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value ); + +AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values ); + +/* + * Get Source parameters + */ +AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + +AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + +AL_API void AL_APIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values ); + + +/* + * Source vector based playback calls + */ + +/* Play, replay, or resume (if paused) a list of Sources */ +AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids ); + +/* Stop a list of Sources */ +AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids ); + +/* Rewind a list of Sources */ +AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids ); + +/* Pause a list of Sources */ +AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids ); + +/* + * Source based playback calls + */ + +/* Play, replay, or resume a Source */ +AL_API void AL_APIENTRY alSourcePlay( ALuint sid ); + +/* Stop a Source */ +AL_API void AL_APIENTRY alSourceStop( ALuint sid ); + +/* Rewind a Source (set playback postiton to beginning) */ +AL_API void AL_APIENTRY alSourceRewind( ALuint sid ); + +/* Pause a Source */ +AL_API void AL_APIENTRY alSourcePause( ALuint sid ); + +/* + * Source Queuing + */ +AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids ); + +AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ); + + +/** + * BUFFER + * Buffer objects are storage space for sample data. + * Buffers are referred to by Sources. One Buffer can be used + * by multiple Sources. + * + * Properties include: - + * + * Frequency (Query only) AL_FREQUENCY ALint + * Size (Query only) AL_SIZE ALint + * Bits (Query only) AL_BITS ALint + * Channels (Query only) AL_CHANNELS ALint + */ + +/* Create Buffer objects */ +AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* buffers ); + +/* Delete Buffer objects */ +AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers ); + +/* Verify a handle is a valid Buffer */ +AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid ); + +/* Specify the data to be copied into a buffer */ +AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); + +/* + * Set Buffer parameters + */ +AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value ); + +AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); + +AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values ); + +AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value ); + +AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); + +AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values ); + +/* + * Get Buffer parameters + */ +AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value ); + +AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); + +AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values ); + +AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value ); + +AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); + +AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values ); + + +/* + * Global Parameters + */ +AL_API void AL_APIENTRY alDopplerFactor( ALfloat value ); + +AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value ); + +AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value ); + +AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel ); + +/* + * Pointer-to-function types, useful for dynamically getting AL entry points. + */ +typedef void (AL_APIENTRY *LPALENABLE)( ALenum capability ); +typedef void (AL_APIENTRY *LPALDISABLE)( ALenum capability ); +typedef ALboolean (AL_APIENTRY *LPALISENABLED)( ALenum capability ); +typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)( ALenum param ); +typedef void (AL_APIENTRY *LPALGETBOOLEANV)( ALenum param, ALboolean* data ); +typedef void (AL_APIENTRY *LPALGETINTEGERV)( ALenum param, ALint* data ); +typedef void (AL_APIENTRY *LPALGETFLOATV)( ALenum param, ALfloat* data ); +typedef void (AL_APIENTRY *LPALGETDOUBLEV)( ALenum param, ALdouble* data ); +typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)( ALenum param ); +typedef ALint (AL_APIENTRY *LPALGETINTEGER)( ALenum param ); +typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)( ALenum param ); +typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)( ALenum param ); +typedef ALenum (AL_APIENTRY *LPALGETERROR)( void ); +typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar* extname ); +typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)( const ALchar* fname ); +typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)( const ALchar* ename ); +typedef void (AL_APIENTRY *LPALLISTENERF)( ALenum param, ALfloat value ); +typedef void (AL_APIENTRY *LPALLISTENER3F)( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALLISTENERFV)( ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALLISTENERI)( ALenum param, ALint value ); +typedef void (AL_APIENTRY *LPALLISTENER3I)( ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALLISTENERIV)( ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETLISTENERF)( ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETLISTENER3F)( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); +typedef void (AL_APIENTRY *LPALGETLISTENERFV)( ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETLISTENERI)( ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETLISTENER3I)( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); +typedef void (AL_APIENTRY *LPALGETLISTENERIV)( ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALGENSOURCES)( ALsizei n, ALuint* sources ); +typedef void (AL_APIENTRY *LPALDELETESOURCES)( ALsizei n, const ALuint* sources ); +typedef ALboolean (AL_APIENTRY *LPALISSOURCE)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEF)( ALuint sid, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALSOURCE3F)( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALSOURCEFV)( ALuint sid, ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALSOURCEI)( ALuint sid, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALSOURCE3I)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALSOURCEIV)( ALuint sid, ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETSOURCEF)( ALuint sid, ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETSOURCE3F)( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); +typedef void (AL_APIENTRY *LPALGETSOURCEFV)( ALuint sid, ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETSOURCEI)( ALuint sid, ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETSOURCE3I)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef void (AL_APIENTRY *LPALGETSOURCEIV)( ALuint sid, ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALSOURCEPLAYV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCESTOPV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEREWINDV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)( ALsizei ns, const ALuint *sids ); +typedef void (AL_APIENTRY *LPALSOURCEPLAY)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCESTOP)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEREWIND)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEPAUSE)( ALuint sid ); +typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, const ALuint *bids ); +typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, ALuint *bids ); +typedef void (AL_APIENTRY *LPALGENBUFFERS)( ALsizei n, ALuint* buffers ); +typedef void (AL_APIENTRY *LPALDELETEBUFFERS)( ALsizei n, const ALuint* buffers ); +typedef ALboolean (AL_APIENTRY *LPALISBUFFER)( ALuint bid ); +typedef void (AL_APIENTRY *LPALBUFFERDATA)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); +typedef void (AL_APIENTRY *LPALBUFFERF)( ALuint bid, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALBUFFER3F)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); +typedef void (AL_APIENTRY *LPALBUFFERFV)( ALuint bid, ALenum param, const ALfloat* values ); +typedef void (AL_APIENTRY *LPALBUFFERI)( ALuint bid, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALBUFFER3I)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); +typedef void (AL_APIENTRY *LPALBUFFERIV)( ALuint bid, ALenum param, const ALint* values ); +typedef void (AL_APIENTRY *LPALGETBUFFERF)( ALuint bid, ALenum param, ALfloat* value ); +typedef void (AL_APIENTRY *LPALGETBUFFER3F)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); +typedef void (AL_APIENTRY *LPALGETBUFFERFV)( ALuint bid, ALenum param, ALfloat* values ); +typedef void (AL_APIENTRY *LPALGETBUFFERI)( ALuint bid, ALenum param, ALint* value ); +typedef void (AL_APIENTRY *LPALGETBUFFER3I)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); +typedef void (AL_APIENTRY *LPALGETBUFFERIV)( ALuint bid, ALenum param, ALint* values ); +typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)( ALfloat value ); +typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)( ALfloat value ); +typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)( ALfloat value ); +typedef void (AL_APIENTRY *LPALDISTANCEMODEL)( ALenum distanceModel ); + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export off +#endif + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif /* AL_AL_H */ diff --git a/include/AL/alc.h b/include/AL/alc.h new file mode 100644 index 00000000..b0bbfbe7 --- /dev/null +++ b/include/AL/alc.h @@ -0,0 +1,281 @@ +#ifndef AL_ALC_H +#define AL_ALC_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(_WIN32) && !defined(_XBOX) + /* _OPENAL32LIB is deprecated */ + #if defined(AL_BUILD_LIBRARY) || defined (_OPENAL32LIB) + #define ALC_API __declspec(dllexport) + #else + #define ALC_API __declspec(dllimport) + #endif +#else + #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) + #define ALC_API __attribute__((visibility("default"))) + #else + #define ALC_API extern + #endif +#endif + +#if defined(_WIN32) + #define ALC_APIENTRY __cdecl +#else + #define ALC_APIENTRY +#endif + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export on +#endif + +/* + * The ALCAPI, ALCAPIENTRY, and ALC_INVALID macros are deprecated, but are + * included for applications porting code from AL 1.0 + */ +#define ALCAPI ALC_API +#define ALCAPIENTRY ALC_APIENTRY +#define ALC_INVALID 0 + + +#define ALC_VERSION_0_1 1 + +typedef struct ALCdevice_struct ALCdevice; +typedef struct ALCcontext_struct ALCcontext; + + +/** 8-bit boolean */ +typedef char ALCboolean; + +/** character */ +typedef char ALCchar; + +/** signed 8-bit 2's complement integer */ +typedef char ALCbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALCubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALCshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALCushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALCint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALCuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALCsizei; + +/** enumerated 32-bit value */ +typedef int ALCenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALCfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALCdouble; + +/** void type (for opaque pointers only) */ +typedef void ALCvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/* Boolean False. */ +#define ALC_FALSE 0 + +/* Boolean True. */ +#define ALC_TRUE 1 + +/** + * followed by <int> Hz + */ +#define ALC_FREQUENCY 0x1007 + +/** + * followed by <int> Hz + */ +#define ALC_REFRESH 0x1008 + +/** + * followed by AL_TRUE, AL_FALSE + */ +#define ALC_SYNC 0x1009 + +/** + * followed by <int> Num of requested Mono (3D) Sources + */ +#define ALC_MONO_SOURCES 0x1010 + +/** + * followed by <int> Num of requested Stereo Sources + */ +#define ALC_STEREO_SOURCES 0x1011 + +/** + * errors + */ + +/** + * No error + */ +#define ALC_NO_ERROR ALC_FALSE + +/** + * No device + */ +#define ALC_INVALID_DEVICE 0xA001 + +/** + * invalid context ID + */ +#define ALC_INVALID_CONTEXT 0xA002 + +/** + * bad enum + */ +#define ALC_INVALID_ENUM 0xA003 + +/** + * bad value + */ +#define ALC_INVALID_VALUE 0xA004 + +/** + * Out of memory. + */ +#define ALC_OUT_OF_MEMORY 0xA005 + + +/** + * The Specifier string for default device + */ +#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 +#define ALC_DEVICE_SPECIFIER 0x1005 +#define ALC_EXTENSIONS 0x1006 + +#define ALC_MAJOR_VERSION 0x1000 +#define ALC_MINOR_VERSION 0x1001 + +#define ALC_ATTRIBUTES_SIZE 0x1002 +#define ALC_ALL_ATTRIBUTES 0x1003 + +/** + * ALC_ENUMERATE_ALL_EXT enums + */ +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 + +/** + * Capture extension + */ +#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 +#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 +#define ALC_CAPTURE_SAMPLES 0x312 + + +/* + * Context Management + */ +ALC_API ALCcontext * ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist ); + +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcProcessContext( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcSuspendContext( ALCcontext *context ); + +ALC_API void ALC_APIENTRY alcDestroyContext( ALCcontext *context ); + +ALC_API ALCcontext * ALC_APIENTRY alcGetCurrentContext( void ); + +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice( ALCcontext *context ); + + +/* + * Device Management + */ +ALC_API ALCdevice * ALC_APIENTRY alcOpenDevice( const ALCchar *devicename ); + +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice( ALCdevice *device ); + + +/* + * Error support. + * Obtain the most recent Context error + */ +ALC_API ALCenum ALC_APIENTRY alcGetError( ALCdevice *device ); + + +/* + * Extension support. + * Query for the presence of an extension, and obtain any appropriate + * function pointers and enum values. + */ +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname ); + +ALC_API void * ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname ); + +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname ); + + +/* + * Query functions + */ +ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param ); + +ALC_API void ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data ); + + +/* + * Capture functions + */ +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureStart( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureStop( ALCdevice *device ); + +ALC_API void ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + +/* + * Pointer-to-function types, useful for dynamically getting ALC entry points. + */ +typedef ALCcontext * (ALC_APIENTRY *LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist); +typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)( ALCcontext *context ); +typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)( ALCcontext *context ); +typedef ALCcontext * (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)( void ); +typedef ALCdevice * (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)( ALCcontext *context ); +typedef ALCdevice * (ALC_APIENTRY *LPALCOPENDEVICE)( const ALCchar *devicename ); +typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)( ALCdevice *device ); +typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)( ALCdevice *device ); +typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)( ALCdevice *device, const ALCchar *extname ); +typedef void * (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname ); +typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname ); +typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)( ALCdevice *device, ALCenum param ); +typedef void (ALC_APIENTRY *LPALCGETINTEGERV)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest ); +typedef ALCdevice * (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); +typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESTART)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)( ALCdevice *device ); +typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); + +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC + #pragma export off +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* AL_ALC_H */ diff --git a/include/COPYING b/include/COPYING new file mode 100644 index 00000000..e463f462 --- /dev/null +++ b/include/COPYING @@ -0,0 +1,483 @@ + + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/openalrc.sample b/openalrc.sample new file mode 100644 index 00000000..74bcba22 --- /dev/null +++ b/openalrc.sample @@ -0,0 +1,51 @@ +# OpenAL config file. Options that are not under a block or are under the +# [general] block are for general, non-backend-specific options. Blocks may +# appear multiple times, and duplicated options will take the last value +# specified. The system-wide settings can be put in /etc/openal/config and +# user-specific override settings in ~/.openalrc + +# Option and block names are case-insenstive. The supplied values are only +# hints and may not be honored (though generally it'll try to get as close as +# possible). These are the current available settings: + +format = AL_FORMAT_STEREO16 # Sets the output format. Can be one of: + # AL_FORMAT_MONO8 (8-bit mono) + # AL_FORMAT_STEREO8 (8-bit stereo) + # AL_FORMAT_QUAD8 (8-bit 4-channel) + # AL_FORMAT_MONO16 (16-bit mono) + # AL_FORMAT_STEREO16 (16-bit stereo) + # AL_FORMAT_QUAD16 (16-bit 4-channel) + # Default is AL_FORMAT_STEREO16 + +frequency = 44100 # Sets the output frequency. Default is 44100 + +refresh = 0 # Sets the number of frames-per-update. Default is calculated as + # 8192*frequency/22050. Note that the actual granularity may or + # may not be less than this. + +# TODO: Implement this option +drivers = # Sets the backend driver list order, comma-seperated. Unknown + # backends and duplicated names are ignored, and unlisted backends + # won't be considered for use. An empty list means the default. + # Default is: + # alsa,oss,dsound,winmm + +[alsa] # ALSA backend stuff +device = default # Sets the device name for the default playback device. + # Default is default + +periods = 4 # Sets the number of update buffers. Default is 4 + +capture = default # Sets the device name for the default capture device. + # Default is default + +[oss] # OSS backend stuff +device = /dev/dsp # Sets the device name for OSS output. Default is /dev/dsp + +periods = 4 # Sets the number of update buffers. Default is 4 + +[dsound] # DirectSound backend stuff + # Nothing yet... + +[winmm] # Windows Multimedia backend stuff + # Nothing yet... |