aboutsummaryrefslogtreecommitdiffstats
path: root/alc/voice.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2020-02-17 17:13:00 -0800
committerChris Robinson <[email protected]>2020-02-17 17:13:25 -0800
commit3122c3b4a109b7d6e288bdde055fc4bbae5517bc (patch)
treeb2eb3a251a243d3a5f9a7566c343bc614c9ff8cc /alc/voice.cpp
parentc8dfd248185359d86410340741122943524ed10b (diff)
Handle running the buffer callback in the voice
Diffstat (limited to 'alc/voice.cpp')
-rw-r--r--alc/voice.cpp76
1 files changed, 66 insertions, 10 deletions
diff --git a/alc/voice.cpp b/alc/voice.cpp
index 752f13a9..19b4da2d 100644
--- a/alc/voice.cpp
+++ b/alc/voice.cpp
@@ -387,6 +387,23 @@ ALfloat *LoadBufferStatic(ALbufferlistitem *BufferListItem, ALbufferlistitem *&B
return SrcBuffer.begin();
}
+ALfloat *LoadBufferCallback(ALbufferlistitem *BufferListItem, const size_t NumChannels,
+ const size_t SampleSize, const size_t chan, size_t NumCallbackSamples,
+ al::span<ALfloat> SrcBuffer)
+{
+ const ALbuffer *Buffer{BufferListItem->mBuffer};
+
+ /* Load what's left to play from the buffer */
+ const size_t DataRem{minz(SrcBuffer.size(), NumCallbackSamples)};
+
+ const al::byte *Data{Buffer->mData.data() + chan*SampleSize};
+
+ LoadSamples(SrcBuffer.data(), Data, NumChannels, Buffer->mFmtType, DataRem);
+ SrcBuffer = SrcBuffer.subspan(DataRem);
+
+ return SrcBuffer.begin();
+}
+
ALfloat *LoadBufferQueue(ALbufferlistitem *BufferListItem, ALbufferlistitem *BufferLoopItem,
const size_t NumChannels, const size_t SampleSize, const size_t chan, size_t DataPosInt,
al::span<ALfloat> SrcBuffer)
@@ -531,7 +548,6 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
ASSUME(SamplesToDo > 0);
/* Get voice info */
- const ALuint vtype{mFlags&VOICE_TYPE_MASK};
ALuint DataPosInt{mPosition.load(std::memory_order_relaxed)};
ALuint DataPosFrac{mPositionFrac.load(std::memory_order_relaxed)};
ALbufferlistitem *BufferListItem{mCurrentBuffer.load(std::memory_order_relaxed)};
@@ -552,6 +568,7 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
ASSUME(NumChannels > 0);
ASSUME(SampleSize > 0);
ASSUME(increment > 0);
+ const auto FrameSize = size_t{NumChannels} * SampleSize;
ALCdevice *Device{Context->mDevice.get()};
const ALuint NumSends{Device->NumAuxSends};
@@ -634,6 +651,32 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
DstBufferSize &= ~3u;
}
+ if((mFlags&(VOICE_IS_CALLBACK|VOICE_CALLBACK_STOPPED)) == VOICE_IS_CALLBACK
+ && BufferListItem)
+ {
+ ALbuffer *buffer{BufferListItem->mBuffer};
+
+ /* Exclude resampler pre-padding from the needed size. */
+ const ALuint toLoad{SrcBufferSize - (MAX_RESAMPLER_PADDING>>1)};
+ if(toLoad > mNumCallbackSamples)
+ {
+ const size_t byteOffset{mNumCallbackSamples*FrameSize};
+ const size_t needBytes{toLoad*FrameSize - byteOffset};
+
+ const ALsizei gotBytes{buffer->Callback(buffer->UserData,
+ &buffer->mData[byteOffset], static_cast<ALsizei>(needBytes))};
+ if(gotBytes < 1)
+ mFlags |= VOICE_CALLBACK_STOPPED;
+ else if(static_cast<ALuint>(gotBytes) < needBytes)
+ {
+ mFlags |= VOICE_CALLBACK_STOPPED;
+ mNumCallbackSamples += static_cast<ALuint>(gotBytes) / FrameSize;
+ }
+ else
+ mNumCallbackSamples = toLoad;
+ }
+ }
+
ASSUME(DstBufferSize > 0);
for(ALuint chan{0};chan < NumChannels;chan++)
{
@@ -649,13 +692,12 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
if UNLIKELY(!BufferListItem)
srciter = std::copy(chandata.mPrevSamples.begin()+(MAX_RESAMPLER_PADDING>>1),
chandata.mPrevSamples.end(), srciter);
- else if(vtype == VOICE_IS_STATIC)
+ else if((mFlags&VOICE_IS_STATIC))
srciter = LoadBufferStatic(BufferListItem, BufferLoopItem, NumChannels,
SampleSize, chan, DataPosInt, {srciter, SrcData.end()});
- else if(vtype == VOICE_IS_CALLBACK)
- {
- /* Not Yet Implemented. */
- }
+ else if((mFlags&VOICE_IS_CALLBACK))
+ srciter = LoadBufferCallback(BufferListItem, NumChannels, SampleSize, chan,
+ mNumCallbackSamples, {srciter, SrcData.end()});
else
srciter = LoadBufferQueue(BufferListItem, BufferLoopItem, NumChannels,
SampleSize, chan, DataPosInt, {srciter, SrcData.end()});
@@ -739,7 +781,8 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
}
/* Update positions */
DataPosFrac += increment*DstBufferSize;
- DataPosInt += DataPosFrac>>FRACTIONBITS;
+ const ALuint SrcSamplesDone{DataPosFrac>>FRACTIONBITS};
+ DataPosInt += SrcSamplesDone;
DataPosFrac &= FRACTIONMASK;
OutPos += DstBufferSize;
@@ -749,7 +792,7 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
{
/* Do nothing extra when there's no buffers. */
}
- else if(vtype == VOICE_IS_STATIC)
+ else if((mFlags&VOICE_IS_STATIC))
{
if(BufferLoopItem)
{
@@ -773,9 +816,22 @@ void ALvoice::mix(const State vstate, ALCcontext *Context, const ALuint SamplesT
}
}
}
- else if(vtype == VOICE_IS_CALLBACK)
+ else if((mFlags&VOICE_IS_CALLBACK))
{
- /* Do nothing extra for callback buffers. */
+ ALbuffer *buffer{BufferListItem->mBuffer};
+ if(SrcSamplesDone < mNumCallbackSamples)
+ {
+ const size_t byteOffset{SrcSamplesDone*FrameSize};
+ const size_t byteEnd{mNumCallbackSamples*FrameSize};
+ std::copy(buffer->mData.data()+byteOffset, buffer->mData.data()+byteEnd,
+ buffer->mData.data());
+ mNumCallbackSamples -= SrcSamplesDone;
+ }
+ else
+ {
+ BufferListItem = nullptr;
+ mNumCallbackSamples = 0;
+ }
}
else
{