Use a temporary stack buffer to store the source buffer data to be mixed

This makes it much easier to pack the playable buffer data so that it's a
continuous data stream. This could normally be broken up otherwise, such as
when using loop points or small queued buffers.
Currently it defaults to a 16KB stack buffer, but this can be overridden at
compile time.
master
Chris Robinson 2010-11-25 11:16:19 -08:00
parent 885a5e9f90
commit f4e0c6a348
1 changed files with 155 additions and 77 deletions

View File

@ -105,8 +105,6 @@ static void MixMono_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
ALfloat value; \
\
increment = Source->Params.Step; \
data += *DataPosInt; \
DataEnd -= *DataPosInt; \
\
DryBuffer = Device->DryBuffer; \
ClickRemoval = Device->ClickRemoval; \
@ -281,8 +279,6 @@ static void MixStereo_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
ALfloat value; \
\
increment = Source->Params.Step; \
data += *DataPosInt * Channels; \
DataEnd -= *DataPosInt; \
\
DryBuffer = Device->DryBuffer; \
ClickRemoval = Device->ClickRemoval; \
@ -457,8 +453,6 @@ static void MixMC_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,
ALfloat value; \
\
increment = Source->Params.Step; \
data += *DataPosInt * Channels; \
DataEnd -= *DataPosInt; \
\
DryBuffer = Device->DryBuffer; \
ClickRemoval = Device->ClickRemoval; \
@ -714,11 +708,18 @@ DECL_MIX(ALubyte, lerp8)
DECL_MIX(ALubyte, cos_lerp8)
/* Stack data size can be whatever. Larger values need more stack, while
* smaller values may need more iterations */
#ifndef STACK_DATA_SIZE
#define STACK_DATA_SIZE 16384
#endif
ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
{
ALbufferlistitem *BufferListItem;
ALint64 DataSize64,DataPos64;
ALint increment;
ALuint FrameSize, Channels, Bytes;
ALuint DataPosInt, DataPosFrac;
ALuint BuffersPlayed;
ALboolean Looping;
@ -731,6 +732,23 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
DataPosInt = Source->position;
DataPosFrac = Source->position_fraction;
Looping = Source->bLooping;
increment = Source->Params.Step;
/* Get buffer info */
FrameSize = Channels = Bytes = 0;
BufferListItem = Source->queue;
for(i = 0;i < Source->BuffersInQueue;i++)
{
const ALbuffer *ALBuffer;
if((ALBuffer=BufferListItem->buffer) != NULL)
{
FrameSize = aluFrameSizeFromFormat(ALBuffer->format);
Channels = aluChannelsFromFormat(ALBuffer->format);
Bytes = aluBytesFromFormat(ALBuffer->format);
break;
}
BufferListItem = BufferListItem->next;
}
/* Get current buffer queue item */
BufferListItem = Source->queue;
@ -739,75 +757,119 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
j = 0;
do {
const ALbuffer *ALBuffer;
ALubyte *Data = NULL;
ALuint DataSize = 0;
ALuint LoopStart = 0;
ALuint LoopEnd = 0;
ALuint Channels, Bytes;
ALubyte SrcData[STACK_DATA_SIZE];
ALuint SrcDataSize = 0;
ALuint BufferSize;
/* Get buffer info */
if((ALBuffer=BufferListItem->buffer) != NULL)
{
Data = ALBuffer->data;
DataSize = ALBuffer->size;
DataSize /= aluFrameSizeFromFormat(ALBuffer->format);
Channels = aluChannelsFromFormat(ALBuffer->format);
Bytes = aluBytesFromFormat(ALBuffer->format);
/* Figure out how many buffer bytes will be needed */
DataSize64 = SamplesToDo-j;
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
DataSize64 >>= FRACTIONBITS;
DataSize64 += BUFFER_PADDING;
DataSize64 *= FrameSize;
LoopStart = 0;
LoopEnd = DataSize;
if(Looping && Source->lSourceType == AL_STATIC)
BufferSize = sizeof(SrcData) - SrcDataSize;
BufferSize = min(DataSize64, BufferSize);
if(Source->lSourceType == AL_STATIC)
{
const ALbuffer *ALBuffer = Source->Buffer;
const ALubyte *Data = ALBuffer->data;
ALuint DataSize;
/* If current pos is beyond the loop range, do not loop */
if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
{
/* If current pos is beyond the loop range, do not loop */
if(DataPosInt >= LoopEnd)
Looping = AL_FALSE;
else
Looping = AL_FALSE;
/* Copy what's left to play in the source buffer, and clear the
* rest of the temp buffer */
DataSize = ALBuffer->size - DataPosInt*FrameSize;
DataSize = min(BufferSize, DataSize);
memcpy(&SrcData[SrcDataSize], &Data[DataPosInt*FrameSize], DataSize);
SrcDataSize += DataSize;
BufferSize -= DataSize;
memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, BufferSize);
SrcDataSize += BufferSize;
BufferSize -= BufferSize;
}
else
{
ALuint LoopStart = ALBuffer->LoopStart;
ALuint LoopEnd = ALBuffer->LoopEnd;
/* Copy what's left of this loop iteration, then copy repeats
* of the loop section */
DataSize = (LoopEnd-DataPosInt) * FrameSize;
DataSize = min(BufferSize, DataSize);
memcpy(&SrcData[SrcDataSize], &Data[DataPosInt*FrameSize], DataSize);
SrcDataSize += DataSize;
BufferSize -= DataSize;
DataSize = (LoopEnd-LoopStart) * FrameSize;
while(BufferSize > 0)
{
LoopStart = ALBuffer->LoopStart;
LoopEnd = ALBuffer->LoopEnd;
DataSize = min(BufferSize, DataSize);
memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
SrcDataSize += DataSize;
BufferSize -= DataSize;
}
}
}
else
{
/* Crawl the buffer queue to fill in the temp buffer */
ALbufferlistitem *BufferListIter = BufferListItem;
ALuint pos = DataPosInt*FrameSize;
while(BufferListIter && BufferSize > 0)
{
const ALbuffer *ALBuffer;
if((ALBuffer=BufferListIter->buffer) != NULL)
{
const ALubyte *Data = ALBuffer->data;
ALuint DataSize = ALBuffer->size;
/* Skip the data already played */
if(DataSize <= pos)
pos -= DataSize;
else
{
Data += pos;
DataSize -= pos;
pos -= pos;
DataSize = min(BufferSize, DataSize);
memcpy(&SrcData[SrcDataSize], Data, DataSize);
SrcDataSize += DataSize;
BufferSize -= DataSize;
}
}
BufferListIter = BufferListIter->next;
if(!BufferListIter && Looping)
BufferListIter = Source->queue;
else if(!BufferListIter)
{
memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, BufferSize);
SrcDataSize += BufferSize;
BufferSize -= BufferSize;
}
}
}
if(DataPosInt >= DataSize)
goto skipmix;
memset(&Data[DataSize*Channels*Bytes], (Bytes==1)?0x80:0, BUFFER_PADDING*Channels*Bytes);
if(BufferListItem->next)
{
ALbuffer *NextBuf = BufferListItem->next->buffer;
if(NextBuf && NextBuf->size)
{
ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
ulExtraSamples = min(NextBuf->size, ulExtraSamples);
memcpy(&Data[DataSize*Channels*Bytes],
NextBuf->data, ulExtraSamples);
}
}
else if(Looping)
{
ALbuffer *NextBuf = Source->queue->buffer;
if(NextBuf && NextBuf->size)
{
ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
ulExtraSamples = min(NextBuf->size, ulExtraSamples);
memcpy(&Data[DataSize*Channels*Bytes],
&((ALubyte*)NextBuf->data)[LoopStart*Channels*Bytes],
ulExtraSamples);
}
}
/* Figure out how many samples we can mix. */
increment = Source->Params.Step;
DataSize64 = LoopEnd;
SrcDataSize /= FrameSize;
SrcDataSize -= BUFFER_PADDING;
DataSize64 = SrcDataSize;
DataSize64 <<= FRACTIONBITS;
DataPos64 = DataPosInt;
DataPos64 <<= FRACTIONBITS;
DataPos64 += DataPosFrac;
BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
DataPos64 = DataPosFrac;
BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
BufferSize = min(BufferSize, (SamplesToDo-j));
switch(Source->Resampler)
@ -815,43 +877,43 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
case POINT_RESAMPLER:
if(Bytes == 4)
Mix_ALfloat_point32(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
else if(Bytes == 2)
Mix_ALshort_point16(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
else if(Bytes == 1)
Mix_ALubyte_point8(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
break;
case LINEAR_RESAMPLER:
if(Bytes == 4)
Mix_ALfloat_lerp32(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
else if(Bytes == 2)
Mix_ALshort_lerp16(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
else if(Bytes == 1)
Mix_ALubyte_lerp8(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
break;
case COSINE_RESAMPLER:
if(Bytes == 4)
Mix_ALfloat_cos_lerp32(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
else if(Bytes == 2)
Mix_ALshort_cos_lerp16(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
else if(Bytes == 1)
Mix_ALubyte_cos_lerp8(Source, Device, Channels,
Data, &DataPosInt, &DataPosFrac, LoopEnd,
SrcData, &DataPosInt, &DataPosFrac, SrcDataSize,
j, SamplesToDo, BufferSize);
break;
case RESAMPLER_MIN:
@ -860,24 +922,37 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
}
j += BufferSize;
skipmix:
/* Handle looping sources */
if(DataPosInt >= LoopEnd)
while(1)
{
const ALbuffer *ALBuffer;
ALuint DataSize = 0;
ALuint LoopStart = 0;
ALuint LoopEnd = 0;
if((ALBuffer=BufferListItem->buffer) != NULL)
{
DataSize = ALBuffer->size / FrameSize;
if(DataSize > DataPosInt)
break;
LoopStart = ALBuffer->LoopStart;
LoopEnd = ALBuffer->LoopEnd;
}
if(BufferListItem->next)
{
BufferListItem = BufferListItem->next;
BuffersPlayed++;
DataPosInt -= DataSize;
}
else if(Looping)
{
BufferListItem = Source->queue;
BuffersPlayed = 0;
if(Source->lSourceType == AL_STATIC)
{
DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
else
DataPosInt -= DataSize;
break;
}
}
else
{
@ -886,7 +961,10 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
BuffersPlayed = Source->BuffersInQueue;
DataPosInt = 0;
DataPosFrac = 0;
break;
}
DataPosInt -= DataSize;
}
} while(State == AL_PLAYING && j < SamplesToDo);