diff options
author | Chris Robinson <[email protected]> | 2022-01-01 21:19:53 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2022-01-01 21:19:53 -0800 |
commit | 72c99b52d8b0af0895a549dad752f57b49fceda1 (patch) | |
tree | a8abe14693d69e27f2da7c2374468d1b824feac8 /core/voice.cpp | |
parent | a271484e7c5056a868767a344e63f8f3feb9437e (diff) |
Use an span of pointers instead of arrays for mixing
Diffstat (limited to 'core/voice.cpp')
-rw-r--r-- | core/voice.cpp | 187 |
1 files changed, 94 insertions, 93 deletions
diff --git a/core/voice.cpp b/core/voice.cpp index 424184af..b303793f 100644 --- a/core/voice.cpp +++ b/core/voice.cpp @@ -201,36 +201,39 @@ const float *DoFilters(BiquadFilter &lpfilter, BiquadFilter &hpfilter, float *ds } -void LoadSamples(const al::span<DeviceBase::MixerBufferLine> dstSamples, const size_t dstOffset, - const al::byte *src, const size_t srcOffset, const FmtType srctype, const FmtChannels srcchans, - const size_t srcstep, const size_t samples) noexcept +template<FmtType Type> +inline void LoadSamples(const al::span<float*> dstSamples, const size_t dstOffset, + const al::byte *src, const size_t srcOffset, const FmtChannels srcChans, const size_t srcStep, + const size_t samples) noexcept +{ + constexpr size_t sampleSize{sizeof(typename al::FmtTypeTraits<Type>::Type)}; + auto s = src + srcOffset*srcStep*sampleSize; + if(srcChans == FmtUHJ2 || srcChans == FmtSuperStereo) + { + al::LoadSampleArray<Type>(dstSamples[0]+dstOffset, s, srcStep, samples); + al::LoadSampleArray<Type>(dstSamples[1]+dstOffset, s+sampleSize, srcStep, samples); + std::fill_n(dstSamples[2]+dstOffset, samples, 0.0f); + } + else + { + for(auto *dst : dstSamples) + { + al::LoadSampleArray<Type>(dst+dstOffset, s, srcStep, samples); + s += sampleSize; + } + } +} + +void LoadSamples(const al::span<float*> dstSamples, const size_t dstOffset, const al::byte *src, + const size_t srcOffset, const FmtType srcType, const FmtChannels srcChans, + const size_t srcStep, const size_t samples) noexcept { #define HANDLE_FMT(T) case T: \ - { \ - constexpr size_t sampleSize{sizeof(al::FmtTypeTraits<T>::Type)}; \ - if(srcchans == FmtUHJ2 || srcchans == FmtSuperStereo) \ - { \ - src += srcOffset*2u*sampleSize; \ - al::LoadSampleArray<T>(dstSamples[0].data() + dstOffset, src, \ - 2u, samples); \ - al::LoadSampleArray<T>(dstSamples[1].data() + dstOffset, \ - src + sampleSize, 2u, samples); \ - std::fill_n(dstSamples[2].data() + dstOffset, samples, 0.0f); \ - } \ - else \ - { \ - src += srcOffset*srcstep*sampleSize; \ - for(auto &dst : dstSamples) \ - { \ - al::LoadSampleArray<T>(dst.data() + dstOffset, src, srcstep, \ - samples); \ - src += sampleSize; \ - } \ - } \ - } \ + LoadSamples<T>(dstSamples, dstOffset, src, srcOffset, srcChans, srcStep, \ + samples); \ break - switch(srctype) + switch(srcType) { HANDLE_FMT(FmtUByte); HANDLE_FMT(FmtShort); @@ -244,8 +247,7 @@ void LoadSamples(const al::span<DeviceBase::MixerBufferLine> dstSamples, const s void LoadBufferStatic(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem, const size_t dataPosInt, const FmtType sampleType, const FmtChannels sampleChannels, - const size_t srcStep, const size_t samplesToLoad, - const al::span<DeviceBase::MixerBufferLine> voiceSamples) + const size_t srcStep, const size_t samplesToLoad, const al::span<float*> voiceSamples) { const uint loopStart{buffer->mLoopStart}; const uint loopEnd{buffer->mLoopEnd}; @@ -256,14 +258,14 @@ void LoadBufferStatic(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem, { /* Load what's left to play from the buffer */ const size_t remaining{minz(samplesToLoad, buffer->mSampleLen-dataPosInt)}; - LoadSamples(voiceSamples, MaxResamplerEdge, buffer->mSamples, dataPosInt, sampleType, - sampleChannels, srcStep, remaining); + LoadSamples(voiceSamples, 0, buffer->mSamples, dataPosInt, sampleType, sampleChannels, + srcStep, remaining); if(const size_t toFill{samplesToLoad - remaining}) { - for(auto &chanbuffer : voiceSamples) + for(auto *chanbuffer : voiceSamples) { - auto srcsamples = chanbuffer.data() + MaxResamplerEdge - 1 + remaining; + auto srcsamples = chanbuffer + remaining - 1; std::fill_n(srcsamples + 1, toFill, *srcsamples); } } @@ -272,16 +274,16 @@ void LoadBufferStatic(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem, { /* Load what's left of this loop iteration */ const size_t remaining{minz(samplesToLoad, loopEnd-dataPosInt)}; - LoadSamples(voiceSamples, MaxResamplerEdge, buffer->mSamples, dataPosInt, sampleType, - sampleChannels, srcStep, remaining); + LoadSamples(voiceSamples, 0, buffer->mSamples, dataPosInt, sampleType, sampleChannels, + srcStep, remaining); /* Load repeats of the loop to fill the buffer. */ const auto loopSize = static_cast<size_t>(loopEnd - loopStart); size_t samplesLoaded{remaining}; while(const size_t toFill{minz(samplesToLoad - samplesLoaded, loopSize)}) { - LoadSamples(voiceSamples, MaxResamplerEdge + samplesLoaded, buffer->mSamples, - loopStart, sampleType, sampleChannels, srcStep, toFill); + LoadSamples(voiceSamples, samplesLoaded, buffer->mSamples, loopStart, sampleType, + sampleChannels, srcStep, toFill); samplesLoaded += toFill; } } @@ -289,18 +291,18 @@ void LoadBufferStatic(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem, void LoadBufferCallback(VoiceBufferItem *buffer, const size_t numCallbackSamples, const FmtType sampleType, const FmtChannels sampleChannels, const size_t srcStep, - const size_t samplesToLoad, const al::span<DeviceBase::MixerBufferLine> voiceSamples) + const size_t samplesToLoad, const al::span<float*> voiceSamples) { /* Load what's left to play from the buffer */ const size_t remaining{minz(samplesToLoad, numCallbackSamples)}; - LoadSamples(voiceSamples, MaxResamplerEdge, buffer->mSamples, 0, sampleType, sampleChannels, - srcStep, remaining); + LoadSamples(voiceSamples, 0, buffer->mSamples, 0, sampleType, sampleChannels, srcStep, + remaining); if(const size_t toFill{samplesToLoad - remaining}) { - for(auto &chanbuffer : voiceSamples) + for(auto *chanbuffer : voiceSamples) { - auto srcsamples = chanbuffer.data() + MaxResamplerEdge - 1 + remaining; + auto srcsamples = chanbuffer + remaining - 1; std::fill_n(srcsamples + 1, toFill, *srcsamples); } } @@ -308,8 +310,7 @@ void LoadBufferCallback(VoiceBufferItem *buffer, const size_t numCallbackSamples void LoadBufferQueue(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem, size_t dataPosInt, const FmtType sampleType, const FmtChannels sampleChannels, - const size_t srcStep, const size_t samplesToLoad, - const al::span<DeviceBase::MixerBufferLine> voiceSamples) + const size_t srcStep, const size_t samplesToLoad, const al::span<float*> voiceSamples) { /* Crawl the buffer queue to fill in the temp buffer */ size_t samplesLoaded{0}; @@ -324,8 +325,8 @@ void LoadBufferQueue(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem, } const size_t remaining{minz(samplesToLoad-samplesLoaded, buffer->mSampleLen-dataPosInt)}; - LoadSamples(voiceSamples, MaxResamplerEdge+samplesLoaded, buffer->mSamples, dataPosInt, - sampleType, sampleChannels, srcStep, remaining); + LoadSamples(voiceSamples, samplesLoaded, buffer->mSamples, dataPosInt, sampleType, + sampleChannels, srcStep, remaining); samplesLoaded += remaining; if(samplesLoaded == samplesToLoad) @@ -338,9 +339,9 @@ void LoadBufferQueue(VoiceBufferItem *buffer, VoiceBufferItem *bufferLoopItem, if(const size_t toFill{samplesToLoad - samplesLoaded}) { size_t chanidx{0}; - for(auto &chanbuffer : voiceSamples) + for(auto *chanbuffer : voiceSamples) { - auto srcsamples = chanbuffer.data() + MaxResamplerEdge - 1 + samplesLoaded; + auto srcsamples = chanbuffer + samplesLoaded - 1; std::fill_n(srcsamples + 1, toFill, *srcsamples); ++chanidx; } @@ -509,9 +510,13 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo else if UNLIKELY(!BufferListItem) Counter = std::min(Counter, 64u); - al::span<DeviceBase::MixerBufferLine> MixingSamples{ - Device->mSampleData.data() + Device->mSampleData.size() - mChans.size(), - mChans.size()}; + std::array<float*,DeviceBase::MixerChannelsMax> SamplePointers; + const al::span<float*> MixingSamples{SamplePointers.data(), mChans.size()}; + auto offset_bufferline = [](DeviceBase::MixerBufferLine &bufline) noexcept -> float* + { return bufline.data() + MaxResamplerEdge; }; + std::transform(Device->mSampleData.end() - mChans.size(), Device->mSampleData.end(), + MixingSamples.begin(), offset_bufferline); + const uint PostPadding{MaxResamplerEdge + (mDecoder ? uint{UhjDecoder::sFilterDelay} : 0u)}; uint buffers_done{0u}; @@ -530,8 +535,8 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo /* +1 to get the src sample count, include padding. */ DataSize64 += 1 + PostPadding; - /* Result is guaranteed to be <= BufferLineSize+ResamplerPrePadding - * since we won't use more src samples than dst samples+padding. + /* Result is guaranteed to be <= BufferLineSize+PostPadding since + * we won't use more src samples than dst samples+padding. */ SrcBufferSize = static_cast<uint>(DataSize64); } @@ -564,14 +569,14 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo } } - if UNLIKELY(!BufferListItem) + if(unlikely(!BufferListItem)) { auto prevSamples = mPrevSamples.data(); - SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerPadding; - for(auto &chanbuffer : MixingSamples) + SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerEdge; + for(auto *chanbuffer : MixingSamples) { auto srcend = std::copy_n(prevSamples->data(), MaxResamplerPadding, - chanbuffer.data()); + chanbuffer-MaxResamplerEdge); ++prevSamples; /* When loading from a voice that ended prematurely, only take @@ -580,17 +585,17 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo */ auto abs_lt = [](const float lhs, const float rhs) noexcept -> bool { return std::abs(lhs) < std::abs(rhs); }; - auto srciter = std::min_element(srcend - MaxResamplerEdge, srcend, abs_lt); + auto srciter = std::min_element(chanbuffer, srcend, abs_lt); - std::fill(srciter+1, chanbuffer.data() + SrcBufferSize, *srciter); + std::fill(srciter+1, chanbuffer + SrcBufferSize, *srciter); } } else { auto prevSamples = mPrevSamples.data(); - for(auto &chanbuffer : MixingSamples) + for(auto *chanbuffer : MixingSamples) { - std::copy_n(prevSamples->data(), MaxResamplerEdge, chanbuffer.data()); + std::copy_n(prevSamples->data(), MaxResamplerEdge, chanbuffer-MaxResamplerEdge); ++prevSamples; } if(mFlags.test(VoiceIsStatic)) @@ -598,26 +603,22 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo mFmtChannels, mFrameStep, SrcBufferSize, MixingSamples); else if(mFlags.test(VoiceIsCallback)) { - if(!mFlags.test(VoiceCallbackStopped)) + if(!mFlags.test(VoiceCallbackStopped) && SrcBufferSize > mNumCallbackSamples) { - if(SrcBufferSize > mNumCallbackSamples) + const size_t byteOffset{mNumCallbackSamples*mFrameSize}; + const size_t needBytes{SrcBufferSize*mFrameSize - byteOffset}; + + const int gotBytes{BufferListItem->mCallback(BufferListItem->mUserData, + &BufferListItem->mSamples[byteOffset], static_cast<int>(needBytes))}; + if(gotBytes < 0) + mFlags.set(VoiceCallbackStopped); + else if(static_cast<uint>(gotBytes) < needBytes) { - const size_t byteOffset{mNumCallbackSamples*mFrameSize}; - const size_t needBytes{SrcBufferSize*mFrameSize - byteOffset}; - - const int gotBytes{BufferListItem->mCallback(BufferListItem->mUserData, - &BufferListItem->mSamples[byteOffset], static_cast<int>(needBytes))}; - if(gotBytes < 0) - mFlags.set(VoiceCallbackStopped); - else if(static_cast<uint>(gotBytes) < needBytes) - { - mFlags.set(VoiceCallbackStopped); - mNumCallbackSamples += static_cast<uint>(static_cast<uint>(gotBytes) / - mFrameSize); - } - else - mNumCallbackSamples = SrcBufferSize; + mFlags.set(VoiceCallbackStopped); + mNumCallbackSamples += static_cast<uint>(gotBytes) / mFrameSize; } + else + mNumCallbackSamples = SrcBufferSize; } LoadBufferCallback(BufferListItem, mNumCallbackSamples, mFmtType, mFmtChannels, mFrameStep, SrcBufferSize, MixingSamples); @@ -626,35 +627,35 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo LoadBufferQueue(BufferListItem, BufferLoopItem, DataPosInt, mFmtType, mFmtChannels, mFrameStep, SrcBufferSize, MixingSamples); + const size_t srcOffset{(increment*DstBufferSize + DataPosFrac)>>MixerFracBits}; if(mDecoder) { - std::array<float*,DeviceBase::MixerChannelsMax> chanptrs; - std::transform(MixingSamples.begin(), MixingSamples.end(), chanptrs.begin(), - [](DeviceBase::MixerBufferLine &bufline) noexcept -> float* - { return bufline.data() + MaxResamplerEdge; }); - const size_t srcOffset{(increment*DstBufferSize + DataPosFrac)>>MixerFracBits}; SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerEdge; - ((*mDecoder).*mDecoderFunc)({chanptrs.data(), MixingSamples.size()}, SrcBufferSize, + ((*mDecoder).*mDecoderFunc)(MixingSamples, SrcBufferSize, srcOffset * likely(vstate == Playing)); } + /* Store the last source samples used for next time. */ + if(likely(vstate == Playing)) + { + prevSamples = mPrevSamples.data(); + for(auto *chanbuffer : MixingSamples) + { + /* Store the last source samples used for next time. */ + std::copy_n(chanbuffer-MaxResamplerEdge+srcOffset, prevSamples->size(), + prevSamples->data()); + ++prevSamples; + } + } } - auto prevSamples = mPrevSamples.data(); auto voiceSamples = MixingSamples.begin(); - const size_t srcOffset{(increment*DstBufferSize + DataPosFrac)>>MixerFracBits}; for(auto &chandata : mChans) { - /* Store the last source samples used for next time. */ - if(likely(vstate == Playing)) - std::copy_n(voiceSamples->data()+srcOffset, MaxResamplerPadding, - prevSamples->data()); - ++prevSamples; - /* Resample, then apply ambisonic upsampling as needed. */ - float *ResampledData{Resample(&mResampleState, - voiceSamples->data() + MaxResamplerEdge, DataPosFrac, increment, + float *ResampledData{Resample(&mResampleState, *voiceSamples, DataPosFrac, increment, {Device->ResampledData, DstBufferSize})}; ++voiceSamples; + if(mFlags.test(VoiceIsAmbisonic)) chandata.mAmbiSplitter.processScale({ResampledData, DstBufferSize}, chandata.mAmbiHFScale, chandata.mAmbiLFScale); |