13#define OVERSAMPLING_FACTORS_VA_LIST "None", "2x", "4x", "8x", "16x"
18#include "HIIR/FPUUpsampler2x.h"
19#include "HIIR/FPUDownsampler2x.h"
40template<
typename T =
double>
44 using BlockProcessFunc = std::function<void(T**, T**,
int)>;
46 OverSampler(EFactor factor = kNone,
bool blockProcessing =
true,
int nInChannels = 1,
int nOutChannels = 1)
47 : mBlockProcessing(blockProcessing)
48 , mNInChannels(nInChannels)
49 , mNOutChannels(nOutChannels)
52 static constexpr double coeffs2x[12] = { 0.036681502163648017, 0.13654762463195794, 0.27463175937945444, 0.42313861743656711, 0.56109869787919531, 0.67754004997416184, 0.76974183386322703, 0.83988962484963892, 0.89226081800387902, 0.9315419599631839, 0.96209454837808417, 0.98781637073289585 };
53 static constexpr double coeffs4x[4] = {0.041893991997656171, 0.16890348243995201, 0.39056077292116603, 0.74389574826847926 };
54 static constexpr double coeffs8x[3] = {0.055748680811302048, 0.24305119574153072, 0.64669913119268196 };
55 static constexpr double coeffs16x[2] = {0.10717745346023573, 0.53091435354504557 };
57 for (
auto c = 0; c < mNInChannels; c++)
59 mUpsampler2x.Add(
new Upsampler2xFPU<12, T>());
60 mUpsampler4x.Add(
new Upsampler2xFPU<4, T>());
61 mUpsampler8x.Add(
new Upsampler2xFPU<3, T>());
62 mUpsampler16x.Add(
new Upsampler2xFPU<2, T>());
64 mUpsampler2x.Get(c)->set_coefs(coeffs2x);
65 mUpsampler4x.Get(c)->set_coefs(coeffs4x);
66 mUpsampler8x.Get(c)->set_coefs(coeffs8x);
67 mUpsampler16x.Get(c)->set_coefs(coeffs16x);
70 mNextInputPtrs.Add(mUp2x.Get());
73 for (
auto c = 0; c < mNOutChannels; c++)
75 mDownsampler2x.Add(
new Downsampler2xFPU<12, T>());
76 mDownsampler4x.Add(
new Downsampler2xFPU<4, T>());
77 mDownsampler8x.Add(
new Downsampler2xFPU<3, T>());
78 mDownsampler16x.Add(
new Downsampler2xFPU<2, T>());
80 mDownsampler2x.Get(c)->set_coefs(coeffs2x);
81 mDownsampler4x.Get(c)->set_coefs(coeffs4x);
82 mDownsampler8x.Get(c)->set_coefs(coeffs8x);
83 mDownsampler16x.Get(c)->set_coefs(coeffs16x);
86 mNextOutputPtrs.Add(mDown2x.Get());
89 SetOverSampling(factor);
96 mUpsampler2x.Empty(
true);
97 mDownsampler2x.Empty(
true);
98 mUpsampler4x.Empty(
true);
99 mDownsampler4x.Empty(
true);
100 mUpsampler8x.Empty(
true);
101 mDownsampler8x.Empty(
true);
102 mUpsampler16x.Empty(
true);
103 mDownsampler16x.Empty(
true);
109 void Reset(
int blockSize = DEFAULT_BLOCK_SIZE)
111 int numBufSamples = 1;
113 if (mBlockProcessing)
114 numBufSamples = blockSize;
121 numBufSamples *= mNInChannels;
123 mUp2x.Resize(2 * numBufSamples);
124 mUp4x.Resize(4 * numBufSamples);
125 mUp8x.Resize(8 * numBufSamples);
126 mUp16x.Resize(16 * numBufSamples);
128 mDown2x.Resize(2 * numBufSamples);
129 mDown4x.Resize(4 * numBufSamples);
130 mDown8x.Resize(8 * numBufSamples);
131 mDown16x.Resize(16 * numBufSamples);
133 mUp16BufferPtrs.Empty();
134 mUp8BufferPtrs.Empty();
135 mUp4BufferPtrs.Empty();
136 mUp2BufferPtrs.Empty();
138 mDown16BufferPtrs.Empty();
139 mDown8BufferPtrs.Empty();
140 mDown4BufferPtrs.Empty();
141 mDown2BufferPtrs.Empty();
143 for (
auto c = 0; c < mNInChannels; c++)
145 mUpsampler2x.Get(c)->clear_buffers();
146 mUpsampler4x.Get(c)->clear_buffers();
147 mUpsampler8x.Get(c)->clear_buffers();
148 mUpsampler16x.Get(c)->clear_buffers();
150 mUp2BufferPtrs.Add(mUp2x.Get() + c * 2 * blockSize);
151 mUp4BufferPtrs.Add(mUp4x.Get() + (c * 4 * blockSize));
152 mUp8BufferPtrs.Add(mUp8x.Get() + (c * 8 * blockSize));
153 mUp16BufferPtrs.Add(mUp16x.Get() + (c * 16 * blockSize));
156 for (
auto c = 0; c < mNOutChannels; c++)
158 mDownsampler2x.Get(c)->clear_buffers();
159 mDownsampler4x.Get(c)->clear_buffers();
160 mDownsampler8x.Get(c)->clear_buffers();
161 mDownsampler16x.Get(c)->clear_buffers();
163 mDown2BufferPtrs.Add(mDown2x.Get() + c * 2 * blockSize);
164 mDown4BufferPtrs.Add(mDown4x.Get() + (c * 4 * blockSize));
165 mDown8BufferPtrs.Add(mDown8x.Get() + (c * 8 * blockSize));
166 mDown16BufferPtrs.Add(mDown16x.Get() + (c * 16 * blockSize));
177 void ProcessBlock(T** inputs, T** outputs,
int nFrames,
int nInChans,
int nOutChans, BlockProcessFunc func)
179 assert(nInChans <= mNInChannels);
180 assert(nOutChans <= mNOutChannels);
182 if (mRate != mPrevRate)
186 mInPtrLoopSrc = &mUp2BufferPtrs;
187 mOutPtrLoopSrc = &mDown2BufferPtrs;
190 mInPtrLoopSrc = &mUp4BufferPtrs;
191 mOutPtrLoopSrc = &mDown4BufferPtrs;
194 mInPtrLoopSrc = &mUp8BufferPtrs;
195 mOutPtrLoopSrc = &mDown8BufferPtrs;
198 mInPtrLoopSrc = &mUp16BufferPtrs;
199 mOutPtrLoopSrc = &mDown16BufferPtrs;
208 for (
auto c = 0; c < nInChans; c++) {
210 mUpsampler2x.Get(c)->process_block(mUp2BufferPtrs.Get(c), inputs[c], nFrames);
213 mUpsampler4x.Get(c)->process_block(mUp4BufferPtrs.Get(c), mUp2BufferPtrs.Get(c), nFrames * 2);
216 mUpsampler8x.Get(c)->process_block(mUp8BufferPtrs.Get(c), mUp4BufferPtrs.Get(c), nFrames * 4);
219 mUpsampler16x.Get(c)->process_block(mUp16BufferPtrs.Get(c), mUp8BufferPtrs.Get(c), nFrames * 8);
224 func(inputs, outputs, nFrames);
226 for (
auto i = 0; i < mRate; i++) {
227 for (
auto c = 0; c < nInChans; c++) {
228 mNextInputPtrs.Set(c, mInPtrLoopSrc->Get(c) + (i * nFrames));
229 mNextOutputPtrs.Set(c, mOutPtrLoopSrc->Get(c) + (i * nFrames));
231 func(mNextInputPtrs.GetList(), mNextOutputPtrs.GetList(), nFrames);
235 for (
auto c = 0; c < nOutChans; c++) {
237 mDownsampler16x.Get(c)->process_block(mDown8BufferPtrs.Get(c), mDown16BufferPtrs.Get(c), nFrames * 8);
240 mDownsampler8x.Get(c)->process_block(mDown4BufferPtrs.Get(c), mDown8BufferPtrs.Get(c), nFrames * 4);
243 mDownsampler4x.Get(c)->process_block(mDown2BufferPtrs.Get(c), mDown4BufferPtrs.Get(c), nFrames * 2);
246 mDownsampler2x.Get(c)->process_block(outputs[c], mDown2BufferPtrs.Get(c), nFrames);
261 mUpsampler2x.Get(0)->process_sample(mUp2x.Get()[0], mUp2x.Get()[1], input);
262 mUpsampler4x.Get(0)->process_block(mUp4x.Get(), mUp2x.Get(), 2);
263 mUpsampler8x.Get(0)->process_block(mUp8x.Get(), mUp4x.Get(), 4);
264 mUpsampler16x.Get(0)->process_block(mUp16x.Get(), mUp8x.Get(), 8);
266 for (
auto i = 0; i < 16; i++)
268 mDown16x.Get()[i] = func(mUp16x.Get()[i]);
271 mDownsampler16x.Get(0)->process_block(mDown8x.Get(), mDown16x.Get(), 8);
272 mDownsampler8x.Get(0)->process_block(mDown4x.Get(), mDown8x.Get(), 4);
273 mDownsampler4x.Get(0)->process_block(mDown2x.Get(), mDown4x.Get(), 2);
274 output = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
278 mUpsampler2x.Get(0)->process_sample(mUp2x.Get()[0], mUp2x.Get()[1], input);
279 mUpsampler4x.Get(0)->process_block(mUp4x.Get(), mUp2x.Get(), 2);
280 mUpsampler8x.Get(0)->process_block(mUp8x.Get(), mUp4x.Get(), 4);
282 for (
auto i = 0; i < 8; i++)
284 mDown8x.Get()[i] = func(mUp8x.Get()[i]);
287 mDownsampler8x.Get(0)->process_block(mDown4x.Get(), mDown8x.Get(), 4);
288 mDownsampler4x.Get(0)->process_block(mDown2x.Get(), mDown4x.Get(), 2);
289 output = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
293 mUpsampler2x.Get(0)->process_sample(mUp2x.Get()[0], mUp2x.Get()[1], input);
294 mUpsampler4x.Get(0)->process_block(mUp4x.Get(), mUp2x.Get(), 2);
296 for (
auto i = 0; i < 4; i++)
298 mDown4x.Get()[i] = func(mUp4x.Get()[i]);
301 mDownsampler4x.Get(0)->process_block(mDown2x.Get(), mDown4x.Get(), 2);
302 output = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
306 mUpsampler2x.Get(0)->process_sample(mUp2x.Get()[0], mUp2x.Get()[1], input);
308 mDown2x.Get()[0] = func(mUp2x.Get()[0]);
309 mDown2x.Get()[1] = func(mUp2x.Get()[1]);
310 output = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
314 output = func(input);
325 auto ProcessDown16x = [&](T input)
327 mDown16x.Get()[mWritePos] = (T) input;
334 mDownsampler16x.Get(0)->process_block(mDown8x.Get(), mDown16x.Get(), 8);
335 mDownsampler8x.Get(0)->process_block(mDown4x.Get(), mDown8x.Get(), 4);
336 mDownsampler4x.Get(0)->process_block(mDown2x.Get(), mDown4x.Get(), 2);
337 mDownSamplerOutput = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
341 auto ProcessDown8x = [&](T input)
343 mDown8x.Get()[mWritePos] = (T) input;
350 mDownsampler8x.Get(0)->process_block(mDown4x.Get(), mDown8x.Get(), 4);
351 mDownsampler4x.Get(0)->process_block(mDown2x.Get(), mDown4x.Get(), 2);
352 mDownSamplerOutput = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
356 auto ProcessDown4x = [&](T input)
358 mDown4x.Get()[mWritePos] = (T) input;
365 mDownsampler4x.Get(0)->process_block(mDown2x.Get(), mDown4x.Get(), 2);
366 mDownSamplerOutput = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
370 auto ProcessDown2x = [&](T input)
372 mDown2x.Get()[mWritePos] = (T) input;
374 mWritePos = !mWritePos;
378 mDownSamplerOutput = mDownsampler2x.Get(0)->process_sample(mDown2x.Get());
384 for (
int j = 0; j < mRate; j++)
390 case 2: ProcessDown2x(output);
break;
391 case 4: ProcessDown4x(output);
break;
392 case 8: ProcessDown8x(output);
break;
393 case 16: ProcessDown16x(output);
break;
399 output = mDownSamplerOutput;
404 void SetOverSampling(EFactor factor)
406 if (factor != mFactor)
409 mRate = std::pow(2, (
int) factor);
415 static EFactor RateToFactor(
int rate)
419 case 1:
return EFactor::kNone;
420 case 2:
return EFactor::k2x;
421 case 4:
return EFactor::k4x;
422 case 8:
return EFactor::k8x;
423 case 16:
return EFactor::k16x;
424 default: assert(0);
return EFactor::kNone;
434 EFactor mFactor = kNone;
438 T mDownSamplerOutput = 0.;
439 bool mBlockProcessing;
444 WDL_TypedBuf<T> mUp16x;
445 WDL_TypedBuf<T> mUp8x;
446 WDL_TypedBuf<T> mUp4x;
447 WDL_TypedBuf<T> mUp2x;
449 WDL_TypedBuf<T> mDown16x;
450 WDL_TypedBuf<T> mDown8x;
451 WDL_TypedBuf<T> mDown4x;
452 WDL_TypedBuf<T> mDown2x;
455 WDL_PtrList<T> mUp16BufferPtrs;
456 WDL_PtrList<T> mUp8BufferPtrs;
457 WDL_PtrList<T> mUp4BufferPtrs;
458 WDL_PtrList<T> mUp2BufferPtrs;
460 WDL_PtrList<T> mDown16BufferPtrs;
461 WDL_PtrList<T> mDown8BufferPtrs;
462 WDL_PtrList<T> mDown4BufferPtrs;
463 WDL_PtrList<T> mDown2BufferPtrs;
465 WDL_PtrList<T> mNextInputPtrs;
466 WDL_PtrList<T> mNextOutputPtrs;
469 WDL_PtrList<T>* mInPtrLoopSrc =
nullptr;
470 WDL_PtrList<T>* mOutPtrLoopSrc =
nullptr;
473 WDL_PtrList<Upsampler2xFPU<12, T>> mUpsampler2x;
474 WDL_PtrList<Upsampler2xFPU<4, T>> mUpsampler4x;
475 WDL_PtrList<Upsampler2xFPU<3, T>> mUpsampler8x;
476 WDL_PtrList<Upsampler2xFPU<2, T>> mUpsampler16x;
478 WDL_PtrList<Downsampler2xFPU<12, T>> mDownsampler2x;
479 WDL_PtrList<Downsampler2xFPU<4, T>> mDownsampler4x;
480 WDL_PtrList<Downsampler2xFPU<3, T>> mDownsampler8x;
481 WDL_PtrList<Downsampler2xFPU<2, T>> mDownsampler16x;
T ProcessGen(std::function< T()> genFunc)
Over-sample an per-sample synthesis function.
T Process(T input, std::function< T(T)> func)
Over sample an input sample with a per-sample function (up-sample input -> process with function -> d...
void ProcessBlock(T **inputs, T **outputs, int nFrames, int nInChans, int nOutChans, BlockProcessFunc func)
Over sample an input block with a per-block function (up sample input -> process with function -> dow...