aboutsummaryrefslogtreecommitdiffstats
path: root/core/voice.cpp
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2021-06-21 09:04:33 -0700
committerChris Robinson <[email protected]>2021-06-21 09:04:33 -0700
commit8f3148ba53c5bbccf24667b2459787ce314f3efe (patch)
treed69781838fc7d196aa9711ee6de762c8cdbf8cae /core/voice.cpp
parent7584458ecdea684c309007412a547777349b9f6c (diff)
Don't allocate full buffer lines in each voice
There's now effectively a 16-channel limit for buffers (as determined by the number of elements in DeviceBase::mSampleData). Any more than that are ignored when mixing.
Diffstat (limited to 'core/voice.cpp')
-rw-r--r--core/voice.cpp58
1 files changed, 36 insertions, 22 deletions
diff --git a/core/voice.cpp b/core/voice.cpp
index 4aadf9fa..261e9a79 100644
--- a/core/voice.cpp
+++ b/core/voice.cpp
@@ -51,7 +51,8 @@ struct NEONTag;
struct CopyTag;
-static_assert(!(sizeof(Voice::BufferLine)&15), "Voice::BufferLine must be a multiple of 16 bytes");
+static_assert(!(sizeof(DeviceBase::MixerBufferLine)&15),
+ "DeviceBase::MixerBufferLine must be a multiple of 16 bytes");
Resampler ResamplerDefault{Resampler::Linear};
@@ -198,7 +199,7 @@ const float *DoFilters(BiquadFilter &lpfilter, BiquadFilter &hpfilter, float *ds
}
-void LoadSamples(const al::span<Voice::BufferLine> dstSamples, const size_t dstOffset,
+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
{
@@ -242,7 +243,7 @@ void LoadSamples(const al::span<Voice::BufferLine> dstSamples, const size_t dstO
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<Voice::BufferLine> voiceSamples)
+ const al::span<DeviceBase::MixerBufferLine> voiceSamples)
{
const uint loopStart{buffer->mLoopStart};
const uint loopEnd{buffer->mLoopEnd};
@@ -286,7 +287,7 @@ 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<Voice::BufferLine> voiceSamples)
+ const size_t samplesToLoad, const al::span<DeviceBase::MixerBufferLine> voiceSamples)
{
/* Load what's left to play from the buffer */
const size_t remaining{minz(samplesToLoad, numCallbackSamples)};
@@ -306,7 +307,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<Voice::BufferLine> voiceSamples)
+ const al::span<DeviceBase::MixerBufferLine> voiceSamples)
{
/* Crawl the buffer queue to fill in the temp buffer */
size_t samplesLoaded{0};
@@ -504,6 +505,9 @@ 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()};
const uint PostPadding{MaxResamplerEdge +
((mFmtChannels==FmtUHJ2 || mFmtChannels==FmtUHJ3 || mFmtChannels==FmtUHJ4)
? uint{UhjDecoder::sFilterDelay} : 0u)};
@@ -535,14 +539,14 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo
DataSize64 = (DataSize64*increment + DataPosFrac) >> MixerFracBits;
DataSize64 += PostPadding;
- if(DataSize64 <= LineSize - MaxResamplerEdge)
+ if(DataSize64 <= DeviceBase::MixerLineSize - MaxResamplerEdge)
SrcBufferSize = static_cast<uint>(DataSize64);
else
{
/* If the source size got saturated, we can't fill the desired
* dst size. Figure out how many samples we can actually mix.
*/
- SrcBufferSize = LineSize - MaxResamplerEdge;
+ SrcBufferSize = DeviceBase::MixerLineSize - MaxResamplerEdge;
DataSize64 = SrcBufferSize - PostPadding;
DataSize64 = ((DataSize64<<MixerFracBits) - DataPosFrac) / increment;
@@ -559,11 +563,13 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo
if UNLIKELY(!BufferListItem)
{
+ auto prevSamples = mPrevSamples.data();
SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerPadding;
- for(auto &chanbuffer : mVoiceSamples)
+ for(auto &chanbuffer : MixingSamples)
{
- auto srciter = chanbuffer.data() + MaxResamplerEdge;
- auto srcend = chanbuffer.data() + MaxResamplerPadding;
+ auto srcend = std::copy_n(prevSamples->data(), MaxResamplerPadding,
+ chanbuffer.data());
+ ++prevSamples;
/* When loading from a voice that ended prematurely, only take
* the samples that get closest to 0 amplitude. This helps
@@ -571,16 +577,22 @@ 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); };
- srciter = std::min_element(srciter, srcend, abs_lt);
+ auto srciter = std::min_element(srcend - MaxResamplerEdge, srcend, abs_lt);
std::fill(srciter+1, chanbuffer.data() + SrcBufferSize, *srciter);
}
}
else
{
+ auto prevSamples = mPrevSamples.data();
+ for(auto &chanbuffer : MixingSamples)
+ {
+ std::copy_n(prevSamples->data(), MaxResamplerEdge, chanbuffer.data());
+ ++prevSamples;
+ }
if((mFlags&VoiceIsStatic))
LoadBufferStatic(BufferListItem, BufferLoopItem, DataPosInt, mFmtType, mFmtChannels,
- mNumChannels, SrcBufferSize, mVoiceSamples);
+ mNumChannels, SrcBufferSize, MixingSamples);
else if((mFlags&VoiceIsCallback))
{
if(!(mFlags&VoiceCallbackStopped))
@@ -605,27 +617,34 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo
}
}
LoadBufferCallback(BufferListItem, mNumCallbackSamples, mFmtType, mFmtChannels,
- mNumChannels, SrcBufferSize, mVoiceSamples);
+ mNumChannels, SrcBufferSize, MixingSamples);
}
else
LoadBufferQueue(BufferListItem, BufferLoopItem, DataPosInt, mFmtType, mFmtChannels,
- mNumChannels, SrcBufferSize, mVoiceSamples);
+ mNumChannels, SrcBufferSize, MixingSamples);
if(mDecoder)
{
const size_t srcOffset{(increment*DstBufferSize + DataPosFrac)>>MixerFracBits};
SrcBufferSize = SrcBufferSize - PostPadding + MaxResamplerEdge;
- mDecoder->decode(mVoiceSamples, MaxResamplerEdge, SrcBufferSize, srcOffset);
+ mDecoder->decode(MixingSamples, MaxResamplerEdge, SrcBufferSize, srcOffset);
}
}
- auto voiceSamples = mVoiceSamples.begin();
+ 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. */
+ 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,
{Device->ResampledData, DstBufferSize})};
+ ++voiceSamples;
if((mFlags&VoiceIsAmbisonic))
chandata.mAmbiSplitter.processHfScale({ResampledData, DstBufferSize},
chandata.mAmbiScale);
@@ -673,11 +692,6 @@ void Voice::mix(const State vstate, ContextBase *Context, const uint SamplesToDo
MixSamples({samples, DstBufferSize}, mSend[send].Buffer,
parms.Gains.Current.data(), TargetGains, Counter, OutPos);
}
-
- /* Store the last source samples used for next time. */
- const size_t srcOffset{(increment*DstBufferSize + DataPosFrac)>>MixerFracBits};
- std::copy_n(voiceSamples->data()+srcOffset, MaxResamplerPadding, voiceSamples->data());
- ++voiceSamples;
}
/* Update positions */
DataPosFrac += increment*DstBufferSize;
@@ -809,7 +823,7 @@ void Voice::prepare(DeviceBase *device)
mStep = 0;
/* Make sure the sample history is cleared. */
- std::fill(mVoiceSamples.begin(), mVoiceSamples.end(), BufferLine{});
+ std::fill(mPrevSamples.begin(), mPrevSamples.end(), HistoryLine{});
/* Don't need to set the VoiceIsAmbisonic flag if the device is not higher
* order than the voice. No HF scaling is necessary to mix it.