92 assert(factor >= 1 && (factor & (factor - 1)) == 0 &&
"Factor must be a power of 2");
93 assert(factor <= (1 << kMaxStages) &&
"Factor must be <= 16 (kMaxStages stages)");
100 factor = std::clamp(factor, 1, 1 << kMaxStages);
102 while ((1 << (numStages_ + 1)) <= factor)
104 factor_ = 1 << numStages_;
117 const int taps = tapsForQuality(quality_);
118 const T beta = betaForQuality(quality_);
120 for (
int stage = 0; stage < numStages_; ++stage)
124 filters_[stage].design(taps, beta, spec.
numChannels, stageMaxSamples);
137 for (
int i = 0; i < numStages_; ++i)
142 [[nodiscard]]
int getFactor() const noexcept {
return factor_; }
153 if (numStages_ == 0)
return 0;
154 const int halfOrder = (tapsForQuality(quality_) - 1) / 2;
161 return 2 * (halfOrder + 1) * (factor_ - 1) / factor_;
176 const int nCh = std::min(input.getNumChannels(), upBuffer_.getNumChannels());
179 const int nS = std::min(input.getNumSamples(), baseSpec_.
maxBlockSize);
183 for (
int ch = 0; ch < nCh; ++ch)
184 std::memcpy(upBuffer_.getChannel(ch), input.getChannel(ch),
static_cast<std::size_t
>(nS) *
sizeof(T));
185 return upBuffer_.toView().getSubView(0, nS);
189 filters_[0].processUpsample(input, upBuffer_.toView(), nCh, nS);
192 int currentLen = nS * 2;
193 for (
int stage = 1; stage < numStages_; ++stage)
195 filters_[stage].processUpsampleInPlace(upBuffer_.toView(), nCh, currentLen);
199 return upBuffer_.toView().getSubView(0, nS * factor_);
214 const int nCh = std::min(output.getNumChannels(), upBuffer_.getNumChannels());
215 const int nS = std::min(output.getNumSamples(), baseSpec_.
maxBlockSize);
219 for (
int ch = 0; ch < nCh; ++ch)
220 std::memcpy(output.getChannel(ch), upBuffer_.getChannel(ch),
static_cast<std::size_t
>(nS) *
sizeof(T));
224 int currentLen = nS * factor_;
226 for (
int stage = numStages_ - 1; stage > 0; --stage)
228 filters_[stage].processDownsampleInPlace(upBuffer_.toView(), nCh, currentLen);
233 filters_[0].processDownsample(upBuffer_.toView(), output, nCh, currentLen);
243 static constexpr int kMaxStages = 4;
252 struct PolyphaseHalfBand
254 std::vector<T> evenTaps;
255 std::vector<T> fullTaps;
258 int delaySamples = 0;
266 std::vector<ChannelState> upChannels;
267 std::vector<ChannelState> downChannels;
276 void design(
int taps, T beta,
int numChannels,
int maxBlockSamples)
278 halfOrder = (taps - 1) / 2;
284 assert((halfOrder & 1) == 1 &&
"half-band polyphase requires odd halfOrder");
289 delaySamples = (halfOrder + 1) / 2;
292 centerTap = fullCoeffs[
static_cast<std::size_t
>(halfOrder)];
299 for (
int i = 0; i < taps; i += 2)
300 evenTaps.push_back(fullCoeffs[
static_cast<std::size_t
>(i)]);
308 fullTaps.assign(fullCoeffs.begin(), fullCoeffs.end());
312 const int upHistorySize =
static_cast<int>(evenTaps.size()) + maxBlockSamples;
313 const int downHistorySize = (taps - 1) + 2 * maxBlockSamples;
315 upChannels.resize(
static_cast<std::size_t
>(numChannels));
316 downChannels.resize(
static_cast<std::size_t
>(numChannels));
318 for (
int ch = 0; ch < numChannels; ++ch)
320 upChannels[ch].history.assign(
static_cast<std::size_t
>(upHistorySize), T(0));
321 downChannels[ch].history.assign(
static_cast<std::size_t
>(downHistorySize), T(0));
328 void reset() noexcept
330 for (
auto& ch : upChannels)
331 std::fill(ch.history.begin(), ch.history.end(), T(0));
332 for (
auto& ch : downChannels)
333 std::fill(ch.history.begin(), ch.history.end(), T(0));
336 void processUpsample(AudioBufferView<const T> input, AudioBufferView<T> output,
int nCh,
int nS)
noexcept
338 const int numTaps =
static_cast<int>(evenTaps.size());
339 const T* taps = evenTaps.data();
340 const T centre2 = centerTap * T(2);
342 for (
int ch = 0; ch < nCh; ++ch)
344 const T* src = input.getChannel(ch);
345 T* dst = output.getChannel(ch);
346 auto& hist = upChannels[ch].history;
349 std::memcpy(hist.data() + numTaps, src,
static_cast<std::size_t
>(nS) *
sizeof(T));
351 const T* histD = hist.data();
352 for (
int i = 0; i < nS; ++i)
357 dst[i * 2 + 1] = histD[i + numTaps - delaySamples] * centre2;
362 std::memmove(hist.data(), hist.data() + nS,
static_cast<std::size_t
>(numTaps) *
sizeof(T));
366 void processUpsampleInPlace(AudioBufferView<T> buffer,
int nCh,
int currentLen)
noexcept
368 const int numTaps =
static_cast<int>(evenTaps.size());
369 const T* taps = evenTaps.data();
370 const T centre2 = centerTap * T(2);
372 for (
int ch = 0; ch < nCh; ++ch)
374 T* data = buffer.getChannel(ch);
375 auto& hist = upChannels[ch].history;
380 std::memcpy(hist.data() + numTaps, data,
static_cast<std::size_t
>(currentLen) *
sizeof(T));
382 const T* histD = hist.data();
383 for (
int i = 0; i < currentLen; ++i)
388 data[i * 2 + 1] = histD[i + numTaps - delaySamples] * centre2;
393 std::memmove(hist.data(), hist.data() + currentLen,
static_cast<std::size_t
>(numTaps) *
sizeof(T));
407 void processDownsample(AudioBufferView<const T> input, AudioBufferView<T> output,
int nCh,
int currentLen)
noexcept
409 const int outLen = currentLen / 2;
410 const int nTaps =
static_cast<int>(fullTaps.size());
411 const int hLen = nTaps - 1;
412 const T* h = fullTaps.data();
414 for (
int ch = 0; ch < nCh; ++ch)
416 const T* src = input.getChannel(ch);
417 T* dst = output.getChannel(ch);
418 auto& hist = downChannels[ch].history;
420 std::memcpy(hist.data() + hLen, src,
static_cast<std::size_t
>(currentLen) *
sizeof(T));
422 const T* histD = hist.data();
423 for (
int n = 0; n < outLen; ++n)
426 std::memmove(hist.data(), hist.data() + currentLen,
static_cast<std::size_t
>(hLen) *
sizeof(T));
430 void processDownsampleInPlace(AudioBufferView<T> buffer,
int nCh,
int currentLen)
noexcept
432 const int outLen = currentLen / 2;
433 const int nTaps =
static_cast<int>(fullTaps.size());
434 const int hLen = nTaps - 1;
435 const T* h = fullTaps.data();
437 for (
int ch = 0; ch < nCh; ++ch)
439 T* data = buffer.getChannel(ch);
440 auto& hist = downChannels[ch].history;
442 std::memcpy(hist.data() + hLen, data,
static_cast<std::size_t
>(currentLen) *
sizeof(T));
444 const T* histD = hist.data();
445 for (
int n = 0; n < outLen; ++n)
448 std::memmove(hist.data(), hist.data() + currentLen,
static_cast<std::size_t
>(hLen) *
sizeof(T));
453 static constexpr int tapsForQuality(
Quality q)
noexcept
465 static constexpr T betaForQuality(
Quality q)
noexcept
480 AudioSpec baseSpec_ {};
481 AudioBuffer<T, MaxChannels> upBuffer_;
483 std::array<PolyphaseHalfBand, kMaxStages> filters_;