17#include "LanczosResampler.h"
43template<
typename T =
double,
int NCHANS=2,
size_t A=12>
46 static_assert(std::is_same<T, float>::value || std::is_same<T, double>::value,
"T must be float or double");
51 kLinearInterpolation = 0,
56 using BlockProcessFunc = std::function<void(T**, T**,
int,
int)>;
57 using LanczosResampler = LanczosResampler<T, NCHANS, A>;
64 : mResamplingMode(mode)
65 , mInnerSampleRate(innerSampleRate)
76 void Reset(
double inputSampleRate,
int maxBlockSize = DEFAULT_BLOCK_SIZE)
78 mOuterSampleRate = inputSampleRate;
79 mInRatio = mOuterSampleRate / mInnerSampleRate;
80 mOutRatio = mInnerSampleRate / mOuterSampleRate;
81 mMaxOuterLength = maxBlockSize;
82 mMaxInnerLength = CalculateMaxInnerLength(mMaxOuterLength);
84 mInputData.Resize(mMaxInnerLength * NCHANS);
85 mOutputData.Resize(mMaxInnerLength * NCHANS);
89 for (
auto chan=0; chan<NCHANS; chan++)
91 mInputPtrs.Add(mInputData.Get() + (chan * mMaxInnerLength));
92 mOutputPtrs.Add(mOutputData.Get() + (chan * mMaxInnerLength));
97 if (mResamplingMode == ESRCMode::kLancsoz)
99 const T outerRate =
static_cast<T
>(mOuterSampleRate);
100 const T innerRate =
static_cast<T
>(mInnerSampleRate);
101 mInResampler = std::make_unique<LanczosResampler>(outerRate, innerRate);
102 mOutResampler = std::make_unique<LanczosResampler>(innerRate, outerRate);
105 const auto outSamplesRequired = mOutResampler->GetNumSamplesRequiredFor(1);
106 const auto inSamplesRequired = mInResampler->GetNumSamplesRequiredFor(outSamplesRequired);
107 mInResampler->PushBlock(mInputPtrs.GetList(), inSamplesRequired, NCHANS);
108 const auto populated = mInResampler->PopBlock(mInputPtrs.GetList(), outSamplesRequired, NCHANS);
109 assert(populated >= outSamplesRequired &&
"Didn't get enough samples required for warm up!");
110 mOutResampler->PushBlock(mOutputPtrs.GetList(), populated, NCHANS);
113 constexpr auto addedLatency = 2;
114 mLatency =
static_cast<int>(inSamplesRequired + addedLatency);
128 void ProcessBlock(T** inputs, T** outputs,
int nFrames,
int nChans, BlockProcessFunc func)
130 if (mInnerSampleRate == mOuterSampleRate)
132 func(inputs, outputs, nFrames, nChans);
136 switch (mResamplingMode)
138 case ESRCMode::kLinearInterpolation:
140 const auto nNewFrames = LinearInterpolate(inputs, mInputPtrs.GetList(), nFrames, nChans, mInRatio, mMaxInnerLength);
141 func(mInputPtrs.GetList(), mOutputPtrs.GetList(), nNewFrames, nChans);
142 LinearInterpolate(mOutputPtrs.GetList(), outputs, nNewFrames, nChans, mOutRatio, nFrames);
145 case ESRCMode::kLancsoz:
147 mInResampler->PushBlock(inputs, nFrames, nChans);
148 const auto maxInnerLength = CalculateMaxInnerLength(nFrames);
150 while (mInResampler->GetNumSamplesRequiredFor(1) == 0)
152 const auto populated = mInResampler->PopBlock(mInputPtrs.GetList(), maxInnerLength, nChans);
153 assert(populated <= maxInnerLength &&
"Received more samples than the encapsulated DSP is able to handle!");
154 func(mInputPtrs.GetList(), mOutputPtrs.GetList(),
static_cast<int>(populated), nChans);
155 mOutResampler->PushBlock(mOutputPtrs.GetList(), populated, nChans);
159 const auto populated =
161 mOutResampler->PopBlock(outputs, nFrames, nChans);
162 assert(populated >= nFrames &&
"Did not yield enough samples to provide the required output buffer!");
164 mInResampler->RenormalizePhases();
165 mOutResampler->RenormalizePhases();
178 static inline int LinearInterpolate(T** inputs, T** outputs,
int inputLength,
int nChans,
double ratio,
int maxOutputLength)
180 const auto outputLength =
181 std::min(
static_cast<int>(std::ceil(
static_cast<double>(inputLength) / ratio)), maxOutputLength);
183 for (
auto writePos=0; writePos<outputLength; writePos++)
185 const auto readPos = ratio *
static_cast<double>(writePos);
186 const auto readPostionTrunc = std::floor(readPos);
187 const auto readPosInt =
static_cast<int>(readPostionTrunc);
189 if (readPosInt < inputLength)
191 const T y =
static_cast<T
>(readPos - readPostionTrunc);
193 for (
auto chan=0; chan<nChans; chan++)
195 const T x0 = inputs[chan][readPosInt];
196 const T x1 = ((readPosInt + 1) < inputLength) ? inputs[chan][readPosInt + 1]
197 : inputs[chan][readPosInt - 1];
198 outputs[chan][writePos] = (T(1) - y) * x0 + y * x1;
209 const auto nBytes = mMaxInnerLength * NCHANS *
sizeof(T);
210 memset(mInputData.Get(), 0, nBytes);
211 memset(mOutputData.Get(), 0, nBytes);
215 int CalculateMaxInnerLength(
const int outerLength)
const
217 return static_cast<int>(std::ceil(
double(outerLength) / mInRatio));
220 WDL_TypedBuf<T> mInputData, mOutputData;
221 WDL_PtrList<T> mInputPtrs, mOutputPtrs;
222 double mInRatio = 0.0, mOutRatio = 0.0;
223 double mOuterSampleRate = DEFAULT_SAMPLE_RATE;
224 const double mInnerSampleRate;
225 int mMaxOuterLength = 0;
226 int mMaxInnerLength = 0;
228 const ESRCMode mResamplingMode;
229 std::unique_ptr<LanczosResampler> mInResampler, mOutResampler;
A multi-channel real-time resampling container that can be used to resample audio processing to a spe...
int GetLatency() const
Get the latency of the resampling, not including any latency of the encapsulated DSP.
void ProcessBlock(T **inputs, T **outputs, int nFrames, int nChans, BlockProcessFunc func)
Resample an input block with a per-block function (resample input -> process with function -> resampl...
RealtimeResampler(double innerSampleRate, ESRCMode mode=ESRCMode::kLancsoz)
Constructor.
void Reset(double inputSampleRate, int maxBlockSize=DEFAULT_BLOCK_SIZE)
Reset the underlying DSP (when the samplerate or max expected block size changes)