Loading...
Searching...
No Matches
juce_Oversampling.cpp
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-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::dsp
{
template <typename SampleType>
struct Oversampling<SampleType>::OversamplingStage
{
OversamplingStage (size_t numChans, size_t newFactor) : numChannels (numChans), factor (newFactor) {}
virtual ~OversamplingStage() {}
//==============================================================================
virtual SampleType getLatencyInSamples() const = 0;
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();
}
AudioBlock<SampleType> getProcessedSamples (size_t numSamples)
{
return AudioBlock<SampleType> (buffer).getSubBlock (0, numSamples);
}
virtual void processSamplesUp (const AudioBlock<const SampleType>&) = 0;
virtual void processSamplesDown (AudioBlock<SampleType>&) = 0;
AudioBuffer<SampleType> buffer;
size_t numChannels, factor;
};
//==============================================================================
template <typename SampleType>
struct OversamplingDummy final : public Oversampling<SampleType>::OversamplingStage
{
using ParentType = typename Oversampling<SampleType>::OversamplingStage;
OversamplingDummy (size_t numChans) : ParentType (numChans, 1) {}
//==============================================================================
SampleType getLatencyInSamples() const override
{
return 0;
}
void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override
{
jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
for (size_t channel = 0; channel < inputBlock.getNumChannels(); ++channel)
ParentType::buffer.copyFrom (static_cast<int> (channel), 0,
inputBlock.getChannelPointer (channel), static_cast<int> (inputBlock.getNumSamples()));
}
void processSamplesDown (AudioBlock<SampleType>& outputBlock) override
{
jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
outputBlock.copyFrom (ParentType::getProcessedSamples (outputBlock.getNumSamples()));
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversamplingDummy)
};
//==============================================================================
template <typename SampleType>
struct Oversampling2TimesEquirippleFIR final : public Oversampling<SampleType>::OversamplingStage
{
using ParentType = typename Oversampling<SampleType>::OversamplingStage;
Oversampling2TimesEquirippleFIR (size_t numChans,
SampleType normalisedTransitionWidthUp,
SampleType stopbandAmplitudedBUp,
SampleType normalisedTransitionWidthDown,
SampleType stopbandAmplitudedBDown)
: ParentType (numChans, 2)
{
coefficientsUp = *FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);
coefficientsDown = *FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);
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));
}
//==============================================================================
SampleType getLatencyInSamples() const override
{
return static_cast<SampleType> (coefficientsUp.getFilterOrder() + coefficientsDown.getFilterOrder()) * 0.5f;
}
void reset() override
{
ParentType::reset();
stateUp.clear();
stateDown.clear();
stateDown2.clear();
position.fill (0);
}
void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override
{
jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::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 = ParentType::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 (AudioBlock<SampleType>& outputBlock) override
{
jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::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 = ParentType::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:
//==============================================================================
FIR::Coefficients<SampleType> coefficientsUp, coefficientsDown;
AudioBuffer<SampleType> stateUp, stateDown, stateDown2;
Array<size_t> position;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Oversampling2TimesEquirippleFIR)
};
//==============================================================================
template <typename SampleType>
struct Oversampling2TimesPolyphaseIIR final : public Oversampling<SampleType>::OversamplingStage
{
using ParentType = typename Oversampling<SampleType>::OversamplingStage;
Oversampling2TimesPolyphaseIIR (size_t numChans,
SampleType normalisedTransitionWidthUp,
SampleType stopbandAmplitudedBUp,
SampleType normalisedTransitionWidthDown,
SampleType stopbandAmplitudedBDown)
: ParentType (numChans, 2)
{
auto structureUp = FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);
auto coeffsUp = getCoefficients (structureUp);
latency = static_cast<SampleType> (-(coeffsUp.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants<double>::twoPi));
auto structureDown = FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);
auto 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.getObjectPointer (i)->coefficients[0]);
for (auto i = 1; i < structureUp.delayedPath.size(); ++i)
coefficientsUp.add (structureUp.delayedPath.getObjectPointer (i)->coefficients[0]);
for (auto i = 0; i < structureDown.directPath.size(); ++i)
coefficientsDown.add (structureDown.directPath.getObjectPointer (i)->coefficients[0]);
for (auto i = 1; i < structureDown.delayedPath.size(); ++i)
coefficientsDown.add (structureDown.delayedPath.getObjectPointer (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));
}
//==============================================================================
SampleType getLatencyInSamples() const override
{
return latency;
}
void reset() override
{
ParentType::reset();
v1Up.clear();
v1Down.clear();
delayDown.fill (0);
}
void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override
{
jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::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 = ParentType::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;
}
}
#if JUCE_DSP_ENABLE_SNAP_TO_ZERO
snapToZero (true);
#endif
}
void processSamplesDown (AudioBlock<SampleType>& outputBlock) override
{
jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::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 = ParentType::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);
}
#if JUCE_DSP_ENABLE_SNAP_TO_ZERO
snapToZero (false);
#endif
}
void snapToZero (bool snapUpProcessing)
{
if (snapUpProcessing)
{
for (auto channel = 0; channel < ParentType::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 < ParentType::buffer.getNumChannels(); ++channel)
{
auto lv1 = v1Down.getWritePointer (channel);
auto numStages = coefficientsDown.size();
for (auto n = 0; n < numStages; ++n)
util::snapToZero (lv1[n]);
}
}
}
private:
//==============================================================================
IIR::Coefficients<SampleType> getCoefficients (typename FilterDesign<SampleType>::IIRPolyphaseAllpassStructure& structure) const
{
constexpr auto one = static_cast<SampleType> (1.0);
Polynomial<SampleType> numerator1 ({ one }), denominator1 ({ one }),
numerator2 ({ one }), denominator2 ({ one });
for (auto* i : structure.directPath)
{
auto coeffs = i->getRawCoefficients();
if (i->getFilterOrder() == 1)
{
numerator1 = numerator1 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));
denominator1 = denominator1.getProductWith (Polynomial<SampleType> ({ one, coeffs[2] }));
}
else
{
numerator1 = numerator1 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));
denominator1 = denominator1.getProductWith (Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));
}
}
for (auto* i : structure.delayedPath)
{
auto coeffs = i->getRawCoefficients();
if (i->getFilterOrder() == 1)
{
numerator2 = numerator2 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));
denominator2 = denominator2.getProductWith (Polynomial<SampleType> ({ one, coeffs[2] }));
}
else
{
numerator2 = numerator2 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));
denominator2 = denominator2.getProductWith (Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));
}
}
auto numeratorf1 = numerator1.getProductWith (denominator2);
auto numeratorf2 = numerator2.getProductWith (denominator1);
auto numerator = numeratorf1.getSumWith (numeratorf2);
auto denominator = denominator1.getProductWith (denominator2);
IIR::Coefficients<SampleType> coeffs;
coeffs.coefficients.clear();
auto inversion = one / denominator[0];
for (int i = 0; i <= numerator.getOrder(); ++i)
coeffs.coefficients.add (numerator[i] * inversion);
for (int 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)
: numChannels (newNumChannels)
{
jassert (numChannels > 0);
addDummyOversamplingStage();
}
template <typename SampleType>
Oversampling<SampleType>::Oversampling (size_t newNumChannels, size_t newFactor,
FilterType newType, bool isMaximumQuality,
bool useIntegerLatency)
: numChannels (newNumChannels), shouldUseIntegerLatency (useIntegerLatency)
{
jassert (isPositiveAndBelow (newFactor, 5) && numChannels > 0);
if (newFactor == 0)
{
addDummyOversamplingStage();
}
else if (newType == FilterType::filterHalfBandPolyphaseIIR)
{
for (size_t n = 0; n < newFactor; ++n)
{
auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.0f);
auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.0f);
auto gaindBStartUp = (isMaximumQuality ? -90.0f : -70.0f);
auto gaindBStartDown = (isMaximumQuality ? -75.0f : -60.0f);
auto gaindBFactorUp = (isMaximumQuality ? 10.0f : 8.0f);
auto gaindBFactorDown = (isMaximumQuality ? 10.0f : 8.0f);
addOversamplingStage (FilterType::filterHalfBandPolyphaseIIR,
twUp, gaindBStartUp + gaindBFactorUp * (float) n,
twDown, gaindBStartDown + gaindBFactorDown * (float) n);
}
}
else if (newType == FilterType::filterHalfBandFIREquiripple)
{
for (size_t n = 0; n < newFactor; ++n)
{
auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.0f);
auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.0f);
auto gaindBStartUp = (isMaximumQuality ? -90.0f : -70.0f);
auto gaindBStartDown = (isMaximumQuality ? -75.0f : -60.0f);
auto gaindBFactorUp = (isMaximumQuality ? 10.0f : 8.0f);
auto gaindBFactorDown = (isMaximumQuality ? 10.0f : 8.0f);
addOversamplingStage (FilterType::filterHalfBandFIREquiripple,
twUp, gaindBStartUp + gaindBFactorUp * (float) n,
twDown, gaindBStartDown + gaindBFactorDown * (float) n);
}
}
}
template <typename SampleType>
Oversampling<SampleType>::~Oversampling()
{
stages.clear();
}
//==============================================================================
template <typename SampleType>
void Oversampling<SampleType>::addDummyOversamplingStage()
{
stages.add (new OversamplingDummy<SampleType> (numChannels));
}
template <typename SampleType>
void Oversampling<SampleType>::addOversamplingStage (FilterType type,
float normalisedTransitionWidthUp,
float stopbandAmplitudedBUp,
float normalisedTransitionWidthDown,
float stopbandAmplitudedBDown)
{
if (type == FilterType::filterHalfBandPolyphaseIIR)
{
stages.add (new Oversampling2TimesPolyphaseIIR<SampleType> (numChannels,
normalisedTransitionWidthUp, stopbandAmplitudedBUp,
normalisedTransitionWidthDown, stopbandAmplitudedBDown));
}
else
{
stages.add (new Oversampling2TimesEquirippleFIR<SampleType> (numChannels,
normalisedTransitionWidthUp, stopbandAmplitudedBUp,
normalisedTransitionWidthDown, stopbandAmplitudedBDown));
}
factorOversampling *= 2;
}
template <typename SampleType>
void Oversampling<SampleType>::clearOversamplingStages()
{
stages.clear();
factorOversampling = 1u;
}
//==============================================================================
template <typename SampleType>
void Oversampling<SampleType>::setUsingIntegerLatency (bool useIntegerLatency) noexcept
{
shouldUseIntegerLatency = useIntegerLatency;
}
template <typename SampleType>
SampleType Oversampling<SampleType>::getLatencyInSamples() const noexcept
{
auto latency = getUncompensatedLatency();
return shouldUseIntegerLatency ? latency + fractionalDelay : latency;
}
template <typename SampleType>
SampleType Oversampling<SampleType>::getUncompensatedLatency() const noexcept
{
auto latency = static_cast<SampleType> (0);
size_t order = 1;
for (auto* stage : stages)
{
order *= stage->factor;
latency += stage->getLatencyInSamples() / static_cast<SampleType> (order);
}
return latency;
}
template <typename SampleType>
size_t Oversampling<SampleType>::getOversamplingFactor() const noexcept
{
return factorOversampling;
}
//==============================================================================
template <typename SampleType>
void Oversampling<SampleType>::initProcessing (size_t maximumNumberOfSamplesBeforeOversampling)
{
jassert (! stages.isEmpty());
auto currentNumSamples = maximumNumberOfSamplesBeforeOversampling;
for (auto* stage : stages)
{
stage->initProcessing (currentNumSamples);
currentNumSamples *= stage->factor;
}
ProcessSpec spec = { 0.0, (uint32) maximumNumberOfSamplesBeforeOversampling, (uint32) numChannels };
delay.prepare (spec);
updateDelayLine();
isReady = true;
reset();
}
template <typename SampleType>
void Oversampling<SampleType>::reset() noexcept
{
jassert (! stages.isEmpty());
if (isReady)
for (auto* stage : stages)
stage->reset();
delay.reset();
}
template <typename SampleType>
AudioBlock<SampleType> Oversampling<SampleType>::processSamplesUp (const AudioBlock<const SampleType>& inputBlock) noexcept
{
jassert (! stages.isEmpty());
if (! isReady)
return {};
auto* firstStage = stages.getUnchecked (0);
firstStage->processSamplesUp (inputBlock);
auto block = firstStage->getProcessedSamples (inputBlock.getNumSamples() * firstStage->factor);
for (int i = 1; i < stages.size(); ++i)
{
stages[i]->processSamplesUp (block);
block = stages[i]->getProcessedSamples (block.getNumSamples() * stages[i]->factor);
}
return block;
}
template <typename SampleType>
void Oversampling<SampleType>::processSamplesDown (AudioBlock<SampleType>& outputBlock) noexcept
{
jassert (! stages.isEmpty());
if (! isReady)
return;
auto currentNumSamples = outputBlock.getNumSamples();
for (int n = 0; n < stages.size() - 1; ++n)
currentNumSamples *= stages.getUnchecked (n)->factor;
for (int n = stages.size() - 1; n > 0; --n)
{
auto& stage = *stages.getUnchecked (n);
auto audioBlock = stages.getUnchecked (n - 1)->getProcessedSamples (currentNumSamples);
stage.processSamplesDown (audioBlock);
currentNumSamples /= stage.factor;
}
stages.getFirst()->processSamplesDown (outputBlock);
if (shouldUseIntegerLatency && fractionalDelay > static_cast<SampleType> (0.0))
{
auto context = ProcessContextReplacing<SampleType> (outputBlock);
delay.process (context);
}
}
template <typename SampleType>
void Oversampling<SampleType>::updateDelayLine()
{
auto latency = getUncompensatedLatency();
fractionalDelay = static_cast<SampleType> (1.0) - (latency - std::floor (latency));
if (approximatelyEqual (fractionalDelay, static_cast<SampleType> (1.0)))
fractionalDelay = static_cast<SampleType> (0.0);
else if (fractionalDelay < static_cast<SampleType> (0.618))
fractionalDelay += static_cast<SampleType> (1.0);
delay.setDelay (fractionalDelay);
}
template class Oversampling<float>;
template class Oversampling<double>;
} // namespace juce::dsp
juce::Array
Definition juce_Array.h:56
juce::Array::add
void add(const ElementType &newElement)
Definition juce_Array.h:418
juce::Array::clear
void clear()
Definition juce_Array.h:188
juce::AudioBuffer
Definition juce_AudioSampleBuffer.h:34
juce::dsp::AudioBlock
Definition juce_AudioBlock.h:68
juce::dsp::AudioBlock::getSubBlock
AudioBlock getSubBlock(size_t newOffset, size_t newLength) const noexcept
Definition juce_AudioBlock.h:369
juce::dsp::AudioBlock::getNumChannels
constexpr size_t getNumChannels() const noexcept
Definition juce_AudioBlock.h:233
juce::dsp::AudioBlock::getChannelPointer
SampleType * getChannelPointer(size_t channel) const noexcept
Definition juce_AudioBlock.h:239
juce::dsp::AudioBlock::copyFrom
AudioBlock & copyFrom(const AudioBlock< OtherSampleType > &src) noexcept
Definition juce_AudioBlock.h:312
juce::dsp::AudioBlock::getNumSamples
constexpr size_t getNumSamples() const noexcept
Definition juce_AudioBlock.h:236
juce::dsp::Oversampling
Definition juce_Oversampling.h:54
juce::dsp::Oversampling::processSamplesDown
void processSamplesDown(AudioBlock< SampleType > &outputBlock) noexcept
Definition juce_Oversampling.cpp:720
juce::dsp::Oversampling::FilterType
FilterType
Definition juce_Oversampling.h:58
juce::dsp::Oversampling::clearOversamplingStages
void clearOversamplingStages()
Definition juce_Oversampling.cpp:624
juce::dsp::Oversampling::initProcessing
void initProcessing(size_t maximumNumberOfSamplesBeforeOversampling)
Definition juce_Oversampling.cpp:667
juce::dsp::Oversampling::getLatencyInSamples
SampleType getLatencyInSamples() const noexcept
Definition juce_Oversampling.cpp:638
juce::dsp::Oversampling::processSamplesUp
AudioBlock< SampleType > processSamplesUp(const AudioBlock< const SampleType > &inputBlock) noexcept
Definition juce_Oversampling.cpp:699
juce::dsp::Oversampling::Oversampling
Oversampling(size_t numChannels=1)
Definition juce_Oversampling.cpp:531
juce::dsp::Oversampling::reset
void reset() noexcept
Definition juce_Oversampling.cpp:687
juce::dsp::Oversampling::addDummyOversamplingStage
void addDummyOversamplingStage()
Definition juce_Oversampling.cpp:595
juce::dsp::Oversampling::~Oversampling
~Oversampling()
Definition juce_Oversampling.cpp:588
juce::dsp::Oversampling::addOversamplingStage
void addOversamplingStage(FilterType, float normalisedTransitionWidthUp, float stopbandAmplitudedBUp, float normalisedTransitionWidthDown, float stopbandAmplitudedBDown)
Definition juce_Oversampling.cpp:601
juce::dsp::Oversampling::getOversamplingFactor
size_t getOversamplingFactor() const noexcept
Definition juce_Oversampling.cpp:660
juce::dsp::Polynomial
Definition juce_Polynomial.h:36
juce::dsp::Polynomial::getProductWith
Polynomial< FloatingType > getProductWith(const Polynomial< FloatingType > &other) const
Definition juce_Polynomial.h:133
juce::MathConstants::twoPi
static constexpr FloatType twoPi
Definition juce_MathsFunctions.h:144
juce::dsp::FIR::Coefficients
Definition juce_FIRFilter.h:214
juce::dsp::FilterDesign::designIIRLowpassHalfBandPolyphaseAllpassMethod
static IIRPolyphaseAllpassStructure designIIRLowpassHalfBandPolyphaseAllpassMethod(FloatType normalisedTransitionWidth, FloatType stopbandAmplitudedB)
Definition juce_FilterDesign.cpp:612
juce::dsp::FilterDesign::designFIRLowpassHalfBandEquirippleMethod
static FIRCoefficientsPtr designFIRLowpassHalfBandEquirippleMethod(FloatType normalisedTransitionWidth, FloatType amplitudedB)
Definition juce_FilterDesign.cpp:235
juce::dsp::FilterDesign::IIRPolyphaseAllpassStructure
Definition juce_FilterDesign.h:257
juce::dsp::IIR::Coefficients
Definition juce_dsp/processors/juce_IIRFilter.h:124
juce::dsp::IIR::Coefficients::coefficients
Array< NumericType > coefficients
Definition juce_dsp/processors/juce_IIRFilter.h:269
juce::dsp::Oversampling2TimesEquirippleFIR
Definition juce_Oversampling.cpp:112
juce::dsp::Oversampling2TimesPolyphaseIIR
Definition juce_Oversampling.cpp:264
juce::dsp::OversamplingDummy
Definition juce_Oversampling.cpp:72
juce::dsp::Oversampling::OversamplingStage
Definition juce_Oversampling.cpp:34
juce::dsp::ProcessContextReplacing
Definition juce_ProcessContext.h:89
juce::dsp::ProcessSpec
Definition juce_ProcessContext.h:36