diff --git a/modules/juce_audio_basics/utilities/juce_Decibels.h b/modules/juce_audio_basics/utilities/juce_Decibels.h index e5eb802622..937cf0a6b7 100644 --- a/modules/juce_audio_basics/utilities/juce_Decibels.h +++ b/modules/juce_audio_basics/utilities/juce_Decibels.h @@ -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 + 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. diff --git a/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp b/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp index fedeb759ea..c1e32254db 100644 --- a/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp +++ b/modules/juce_audio_basics/utilities/juce_IIRFilter.cpp @@ -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::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::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::pi * frequency / sampleRate); - auto nSquared = n * n; - auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared); + const auto n = std::tan (MathConstants::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::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::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::pi * frequency / sampleRate); - auto nSquared = n * n; - auto c1 = 1.0 / (1.0 + n / Q + nSquared); + const auto n = 1.0 / std::tan (MathConstants::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::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::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::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::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::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::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::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::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, diff --git a/modules/juce_dsp/processors/juce_IIRFilter.cpp b/modules/juce_dsp/processors/juce_IIRFilter.cpp index 69f99417fc..37bed1e8fb 100644 --- a/modules/juce_dsp/processors/juce_IIRFilter.cpp +++ b/modules/juce_dsp/processors/juce_IIRFilter.cpp @@ -30,6 +30,8 @@ namespace dsp namespace IIR { +constexpr auto minimumDecibels = -300.0; + template std::array ArrayCoefficients::makeFirstOrderLowPass (double sampleRate, NumericType frequency) @@ -37,7 +39,7 @@ std::array ArrayCoefficients::makeFirstOrderLowPass jassert (sampleRate > 0.0); jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); return { { n, n, n + 1, n - 1 } }; } @@ -49,7 +51,7 @@ std::array ArrayCoefficients::makeFirstOrderHighPas jassert (sampleRate > 0.0); jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); return { { 1, -1, n + 1, n - 1 } }; } @@ -61,7 +63,7 @@ std::array ArrayCoefficients::makeFirstOrderAllPass jassert (sampleRate > 0.0); jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); return { { n - 1, n + 1, n + 1, n - 1 } }; } @@ -82,10 +84,10 @@ std::array ArrayCoefficients::makeLowPass (double s jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); return { { c1, c1 * 2, c1, 1, c1 * 2 * (1 - nSquared), @@ -108,10 +110,10 @@ std::array ArrayCoefficients::makeHighPass (double jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); + const auto n = std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); return { { c1, c1 * -2, c1, 1, c1 * 2 * (nSquared - 1), @@ -134,10 +136,10 @@ std::array ArrayCoefficients::makeBandPass (double jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); return { { c1 * n * invQ, 0, -c1 * n * invQ, 1, @@ -161,12 +163,12 @@ std::array ArrayCoefficients::makeNotch (double sam jassert (frequency > 0 && frequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0.0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + n * invQ + nSquared); - auto b0 = c1 * (1 + nSquared); - auto b1 = 2 * c1 * (1 - nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + n * invQ + nSquared); + const auto b0 = c1 * (1 + nSquared); + const auto b1 = 2 * c1 * (1 - nSquared); return { { b0, b1, b0, 1, b1, c1 * (1 - n * invQ + nSquared) } }; } @@ -187,12 +189,12 @@ std::array ArrayCoefficients::makeAllPass (double s jassert (frequency > 0 && frequency <= sampleRate * 0.5); jassert (Q > 0); - auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); - auto nSquared = n * n; - auto invQ = 1 / Q; - auto c1 = 1 / (1 + invQ * n + nSquared); - auto b0 = c1 * (1 - n * invQ + nSquared); - auto b1 = c1 * 2 * (1 - nSquared); + const auto n = 1 / std::tan (MathConstants::pi * frequency / static_cast (sampleRate)); + const auto nSquared = n * n; + const auto invQ = 1 / Q; + const auto c1 = 1 / (1 + invQ * n + nSquared); + const auto b0 = c1 * (1 - n * invQ + nSquared); + const auto b1 = c1 * 2 * (1 - nSquared); return { { b0, b1, 1, 1, b1, b0 } }; } @@ -207,13 +209,13 @@ std::array ArrayCoefficients::makeLowShelf (double jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5); jassert (Q > 0.0); - auto A = jmax (static_cast (0.0), std::sqrt (gainFactor)); - auto aminus1 = A - 1; - auto aplus1 = A + 1; - auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (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, (NumericType) minimumDecibels)); + const auto aminus1 = A - 1; + const auto aplus1 = A + 1; + const auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (sampleRate); + const auto coso = std::cos (omega); + const auto beta = std::sin (omega) * std::sqrt (A) / Q; + const auto aminus1TimesCoso = aminus1 * coso; return { { A * (aplus1 - aminus1TimesCoso + beta), A * 2 * (aminus1 - aplus1 * coso), @@ -233,13 +235,13 @@ std::array ArrayCoefficients::makeHighShelf (double jassert (cutOffFrequency > 0 && cutOffFrequency <= static_cast (sampleRate * 0.5)); jassert (Q > 0); - auto A = jmax (static_cast (0.0), std::sqrt (gainFactor)); - auto aminus1 = A - 1; - auto aplus1 = A + 1; - auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (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, (NumericType) minimumDecibels)); + const auto aminus1 = A - 1; + const auto aplus1 = A + 1; + const auto omega = (2 * MathConstants::pi * jmax (cutOffFrequency, static_cast (2.0))) / static_cast (sampleRate); + const auto coso = std::cos (omega); + const auto beta = std::sin (omega) * std::sqrt (A) / Q; + const auto aminus1TimesCoso = aminus1 * coso; return { { A * (aplus1 + aminus1TimesCoso + beta), A * -2 * (aminus1 + aplus1 * coso), @@ -260,12 +262,12 @@ std::array ArrayCoefficients::makePeakFilter (doubl jassert (Q > 0); jassert (gainFactor > 0); - auto A = jmax (static_cast (0.0), std::sqrt (gainFactor)); - auto omega = (2 * MathConstants::pi * jmax (frequency, static_cast (2.0))) / static_cast (sampleRate); - auto alpha = std::sin (omega) / (Q * 2); - auto c2 = -2 * std::cos (omega); - auto alphaTimesA = alpha * A; - auto alphaOverA = alpha / A; + const auto A = std::sqrt (Decibels::gainWithLowerBound (gainFactor, (NumericType) minimumDecibels)); + const auto omega = (2 * MathConstants::pi * jmax (frequency, static_cast (2.0))) / static_cast (sampleRate); + const auto alpha = std::sin (omega) / (Q * 2); + const auto c2 = -2 * std::cos (omega); + const auto alphaTimesA = alpha * A; + const auto alphaOverA = alpha / A; return { { 1 + alphaTimesA, c2, 1 - alphaTimesA, 1 + alphaOverA, c2, 1 - alphaOverA } }; }