From 2b6abdb28dbc796f656ee6788a20018ca1d844a3 Mon Sep 17 00:00:00 2001 From: Dan Minor Date: Thu, 12 May 2016 09:15:18 -0400 Subject: [PATCH] Bug 1265408 - Avoid complex division in getFrequencyResponse; r=padenot Using the division operator on std::complex values fails on our linux64 AWS test machines, yielding infinities and NaNs for valid inputs. Presumably this could affect machines in the wild as well. This patch removes the use of the division operator and replaces it with real operations. MozReview-Commit-ID: 4s7xUf9ja0F --HG-- extra : rebase_source : cdfee7070a50eefbf8e50aee3993cf8993cd32b4 --- dom/media/webaudio/blink/Biquad.cpp | 16 ++++++++++++---- dom/media/webaudio/blink/IIRFilter.cpp | 10 +++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/dom/media/webaudio/blink/Biquad.cpp b/dom/media/webaudio/blink/Biquad.cpp index fbc4cf0776d1..8b7e17cec020 100644 --- a/dom/media/webaudio/blink/Biquad.cpp +++ b/dom/media/webaudio/blink/Biquad.cpp @@ -175,7 +175,7 @@ void Biquad::setHighpassParams(double cutoff, double resonance) void Biquad::setNormalizedCoefficients(double b0, double b1, double b2, double a0, double a1, double a2) { double a0Inverse = 1 / a0; - + m_b0 = b0 * a0Inverse; m_b1 = b1 * a0Inverse; m_b2 = b2 * a0Inverse; @@ -376,7 +376,7 @@ void Biquad::setBandpassParams(double frequency, double Q) if (Q > 0) { double alpha = sin(w0) / (2 * Q); double k = cos(w0); - + double b0 = alpha; double b1 = 0; double b2 = -alpha; @@ -451,13 +451,21 @@ void Biquad::getFrequencyResponse(int nFrequencies, double b2 = m_b2; double a1 = m_a1; double a2 = m_a2; - + for (int k = 0; k < nFrequencies; ++k) { double omega = -M_PI * frequency[k]; Complex z = Complex(cos(omega), sin(omega)); Complex numerator = b0 + (b1 + b2 * z) * z; Complex denominator = Complex(1, 0) + (a1 + a2 * z) * z; - Complex response = numerator / denominator; + // Strangely enough, using complex division: + // e.g. Complex response = numerator / denominator; + // fails on our test machines, yielding infinities and NaNs, so we do + // things the long way here. + double n = norm(denominator); + double r = (real(numerator)*real(denominator) + imag(numerator)*imag(denominator)) / n; + double i = (imag(numerator)*real(denominator) - real(numerator)*imag(denominator)) / n; + std::complex response = std::complex(r, i); + magResponse[k] = static_cast(abs(response)); phaseResponse[k] = static_cast(atan2(imag(response), real(response))); } diff --git a/dom/media/webaudio/blink/IIRFilter.cpp b/dom/media/webaudio/blink/IIRFilter.cpp index 3bfafbce364b..94ec129c7376 100644 --- a/dom/media/webaudio/blink/IIRFilter.cpp +++ b/dom/media/webaudio/blink/IIRFilter.cpp @@ -129,7 +129,15 @@ void IIRFilter::getFrequencyResponse(int nFrequencies, const float* frequency, f std::complex numerator = evaluatePolynomial(m_feedforward->Elements(), zRecip, m_feedforward->Length() - 1); std::complex denominator = evaluatePolynomial(m_feedback->Elements(), zRecip, m_feedback->Length() - 1); - std::complex response = numerator / denominator; + // Strangely enough, using complex division: + // e.g. Complex response = numerator / denominator; + // fails on our test machines, yielding infinities and NaNs, so we do + // things the long way here. + double n = norm(denominator); + double r = (real(numerator)*real(denominator) + imag(numerator)*imag(denominator)) / n; + double i = (imag(numerator)*real(denominator) - real(numerator)*imag(denominator)) / n; + std::complex response = std::complex(r, i); + magResponse[k] = static_cast(abs(response)); phaseResponse[k] = static_cast(atan2(imag(response), real(response))); }