aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/converter.cpp92
-rw-r--r--core/converter.h1
2 files changed, 93 insertions, 0 deletions
diff --git a/core/converter.cpp b/core/converter.cpp
index b3994d3f..dea31bd5 100644
--- a/core/converter.cpp
+++ b/core/converter.cpp
@@ -309,6 +309,98 @@ uint SampleConverter::convert(const void **src, uint *srcframes, void *dst, uint
return pos;
}
+uint SampleConverter::convertPlanar(const void **src, uint *srcframes, void **dst, uint dstframes)
+{
+ const uint increment{mIncrement};
+ uint NumSrcSamples{*srcframes};
+
+ FPUCtl mixer_mode{};
+ uint pos{0};
+ while(pos < dstframes && NumSrcSamples > 0)
+ {
+ const uint prepcount{mSrcPrepCount};
+ const uint readable{minu(NumSrcSamples, BufferLineSize - prepcount)};
+
+ if(prepcount < MaxResamplerPadding && MaxResamplerPadding-prepcount >= readable)
+ {
+ /* Not enough input samples to generate an output sample. Store
+ * what we're given for later.
+ */
+ for(size_t chan{0u};chan < mChan.size();chan++)
+ {
+ LoadSamples(&mChan[chan].PrevSamples[prepcount],
+ static_cast<const std::byte*>(src[chan]), 1, mSrcType, readable);
+ src[chan] = static_cast<const std::byte*>(src[chan]) + mSrcTypeSize*readable;
+ }
+
+ mSrcPrepCount = prepcount + readable;
+ NumSrcSamples = 0;
+ break;
+ }
+
+ float *RESTRICT SrcData{mSrcSamples};
+ float *RESTRICT DstData{mDstSamples};
+ uint DataPosFrac{mFracOffset};
+ uint64_t DataSize64{prepcount};
+ DataSize64 += readable;
+ DataSize64 -= MaxResamplerPadding;
+ DataSize64 <<= MixerFracBits;
+ DataSize64 -= DataPosFrac;
+
+ /* If we have a full prep, we can generate at least one sample. */
+ auto DstSize = static_cast<uint>(
+ clampu64((DataSize64 + increment-1)/increment, 1, BufferLineSize));
+ DstSize = minu(DstSize, dstframes-pos);
+
+ const uint DataPosEnd{DstSize*increment + DataPosFrac};
+ const uint SrcDataEnd{DataPosEnd>>MixerFracBits};
+
+ assert(prepcount+readable >= SrcDataEnd);
+ const uint nextprep{minu(prepcount + readable - SrcDataEnd, MaxResamplerPadding)};
+
+ for(size_t chan{0u};chan < mChan.size();chan++)
+ {
+ /* Load the previous samples into the source data first, then the
+ * new samples from the input buffer.
+ */
+ std::copy_n(mChan[chan].PrevSamples, prepcount, SrcData);
+ LoadSamples(SrcData + prepcount, src[chan], 1, mSrcType, readable);
+
+ /* Store as many prep samples for next time as possible, given the
+ * number of output samples being generated.
+ */
+ std::copy_n(SrcData+SrcDataEnd, nextprep, mChan[chan].PrevSamples);
+ std::fill(std::begin(mChan[chan].PrevSamples)+nextprep,
+ std::end(mChan[chan].PrevSamples), 0.0f);
+
+ /* Now resample, and store the result in the output buffer. */
+ mResample(&mState, SrcData+MaxResamplerEdge, DataPosFrac, increment,
+ {DstData, DstSize});
+
+ std::byte *DstSamples = static_cast<std::byte*>(dst[chan]) + pos*mDstTypeSize;
+ StoreSamples(DstSamples, DstData, 1, mDstType, DstSize);
+ }
+
+ /* Update the number of prep samples still available, as well as the
+ * fractional offset.
+ */
+ mSrcPrepCount = nextprep;
+ mFracOffset = DataPosEnd & MixerFracMask;
+
+ /* Update the src and dst pointers in case there's still more to do. */
+ const uint srcread{minu(NumSrcSamples, SrcDataEnd + mSrcPrepCount - prepcount)};
+ for(size_t chan{0u};chan < mChan.size();chan++)
+ src[chan] = static_cast<const std::byte*>(src[chan]) + mSrcTypeSize*srcread;
+ NumSrcSamples -= srcread;
+
+ pos += DstSize;
+ }
+
+ *srcframes = NumSrcSamples;
+
+ return pos;
+}
+
void ChannelConverter::convert(const void *src, float *dst, uint frames) const
{
diff --git a/core/converter.h b/core/converter.h
index 01becea2..d811b46b 100644
--- a/core/converter.h
+++ b/core/converter.h
@@ -36,6 +36,7 @@ struct SampleConverter {
SampleConverter(size_t numchans) : mChan{numchans} { }
uint convert(const void **src, uint *srcframes, void *dst, uint dstframes);
+ uint convertPlanar(const void **src, uint *srcframes, void **dst, uint dstframes);
uint availableOut(uint srcframes) const;
using SampleOffset = std::chrono::duration<int64_t, std::ratio<1,MixerFracOne>>;