1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

IIRFilter: Fix potential divide by zero

This commit is contained in:
Anthony Nicholls 2023-08-18 15:40:42 +01:00
parent 2aff537ced
commit f2e03eade0
3 changed files with 101 additions and 83 deletions

View file

@ -60,6 +60,20 @@ public:
: minusInfinityDb;
}
/** Restricts a gain value based on a lower bound specified in dBFS.
This is useful if you want to make sure a gain value never reaches zero.
*/
template <typename Type>
static Type gainWithLowerBound (Type gain, Type lowerBoundDb)
{
// You probably want to use a negative decibel value or the gain will
// be restricted to boosting only!
jassert (lowerBoundDb < (Type) 0.0);
return jmax ((Type) gain, Decibels::decibelsToGain (lowerBoundDb, lowerBoundDb - (Type) 1.0));
}
//==============================================================================
/** Converts a decibel reading to a string.

View file

@ -23,6 +23,8 @@
namespace juce
{
constexpr auto minimumDecibels = -300.0f;
IIRCoefficients::IIRCoefficients() noexcept
{
zeromem (coefficients, sizeof (coefficients));
@ -44,7 +46,7 @@ IIRCoefficients& IIRCoefficients::operator= (const IIRCoefficients& other) noexc
IIRCoefficients::IIRCoefficients (double c1, double c2, double c3,
double c4, double c5, double c6) noexcept
{
auto a = 1.0 / c4;
const auto a = 1.0 / c4;
coefficients[0] = (float) (c1 * a);
coefficients[1] = (float) (c2 * a);
@ -67,9 +69,9 @@ IIRCoefficients IIRCoefficients::makeLowPass (double sampleRate,
jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
auto nSquared = n * n;
auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
const auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
const auto nSquared = n * n;
const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
return IIRCoefficients (c1,
c1 * 2.0,
@ -93,9 +95,9 @@ IIRCoefficients IIRCoefficients::makeHighPass (double sampleRate,
jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto n = std::tan (MathConstants<double>::pi * frequency / sampleRate);
auto nSquared = n * n;
auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
const auto n = std::tan (MathConstants<double>::pi * frequency / sampleRate);
const auto nSquared = n * n;
const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
return IIRCoefficients (c1,
c1 * -2.0,
@ -119,9 +121,9 @@ IIRCoefficients IIRCoefficients::makeBandPass (double sampleRate,
jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
auto nSquared = n * n;
auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
const auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
const auto nSquared = n * n;
const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
return IIRCoefficients (c1 * n / Q,
0.0,
@ -145,9 +147,9 @@ IIRCoefficients IIRCoefficients::makeNotchFilter (double sampleRate,
jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
auto nSquared = n * n;
auto c1 = 1.0 / (1.0 + n / Q + nSquared);
const auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
const auto nSquared = n * n;
const auto c1 = 1.0 / (1.0 + n / Q + nSquared);
return IIRCoefficients (c1 * (1.0 + nSquared),
2.0 * c1 * (1.0 - nSquared),
@ -171,9 +173,9 @@ IIRCoefficients IIRCoefficients::makeAllPass (double sampleRate,
jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
auto nSquared = n * n;
auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
const auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
const auto nSquared = n * n;
const auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
return IIRCoefficients (c1 * (1.0 - n / Q + nSquared),
c1 * 2.0 * (1.0 - nSquared),
@ -192,13 +194,13 @@ IIRCoefficients IIRCoefficients::makeLowShelf (double sampleRate,
jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto A = jmax (0.0f, std::sqrt (gainFactor));
auto aminus1 = A - 1.0;
auto aplus1 = A + 1.0;
auto omega = (MathConstants<double>::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate;
auto coso = std::cos (omega);
auto beta = std::sin (omega) * std::sqrt (A) / Q;
auto aminus1TimesCoso = aminus1 * coso;
const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, minimumDecibels));
const auto aminus1 = A - 1.0;
const auto aplus1 = A + 1.0;
const auto omega = (MathConstants<double>::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate;
const auto coso = std::cos (omega);
const auto beta = std::sin (omega) * std::sqrt (A) / Q;
const auto aminus1TimesCoso = aminus1 * coso;
return IIRCoefficients (A * (aplus1 - aminus1TimesCoso + beta),
A * 2.0 * (aminus1 - aplus1 * coso),
@ -217,13 +219,13 @@ IIRCoefficients IIRCoefficients::makeHighShelf (double sampleRate,
jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto A = jmax (0.0f, std::sqrt (gainFactor));
auto aminus1 = A - 1.0;
auto aplus1 = A + 1.0;
auto omega = (MathConstants<double>::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate;
auto coso = std::cos (omega);
auto beta = std::sin (omega) * std::sqrt (A) / Q;
auto aminus1TimesCoso = aminus1 * coso;
const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, minimumDecibels));
const auto aminus1 = A - 1.0;
const auto aplus1 = A + 1.0;
const auto omega = (MathConstants<double>::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate;
const auto coso = std::cos (omega);
const auto beta = std::sin (omega) * std::sqrt (A) / Q;
const auto aminus1TimesCoso = aminus1 * coso;
return IIRCoefficients (A * (aplus1 + aminus1TimesCoso + beta),
A * -2.0 * (aminus1 + aplus1 * coso),
@ -242,12 +244,12 @@ IIRCoefficients IIRCoefficients::makePeakFilter (double sampleRate,
jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
jassert (Q > 0.0);
auto A = jmax (0.0f, std::sqrt (gainFactor));
auto omega = (MathConstants<double>::twoPi * jmax (frequency, 2.0)) / sampleRate;
auto alpha = 0.5 * std::sin (omega) / Q;
auto c2 = -2.0 * std::cos (omega);
auto alphaTimesA = alpha * A;
auto alphaOverA = alpha / A;
const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, minimumDecibels));
const auto omega = (MathConstants<double>::twoPi * jmax (frequency, 2.0)) / sampleRate;
const auto alpha = 0.5 * std::sin (omega) / Q;
const auto c2 = -2.0 * std::cos (omega);
const auto alphaTimesA = alpha * A;
const auto alphaOverA = alpha / A;
return IIRCoefficients (1.0 + alphaTimesA,
c2,