35 template <
typename SampleType>
38 OversamplingStage (
size_t numChans,
size_t newFactor) : numChannels (numChans), factor (newFactor) {}
39 virtual ~OversamplingStage() {}
44 virtual void initProcessing (
size_t maximumNumberOfSamplesBeforeOversampling)
46 buffer.setSize (static_cast<int> (numChannels),
47 static_cast<int> (maximumNumberOfSamplesBeforeOversampling * factor),
65 size_t numChannels, factor;
73 template <
typename SampleType>
88 jassert (inputBlock.
getNumChannels() <=
static_cast<size_t> (ParentType::buffer.getNumChannels()));
89 jassert (inputBlock.
getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
91 for (
size_t channel = 0; channel < inputBlock.
getNumChannels(); ++channel)
92 ParentType::buffer.copyFrom (static_cast<int> (channel), 0,
98 jassert (outputBlock.
getNumChannels() <=
static_cast<size_t> (ParentType::buffer.getNumChannels()));
99 jassert (outputBlock.
getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
113 template <
typename SampleType>
119 SampleType normalisedTransitionWidthUp,
120 SampleType stopbandAmplitudedBUp,
121 SampleType normalisedTransitionWidthDown,
122 SampleType stopbandAmplitudedBDown)
123 : ParentType (numChans, 2)
128 auto N = coefficientsUp.getFilterOrder() + 1;
129 stateUp.setSize (static_cast<int> (this->numChannels), static_cast<int> (N));
131 N = coefficientsDown.getFilterOrder() + 1;
133 auto Ndiv4 = Ndiv2 / 2;
135 stateDown.setSize (static_cast<int> (this->numChannels), static_cast<int> (N));
136 stateDown2.setSize (static_cast<int> (this->numChannels), static_cast<int> (Ndiv4 + 1));
138 position.resize (static_cast<int> (this->numChannels));
144 return static_cast<SampleType
> (coefficientsUp.getFilterOrder() + coefficientsDown.getFilterOrder()) * 0.5f;
147 void reset()
override 160 jassert (inputBlock.
getNumChannels() <=
static_cast<size_t> (ParentType::buffer.getNumChannels()));
161 jassert (inputBlock.
getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
164 auto fir = coefficientsUp.getRawCoefficients();
165 auto N = coefficientsUp.getFilterOrder() + 1;
170 for (
size_t channel = 0; channel < inputBlock.
getNumChannels(); ++channel)
172 auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
173 auto buf = stateUp.getWritePointer (static_cast<int> (channel));
176 for (
size_t i = 0; i < numSamples; ++i)
179 buf[N - 1] = 2 * samples[i];
182 auto out =
static_cast<SampleType
> (0.0);
184 for (
size_t k = 0; k < Ndiv2; k += 2)
185 out += (buf[k] + buf[N - k - 1]) * fir[k];
188 bufferSamples[i << 1] = out;
189 bufferSamples[(i << 1) + 1] = buf[Ndiv2 + 1] * fir[Ndiv2];
192 for (
size_t k = 0; k < N - 2; k += 2)
200 jassert (outputBlock.
getNumChannels() <=
static_cast<size_t> (ParentType::buffer.getNumChannels()));
201 jassert (outputBlock.
getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
204 auto fir = coefficientsDown.getRawCoefficients();
205 auto N = coefficientsDown.getFilterOrder() + 1;
207 auto Ndiv4 = Ndiv2 / 2;
211 for (
size_t channel = 0; channel < outputBlock.
getNumChannels(); ++channel)
213 auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
214 auto buf = stateDown.getWritePointer (static_cast<int> (channel));
215 auto buf2 = stateDown2.getWritePointer (static_cast<int> (channel));
217 auto pos = position.getUnchecked (static_cast<int> (channel));
219 for (
size_t i = 0; i < numSamples; ++i)
222 buf[N - 1] = bufferSamples[i << 1];
225 auto out =
static_cast<SampleType
> (0.0);
227 for (
size_t k = 0; k < Ndiv2; k += 2)
228 out += (buf[k] + buf[N - k - 1]) * fir[k];
231 out += buf2[pos] * fir[Ndiv2];
232 buf2[pos] = bufferSamples[(i << 1) + 1];
237 for (
size_t k = 0; k < N - 2; ++k)
241 pos = (pos == 0 ? Ndiv4 : pos - 1);
244 position.setUnchecked (static_cast<int> (channel), pos);
265 template <
typename SampleType>
271 SampleType normalisedTransitionWidthUp,
272 SampleType stopbandAmplitudedBUp,
273 SampleType normalisedTransitionWidthDown,
274 SampleType stopbandAmplitudedBDown)
275 : ParentType (numChans, 2)
278 auto coeffsUp = getCoefficients (structureUp);
282 auto coeffsDown = getCoefficients (structureDown);
285 for (
auto i = 0; i < structureUp.directPath.size(); ++i)
286 coefficientsUp.add (structureUp.directPath.getObjectPointer (i)->coefficients[0]);
288 for (
auto i = 1; i < structureUp.delayedPath.size(); ++i)
289 coefficientsUp.add (structureUp.delayedPath.getObjectPointer (i)->coefficients[0]);
291 for (
auto i = 0; i < structureDown.directPath.size(); ++i)
292 coefficientsDown.add (structureDown.directPath.getObjectPointer (i)->coefficients[0]);
294 for (
auto i = 1; i < structureDown.delayedPath.size(); ++i)
295 coefficientsDown.add (structureDown.delayedPath.getObjectPointer (i)->coefficients[0]);
297 v1Up.setSize (static_cast<int> (this->numChannels), coefficientsUp.size());
298 v1Down.setSize (static_cast<int> (this->numChannels), coefficientsDown.size());
299 delayDown.resize (static_cast<int> (this->numChannels));
308 void reset()
override 318 jassert (inputBlock.
getNumChannels() <=
static_cast<size_t> (ParentType::buffer.getNumChannels()));
319 jassert (inputBlock.
getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
322 auto coeffs = coefficientsUp.getRawDataPointer();
323 auto numStages = coefficientsUp.size();
324 auto delayedStages = numStages / 2;
325 auto directStages = numStages - delayedStages;
329 for (
size_t channel = 0; channel < inputBlock.
getNumChannels(); ++channel)
331 auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
332 auto lv1 = v1Up.getWritePointer (static_cast<int> (channel));
335 for (
size_t i = 0; i < numSamples; ++i)
338 auto input = samples[i];
340 for (
auto n = 0; n < directStages; ++n)
342 auto alpha = coeffs[n];
343 auto output = alpha * input + lv1[n];
344 lv1[n] = input - alpha * output;
349 bufferSamples[i << 1] = input;
354 for (
auto n = directStages; n < numStages; ++n)
356 auto alpha = coeffs[n];
357 auto output = alpha * input + lv1[n];
358 lv1[n] = input - alpha * output;
363 bufferSamples[(i << 1) + 1] = input;
373 jassert (outputBlock.
getNumChannels() <=
static_cast<size_t> (ParentType::buffer.getNumChannels()));
374 jassert (outputBlock.
getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
377 auto coeffs = coefficientsDown.getRawDataPointer();
378 auto numStages = coefficientsDown.size();
379 auto delayedStages = numStages / 2;
380 auto directStages = numStages - delayedStages;
384 for (
size_t channel = 0; channel < outputBlock.
getNumChannels(); ++channel)
386 auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
387 auto lv1 = v1Down.getWritePointer (static_cast<int> (channel));
389 auto delay = delayDown.getUnchecked (static_cast<int> (channel));
391 for (
size_t i = 0; i < numSamples; ++i)
394 auto input = bufferSamples[i << 1];
396 for (
auto n = 0; n < directStages; ++n)
398 auto alpha = coeffs[n];
399 auto output = alpha * input + lv1[n];
400 lv1[n] = input - alpha * output;
404 auto directOut = input;
407 input = bufferSamples[(i << 1) + 1];
409 for (
auto n = directStages; n < numStages; ++n)
411 auto alpha = coeffs[n];
412 auto output = alpha * input + lv1[n];
413 lv1[n] = input - alpha * output;
418 samples[i] = (delay + directOut) * static_cast<SampleType> (0.5);
422 delayDown.setUnchecked (static_cast<int> (channel), delay);
429 void snapToZero (
bool snapUpProcessing)
431 if (snapUpProcessing)
433 for (
auto channel = 0; channel < ParentType::buffer.getNumChannels(); ++channel)
435 auto lv1 = v1Up.getWritePointer (channel);
436 auto numStages = coefficientsUp.size();
438 for (
auto n = 0; n < numStages; ++n)
439 util::snapToZero (lv1[n]);
444 for (
auto channel = 0; channel < ParentType::buffer.getNumChannels(); ++channel)
446 auto lv1 = v1Down.getWritePointer (channel);
447 auto numStages = coefficientsDown.size();
449 for (
auto n = 0; n < numStages; ++n)
450 util::snapToZero (lv1[n]);
462 constexpr
auto one =
static_cast<SampleType
> (1.0);
465 numerator2 ({ one }), denominator2 ({ one });
467 for (
auto* i : structure.directPath)
469 auto coeffs = i->getRawCoefficients();
471 if (i->getFilterOrder() == 1)
483 for (
auto* i : structure.delayedPath)
485 auto coeffs = i->getRawCoefficients();
487 if (i->getFilterOrder() == 1)
499 auto numeratorf1 = numerator1.getProductWith (denominator2);
500 auto numeratorf2 = numerator2.getProductWith (denominator1);
501 auto numerator = numeratorf1.getSumWith (numeratorf2);
502 auto denominator = denominator1.getProductWith (denominator2);
507 auto inversion = one / denominator[0];
509 for (
auto i = 0; i <= numerator.getOrder(); ++i)
512 for (
auto i = 1; i <= denominator.getOrder(); ++i)
531 template <
typename SampleType>
533 : numChannels (newNumChannels)
535 jassert (numChannels > 0);
540 template <
typename SampleType>
543 : numChannels (newNumChannels)
545 jassert (isPositiveAndBelow (newFactor, 5) && numChannels > 0);
551 else if (newType == FilterType::filterHalfBandPolyphaseIIR)
553 for (
size_t n = 0; n < newFactor; ++n)
555 auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.0f);
556 auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.0f);
558 auto gaindBStartUp = (isMaximumQuality ? -90.0f : -70.0f);
559 auto gaindBStartDown = (isMaximumQuality ? -75.0f : -60.0f);
560 auto gaindBFactorUp = (isMaximumQuality ? 10.0f : 8.0f);
561 auto gaindBFactorDown = (isMaximumQuality ? 10.0f : 8.0f);
564 twUp, gaindBStartUp + gaindBFactorUp * n,
565 twDown, gaindBStartDown + gaindBFactorDown * n);
568 else if (newType == FilterType::filterHalfBandFIREquiripple)
570 for (
size_t n = 0; n < newFactor; ++n)
572 auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.0f);
573 auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.0f);
575 auto gaindBStartUp = (isMaximumQuality ? -90.0f : -70.0f);
576 auto gaindBStartDown = (isMaximumQuality ? -75.0f : -60.0f);
577 auto gaindBFactorUp = (isMaximumQuality ? 10.0f : 8.0f);
578 auto gaindBFactorDown = (isMaximumQuality ? 10.0f : 8.0f);
581 twUp, gaindBStartUp + gaindBFactorUp * n,
582 twDown, gaindBStartDown + gaindBFactorDown * n);
587 template <
typename SampleType>
594 template <
typename SampleType>
600 template <
typename SampleType>
602 float normalisedTransitionWidthUp,
603 float stopbandAmplitudedBUp,
604 float normalisedTransitionWidthDown,
605 float stopbandAmplitudedBDown)
607 if (type == FilterType::filterHalfBandPolyphaseIIR)
610 normalisedTransitionWidthUp, stopbandAmplitudedBUp,
611 normalisedTransitionWidthDown, stopbandAmplitudedBDown));
616 normalisedTransitionWidthUp, stopbandAmplitudedBUp,
617 normalisedTransitionWidthDown, stopbandAmplitudedBDown));
620 factorOversampling *= 2;
623 template <
typename SampleType>
627 factorOversampling = 1u;
631 template <
typename SampleType>
634 auto latency =
static_cast<SampleType
> (0);
637 for (
auto* stage : stages)
639 order *= stage->factor;
640 latency += stage->getLatencyInSamples() /
static_cast<SampleType
> (order);
646 template <
typename SampleType>
649 return factorOversampling;
653 template <
typename SampleType>
656 jassert (! stages.isEmpty());
657 auto currentNumSamples = maximumNumberOfSamplesBeforeOversampling;
659 for (
auto* stage : stages)
661 stage->initProcessing (currentNumSamples);
662 currentNumSamples *= stage->factor;
669 template <
typename SampleType>
672 jassert (! stages.isEmpty());
675 for (
auto* stage : stages)
679 template <
typename SampleType>
682 jassert (! stages.isEmpty());
687 auto* firstStage = stages.getUnchecked (0);
688 firstStage->processSamplesUp (inputBlock);
689 auto block = firstStage->getProcessedSamples (inputBlock.getNumSamples() * firstStage->factor);
691 for (
int i = 1; i < stages.size(); ++i)
693 stages[i]->processSamplesUp (block);
694 block = stages[i]->getProcessedSamples (block.getNumSamples() * stages[i]->factor);
700 template <
typename SampleType>
703 jassert (! stages.isEmpty());
708 auto currentNumSamples = outputBlock.getNumSamples();
710 for (
int n = 0; n < stages.size() - 1; ++n)
711 currentNumSamples *= stages.getUnchecked(n)->factor;
713 for (
int n = stages.size() - 1; n > 0; --n)
715 auto& stage = *stages.getUnchecked(n);
716 auto audioBlock = stages.getUnchecked (n - 1)->getProcessedSamples (currentNumSamples);
717 stage.processSamplesDown (audioBlock);
719 currentNumSamples /= stage.factor;
722 stages.getFirst()->processSamplesDown (outputBlock);
void addDummyOversamplingStage()
Adds a new "dummy" oversampling stage, which does nothing to the signal.
Abstract class for the provided oversampling stages used internally in the Oversampling class...
AudioBlock & copyFrom(const AudioBlock< OtherSampleType > &src) noexcept
Copies the values in src to this block.
static IIRPolyphaseAllpassStructure designIIRLowpassHalfBandPolyphaseAllpassMethod(FloatType normalisedTransitionWidth, FloatType stopbandAmplitudedB)
This method generates arrays of IIR::Coefficients for a low-pass filter, with a cutoff frequency at h...
Array< NumericType > coefficients
The raw coefficients.
Oversampling stage class performing 2 times oversampling using the Filter Design IIR Polyphase Allpas...
void add(const ElementType &newElement)
Appends a new element at the end of the array.
void initProcessing(size_t maximumNumberOfSamplesBeforeOversampling)
Must be called before any processing, to set the buffer sizes of the internal buffers of the oversamp...
Minimal and lightweight data-structure which contains a list of pointers to channels containing some ...
AudioBlock< SampleType > processSamplesUp(const AudioBlock< const SampleType > &inputBlock) noexcept
Must be called to perform the upsampling, prior to any oversampled processing.
constexpr size_t getNumSamples() const noexcept
Returns the number of samples referenced by this block.
size_t getOversamplingFactor() noexcept
Returns the current oversampling factor.
A set of coefficients for use in an Filter object.
void reset() noexcept
Resets the processing pipeline, ready to oversample a new stream of data.
Oversampling stage class performing 2 times oversampling using the Filter Design FIR Equiripple metho...
~Oversampling()
Destructor.
void clear()
Removes all elements from the array.
static FIRCoefficientsPtr designFIRLowpassHalfBandEquirippleMethod(FloatType normalisedTransitionWidth, FloatType amplitudedB)
This method generates a FIR::Coefficients for a low-pass filter, with a cutoff frequency at half band...
SampleType getLatencyInSamples() noexcept
Returns the latency in samples of the whole processing.
void processSamplesDown(AudioBlock< SampleType > &outputBlock) noexcept
Must be called to perform the downsampling, after the upsampling and the non-linear processing...
void clearOversamplingStages()
Removes all the previously registered oversampling stages, so you can add your own from scratch...
A processing class performing multi-channel oversampling.
void addOversamplingStage(FilterType, float normalisedTransitionWidthUp, float stopbandAmplitudedBUp, float normalisedTransitionWidthDown, float stopbandAmplitudedBDown)
Adds a new oversampling stage to the Oversampling class, multiplying the current oversampling factor ...
The structure returned by the function designIIRLowpassHalfBandPolyphaseAllpassMethod.
SampleType * getChannelPointer(size_t channel) const noexcept
Returns a raw pointer into one of the channels in this block.
Oversampling(size_t numChannels, size_t factor, FilterType type, bool isMaxQuality=true)
Constructor of the oversampling class.
Commonly used mathematical constants.
Dummy oversampling stage class which simply copies and pastes the input signal, which could be equiva...
constexpr size_t getNumChannels() const noexcept
Returns the number of channels referenced by this block.
Polynomial< FloatingType > getProductWith(const Polynomial< FloatingType > &other) const
computes the product of two polynomials and return the result
A class representing a polynomial.
FilterType
The type of filter that can be used for the oversampling processing.