diff options
author | Chris Robinson <[email protected]> | 2015-10-15 07:29:25 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2015-10-15 07:29:25 -0700 |
commit | 97f53d941c32b24470a0f589853ce60cfbe7f15b (patch) | |
tree | 06ced97b1b83511279a5a237d5e2721ac14bbda2 | |
parent | 3c54ba3901d93093406a7e5129bb43badcc6cf50 (diff) |
Store the source's previous samples with the voice
This helps avoid different results when looping is toggled within a couple
samples of the loop point, or when a processed buffer is removed while the
source is only a couple samples into the next buffer.
-rw-r--r-- | Alc/mixer.c | 124 | ||||
-rw-r--r-- | OpenAL32/Include/alSource.h | 2 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 3 | ||||
-rw-r--r-- | OpenAL32/alSource.c | 12 |
4 files changed, 49 insertions, 92 deletions
diff --git a/Alc/mixer.c b/Alc/mixer.c index 2f38ef3f..dd62ab73 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -57,16 +57,17 @@ enum Resampler { static enum Resampler DefaultResampler = LinearResampler; -/* Each entry is a pair, where the first is the number of samples needed before - * the current position, and the second is the number of samples needed after - * (not including) the current position, for the given resampler. +/* Specifies the number of samples needed after (not including) the current + * position, for the given resampler. */ -static const ALsizei ResamplerPadding[ResamplerMax][2] = { - {0, 0}, /* Point */ - {0, 1}, /* Linear */ - {1, 2}, /* FIR4 */ - {3, 4}, /* FIR8 */ +static const ALsizei ResamplerPadding[ResamplerMax] = { + 0, /* Point */ + 1, /* Linear */ + 2, /* FIR4 */ + 4, /* FIR8 */ }; +/* FIR8 requires 3 extra samples before the current position. */ +static_assert(MAX_PREVIOUS_SAMPLES >= 3, "MAX_PREVIOUS_SAMPLES must be at least 3!"); static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; @@ -342,8 +343,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam OutPos = 0; do { - const ALuint BufferPrePadding = ResamplerPadding[DefaultResampler][0]; - const ALuint BufferPadding = ResamplerPadding[DefaultResampler][1]; + const ALuint BufferPadding = ResamplerPadding[DefaultResampler]; ALuint SrcBufferSize, DstBufferSize; /* Figure out how many buffer samples will be needed */ @@ -351,13 +351,13 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam DataSize64 *= increment; DataSize64 += DataPosFrac+FRACTIONMASK; DataSize64 >>= FRACTIONBITS; - DataSize64 += BufferPadding+BufferPrePadding; + DataSize64 += BufferPadding+MAX_PREVIOUS_SAMPLES; SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE); /* Figure out how many samples we can actually mix from this. */ DataSize64 = SrcBufferSize; - DataSize64 -= BufferPadding+BufferPrePadding; + DataSize64 -= BufferPadding+MAX_PREVIOUS_SAMPLES; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; @@ -373,7 +373,11 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { const ALfloat *ResampledData; ALfloat *SrcData = Device->SourceData; - ALuint SrcDataSize = 0; + ALuint SrcDataSize; + + /* Load the previous samples into the source data first. */ + memcpy(SrcData, voice->PrevSamples[chan], MAX_PREVIOUS_SAMPLES*sizeof(ALfloat)); + SrcDataSize = MAX_PREVIOUS_SAMPLES; if(Source->SourceType == AL_STATIC) { @@ -382,7 +386,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ALuint DataSize; ALuint pos; - /* Offset to current channel */ + /* Offset buffer data to current channel */ Data += chan*SampleSize; /* If current pos is beyond the loop range, do not loop */ @@ -390,21 +394,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { Looping = AL_FALSE; - if(DataPosInt >= BufferPrePadding) - pos = DataPosInt - BufferPrePadding; - else - { - DataSize = BufferPrePadding - DataPosInt; - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - - SilenceSamples(&SrcData[SrcDataSize], DataSize); - SrcDataSize += DataSize; - - pos = 0; - } - - /* Copy what's left to play in the source buffer, and clear the - * rest of the temp buffer */ + /* Load what's left to play from the source buffer, and + * clear the rest of the temp buffer */ + pos = DataPosInt; DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos); LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize], @@ -419,29 +411,9 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam ALuint LoopStart = ALBuffer->LoopStart; ALuint LoopEnd = ALBuffer->LoopEnd; - if(DataPosInt >= LoopStart) - { - pos = DataPosInt-LoopStart; - while(pos < BufferPrePadding) - pos += LoopEnd-LoopStart; - pos -= BufferPrePadding; - pos += LoopStart; - } - else if(DataPosInt >= BufferPrePadding) - pos = DataPosInt - BufferPrePadding; - else - { - DataSize = BufferPrePadding - DataPosInt; - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - - SilenceSamples(&SrcData[SrcDataSize], DataSize); - SrcDataSize += DataSize; - - pos = 0; - } - - /* Copy what's left of this loop iteration, then copy repeats - * of the loop section */ + /* Load what's left of this loop iteration, then load + * repeats of the loop section */ + pos = DataPosInt; DataSize = LoopEnd - pos; DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); @@ -464,45 +436,7 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam { /* Crawl the buffer queue to fill in the temp buffer */ ALbufferlistitem *tmpiter = BufferListItem; - ALuint pos; - - if(DataPosInt >= BufferPrePadding) - pos = DataPosInt - BufferPrePadding; - else - { - pos = BufferPrePadding - DataPosInt; - while(pos > 0) - { - ALbufferlistitem *prev; - if((prev=tmpiter->prev) != NULL) - tmpiter = prev; - else if(Looping) - { - while(tmpiter->next) - tmpiter = tmpiter->next; - } - else - { - ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos); - - SilenceSamples(&SrcData[SrcDataSize], DataSize); - SrcDataSize += DataSize; - - pos = 0; - break; - } - - if(tmpiter->buffer) - { - if((ALuint)tmpiter->buffer->SampleLen > pos) - { - pos = tmpiter->buffer->SampleLen - pos; - break; - } - pos -= tmpiter->buffer->SampleLen; - } - } - } + ALuint pos = DataPosInt; while(tmpiter && SrcBufferSize > SrcDataSize) { @@ -538,9 +472,15 @@ ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint Sam } } + /* Store the last source samples used for next time. */ + memcpy(voice->PrevSamples[chan], + &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], + MAX_PREVIOUS_SAMPLES*sizeof(ALfloat) + ); + /* Now resample, then filter and mix to the appropriate outputs. */ ResampledData = Resample( - &SrcData[BufferPrePadding], DataPosFrac, increment, + &SrcData[MAX_PREVIOUS_SAMPLES], DataPosFrac, increment, Device->ResampledData, DstBufferSize ); { diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 89c210b9..34c3575b 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -35,6 +35,8 @@ typedef struct ALvoice { ALuint Offset; /* Number of output samples mixed since starting. */ + alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PREVIOUS_SAMPLES]; + DirectParams Direct; SendParams Send[MAX_SENDS]; } ALvoice; diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 051a0f0d..ba7afedb 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -32,6 +32,9 @@ #define MAX_PITCH (255) +/* Maximum number of previous buffer samples needed for resampling. */ +#define MAX_PREVIOUS_SAMPLES 4 + #ifdef __cplusplus extern "C" { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index f5b7111f..f91b3878 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -2574,6 +2574,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; + ALboolean discontinuity; ALvoice *voice = NULL; ALsizei i; @@ -2594,13 +2595,20 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) Source->position = 0; Source->position_fraction = 0; ATOMIC_STORE(&Source->current_buffer, BufferList); + discontinuity = AL_TRUE; } else + { Source->state = AL_PLAYING; + discontinuity = AL_FALSE; + } // Check if an Offset has been set if(Source->Offset >= 0.0) + { ApplyOffset(Source); + /* discontinuity = AL_TRUE;??? */ + } /* If there's nothing to play, or device is disconnected, go right to * stopped */ @@ -2631,6 +2639,10 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice->Source = Source; } + /* Clear previous samples if playback is discontinuous. */ + if(discontinuity) + memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + voice->Direct.Moving = AL_FALSE; voice->Direct.Counter = 0; for(i = 0;i < MAX_INPUT_CHANNELS;i++) |