diff options
author | Chris Robinson <[email protected]> | 2020-02-17 17:13:00 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2020-02-17 17:13:25 -0800 |
commit | 3122c3b4a109b7d6e288bdde055fc4bbae5517bc (patch) | |
tree | b2eb3a251a243d3a5f9a7566c343bc614c9ff8cc | |
parent | c8dfd248185359d86410340741122943524ed10b (diff) |
Handle running the buffer callback in the voice
-rw-r--r-- | al/buffer.cpp | 7 | ||||
-rw-r--r-- | al/buffer.h | 2 | ||||
-rw-r--r-- | al/source.cpp | 4 | ||||
-rw-r--r-- | alc/voice.cpp | 76 | ||||
-rw-r--r-- | alc/voice.h | 19 |
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; |