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
This commit is contained in:
Dan Minor 2016-05-12 09:15:18 -04:00
parent 77a0cbd919
commit 2b6abdb28d
2 changed files with 21 additions and 5 deletions

View File

@ -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<double> response = std::complex<double>(r, i);
magResponse[k] = static_cast<float>(abs(response));
phaseResponse[k] = static_cast<float>(atan2(imag(response), real(response)));
}

View File

@ -129,7 +129,15 @@ void IIRFilter::getFrequencyResponse(int nFrequencies, const float* frequency, f
std::complex<double> numerator = evaluatePolynomial(m_feedforward->Elements(), zRecip, m_feedforward->Length() - 1);
std::complex<double> denominator = evaluatePolynomial(m_feedback->Elements(), zRecip, m_feedback->Length() - 1);
std::complex<double> 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<double> response = std::complex<double>(r, i);
magResponse[k] = static_cast<float>(abs(response));
phaseResponse[k] = static_cast<float>(atan2(imag(response), real(response)));
}