aboutsummaryrefslogtreecommitdiffstats
path: root/core/voice.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2022-01-01 21:19:53 -0800
committerChris Robinson <[email protected]>2022-01-01 21:19:53 -0800
commit72c99b52d8b0af0895a549dad752f57b49fceda1 (patch)
treea8abe14693d69e27f2da7c2374468d1b824feac8 /core/voice.cpp
parenta271484e7c5056a868767a344e63f8f3feb9437e (diff)
Use an span of pointers instead of arrays for mixing
Diffstat (limited to 'core/voice.cpp')
-rw-r--r--core/voice.cpp187
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);