|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
-
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
- namespace dsp
- {
-
- /** Abstract class for the provided oversampling engines used internally in
- the Oversampling class.
- */
- template <typename SampleType>
- class OversamplingEngine
- {
- public:
- //===============================================================================
- OversamplingEngine (size_t newNumChannels, size_t newFactor)
- : numChannels (newNumChannels), factor (newFactor)
- {
- }
-
- virtual ~OversamplingEngine() {}
-
- //===============================================================================
- virtual SampleType getLatencyInSamples() = 0;
- size_t getFactor() { return factor; }
-
- virtual void initProcessing (size_t maximumNumberOfSamplesBeforeOversampling)
- {
- buffer.setSize (static_cast<int> (numChannels), static_cast<int> (maximumNumberOfSamplesBeforeOversampling * factor), false, false, true);
- }
-
- virtual void reset()
- {
- buffer.clear();
- }
-
- dsp::AudioBlock<SampleType> getProcessedSamples (size_t numSamples)
- {
- return dsp::AudioBlock<SampleType> (buffer).getSubBlock (0, numSamples);
- }
-
- virtual void processSamplesUp (dsp::AudioBlock<SampleType> &inputBlock) = 0;
- virtual void processSamplesDown (dsp::AudioBlock<SampleType> &outputBlock) = 0;
-
- protected:
- //===============================================================================
- AudioBuffer<SampleType> buffer;
- size_t numChannels, factor;
- };
-
-
- //===============================================================================
- /** Dummy oversampling engine class which simply copies and pastes the input
- signal, which could be equivalent to a "one time" oversampling processing.
- */
- template <typename SampleType>
- class OversamplingDummy : public OversamplingEngine<SampleType>
- {
- public:
- //===============================================================================
- OversamplingDummy (size_t numChans) : OversamplingEngine<SampleType> (numChans, 1) {}
- ~OversamplingDummy() {}
-
- //===============================================================================
- SampleType getLatencyInSamples() override
- {
- return 0.f;
- }
-
- void processSamplesUp (dsp::AudioBlock<SampleType> &inputBlock) override
- {
- jassert (inputBlock.getNumChannels() <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumChannels()));
- jassert (inputBlock.getNumSamples() * OversamplingEngine<SampleType>::factor <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumSamples()));
-
- for (size_t channel = 0; channel < inputBlock.getNumChannels(); ++channel)
- OversamplingEngine<SampleType>::buffer.copyFrom (static_cast<int> (channel), 0,
- inputBlock.getChannelPointer (channel), static_cast<int> (inputBlock.getNumSamples()));
- }
-
- void processSamplesDown (dsp::AudioBlock<SampleType> &outputBlock) override
- {
- jassert (outputBlock.getNumChannels() <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumChannels()));
- jassert (outputBlock.getNumSamples() * OversamplingEngine<SampleType>::factor <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumSamples()));
-
- outputBlock.copy (OversamplingEngine<SampleType>::getProcessedSamples (outputBlock.getNumSamples()));
- }
-
- private:
- //===============================================================================
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversamplingDummy)
- };
-
- //===============================================================================
- /** Oversampling engine class performing 2 times oversampling using the Filter
- Design FIR Equiripple method. The resulting filter is linear phase,
- symmetric, and has every two samples but the middle one equal to zero,
- leading to specific processing optimizations.
- */
- template <typename SampleType>
- class Oversampling2TimesEquirippleFIR : public OversamplingEngine<SampleType>
- {
- public:
- //===============================================================================
- Oversampling2TimesEquirippleFIR (size_t numChans,
- SampleType normalizedTransitionWidthUp,
- SampleType stopbandAttenuationdBUp,
- SampleType normalizedTransitionWidthDown,
- SampleType stopbandAttenuationdBDown)
- : OversamplingEngine<SampleType> (numChans, 2)
- {
- coefficientsUp = *dsp::FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalizedTransitionWidthUp, stopbandAttenuationdBUp);
- coefficientsDown = *dsp::FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalizedTransitionWidthDown, stopbandAttenuationdBDown);
-
- auto N = coefficientsUp.getFilterOrder() + 1;
- stateUp.setSize (static_cast<int> (this->numChannels), static_cast<int> (N));
-
- N = coefficientsDown.getFilterOrder() + 1;
- auto Ndiv2 = N / 2;
- auto Ndiv4 = Ndiv2 / 2;
-
- stateDown.setSize (static_cast<int> (this->numChannels), static_cast<int> (N));
- stateDown2.setSize (static_cast<int> (this->numChannels), static_cast<int> (Ndiv4 + 1));
-
- position.resize (static_cast<int> (this->numChannels));
- }
-
- ~Oversampling2TimesEquirippleFIR() {}
-
- //===============================================================================
- SampleType getLatencyInSamples() override
- {
- return static_cast<SampleType> (coefficientsUp.getFilterOrder() + coefficientsDown.getFilterOrder()) * 0.5f;
- }
-
- void reset() override
- {
- OversamplingEngine<SampleType>::reset();
-
- stateUp.clear();
- stateDown.clear();
- stateDown2.clear();
-
- position.fill (0);
- }
-
- void processSamplesUp (dsp::AudioBlock<SampleType> &inputBlock) override
- {
- jassert (inputBlock.getNumChannels() <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumChannels()));
- jassert (inputBlock.getNumSamples() * OversamplingEngine<SampleType>::factor <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumSamples()));
-
- // Initialization
- auto fir = coefficientsUp.getRawCoefficients();
- auto N = coefficientsUp.getFilterOrder() + 1;
- auto Ndiv2 = N / 2;
- auto numSamples = inputBlock.getNumSamples();
-
- // Processing
- for (size_t channel = 0; channel < inputBlock.getNumChannels(); ++channel)
- {
- auto bufferSamples = OversamplingEngine<SampleType>::buffer.getWritePointer (static_cast<int> (channel));
- auto buf = stateUp.getWritePointer (static_cast<int> (channel));
- auto samples = inputBlock.getChannelPointer (channel);
-
- for (size_t i = 0; i < numSamples; ++i)
- {
- // Input
- buf[N - 1] = 2 * samples[i];
-
- // Convolution
- auto out = static_cast<SampleType> (0.0);
- for (size_t k = 0; k < Ndiv2; k += 2)
- out += (buf[k] + buf[N - k - 1]) * fir[k];
-
- // Outputs
- bufferSamples[i << 1] = out;
- bufferSamples[(i << 1) + 1] = buf[Ndiv2 + 1] * fir[Ndiv2];
-
- // Shift data
- for (size_t k = 0; k < N - 2; k += 2)
- buf[k] = buf[k + 2];
- }
- }
- }
-
- void processSamplesDown (dsp::AudioBlock<SampleType> &outputBlock) override
- {
- jassert (outputBlock.getNumChannels() <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumChannels()));
- jassert (outputBlock.getNumSamples() * OversamplingEngine<SampleType>::factor <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumSamples()));
-
- // Initialization
- auto fir = coefficientsDown.getRawCoefficients();
- auto N = coefficientsDown.getFilterOrder() + 1;
- auto Ndiv2 = N / 2;
- auto Ndiv4 = Ndiv2 / 2;
- auto numSamples = outputBlock.getNumSamples();
-
- // Processing
- for (size_t channel = 0; channel < outputBlock.getNumChannels(); ++channel)
- {
- auto bufferSamples = OversamplingEngine<SampleType>::buffer.getWritePointer (static_cast<int> (channel));
- auto buf = stateDown.getWritePointer (static_cast<int> (channel));
- auto buf2 = stateDown2.getWritePointer (static_cast<int> (channel));
- auto samples = outputBlock.getChannelPointer (channel);
- auto pos = position.getUnchecked (static_cast<int> (channel));
-
- for (size_t i = 0; i < numSamples; ++i)
- {
- // Input
- buf[N - 1] = bufferSamples[i << 1];
-
- // Convolution
- auto out = static_cast<SampleType> (0.0);
- for (size_t k = 0; k < Ndiv2; k += 2)
- out += (buf[k] + buf[N - k - 1]) * fir[k];
-
- // Output
- out += buf2[pos] * fir[Ndiv2];
- buf2[pos] = bufferSamples[(i << 1) + 1];
-
- samples[i] = out;
-
- // Shift data
- for (size_t k = 0; k < N - 2; ++k)
- buf[k] = buf[k + 2];
-
- // Circular buffer
- pos = (pos == 0 ? Ndiv4 : pos - 1);
- }
-
- position.setUnchecked (static_cast<int> (channel), pos);
- }
-
- }
-
- private:
- //===============================================================================
- dsp::FIR::Coefficients<SampleType> coefficientsUp, coefficientsDown;
- AudioBuffer<SampleType> stateUp, stateDown, stateDown2;
- Array<size_t> position;
-
- //===============================================================================
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Oversampling2TimesEquirippleFIR)
- };
-
-
- //===============================================================================
- /** Oversampling engine class performing 2 times oversampling using the Filter
- Design IIR Polyphase Allpass Cascaded method. The resulting filter is minimum
- phase, and provided with a method to get the exact resulting latency.
- */
- template <typename SampleType>
- class Oversampling2TimesPolyphaseIIR : public OversamplingEngine<SampleType>
- {
- public:
- //===============================================================================
- Oversampling2TimesPolyphaseIIR (size_t numChans,
- SampleType normalizedTransitionWidthUp,
- SampleType stopbandAttenuationdBUp,
- SampleType normalizedTransitionWidthDown,
- SampleType stopbandAttenuationdBDown)
- : OversamplingEngine<SampleType> (numChans, 2)
- {
- auto structureUp = dsp::FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalizedTransitionWidthUp, stopbandAttenuationdBUp);
- dsp::IIR::Coefficients<SampleType> coeffsUp = getCoefficients (structureUp);
- latency = static_cast<SampleType> (-(coeffsUp.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants<double>::twoPi));
-
- auto structureDown = dsp::FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalizedTransitionWidthDown, stopbandAttenuationdBDown);
- dsp::IIR::Coefficients<SampleType> coeffsDown = getCoefficients (structureDown);
- latency += static_cast<SampleType> (-(coeffsDown.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants<double>::twoPi));
-
- for (auto i = 0; i < structureUp.directPath.size(); ++i)
- coefficientsUp.add (structureUp.directPath[i].coefficients[0]);
-
- for (auto i = 1; i < structureUp.delayedPath.size(); ++i)
- coefficientsUp.add (structureUp.delayedPath[i].coefficients[0]);
-
- for (auto i = 0; i < structureDown.directPath.size(); ++i)
- coefficientsDown.add (structureDown.directPath[i].coefficients[0]);
-
- for (auto i = 1; i < structureDown.delayedPath.size(); ++i)
- coefficientsDown.add (structureDown.delayedPath[i].coefficients[0]);
-
- v1Up.setSize (static_cast<int> (this->numChannels), coefficientsUp.size());
- v1Down.setSize (static_cast<int> (this->numChannels), coefficientsDown.size());
- delayDown.resize (static_cast<int> (this->numChannels));
- }
-
- ~Oversampling2TimesPolyphaseIIR() {}
-
- //===============================================================================
- SampleType getLatencyInSamples() override
- {
- return latency;
- }
-
- void reset() override
- {
- OversamplingEngine<SampleType>::reset();
-
- v1Up.clear();
- v1Down.clear();
- delayDown.fill (0);
- }
-
- void processSamplesUp (dsp::AudioBlock<SampleType> &inputBlock) override
- {
- jassert (inputBlock.getNumChannels() <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumChannels()));
- jassert (inputBlock.getNumSamples() * OversamplingEngine<SampleType>::factor <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumSamples()));
-
- // Initialization
- auto coeffs = coefficientsUp.getRawDataPointer();
- auto numStages = coefficientsUp.size();
- auto delayedStages = numStages / 2;
- auto directStages = numStages - delayedStages;
- auto numSamples = inputBlock.getNumSamples();
-
- // Processing
- for (size_t channel = 0; channel < inputBlock.getNumChannels(); ++channel)
- {
- auto bufferSamples = OversamplingEngine<SampleType>::buffer.getWritePointer (static_cast<int> (channel));
- auto lv1 = v1Up.getWritePointer (static_cast<int> (channel));
- auto samples = inputBlock.getChannelPointer (channel);
-
- for (size_t i = 0; i < numSamples; ++i)
- {
- // Direct path cascaded allpass filters
- auto input = samples[i];
- for (auto n = 0; n < directStages; ++n)
- {
- auto alpha = coeffs[n];
- auto output = alpha * input + lv1[n];
- lv1[n] = input - alpha * output;
- input = output;
- }
-
- // Output
- bufferSamples[i << 1] = input;
-
- // Delayed path cascaded allpass filters
- input = samples[i];
- for (auto n = directStages; n < numStages; ++n)
- {
- auto alpha = coeffs[n];
- auto output = alpha * input + lv1[n];
- lv1[n] = input - alpha * output;
- input = output;
- }
-
- // Output
- bufferSamples[(i << 1) + 1] = input;
- }
- }
-
- // Snap To Zero
- snapToZero (true);
- }
-
- void processSamplesDown (dsp::AudioBlock<SampleType> &outputBlock) override
- {
- jassert (outputBlock.getNumChannels() <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumChannels()));
- jassert (outputBlock.getNumSamples() * OversamplingEngine<SampleType>::factor <= static_cast<size_t> (OversamplingEngine<SampleType>::buffer.getNumSamples()));
-
- // Initialization
- auto coeffs = coefficientsDown.getRawDataPointer();
- auto numStages = coefficientsDown.size();
- auto delayedStages = numStages / 2;
- auto directStages = numStages - delayedStages;
- auto numSamples = outputBlock.getNumSamples();
-
- // Processing
- for (size_t channel = 0; channel < outputBlock.getNumChannels(); ++channel)
- {
- auto bufferSamples = OversamplingEngine<SampleType>::buffer.getWritePointer (static_cast<int> (channel));
- auto lv1 = v1Down.getWritePointer (static_cast<int> (channel));
- auto samples = outputBlock.getChannelPointer (channel);
- auto delay = delayDown.getUnchecked (static_cast<int> (channel));
-
- for (size_t i = 0; i < numSamples; ++i)
- {
- // Direct path cascaded allpass filters
- auto input = bufferSamples[i << 1];
- for (auto n = 0; n < directStages; ++n)
- {
- auto alpha = coeffs[n];
- auto output = alpha * input + lv1[n];
- lv1[n] = input - alpha * output;
- input = output;
- }
- auto directOut = input;
-
- // Delayed path cascaded allpass filters
- input = bufferSamples[(i << 1) + 1];
- for (auto n = directStages; n < numStages; ++n)
- {
- auto alpha = coeffs[n];
- auto output = alpha * input + lv1[n];
- lv1[n] = input - alpha * output;
- input = output;
- }
-
- // Output
- samples[i] = (delay + directOut) * static_cast<SampleType> (0.5);
- delay = input;
- }
-
- delayDown.setUnchecked (static_cast<int> (channel), delay);
- }
-
- // Snap To Zero
- snapToZero (false);
- }
-
- void snapToZero (bool snapUpProcessing)
- {
- if (snapUpProcessing)
- {
- for (auto channel = 0; channel < OversamplingEngine<SampleType>::buffer.getNumChannels(); ++channel)
- {
- auto lv1 = v1Up.getWritePointer (channel);
- auto numStages = coefficientsUp.size();
-
- for (auto n = 0; n < numStages; ++n)
- util::snapToZero (lv1[n]);
- }
- }
- else
- {
- for (auto channel = 0; channel < OversamplingEngine<SampleType>::buffer.getNumChannels(); ++channel)
- {
- auto lv1 = v1Down.getWritePointer (channel);
- auto numStages = coefficientsDown.size();
-
- for (auto n = 0; n < numStages; ++n)
- util::snapToZero (lv1[n]);
- }
- }
- }
-
- private:
- //===============================================================================
- /** This function calculates the equivalent high order IIR filter of a given
- polyphase cascaded allpass filters structure.
- */
- const dsp::IIR::Coefficients<SampleType> getCoefficients (typename dsp::FilterDesign<SampleType>::IIRPolyphaseAllpassStructure& structure) const
- {
- dsp::Polynomial<SampleType> numerator1 ({ static_cast<SampleType> (1.0) });
- dsp::Polynomial<SampleType> denominator1 ({ static_cast<SampleType> (1.0) });
- dsp::Polynomial<SampleType> numerator2 ({ static_cast<SampleType> (1.0) });
- dsp::Polynomial<SampleType> denominator2 ({ static_cast<SampleType> (1.0) });
-
- dsp::Polynomial<SampleType> temp;
-
- for (auto n = 0; n < structure.directPath.size(); ++n)
- {
- auto* coeffs = structure.directPath.getReference (n).getRawCoefficients();
-
- if (structure.directPath[n].getFilterOrder() == 1)
- {
- temp = dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1] });
- numerator1 = numerator1.getProductWith (temp);
-
- temp = dsp::Polynomial<SampleType> ({ static_cast<SampleType> (1.0), coeffs[2] });
- denominator1 = denominator1.getProductWith (temp);
- }
- else
- {
- temp = dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] });
- numerator1 = numerator1.getProductWith (temp);
-
- temp = dsp::Polynomial<SampleType> ({ static_cast<SampleType> (1.0), coeffs[3], coeffs[4] });
- denominator1 = denominator1.getProductWith (temp);
- }
- }
-
- for (auto n = 0; n < structure.delayedPath.size(); ++n)
- {
- auto* coeffs = structure.delayedPath.getReference (n).getRawCoefficients();
-
- if (structure.delayedPath[n].getFilterOrder() == 1)
- {
- temp = dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1] });
- numerator2 = numerator2.getProductWith (temp);
-
- temp = dsp::Polynomial<SampleType> ({ static_cast<SampleType> (1.0), coeffs[2] });
- denominator2 = denominator2.getProductWith (temp);
- }
- else
- {
- temp = dsp::Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] });
- numerator2 = numerator2.getProductWith (temp);
-
- temp = dsp::Polynomial<SampleType> ({ static_cast<SampleType> (1.0), coeffs[3], coeffs[4] });
- denominator2 = denominator2.getProductWith (temp);
- }
- }
-
- dsp::Polynomial<SampleType> numeratorf1 = numerator1.getProductWith (denominator2);
- dsp::Polynomial<SampleType> numeratorf2 = numerator2.getProductWith (denominator1);
- dsp::Polynomial<SampleType> numerator = numeratorf1.getSumWith (numeratorf2);
- dsp::Polynomial<SampleType> denominator = denominator1.getProductWith (denominator2);
-
- dsp::IIR::Coefficients<SampleType> coeffs;
-
- coeffs.coefficients.clear();
- auto inversion = static_cast<SampleType> (1.0) / denominator[0];
-
- for (auto i = 0; i <= numerator.getOrder(); ++i)
- coeffs.coefficients.add (numerator[i] * inversion);
-
- for (auto i = 1; i <= denominator.getOrder(); ++i)
- coeffs.coefficients.add (denominator[i] * inversion);
-
- return coeffs;
- }
-
- //===============================================================================
- Array<SampleType> coefficientsUp, coefficientsDown;
- SampleType latency;
-
- AudioBuffer<SampleType> v1Up, v1Down;
- Array<SampleType> delayDown;
-
- //===============================================================================
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Oversampling2TimesPolyphaseIIR)
- };
-
-
- //===============================================================================
- template <typename SampleType>
- Oversampling<SampleType>::Oversampling (size_t newNumChannels, size_t newFactor, FilterType newType, bool newMaxQuality)
- {
- jassert (newFactor >= 0 && newFactor <= 4 && newNumChannels > 0);
-
- factorOversampling = static_cast<size_t> (1) << newFactor;
- isMaximumQuality = newMaxQuality;
- type = newType;
- numChannels = newNumChannels;
-
- if (newFactor == 0)
- {
- numStages = 1;
- engines.add (new OversamplingDummy<SampleType> (numChannels));
- }
- else if (type == FilterType::filterHalfBandPolyphaseIIR)
- {
- numStages = newFactor;
-
- for (size_t n = 0; n < numStages; ++n)
- {
- auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.f);
- auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.f);
-
- auto gaindBStartUp = (isMaximumQuality ? -75.f : -65.f);
- auto gaindBStartDown = (isMaximumQuality ? -70.f : -60.f);
- auto gaindBFactorUp = (isMaximumQuality ? 10.f : 8.f);
- auto gaindBFactorDown = (isMaximumQuality ? 10.f : 8.f);
-
- engines.add (new Oversampling2TimesPolyphaseIIR<SampleType> (numChannels,
- twUp, gaindBStartUp + gaindBFactorUp * n,
- twDown, gaindBStartDown + gaindBFactorDown * n));
- }
- }
- else if (type == FilterType::filterHalfBandFIREquiripple)
- {
- numStages = newFactor;
-
- for (size_t n = 0; n < numStages; ++n)
- {
- auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.f);
- auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.f);
-
- auto gaindBStartUp = (isMaximumQuality ? -90.f : -70.f);
- auto gaindBStartDown = (isMaximumQuality ? -70.f : -60.f);
- auto gaindBFactorUp = (isMaximumQuality ? 10.f : 8.f);
- auto gaindBFactorDown = (isMaximumQuality ? 10.f : 8.f);
-
- engines.add (new Oversampling2TimesEquirippleFIR<SampleType> (numChannels,
- twUp, gaindBStartUp + gaindBFactorUp * n,
- twDown, gaindBStartDown + gaindBFactorDown * n));
- }
- }
- }
-
- template <typename SampleType>
- Oversampling<SampleType>::~Oversampling()
- {
- engines.clear();
- }
-
- //===============================================================================
- template <typename SampleType>
- SampleType Oversampling<SampleType>::getLatencyInSamples() noexcept
- {
- auto latency = static_cast<SampleType> (0);
- size_t order = 1;
-
- for (size_t n = 0; n < numStages; ++n)
- {
- auto& engine = *engines[static_cast<int> (n)];
-
- order *= engine.getFactor();
- latency += engine.getLatencyInSamples() / static_cast<SampleType> (order);
- }
-
- return latency;
- }
-
- template <typename SampleType>
- size_t Oversampling<SampleType>::getOversamplingFactor() noexcept
- {
- return factorOversampling;
- }
-
- //===============================================================================
- template <typename SampleType>
- void Oversampling<SampleType>::initProcessing (size_t maximumNumberOfSamplesBeforeOversampling)
- {
- jassert (! engines.isEmpty());
- auto currentNumSamples = maximumNumberOfSamplesBeforeOversampling;
-
- for (size_t n = 0; n < numStages; ++n)
- {
- auto& engine = *engines[static_cast<int> (n)];
-
- engine.initProcessing (currentNumSamples);
- currentNumSamples *= engine.getFactor();
- }
-
- isReady = true;
- reset();
- }
-
- template <typename SampleType>
- void Oversampling<SampleType>::reset() noexcept
- {
- jassert (! engines.isEmpty());
-
- if (isReady)
- for (auto n = 0; n < engines.size(); ++n)
- engines[n]->reset();
- }
-
- template <typename SampleType>
- typename dsp::AudioBlock<SampleType> Oversampling<SampleType>::processSamplesUp (const dsp::AudioBlock<SampleType> &inputBlock) noexcept
- {
- jassert (! engines.isEmpty());
-
- if (! isReady)
- return dsp::AudioBlock<SampleType>();
-
- dsp::AudioBlock<SampleType> audioBlock = inputBlock;
-
- for (size_t n = 0; n < numStages; ++n)
- {
- auto& engine = *engines[static_cast<int> (n)];
- engine.processSamplesUp (audioBlock);
- audioBlock = engine.getProcessedSamples (audioBlock.getNumSamples() * engine.getFactor());
- }
-
- return audioBlock;
- }
-
- template <typename SampleType>
- void Oversampling<SampleType>::processSamplesDown (dsp::AudioBlock<SampleType> &outputBlock) noexcept
- {
- jassert (! engines.isEmpty());
-
- if (! isReady)
- return;
-
- auto currentNumSamples = outputBlock.getNumSamples();
-
- for (size_t n = 0; n < numStages - 1; ++n)
- currentNumSamples *= engines[static_cast<int> (n)]->getFactor();
-
- for (size_t n = numStages - 1; n > 0; --n)
- {
- auto& engine = *engines[static_cast<int> (n)];
-
- auto audioBlock = engines[static_cast<int> (n - 1)]->getProcessedSamples (currentNumSamples);
- engine.processSamplesDown (audioBlock);
-
- currentNumSamples /= engine.getFactor();
- }
-
- engines[static_cast<int> (0)]->processSamplesDown (outputBlock);
- }
-
- template class Oversampling<float>;
- template class Oversampling<double>;
-
- } // namespace dsp
- } // namespace juce
|