diff options
author | Chris Robinson <[email protected]> | 2010-11-25 11:16:19 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2010-11-25 11:16:19 -0800 |
commit | f4e0c6a348253c6d7154e7a8f18a209c5133c5b3 (patch) | |
tree | 60f436283a40565a3555c293641f961ad68d9801 | |
parent | 885a5e9f906cf6c49e7c2688167cbffce74ab61c (diff) |
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.
-rw-r--r-- | Alc/mixer.c | 222 |
1 files changed, 150 insertions, 72 deletions
diff --git a/Alc/mixer.c b/Alc/mixer.c index 1d422da0..7687facf 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -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) + /* Figure out how many buffer bytes will be needed */ + DataSize64 = SamplesToDo-j; + DataSize64 *= increment; + DataSize64 += DataPosFrac+FRACTIONMASK; + DataSize64 >>= FRACTIONBITS; + DataSize64 += BUFFER_PADDING; + DataSize64 *= FrameSize; + + BufferSize = sizeof(SrcData) - SrcDataSize; + BufferSize = min(DataSize64, BufferSize); + + if(Source->lSourceType == AL_STATIC) { - Data = ALBuffer->data; - DataSize = ALBuffer->size; - DataSize /= aluFrameSizeFromFormat(ALBuffer->format); - Channels = aluChannelsFromFormat(ALBuffer->format); - Bytes = aluBytesFromFormat(ALBuffer->format); - - LoopStart = 0; - LoopEnd = DataSize; - if(Looping && 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 - { - LoopStart = ALBuffer->LoopStart; - LoopEnd = ALBuffer->LoopEnd; - } - } - } + Looping = AL_FALSE; - if(DataPosInt >= DataSize) - goto skipmix; + /* 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); - 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) + memcpy(&SrcData[SrcDataSize], &Data[DataPosInt*FrameSize], DataSize); + SrcDataSize += DataSize; + BufferSize -= DataSize; + + memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, BufferSize); + SrcDataSize += BufferSize; + BufferSize -= BufferSize; + } + else { - ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes; - ulExtraSamples = min(NextBuf->size, ulExtraSamples); - memcpy(&Data[DataSize*Channels*Bytes], - NextBuf->data, ulExtraSamples); + 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) + { + DataSize = min(BufferSize, DataSize); + + memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize); + SrcDataSize += DataSize; + BufferSize -= DataSize; + } } } - else if(Looping) + else { - ALbuffer *NextBuf = Source->queue->buffer; - if(NextBuf && NextBuf->size) + /* Crawl the buffer queue to fill in the temp buffer */ + ALbufferlistitem *BufferListIter = BufferListItem; + ALuint pos = DataPosInt*FrameSize; + + while(BufferListIter && BufferSize > 0) { - ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes; - ulExtraSamples = min(NextBuf->size, ulExtraSamples); - memcpy(&Data[DataSize*Channels*Bytes], - &((ALubyte*)NextBuf->data)[LoopStart*Channels*Bytes], - ulExtraSamples); + 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; + } } } /* 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); |