Bug 1265408 - Add buffersAreZero to IIRFilter; r=karlt draft
authorDan Minor <dminor@mozilla.com>
Fri, 27 May 2016 06:59:37 -0400
changeset 372082 7baaf46f1f721c139aa9868b36b3b2c8cddee131
parent 370426 8f8b76191e295d471aa96083480ac7566d020549
child 372083 aab08a556fcb4ef7fc083d357fe8a55033d2d2c4
push id19434
push userdminor@mozilla.com
push dateFri, 27 May 2016 11:00:28 +0000
reviewerskarlt
bugs1265408
milestone49.0a1
Bug 1265408 - Add buffersAreZero to IIRFilter; r=karlt MozReview-Commit-ID: CM5x62GMXcj
dom/media/webaudio/blink/IIRFilter.cpp
dom/media/webaudio/blink/IIRFilter.h
--- a/dom/media/webaudio/blink/IIRFilter.cpp
+++ b/dom/media/webaudio/blink/IIRFilter.cpp
@@ -1,16 +1,19 @@
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "IIRFilter.h"
+#include "WebAudioUtils.h"
 
 #include <complex>
 
+using mozilla::dom::WebAudioUtils::FuzzyEqual;
+
 namespace blink {
 
 // The length of the memory buffers for the IIR filter.  This MUST be a power of two and must be
 // greater than the possible length of the filter coefficients.
 const int kBufferLength = 32;
 static_assert(kBufferLength >= IIRFilter::kMaxOrder + 1,
     "Internal IIR buffer length must be greater than maximum IIR Filter order.");
 
@@ -93,17 +96,23 @@ void IIRFilter::process(const float* sou
             yn -= feedback[k] * yBuffer[(m_bufferIndex - k) & (kBufferLength - 1)];
 
         // Save the current input and output values in the memory buffers for the next output.
         m_xBuffer[m_bufferIndex] = sourceP[n];
         m_yBuffer[m_bufferIndex] = yn;
 
         m_bufferIndex = (m_bufferIndex + 1) & (kBufferLength - 1);
 
-        destP[n] = yn;
+        // Avoid introducing a stream of subnormals
+        // TODO: Remove this code when Bug 1157635 is fixed.
+        if (yn == 0.0 || fabs(yn) >= FLT_MIN) {
+            destP[n] = yn;
+        } else {
+            destP[n] = 0.0;
+        }
     }
 }
 
 void IIRFilter::getFrequencyResponse(int nFrequencies, const float* frequency, float* magResponse, float* phaseResponse)
 {
     // Evaluate the z-transform of the filter at the given normalized frequencies from 0 to 1. (One
     // corresponds to the Nyquist frequency.)
     //
@@ -124,9 +133,29 @@ void IIRFilter::getFrequencyResponse(int
         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;
         magResponse[k] = static_cast<float>(abs(response));
         phaseResponse[k] = static_cast<float>(atan2(imag(response), real(response)));
     }
 }
 
+bool IIRFilter::buffersAreZero()
+{
+    double* xBuffer = m_xBuffer.Elements();
+    double* yBuffer = m_yBuffer.Elements();
+
+    for (size_t k = 0; k < m_feedforward->Length(); ++k) {
+        if (xBuffer[(m_bufferIndex - k) & (kBufferLength - 1)] != 0.0) {
+            return false;
+        }
+    }
+
+    for (size_t k = 0; k < m_feedback->Length(); ++k) {
+        if (yBuffer[(m_bufferIndex - k) & (kBufferLength - 1)] >= FLT_MIN) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 } // namespace blink
--- a/dom/media/webaudio/blink/IIRFilter.h
+++ b/dom/media/webaudio/blink/IIRFilter.h
@@ -21,16 +21,18 @@ public:
 
     void reset();
 
     void getFrequencyResponse(int nFrequencies,
         const float* frequency,
         float* magResponse,
         float* phaseResponse);
 
+    bool buffersAreZero();
+
 private:
     // Filter memory
     //
     // For simplicity, we assume |m_xBuffer| and |m_yBuffer| have the same length, and the length is
     // a power of two.  Since the number of coefficients has a fixed upper length, the size of
     // xBuffer and yBuffer is fixed. |m_xBuffer| holds the old input values and |m_yBuffer| holds
     // the old output values needed to compute the new output value.
     //