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.
This commit is contained in:
parent
3c54ba3901
commit
97f53d941c
124
Alc/mixer.c
124
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
|
||||
);
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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" {
|
||||
|
@ -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++)
|
||||
|
Loading…
x
Reference in New Issue
Block a user