aboutsummaryrefslogtreecommitdiffstats
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
parentc8dfd248185359d86410340741122943524ed10b (diff)
Handle running the buffer callback in the voice
-rw-r--r--al/buffer.cpp7
-rw-r--r--al/buffer.h2
-rw-r--r--al/source.cpp4
-rw-r--r--alc/voice.cpp76
-rw-r--r--alc/voice.h19
5 files changed, 83 insertions, 25 deletions
diff --git a/al/buffer.cpp b/al/buffer.cpp
index b2543434..96c6b4fc 100644
--- a/al/buffer.cpp
+++ b/al/buffer.cpp
@@ -594,11 +594,8 @@ void PrepareCallback(ALCcontext *context, ALbuffer *ALBuf, ALsizei freq,
if UNLIKELY(static_cast<long>(SrcType) != static_cast<long>(DstType))
SETERR_RETURN(context, AL_INVALID_ENUM,, "Unsupported callback format");
- if(!ALBuf->mData.empty())
- {
- ALBuf->mData.clear();
- ALBuf->mData.shrink_to_fit();
- }
+ ALBuf->mData = al::vector<al::byte,16>(FrameSizeFromFmt(DstChannels, DstType) *
+ size_t{BUFFERSIZE + (MAX_RESAMPLER_PADDING>>1)});
ALBuf->Callback = callback;
ALBuf->UserData = userptr;
diff --git a/al/buffer.h b/al/buffer.h
index d1c3c747..61ae1863 100644
--- a/al/buffer.h
+++ b/al/buffer.h
@@ -61,6 +61,8 @@ enum FmtChannels : unsigned char {
ALuint BytesFromFmt(FmtType type) noexcept;
ALuint ChannelsFromFmt(FmtChannels chans) noexcept;
+inline ALuint FrameSizeFromFmt(FmtChannels chans, FmtType type) noexcept
+{ return ChannelsFromFmt(chans) * BytesFromFmt(type); }
struct ALbuffer {
diff --git a/al/source.cpp b/al/source.cpp
index bc850a6d..d456401c 100644
--- a/al/source.cpp
+++ b/al/source.cpp
@@ -2764,9 +2764,8 @@ START_API_FUNC
assert(voice != voices_end);
auto vidx = static_cast<ALuint>(std::distance(context->mVoices.data(), voice));
- voice->mPlayState.store(ALvoice::Stopped, std::memory_order_release);
- source->PropsClean.test_and_set(std::memory_order_acquire);
+ source->PropsClean.test_and_set(std::memory_order_acq_rel);
UpdateSourceProps(source, voice, context.get());
/* A source that's not playing or paused has any offset applied when it
@@ -2804,6 +2803,7 @@ START_API_FUNC
voice->mFlags = start_fading ? VOICE_IS_FADING : 0;
if(source->SourceType == AL_STATIC) voice->mFlags |= VOICE_IS_STATIC;
+ voice->mNumCallbackSamples = 0;
/* Don't need to set the VOICE_IS_AMBISONIC flag if the device is not
* higher order than the voice. No HF scaling is necessary to mix it.
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
{
diff --git a/alc/voice.h b/alc/voice.h
index a5b6fac5..73344271 100644
--- a/alc/voice.h
+++ b/alc/voice.h
@@ -180,12 +180,13 @@ struct ALvoiceProps : public ALvoicePropsBase {
DEF_NEWDEL(ALvoiceProps)
};
-#define VOICE_IS_STATIC (1u<<0)
-#define VOICE_IS_CALLBACK (1u<<1)
-#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */
-#define VOICE_IS_FADING (1u<<3) /* Fading sources use gain stepping for smooth transitions. */
-#define VOICE_HAS_HRTF (1u<<4)
-#define VOICE_HAS_NFC (1u<<5)
+#define VOICE_IS_STATIC (1u<<0)
+#define VOICE_IS_CALLBACK (1u<<1)
+#define VOICE_IS_AMBISONIC (1u<<2) /* Voice needs HF scaling for ambisonic upsampling. */
+#define VOICE_CALLBACK_STOPPED (1u<<3)
+#define VOICE_IS_FADING (1u<<4) /* Fading sources use gain stepping for smooth transitions. */
+#define VOICE_HAS_HRTF (1u<<5)
+#define VOICE_HAS_NFC (1u<<6)
#define VOICE_TYPE_MASK (VOICE_IS_STATIC | VOICE_IS_CALLBACK)
@@ -229,13 +230,14 @@ struct ALvoice {
ALuint mAmbiOrder;
/** Current target parameters used for mixing. */
- ALuint mStep;
+ ALuint mStep{0};
ResamplerFunc mResampler;
InterpState mResampleState;
- ALuint mFlags;
+ ALuint mFlags{};
+ ALuint mNumCallbackSamples{0};
struct TargetData {
int FilterType;
@@ -295,6 +297,7 @@ struct ALvoice {
mResampleState = rhs.mResampleState;
mFlags = rhs.mFlags;
+ mNumCallbackSamples = rhs.mNumCallbackSamples;
mDirect = rhs.mDirect;
mSend = rhs.mSend;