aboutsummaryrefslogtreecommitdiffstats
path: root/OpenAL32/alSource.c
diff options
context:
space:
mode:
Diffstat (limited to 'OpenAL32/alSource.c')
-rw-r--r--OpenAL32/alSource.c2108
1 files changed, 2108 insertions, 0 deletions
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;
+}