From fc4c867f27ed6e4c4cee8f5a5228c2c9543e7ee9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Nov 2008 05:57:32 -0800 Subject: [PATCH] Add initial AL_EXTX_buffer_sub_data support Note that this is an in-development extension, as noted by the EXTX moniker instead of EXT. It's behavior is subject to change, and the extension string will be removed (replaced with the official string once it's finalized). Developers are discouraged from using this in production code, though feel free to play around with it. --- Alc/ALc.c | 2 +- OpenAL32/Include/alBuffer.h | 2 + OpenAL32/alBuffer.c | 104 ++++++++++++++++++++++++++++++++++++++++ OpenAL32/alExtension.c | 3 ++ OpenAL32/alSource.c | 113 +++++++++++++++++++++++++++++++++----------- include/AL/alext.h | 8 ++++ 6 files changed, 203 insertions(+), 29 deletions(-) diff --git a/Alc/ALc.c b/Alc/ALc.c index 4a254f88..9fe51c1c 100644 --- a/Alc/ALc.c +++ b/Alc/ALc.c @@ -444,7 +444,7 @@ static ALvoid InitContext(ALCcontext *pContext) pContext->lNumStereoSources = 1; pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources; - pContext->ExtensionList = "AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic"; + pContext->ExtensionList = "AL_EXTX_buffer_sub_data AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic"; level = GetConfigValueInt(NULL, "cf_level", 0); if(level > 0 && level <= 6) diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h index 5ae367ed..75e97d18 100644 --- a/OpenAL32/Include/alBuffer.h +++ b/OpenAL32/Include/alBuffer.h @@ -24,6 +24,8 @@ typedef struct ALbuffer_struct struct ALbuffer_struct *next; } ALbuffer; +ALvoid ALAPIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); + ALvoid ReleaseALBuffers(ALvoid); #ifdef __cplusplus diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c index a8258d04..959d3098 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.c @@ -405,6 +405,110 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d ProcessContext(Context); } +/* +* alBufferSubDataEXT(ALuint buffer,ALenum format,ALvoid *data,ALsizei offset,ALsizei length) +* +* Fill buffer with audio data +*/ +ALvoid ALAPIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length) +{ + ALCcontext *Context; + ALbuffer *ALBuf; + + Context = alcGetCurrentContext(); + SuspendContext(Context); + + if(alIsBuffer(buffer) && buffer != 0) + { + ALBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffer); + if(ALBuf->data == NULL) + { + // buffer does not have any data + alSetError(AL_INVALID_NAME); + } + else if(length < 0 || offset < 0 || (length > 0 && data == NULL)) + { + // data is NULL or offset/length is negative + alSetError(AL_INVALID_VALUE); + } + else + { + switch(format) + { + case AL_FORMAT_REAR8: + case AL_FORMAT_REAR16: + case AL_FORMAT_REAR32: { + ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 : + ((format==AL_FORMAT_REAR16) ? 2 : + 4)); + + if(ALBuf->eOriginalFormat != AL_FORMAT_REAR8 && + ALBuf->eOriginalFormat != AL_FORMAT_REAR16 && + ALBuf->eOriginalFormat != AL_FORMAT_REAR32) + { + alSetError(AL_INVALID_ENUM); + break; + } + + if(ALBuf->size/4/sizeof(ALshort) < (ALuint)offset+length) + { + alSetError(AL_INVALID_VALUE); + break; + } + + ConvertDataRear(&ALBuf->data[offset*4], data, OrigBytes, length*2); + } break; + + case AL_FORMAT_MONO_IMA4: + case AL_FORMAT_STEREO_IMA4: { + int Channels = aluChannelsFromFormat(ALBuf->format); + + if(ALBuf->eOriginalFormat != format) + { + alSetError(AL_INVALID_ENUM); + break; + } + + if((offset%65) != 0 || (length%65) != 0 || + ALBuf->size/Channels/sizeof(ALshort) < (ALuint)offset+length) + { + alSetError(AL_INVALID_VALUE); + break; + } + + ConvertDataIMA4(&ALBuf->data[offset*Channels], data, Channels, length/65*Channels); + } break; + + default: { + ALuint Channels = aluChannelsFromFormat(format); + ALuint Bytes = aluBytesFromFormat(format); + + if(Channels != aluChannelsFromFormat(ALBuf->format)) + { + alSetError(AL_INVALID_ENUM); + break; + } + + if(ALBuf->size/Channels/sizeof(ALshort) < (ALuint)offset+length) + { + alSetError(AL_INVALID_VALUE); + break; + } + + ConvertData(&ALBuf->data[offset*Channels], data, Bytes, length*Channels); + } break; + } + } + } + else + { + // Invalid Buffer Name + alSetError(AL_INVALID_NAME); + } + + ProcessContext(Context); +} + ALAPI void ALAPIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue) { diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c index 876aa41f..4eef8ba5 100644 --- a/OpenAL32/alExtension.c +++ b/OpenAL32/alExtension.c @@ -30,6 +30,7 @@ #include "alEffect.h" #include "alAuxEffectSlot.h" #include "alSource.h" +#include "alBuffer.h" #include "AL/al.h" #include "AL/alc.h" @@ -144,6 +145,8 @@ static ALfunction function[]= { { "alGetAuxiliaryEffectSlotf", (ALvoid *) alGetAuxiliaryEffectSlotf }, { "alGetAuxiliaryEffectSlotfv", (ALvoid *) alGetAuxiliaryEffectSlotfv}, + { "alBufferSubDataEXT", (ALvoid *) alBufferSubDataEXT }, + { NULL, (ALvoid *) NULL } }; static ALenums enumeration[]={ diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index dd88ed08..aa2d5719 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -33,7 +33,7 @@ #include "alAuxEffectSlot.h" static ALvoid InitSourceParams(ALsource *pSource); -static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset); +static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize); static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext); static ALint GetByteOffset(ALsource *pSource); @@ -853,7 +853,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV { ALCcontext *pContext; ALsource *pSource; - ALfloat flOffset; + ALfloat flOffset[2]; pContext = alcGetCurrentContext(); if (pContext) @@ -903,8 +903,20 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - if (GetSourceOffset(pSource, eParam, &flOffset)) - *pflValue = flOffset; + if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize)) + *pflValue = flOffset[0]; + else + alSetError(AL_INVALID_OPERATION); + break; + + case AL_SEC_RW_OFFSETS_EXT: + case AL_SAMPLE_RW_OFFSETS_EXT: + case AL_BYTE_RW_OFFSETS_EXT: + if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize)) + { + pflValue[0] = flOffset[0]; + pflValue[1] = flOffset[1]; + } else alSetError(AL_INVALID_OPERATION); break; @@ -1089,7 +1101,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu { ALCcontext *pContext; ALsource *pSource; - ALfloat flOffset; + ALfloat flOffset[2]; pContext = alcGetCurrentContext(); if (pContext) @@ -1162,8 +1174,20 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - if (GetSourceOffset(pSource, eParam, &flOffset)) - *plValue = (ALint)flOffset; + if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize)) + *plValue = (ALint)flOffset[0]; + else + alSetError(AL_INVALID_OPERATION); + break; + + case AL_SEC_RW_OFFSETS_EXT: + case AL_SAMPLE_RW_OFFSETS_EXT: + case AL_BYTE_RW_OFFSETS_EXT: + if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize)) + { + plValue[0] = (ALint)flOffset[0]; + plValue[1] = (ALint)flOffset[1]; + } else alSetError(AL_INVALID_OPERATION); break; @@ -1997,12 +2021,13 @@ static ALvoid InitSourceParams(ALsource *pSource) Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds) The offset is relative to the start of the queue (not the start of the current buffer) */ -static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset) +static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize) { ALbufferlistitem *pBufferList; ALbuffer *pBuffer; ALfloat flBufferFreq; - ALint lBytesPlayed, lChannels; + ALint lChannels; + ALint readPos, writePos; ALenum eOriginalFormat; ALboolean bReturn = AL_TRUE; ALint lTotalBufferDataSize; @@ -2016,15 +2041,20 @@ static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOf lChannels = aluChannelsFromFormat(pBuffer->format); // Get Current BytesPlayed - lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer + readPos = 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; + readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size; pBufferList = pBufferList->next; } + if(pSource->state == AL_PLAYING) + writePos = readPos + (updateSize * lChannels * 2); + else + writePos = readPos; + lTotalBufferDataSize = 0; pBufferList = pSource->queue; while (pBufferList) @@ -2036,64 +2066,91 @@ static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOf if (pSource->bLooping) { - if (lBytesPlayed < 0) - lBytesPlayed = 0; + if(readPos < 0) + readPos = 0; else - lBytesPlayed = lBytesPlayed % lTotalBufferDataSize; + readPos %= lTotalBufferDataSize; + if(writePos < 0) + writePos = 0; + else + writePos %= lTotalBufferDataSize; } else { // Clamp BytesPlayed to within 0 and lTotalBufferDataSize - if(lBytesPlayed < 0) - lBytesPlayed = 0; - if(lBytesPlayed > lTotalBufferDataSize) - lBytesPlayed = lTotalBufferDataSize; + if(readPos < 0) + readPos = 0; + else if(readPos > lTotalBufferDataSize) + readPos = lTotalBufferDataSize; + if(writePos < 0) + writePos = 0; + else if(writePos > lTotalBufferDataSize) + writePos = lTotalBufferDataSize; } switch (eName) { case AL_SEC_OFFSET: - *pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq)); + case AL_SEC_RW_OFFSETS_EXT: + pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq); + pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq); break; case AL_SAMPLE_OFFSET: - *pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2)); + case AL_SAMPLE_RW_OFFSETS_EXT: + pflOffset[0] = (ALfloat)(readPos / (lChannels * 2)); + pflOffset[1] = (ALfloat)(writePos / (lChannels * 2)); break; case AL_BYTE_OFFSET: + case AL_BYTE_RW_OFFSETS_EXT: // Take into account the original format of the Buffer 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); + readPos = (ALint)((ALfloat)readPos / 3.6111f); + writePos = (ALint)((ALfloat)writePos / 3.6111f); // Round down to nearest ADPCM block - *pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels); + pflOffset[0] = (ALfloat)((readPos / (36 * lChannels)) * 36 * lChannels); + if(pSource->state == AL_PLAYING) + { + // Round up to nearest ADPCM block + pflOffset[1] = (ALfloat)(((writePos + (36 * lChannels) - 1) / (36 * lChannels)) * 36 * lChannels); + } + else + pflOffset[1] = pflOffset[0]; } else if (eOriginalFormat == AL_FORMAT_REAR8) { - *pflOffset = (ALfloat)(lBytesPlayed >> 2); + pflOffset[0] = (ALfloat)(readPos >> 2); + pflOffset[1] = (ALfloat)(writePos >> 2); } else if (eOriginalFormat == AL_FORMAT_REAR16) { - *pflOffset = (ALfloat)(lBytesPlayed >> 1); + pflOffset[0] = (ALfloat)(readPos >> 1); + pflOffset[1] = (ALfloat)(writePos >> 1); } else if (aluBytesFromFormat(eOriginalFormat) == 1) { - *pflOffset = (ALfloat)(lBytesPlayed >> 1); + pflOffset[0] = (ALfloat)(readPos >> 1); + pflOffset[1] = (ALfloat)(writePos >> 1); } else if (aluBytesFromFormat(eOriginalFormat) == 4) { - *pflOffset = (ALfloat)(lBytesPlayed << 1); + pflOffset[0] = (ALfloat)(readPos << 1); + pflOffset[1] = (ALfloat)(writePos << 1); } else { - *pflOffset = (ALfloat)lBytesPlayed; + pflOffset[0] = (ALfloat)readPos; + pflOffset[1] = (ALfloat)writePos; } break; } } else { - *pflOffset = 0.0f; + pflOffset[0] = 0.0f; + pflOffset[1] = 0.0f; } return bReturn; diff --git a/include/AL/alext.h b/include/AL/alext.h index 9dffcdee..4549d3d9 100644 --- a/include/AL/alext.h +++ b/include/AL/alext.h @@ -91,6 +91,14 @@ extern "C" { #define AL_FORMAT_STEREO_IMA4 0x1301 #endif +#ifndef AL_EXT_buffer_sub_data +#define AL_EXT_buffer_sub_data 1 +#define AL_BYTE_RW_OFFSETS_EXT 0x1031 +#define AL_SAMPLE_RW_OFFSETS_EXT 0x1032 +#define AL_SEC_RW_OFFSETS_EXT 0x1033 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATAEXTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +#endif + #ifdef __cplusplus } #endif -- 2.11.4.GIT