Use sample frames when handling the buffer length

This commit is contained in:
Chris Robinson 2011-10-03 10:07:50 -07:00
parent 35b4b31d57
commit 11caba9807
4 changed files with 79 additions and 104 deletions

View File

@ -622,7 +622,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
/* Copy what's left to play in the source buffer, and clear the
* rest of the temp buffer */
DataSize = ALBuffer->size/FrameSize - pos;
DataSize = ALBuffer->SampleLen - pos;
DataSize = minu(BufferSize, DataSize);
memcpy(&SrcData[SrcDataSize*FrameSize], &Data[pos*FrameSize], DataSize*FrameSize);
@ -715,12 +715,12 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
if(BufferListIter->buffer)
{
if((ALuint)BufferListIter->buffer->size/FrameSize > pos)
if((ALuint)BufferListIter->buffer->SampleLen > pos)
{
pos = BufferListIter->buffer->size/FrameSize - pos;
pos = BufferListIter->buffer->SampleLen - pos;
break;
}
pos -= BufferListIter->buffer->size/FrameSize;
pos -= BufferListIter->buffer->SampleLen;
}
}
}
@ -731,7 +731,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
if((ALBuffer=BufferListIter->buffer) != NULL)
{
const ALubyte *Data = ALBuffer->data;
ALuint DataSize = ALBuffer->size/FrameSize;
ALuint DataSize = ALBuffer->SampleLen;
/* Skip the data already played */
if(DataSize <= pos)
@ -785,7 +785,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
if((ALBuffer=BufferListItem->buffer) != NULL)
{
DataSize = ALBuffer->size / FrameSize;
DataSize = ALBuffer->SampleLen;
LoopStart = ALBuffer->LoopStart;
LoopEnd = ALBuffer->LoopEnd;
if(LoopEnd > DataPosInt)

View File

@ -69,10 +69,11 @@ static __inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType typ
typedef struct ALbuffer
{
ALvoid *data;
ALsizei size;
ALsizei Frequency;
ALenum Format;
ALsizei Frequency;
ALenum Format;
ALsizei SampleLen;
enum FmtChannels FmtChannels;
enum FmtType FmtType;

View File

@ -550,14 +550,12 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
else
{
ALuint FrameSize;
ALsizei FrameCount;
WriteLock(&ALBuf->lock);
FrameSize = FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType);
FrameCount = ALBuf->size / FrameSize;
if(channels != (ALenum)ALBuf->FmtChannels)
alSetError(Context, AL_INVALID_ENUM);
else if(offset > FrameCount || samples > FrameCount-offset)
else if(offset > ALBuf->SampleLen || samples > ALBuf->SampleLen-offset)
alSetError(Context, AL_INVALID_VALUE);
else if(type == UserFmtIMA4 && (samples%65) != 0)
alSetError(Context, AL_INVALID_VALUE);
@ -598,14 +596,12 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
else
{
ALuint FrameSize;
ALsizei FrameCount;
ReadLock(&ALBuf->lock);
FrameSize = FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType);
FrameCount = ALBuf->size / FrameSize;
if(channels != (ALenum)ALBuf->FmtChannels)
alSetError(Context, AL_INVALID_ENUM);
else if(offset > FrameCount || samples > FrameCount-offset)
else if(offset > ALBuf->SampleLen || samples > ALBuf->SampleLen-offset)
alSetError(Context, AL_INVALID_VALUE);
else if(type == UserFmtIMA4 && (samples%65) != 0)
alSetError(Context, AL_INVALID_VALUE);
@ -804,20 +800,13 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum eParam, const ALint* pl
WriteLock(&ALBuf->lock);
if(ALBuf->ref != 0)
alSetError(pContext, AL_INVALID_OPERATION);
else if(plValues[0] < 0 || plValues[1] < 0 ||
plValues[0] >= plValues[1] || ALBuf->size == 0)
else if(plValues[0] >= plValues[1] || plValues[0] < 0 ||
plValues[1] > ALBuf->SampleLen)
alSetError(pContext, AL_INVALID_VALUE);
else
{
ALint maxlen = ALBuf->size /
FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType);
if(plValues[0] > maxlen || plValues[1] > maxlen)
alSetError(pContext, AL_INVALID_VALUE);
else
{
ALBuf->LoopStart = plValues[0];
ALBuf->LoopEnd = plValues[1];
}
ALBuf->LoopStart = plValues[0];
ALBuf->LoopEnd = plValues[1];
}
WriteUnlock(&ALBuf->lock);
break;
@ -852,10 +841,8 @@ AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum eParam, ALfloat *pf
{
case AL_SEC_LENGTH:
ReadLock(&pBuffer->lock);
if(pBuffer->size != 0)
*pflValue = (pBuffer->size /
FrameSizeFromFmt(pBuffer->FmtChannels, pBuffer->FmtType)) /
(ALfloat)pBuffer->Frequency;
if(pBuffer->SampleLen != 0)
*pflValue = pBuffer->SampleLen / (ALfloat)pBuffer->Frequency;
else
*pflValue = 0.0f;
ReadUnlock(&pBuffer->lock);
@ -963,7 +950,10 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plVa
break;
case AL_SIZE:
*plValue = pBuffer->size;
ReadLock(&pBuffer->lock);
*plValue = pBuffer->SampleLen *
FrameSizeFromFmt(pBuffer->FmtChannels, pBuffer->FmtType);
ReadUnlock(&pBuffer->lock);
break;
case AL_INTERNAL_FORMAT:
@ -975,13 +965,7 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plVa
break;
case AL_SAMPLE_LENGTH:
ReadLock(&pBuffer->lock);
if(pBuffer->size != 0)
*plValue = pBuffer->size /
FrameSizeFromFmt(pBuffer->FmtChannels, pBuffer->FmtType);
else
*plValue = 0;
ReadUnlock(&pBuffer->lock);
*plValue = pBuffer->SampleLen;
break;
default:
@ -2028,7 +2012,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
return AL_OUT_OF_MEMORY;
}
ALBuf->data = temp;
ALBuf->size = (ALsizei)newsize;
ALBuf->SampleLen = frames*65;
if(data != NULL)
ConvertData(ALBuf->data, DstType, data, SrcType, NewChannels, frames);
@ -2061,7 +2045,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
return AL_OUT_OF_MEMORY;
}
ALBuf->data = temp;
ALBuf->size = (ALsizei)newsize;
ALBuf->SampleLen = frames;
if(data != NULL)
ConvertData(ALBuf->data, DstType, data, SrcType, NewChannels, frames);
@ -2086,7 +2070,7 @@ static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei f
ALBuf->Format = NewFormat;
ALBuf->LoopStart = 0;
ALBuf->LoopEnd = (ALsizei)(newsize / NewChannels / NewBytes);
ALBuf->LoopEnd = ALBuf->SampleLen;
WriteUnlock(&ALBuf->lock);
return AL_NO_ERROR;

View File

@ -48,7 +48,7 @@ const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
static ALvoid InitSourceParams(ALsource *Source);
static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
static ALint GetByteOffset(ALsource *Source);
static ALint GetSampleOffset(ALsource *Source);
AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
@ -1866,7 +1866,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
BufferList = Source->queue;
while(BufferList)
{
if(BufferList->buffer != NULL && BufferList->buffer->size)
if(BufferList->buffer != NULL && BufferList->buffer->SampleLen)
break;
BufferList = BufferList->next;
}
@ -1960,11 +1960,9 @@ static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, A
{
const ALbufferlistitem *BufferList;
const ALbuffer *Buffer = NULL;
enum UserFmtType OriginalType;
ALsizei BufferFreq;
ALint Channels, Bytes;
ALuint BufferFreq = 0;
ALuint readPos, writePos;
ALuint TotalBufferDataSize;
ALuint totalBufferLen;
ALuint i;
// Find the first non-NULL Buffer in the Queue
@ -1974,6 +1972,7 @@ static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, A
if(BufferList->buffer)
{
Buffer = BufferList->buffer;
BufferFreq = Buffer->Frequency;
break;
}
BufferList = BufferList->next;
@ -1986,64 +1985,58 @@ static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, A
return;
}
// Get Current Buffer Size and frequency (in milliseconds)
BufferFreq = Buffer->Frequency;
OriginalType = Buffer->OriginalType;
Channels = ChannelsFromFmt(Buffer->FmtChannels);
Bytes = BytesFromFmt(Buffer->FmtType);
// Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
readPos = Source->position * Channels * Bytes;
// Add byte length of any processed buffers in the queue
TotalBufferDataSize = 0;
// Get Current SamplesPlayed (NOTE : This is the offset into the *current* buffer)
readPos = Source->position;
// Add length of any processed buffers in the queue
totalBufferLen = 0;
BufferList = Source->queue;
for(i = 0;BufferList;i++)
{
if(BufferList->buffer)
{
if(i < Source->BuffersPlayed)
readPos += BufferList->buffer->size;
TotalBufferDataSize += BufferList->buffer->size;
readPos += BufferList->buffer->SampleLen;
totalBufferLen += BufferList->buffer->SampleLen;
}
BufferList = BufferList->next;
}
if(Source->state == AL_PLAYING)
writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
writePos = readPos + (ALuint)(updateLen*BufferFreq);
else
writePos = readPos;
if(Source->bLooping)
{
readPos %= TotalBufferDataSize;
writePos %= TotalBufferDataSize;
readPos %= totalBufferLen;
writePos %= totalBufferLen;
}
else
{
// Wrap positions back to 0
if(readPos >= TotalBufferDataSize)
if(readPos >= totalBufferLen)
readPos = 0;
if(writePos >= TotalBufferDataSize)
if(writePos >= totalBufferLen)
writePos = 0;
}
switch(name)
{
case AL_SEC_OFFSET:
offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
offset[0] = (ALdouble)readPos / Buffer->Frequency;
offset[1] = (ALdouble)writePos / Buffer->Frequency;
break;
case AL_SAMPLE_OFFSET:
case AL_SAMPLE_RW_OFFSETS_SOFT:
offset[0] = (ALdouble)(readPos / (Channels * Bytes));
offset[1] = (ALdouble)(writePos / (Channels * Bytes));
offset[0] = (ALdouble)readPos;
offset[1] = (ALdouble)writePos;
break;
case AL_BYTE_OFFSET:
case AL_BYTE_RW_OFFSETS_SOFT:
// Take into account the original format of the Buffer
if(OriginalType == UserFmtIMA4)
if(Buffer->OriginalType == UserFmtIMA4)
{
ALuint FrameBlockSize = 65 * Bytes * Channels;
ALuint BlockSize = 36 * Channels;
ALuint BlockSize = 36 * ChannelsFromFmt(Buffer->FmtChannels);
ALuint FrameBlockSize = 65;
// Round down to nearest ADPCM block
offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
@ -2058,9 +2051,9 @@ static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, A
}
else
{
ALuint OrigBytes = BytesFromUserFmt(OriginalType);
offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
offset[0] = (ALdouble)(readPos * FrameSize);
offset[1] = (ALdouble)(writePos * FrameSize);
}
break;
}
@ -2077,45 +2070,44 @@ ALboolean ApplyOffset(ALsource *Source)
{
const ALbufferlistitem *BufferList;
const ALbuffer *Buffer;
ALint lBufferSize, lTotalBufferSize;
ALint BuffersPlayed;
ALint lByteOffset;
ALint bufferLen, totalBufferLen;
ALint buffersPlayed;
ALint offset;
// Get true byte offset
lByteOffset = GetByteOffset(Source);
offset = GetSampleOffset(Source);
// If the offset is invalid, don't apply it
if(lByteOffset == -1)
if(offset == -1)
return AL_FALSE;
// Sort out the queue (pending and processed states)
BufferList = Source->queue;
lTotalBufferSize = 0;
BuffersPlayed = 0;
totalBufferLen = 0;
buffersPlayed = 0;
while(BufferList)
{
Buffer = BufferList->buffer;
lBufferSize = Buffer ? Buffer->size : 0;
bufferLen = Buffer ? Buffer->SampleLen : 0;
if(lBufferSize <= lByteOffset-lTotalBufferSize)
if(bufferLen <= offset-totalBufferLen)
{
// Offset is past this buffer so increment BuffersPlayed
BuffersPlayed++;
buffersPlayed++;
}
else if(lTotalBufferSize <= lByteOffset)
else if(totalBufferLen <= offset)
{
// Offset is within this buffer
Source->BuffersPlayed = BuffersPlayed;
Source->BuffersPlayed = buffersPlayed;
// SW Mixer Positions are in Samples
Source->position = (lByteOffset - lTotalBufferSize) /
FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
Source->position = offset - totalBufferLen;
return AL_TRUE;
}
// Increment the TotalBufferSize
lTotalBufferSize += lBufferSize;
totalBufferLen += bufferLen;
// Move on to next buffer in the Queue
BufferList = BufferList->next;
@ -2126,17 +2118,17 @@ ALboolean ApplyOffset(ALsource *Source)
/*
GetByteOffset
GetSampleOffset
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 float)
Returns the sample 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
*/
static ALint GetByteOffset(ALsource *Source)
static ALint GetSampleOffset(ALsource *Source)
{
const ALbuffer *Buffer = NULL;
const ALbufferlistitem *BufferList;
ALint ByteOffset = -1;
ALint Offset = -1;
// Find the first non-NULL Buffer in the Queue
BufferList = Source->queue;
@ -2161,33 +2153,31 @@ static ALint GetByteOffset(ALsource *Source)
{
case AL_BYTE_OFFSET:
// Take into consideration the original format
ByteOffset = Source->lOffset;
Offset = Source->lOffset;
if(Buffer->OriginalType == UserFmtIMA4)
{
// Round down to nearest ADPCM block
ByteOffset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
Offset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
// Multiply by compression rate (65 sample frames per block)
ByteOffset *= 65;
Offset *= 65;
}
else
ByteOffset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
break;
case AL_SAMPLE_OFFSET:
ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
Offset = Source->lOffset;
break;
case AL_SEC_OFFSET:
// Note - lOffset is internally stored as Milliseconds
ByteOffset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
Offset = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
break;
}
// Clear Offset
Source->lOffset = -1;
return ByteOffset;
return Offset;
}