Bug 1265408 - Use blink IIRFilterNode tests; r=padenot
authorDan Minor <dminor@mozilla.com>
Fri, 06 May 2016 15:07:11 -0400
changeset 300893 492d7b059416cd528596516fe727d55a9635b4aa
parent 300892 49a685db15355f7a404ecf0f50938850981a4663
child 300894 021ffc7c02e67aaf8d8afaea80403450923f44a6
push id78119
push userdminor@mozilla.com
push dateTue, 07 Jun 2016 16:03:45 +0000
treeherdermozilla-inbound@021ffc7c02e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1265408
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1265408 - Use blink IIRFilterNode tests; r=padenot MozReview-Commit-ID: 972FZ6lC7vr
dom/media/webaudio/moz.build
dom/media/webaudio/test/blink/iirfilter-getFrequencyResponse.html
dom/media/webaudio/test/blink/iirfilter.html
dom/media/webaudio/test/blink/mochitest.ini
dom/media/webaudio/test/blink/test_iirFilterNode.html
dom/media/webaudio/test/blink/test_iirFilterNodeGetFrequencyResponse.html
--- a/dom/media/webaudio/moz.build
+++ b/dom/media/webaudio/moz.build
@@ -7,16 +7,17 @@
 with Files('*'):
     BUG_COMPONENT = ('Core', 'Web Audio')
 
 DIRS += ['blink']
 
 TEST_DIRS += ['compiledtest']
 
 MOCHITEST_MANIFESTS += [
+    'test/blink/mochitest.ini',
     'test/mochitest.ini',
 ]
 
 TEST_HARNESS_FILES.testing.mochitest.tests.dom.media.webaudio.test.blink += [
     'test/blink/audio-testing.js',
     'test/blink/convolution-testing.js',
     'test/blink/panner-model-testing.js',
 ]
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/test/blink/mochitest.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+tags=msg
+tags = webaudio
+subsuite = media
+skip-if = ((buildapp == 'b2g') && (toolkit != 'gonk' || debug)) #b2g-debug,b2g-desktop(bug 916135)
+support-files =
+  biquad-filters.js
+  ../webaudio.js
+
+[test_iirFilterNode.html]
+[test_iirFilterNodeGetFrequencyResponse.html]
rename from dom/media/webaudio/test/blink/iirfilter.html
rename to dom/media/webaudio/test/blink/test_iirFilterNode.html
--- a/dom/media/webaudio/test/blink/iirfilter.html
+++ b/dom/media/webaudio/test/blink/test_iirFilterNode.html
@@ -1,574 +1,467 @@
-<!doctype html>
+<!DOCTYPE HTML>
 <html>
-  <head>
-    <title>Test Basic IIRFilterNode Operation</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/biquad-filters.js"></script>
-  </head>
+<head>
+  <title>Test IIRFilterNode GetFrequencyResponse</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <script type="text/javascript" src="biquad-filters.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
 
-  <body>
-    <script>
-      description("Test Basic IIRFilterNode Operation");
-      window.jsTestIsAsync = true;
-
-      var sampleRate = 48000;
-      var testDurationSec = 1;
-      var testFrames = testDurationSec * sampleRate;
-
-      var audit = Audit.createTaskRunner();
-
-      audit.defineTask("coefficient-normalization", function (done) {
-        // Test that the feedback coefficients are normalized.  Do this be creating two
-        // IIRFilterNodes.  One has normalized coefficients, and one doesn't.  Compute the
-        // difference and make sure they're the same.
-        var success = true;
-        var context = new OfflineAudioContext(2, testFrames, sampleRate);
+SimpleTest.waitForExplicitFinish();
 
-        // Use a simple impulse as the source.
-        var buffer = context.createBuffer(1, 1, sampleRate);
-        buffer.getChannelData(0)[0] = 1;
-        var source = context.createBufferSource();
-        source.buffer = buffer;
-
-        // Gain node for computing the difference between the filters.
-        var gain = context.createGain();
-        gain.gain.value = -1;
-
-        // The IIR filters.  Use a common feedforward array.
-        var ff = [1];
+addLoadEvent(function() {
+  var sampleRate = 48000;
+  var testDurationSec = 1;
+  var testFrames = testDurationSec * sampleRate;
 
-        var fb1 = [1, .9];
+  var testPromises = []
+  testPromises.push(function () {
+    // Test that the feedback coefficients are normalized.  Do this be creating two
+    // IIRFilterNodes.  One has normalized coefficients, and one doesn't.  Compute the
+    // difference and make sure they're the same.
+    var context = new OfflineAudioContext(2, testFrames, sampleRate);
 
-        var fb2 = new Float64Array(2);
-        // Scale the feedback coefficients by an arbitrary factor.
-        var coefScaleFactor = 2;
-        for (var k = 0; k < fb2.length; ++k) {
-          fb2[k] = coefScaleFactor * fb1[k];
-        }
-
-        var iir1;
-        var iir2;
-
-        success = Should("createIIRFilter with normalized coefficients", function () {
-          iir1 = context.createIIRFilter(ff, fb1);
-        }).notThrow() && success;
+    // Use a simple impulse as the source.
+    var buffer = context.createBuffer(1, 1, sampleRate);
+    buffer.getChannelData(0)[0] = 1;
+    var source = context.createBufferSource();
+    source.buffer = buffer;
 
-        success = Should("createIIRFilter with unnormalized coefficients", function () {
-          iir2 = context.createIIRFilter(ff, fb2);
-        }).notThrow() && success;
+    // Gain node for computing the difference between the filters.
+    var gain = context.createGain();
+    gain.gain.value = -1;
 
-        // Create the graph.  The output of iir1 (normalized coefficients) is channel 0, and the
-        // output of iir2 (unnormalized coefficients), with appropriate scaling, is channel 1.
-        var merger = context.createChannelMerger(2);
-        source.connect(iir1);
-        source.connect(iir2);
-        iir1.connect(merger, 0, 0);
-        iir2.connect(gain);
+    // The IIR filters.  Use a common feedforward array.
+    var ff = [1];
+
+    var fb1 = [1, .9];
 
-        // The gain for the gain node should be set to compensate for the scaling of the
-        // coefficients.  Since iir2 has scaled the coefficients by coefScaleFactor, the output is
-        // reduced by the same factor, so adjust the gain to scale the output of iir2 back up.
-        gain.gain.value = coefScaleFactor;
-        gain.connect(merger, 0, 1);
-
-        merger.connect(context.destination);
+    var fb2 = new Float64Array(2);
+    // Scale the feedback coefficients by an arbitrary factor.
+    var coefScaleFactor = 2;
+    for (var k = 0; k < fb2.length; ++k) {
+      fb2[k] = coefScaleFactor * fb1[k];
+    }
 
-        source.start();
-
-        // Rock and roll!
-
-        context.startRendering().then(function (result) {
-          // Find the max amplitude of the result, which should be near zero.
-          var iir1Data = result.getChannelData(0);
-          var iir2Data = result.getChannelData(1);
+    var iir1 = context.createIIRFilter(ff, fb1);
+    var iir2 = context.createIIRFilter(ff, fb2);
 
-          // Threshold isn't exactly zero because the arithmetic is done differently between the
-          // IIRFilterNode and the BiquadFilterNode.
-          success = Should("Output of IIR filter with unnormalized coefficients", iir2Data)
-            .beCloseToArray(iir1Data, 2.1958e-38) && success;
-          if (success)
-            testPassed("IIRFilter coefficients correctly normalized.\n");
-          else
-            testFailed("IIRFilter coefficients not correctly normalized.\n");
-        }).then(done);
-      });
-
-      audit.defineTask("one-zero", function (done) {
-        // Create a simple 1-zero filter and compare with the expected output.
-        var context = new OfflineAudioContext(1, testFrames, sampleRate);
+    // Create the graph.  The output of iir1 (normalized coefficients) is channel 0, and the
+    // output of iir2 (unnormalized coefficients), with appropriate scaling, is channel 1.
+    var merger = context.createChannelMerger(2);
+    source.connect(iir1);
+    source.connect(iir2);
+    iir1.connect(merger, 0, 0);
+    iir2.connect(gain);
 
-        // Use a simple impulse as the source
-        var buffer = context.createBuffer(1, 1, sampleRate);
-        buffer.getChannelData(0)[0] = 1;
-        var source = context.createBufferSource();
-        source.buffer = buffer;
+    // The gain for the gain node should be set to compensate for the scaling of the
+    // coefficients.  Since iir2 has scaled the coefficients by coefScaleFactor, the output is
+    // reduced by the same factor, so adjust the gain to scale the output of iir2 back up.
+    gain.gain.value = coefScaleFactor;
+    gain.connect(merger, 0, 1);
 
-        // The filter is y(n) = 0.5*(x(n) + x(n-1)), a simple 2-point moving average.  This is
-        // rather arbitrary; keep it simple.
+    merger.connect(context.destination);
 
-        var iir = context.createIIRFilter([0.5, 0.5], [1]);
+    source.start();
 
-        // Create the graph
-        source.connect(iir);
-        iir.connect(context.destination);
+    // Rock and roll!
 
-        // Rock and roll!
-        source.start();
+    return context.startRendering().then(function (result) {
+      // Find the max amplitude of the result, which should be near zero.
+      var iir1Data = result.getChannelData(0);
+      var iir2Data = result.getChannelData(1);
 
-        context.startRendering().then(function (result) {
-          var actual = result.getChannelData(0);
-          var expected = new Float64Array(testFrames);
-          // The filter is a simple 2-point moving average of an impulse, so the first two values
-          // are non-zero and the rest are zero.
-          expected[0] = 0.5;
-          expected[1] = 0.5;
-          Should('IIR 1-zero output', actual).beCloseToArray(expected, 0);
-        }).then(done);
-      });
+      // Threshold isn't exactly zero because the arithmetic is done differently between the
+      // IIRFilterNode and the BiquadFilterNode.
+      compareChannels(iir1Data, iir2Data);
+    });
+  }());
 
-      audit.defineTask("one-pole", function (done) {
-        // Create a simple 1-pole filter and compare with the expected output.
-
-        // The filter is y(n) + c*y(n-1)= x(n).  The analytical response is (-c)^n, so choose a
-        // suitable number of frames to run the test for where the output isn't flushed to zero.
-        var c = 0.9;
-        var eps = 1e-20;
-        var duration = Math.floor(Math.log(eps) / Math.log(Math.abs(c)));
-        var context = new OfflineAudioContext(1, duration, sampleRate);
+  testPromises.push(function () {
+    // Create a simple 1-zero filter and compare with the expected output.
+    var context = new OfflineAudioContext(1, testFrames, sampleRate);
 
-        // Use a simple impulse as the source
-        var buffer = context.createBuffer(1, 1, sampleRate);
-        buffer.getChannelData(0)[0] = 1;
-        var source = context.createBufferSource();
-        source.buffer = buffer;
+    // Use a simple impulse as the source
+    var buffer = context.createBuffer(1, 1, sampleRate);
+    buffer.getChannelData(0)[0] = 1;
+    var source = context.createBufferSource();
+    source.buffer = buffer;
 
-        var iir = context.createIIRFilter([1], [1, c]);
-
-        // Create the graph
-        source.connect(iir);
-        iir.connect(context.destination);
-
-        // Rock and roll!
-        source.start();
+    // The filter is y(n) = 0.5*(x(n) + x(n-1)), a simple 2-point moving average.  This is
+    // rather arbitrary; keep it simple.
 
-        context.startRendering().then(function (result) {
-          var actual = result.getChannelData(0);
-          var expected = new Float64Array(actual.length);
+    var iir = context.createIIRFilter([0.5, 0.5], [1]);
 
-          // The filter is a simple 1-pole filter: y(n) = -c*y(n-k)+x(n), with an impulse as the
-          // input.
-          expected[0] = 1;
-          for (k = 1; k < testFrames; ++k) {
-            expected[k] = -c * expected[k-1];
-          }
+    // Create the graph
+    source.connect(iir);
+    iir.connect(context.destination);
 
-          // Threshold isn't exactly zero due to round-off in the single-precision IIRFilterNode
-          // computations versus the double-precision Javascript computations.
-          Should('IIR 1-pole output', actual, {verbose: true})
-            .beCloseToArray(expected, {relativeThreshold: 5.723e-8});
-        }).then(done);
-      });
+    // Rock and roll!
+    source.start();
 
-      // Return a function suitable for use as a defineTask function.  This function creates an
-      // IIRFilterNode equivalent to the specified BiquadFilterNode and compares the outputs.  The
-      // outputs from the two filters should be virtually identical.
-      function testWithBiquadFilter (filterType, errorThreshold, snrThreshold) {
-        return function (done) {
-          var context = new OfflineAudioContext(2, testFrames, sampleRate);
-
-          // Use a constant (step function) as the source
-          var buffer = createConstantBuffer(context, testFrames, 1);
-          var source = context.createBufferSource();
-          source.buffer = buffer;
+    return context.startRendering().then(function (result) {
+      var actual = result.getChannelData(0);
+      var expected = new Float64Array(testFrames);
+      // The filter is a simple 2-point moving average of an impulse, so the first two values
+      // are non-zero and the rest are zero.
+      expected[0] = 0.5;
+      expected[1] = 0.5;
+      compareChannels(actual, expected);
+    });
+  }());
 
-      
-          // Create the biquad.  Choose some rather arbitrary values for Q and gain for the biquad
-          // so that the shelf filters aren't identical.
-          var biquad = context.createBiquadFilter();
-          biquad.type = filterType;
-          biquad.Q.value = 10;
-          biquad.gain.value = 10;
+  testPromises.push(function () {
+    // Create a simple 1-pole filter and compare with the expected output.
 
-          // Create the equivalent IIR Filter node by computing the coefficients of the given biquad
-          // filter type.
-          var nyquist = sampleRate / 2;
-          var coef = createFilter(filterType,
-                                  biquad.frequency.value / nyquist,
-                                  biquad.Q.value,
-                                  biquad.gain.value);
-
-          var iir = context.createIIRFilter([coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
+    // The filter is y(n) + c*y(n-1)= x(n).  The analytical response is (-c)^n, so choose a
+    // suitable number of frames to run the test for where the output isn't flushed to zero.
+    var c = 0.9;
+    var eps = 1e-20;
+    var duration = Math.floor(Math.log(eps) / Math.log(Math.abs(c)));
+    var context = new OfflineAudioContext(1, duration, sampleRate);
 
-          var merger = context.createChannelMerger(2);
-          // Create the graph
-          source.connect(biquad);
-          source.connect(iir);
+    // Use a simple impulse as the source
+    var buffer = context.createBuffer(1, 1, sampleRate);
+    buffer.getChannelData(0)[0] = 1;
+    var source = context.createBufferSource();
+    source.buffer = buffer;
 
-          biquad.connect(merger, 0, 0);
-          iir.connect(merger, 0, 1);
+    var iir = context.createIIRFilter([1], [1, c]);
 
-          merger.connect(context.destination);
-
-          // Rock and roll!
-          source.start();
+    // Create the graph
+    source.connect(iir);
+    iir.connect(context.destination);
 
-          context.startRendering().then(function (result) {
-            // Find the max amplitude of the result, which should be near zero.
-            var expected = result.getChannelData(0);
-            var actual = result.getChannelData(1);
+    // Rock and roll!
+    source.start();
 
-            // On MacOSX, WebAudio uses an optimized Biquad implementation that is different from
-            // the implementation used for Linux and Windows.  This will cause the output to differ,
-            // even if the threshold passes.  Thus, only print out a very small number of elements
-            // of the array where we have tested that they are consistent.
-            Should("IIRFilter for Biquad " + filterType, actual, {
-                precision: 5,
-                verbose: true
-              })
-              .beCloseToArray(expected, errorThreshold);
+    return context.startRendering().then(function (result) {
+      var actual = result.getChannelData(0);
+      var expected = new Float64Array(actual.length);
 
-            var snr = 10*Math.log10(computeSNR(actual, expected));
-            Should("SNR for IIRFIlter for Biquad " + filterType, snr).beGreaterThanOrEqualTo(snrThreshold);
-          }).then(done);
-        };
+      // The filter is a simple 1-pole filter: y(n) = -c*y(n-k)+x(n), with an impulse as the
+      // input.
+      expected[0] = 1;
+      for (k = 1; k < testFrames; ++k) {
+        expected[k] = -c * expected[k-1];
       }
 
-      // Thresholds here are experimentally determined.
-      var biquadTestConfigs = [{
-        filterType: "lowpass",
-        snrThreshold: 91.222,
-        errorThreshold: {
-          relativeThreshold: 4.15e-5
-        }
-      }, {
-        filterType: "highpass",
-        snrThreshold: 107.246,
-        errorThreshold: {
-          absoluteThreshold: 2.9e-6,
-          relativeThreshold: 3e-5
-        }
-      }, {
-        filterType: "bandpass",
-        snrThreshold: 104.060,
-        errorThreshold: {
-          absoluteThreshold: 2e-7,
-          relativeThreshold: 8.7e-4
-        }
-      }, {
-        filterType: "notch",
-        snrThreshold: 91.312,
-        errorThreshold: {
-          absoluteThreshold: 0,
-          relativeThreshold: 4.22e-5
-        }
-      }, {
-        filterType: "allpass",
-        snrThreshold: 91.319,
-        errorThreshold: {
-          absoluteThreshold: 0,
-          relativeThreshold: 4.31e-5
-        }
-      }, {
-        filterType: "lowshelf",
-        snrThreshold: 90.609,
-        errorThreshold: {
-          absoluteThreshold: 0,
-          relativeThreshold: 2.98e-5
-        }
-      }, {
-        filterType: "highshelf",
-        snrThreshold: 103.159,
-        errorThreshold: {
-          absoluteThreshold: 0,
-          relativeThreshold: 1.24e-5
-        }
-      }, {
-        filterType: "peaking",
-        snrThreshold: 91.504,
-        errorThreshold: {
-          absoluteThreshold: 0,
-          relativeThreshold: 5.05e-5
-        }
-      }];
+      compareChannels(actual, expected);
+    });
+  }());
+
+  // This function creates an IIRFilterNode equivalent to the specified
+  // BiquadFilterNode and compares the outputs.  The
+  // outputs from the two filters should be virtually identical.
+  function testWithBiquadFilter(filterType) {
+    var context = new OfflineAudioContext(2, testFrames, sampleRate);
+
+    // Use a constant (step function) as the source
+    var buffer = context.createBuffer(1, testFrames, context.sampleRate);
+    for (var i = 0; i < testFrames; ++i) {
+      buffer.getChannelData(0)[i] = 1;
+    }
+    var source = context.createBufferSource();
+    source.buffer = buffer;
+
+    // Create the biquad.  Choose some rather arbitrary values for Q and gain for the biquad
+    // so that the shelf filters aren't identical.
+    var biquad = context.createBiquadFilter();
+    biquad.type = filterType;
+    biquad.Q.value = 10;
+    biquad.gain.value = 10;
+
+    // Create the equivalent IIR Filter node by computing the coefficients of the given biquad
+    // filter type.
+    var nyquist = sampleRate / 2;
+    var coef = createFilter(filterType,
+                            biquad.frequency.value / nyquist,
+                            biquad.Q.value,
+                            biquad.gain.value);
+
+    var iir = context.createIIRFilter([coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
+
+    var merger = context.createChannelMerger(2);
+    // Create the graph
+    source.connect(biquad);
+    source.connect(iir);
+
+    biquad.connect(merger, 0, 0);
+    iir.connect(merger, 0, 1);
+
+    merger.connect(context.destination);
+
+    // Rock and roll!
+    source.start();
+
+    return context.startRendering().then(function (result) {
+      // Find the max amplitude of the result, which should be near zero.
+      var expected = result.getChannelData(0);
+      var actual = result.getChannelData(1);
+      compareChannels(actual, expected);
+    });
+  }
+
+  biquadFilterTypes = ["lowpass", "highpass", "bandpass", "notch",
+                       "allpass", "lowshelf", "highshelf", "peaking"];
+
+  // Create a set of tasks based on biquadTestConfigs.
+  for (var i = 0; i < biquadFilterTypes.length; ++i) {
+    testPromises.push(testWithBiquadFilter(biquadFilterTypes[i]));
+  }
+
+  testPromises.push(function () {
+    // Multi-channel test.  Create a biquad filter and the equivalent IIR filter.  Filter the
+    // same multichannel signal and compare the results.
+    var nChannels = 3;
+    var context = new OfflineAudioContext(nChannels, testFrames, sampleRate);
+
+    // Create a set of oscillators as the multi-channel source.
+    var source = [];
 
-      // Create a set of tasks based on biquadTestConfigs.
-      for (k = 0; k < biquadTestConfigs.length; ++k) {
-        var config = biquadTestConfigs[k];
-        var name = k + ": " + config.filterType;
-        audit.defineTask(name, testWithBiquadFilter(config.filterType, config.errorThreshold, config.snrThreshold));
+    for (k = 0; k < nChannels; ++k) {
+      source[k] = context.createOscillator();
+      source[k].type = "sawtooth";
+      // The frequency of the oscillator is pretty arbitrary, but each oscillator should have a
+      // different frequency.
+      source[k].frequency.value = 100 + k * 100;
+    }
+
+    var merger = context.createChannelMerger(3);
+
+    var biquad = context.createBiquadFilter();
+
+    // Create the equivalent IIR Filter node.
+    var nyquist = sampleRate / 2;
+    var coef = createFilter(biquad.type,
+      biquad.frequency.value / nyquist,
+      biquad.Q.value,
+      biquad.gain.value);
+    var fb = [1, coef.a1, coef.a2];
+    var ff = [coef.b0, coef.b1, coef.b2];
+
+    var iir = context.createIIRFilter(ff, fb);
+    // Gain node to compute the difference between the IIR and biquad filter.
+    var gain = context.createGain();
+    gain.gain.value = -1;
+
+    // Create the graph.
+    for (k = 0; k < nChannels; ++k)
+      source[k].connect(merger, 0, k);
+
+    merger.connect(biquad);
+    merger.connect(iir);
+    iir.connect(gain);
+    biquad.connect(context.destination);
+    gain.connect(context.destination);
+
+    for (k = 0; k < nChannels; ++k)
+      source[k].start();
+
+    return context.startRendering().then(function (result) {
+      var errorThresholds = [3.7671e-5, 3.0071e-5, 2.6241e-5];
+
+      // Check the difference signal on each channel
+      for (channel = 0; channel < result.numberOfChannels; ++channel) {
+        // Find the max amplitude of the result, which should be near zero.
+        var data = result.getChannelData(channel);
+        var maxError = data.reduce(function(reducedValue, currentValue) {
+          return Math.max(reducedValue, Math.abs(currentValue));
+        });
+
+        ok(maxError <= errorThresholds[channel], "Max difference between IIR and Biquad on channel " + channel);
+      }
+    });
+  }());
+
+  testPromises.push(function () {
+    // Apply an IIRFilter to the given input signal.
+    //
+    // IIR filter in the time domain is
+    //
+    //   y[n] = sum(ff[k]*x[n-k], k, 0, M) - sum(fb[k]*y[n-k], k, 1, N)
+    //
+    function iirFilter(input, feedforward, feedback) {
+      // For simplicity, create an x buffer that contains the input, and a y buffer that contains
+      // the output.  Both of these buffers have an initial work space to implement the initial
+      // memory of the filter.
+      var workSize = Math.max(feedforward.length, feedback.length);
+      var x = new Float32Array(input.length + workSize);
+
+      // Float64 because we want to match the implementation that uses doubles to minimize
+      // roundoff.
+      var y = new Float64Array(input.length + workSize);
+
+      // Copy the input over.
+      for (var k = 0; k < input.length; ++k)
+        x[k + feedforward.length] = input[k];
+
+      // Run the filter
+      for (var n = 0; n < input.length; ++n) {
+        var index = n + workSize;
+        var yn = 0;
+        for (var k = 0; k < feedforward.length; ++k)
+          yn += feedforward[k] * x[index - k];
+        for (var k = 0; k < feedback.length; ++k)
+          yn -= feedback[k] * y[index - k];
+
+        y[index] = yn;
       }
 
-      audit.defineTask("multi-channel", function (done) {
-        // Multi-channel test.  Create a biquad filter and the equivalent IIR filter.  Filter the
-        // same multichannel signal and compare the results.
-        var nChannels = 3;
-        var context = new OfflineAudioContext(nChannels, testFrames, sampleRate);
-
-        // Create a set of oscillators as the multi-channel source.
-        var source = [];
+      return y.slice(workSize).map(Math.fround);
+    }
 
-        for (k = 0; k < nChannels; ++k) {
-          source[k] = context.createOscillator();
-          source[k].type = "sawtooth";
-          // The frequency of the oscillator is pretty arbitrary, but each oscillator should have a
-          // different frequency.
-          source[k].frequency.value = 100 + k * 100;
-        }
-
-        var merger = context.createChannelMerger(3);
-
-        var biquad = context.createBiquadFilter();
-
-        // Create the equivalent IIR Filter node.
-        var nyquist = sampleRate / 2;
-        var coef = createFilter(biquad.type,
-          biquad.frequency.value / nyquist,
-          biquad.Q.value,
-          biquad.gain.value);
-        var fb = [1, coef.a1, coef.a2];
-        var ff = [coef.b0, coef.b1, coef.b2];
+    // Cascade the two given biquad filters to create one IIR filter.
+    function cascadeBiquads(f1Coef, f2Coef) {
+      // The biquad filters are:
+      //
+      // f1 = (b10 + b11/z + b12/z^2)/(1 + a11/z + a12/z^2);
+      // f2 = (b20 + b21/z + b22/z^2)/(1 + a21/z + a22/z^2);
+      //
+      // To cascade them, multiply the two transforms together to get a fourth order IIR filter.
 
-        var iir = context.createIIRFilter(ff, fb);
-        // Gain node to compute the difference between the IIR and biquad filter.
-        var gain = context.createGain();
-        gain.gain.value = -1;
-
-        // Create the graph.
-        for (k = 0; k < nChannels; ++k)
-          source[k].connect(merger, 0, k);
-
-        merger.connect(biquad);
-        merger.connect(iir);
-        iir.connect(gain);
-        biquad.connect(context.destination);
-        gain.connect(context.destination);
+      var numProduct = [f1Coef.b0 * f2Coef.b0,
+        f1Coef.b0 * f2Coef.b1 + f1Coef.b1 * f2Coef.b0,
+        f1Coef.b0 * f2Coef.b2 + f1Coef.b1 * f2Coef.b1 + f1Coef.b2 * f2Coef.b0,
+        f1Coef.b1 * f2Coef.b2 + f1Coef.b2 * f2Coef.b1,
+        f1Coef.b2 * f2Coef.b2
+      ];
 
-        for (k = 0; k < nChannels; ++k)
-          source[k].start();
-
-        context.startRendering().then(function (result) {
-          var success = true;
-          var errorThresholds = [3.7671e-5, 3.0071e-5, 2.6241e-5];
+      var denProduct = [1,
+        f2Coef.a1 + f1Coef.a1,
+        f2Coef.a2 + f1Coef.a1 * f2Coef.a1 + f1Coef.a2,
+        f1Coef.a1 * f2Coef.a2 + f1Coef.a2 * f2Coef.a1,
+        f1Coef.a2 * f2Coef.a2
+      ];
 
-          // Check the difference signal on each channel
-          for (channel = 0; channel < result.numberOfChannels; ++channel) {
-            // Find the max amplitude of the result, which should be near zero.
-            var data = result.getChannelData(channel);
-            var maxError = data.reduce(function(reducedValue, currentValue) {
-              return Math.max(reducedValue, Math.abs(currentValue));
-            });
-
-            success = Should("Max difference between IIR and Biquad on channel " + channel,
-              maxError).beLessThanOrEqualTo(errorThresholds[channel]);
-          }
+      return {
+        ff: numProduct,
+        fb: denProduct
+      }
+    }
 
-          if (success) {
-            testPassed("IIRFilter correctly processed " + result.numberOfChannels +
-              "-channel input.");
-          } else {
-            testFailed("IIRFilter failed to correctly process " + result.numberOfChannels +
-              "-channel input.");
-          }
-        }).then(done);
-      });
+    // Find the magnitude of the root of the quadratic that has the maximum magnitude.
+    //
+    // The quadratic is z^2 + a1 * z + a2 and we want the root z that has the largest magnitude.
+    function largestRootMagnitude(a1, a2) {
+      var discriminant = a1 * a1 - 4 * a2;
+      if (discriminant < 0) {
+        // Complex roots:  -a1/2 +/- i*sqrt(-d)/2.  Thus the magnitude of each root is the same
+        // and is sqrt(a1^2/4 + |d|/4)
+        var d = Math.sqrt(-discriminant);
+        return Math.hypot(a1 / 2, d / 2);
+      } else {
+        // Real roots
+        var d = Math.sqrt(discriminant);
+        return Math.max(Math.abs((-a1 + d) / 2), Math.abs((-a1 - d) / 2));
+      }
+    }
 
-      // Apply an IIRFilter to the given input signal.
-      //
-      // IIR filter in the time domain is
-      //
-      //   y[n] = sum(ff[k]*x[n-k], k, 0, M) - sum(fb[k]*y[n-k], k, 1, N)
-      //
-      function iirFilter(input, feedforward, feedback) {
-        // For simplicity, create an x buffer that contains the input, and a y buffer that contains
-        // the output.  Both of these buffers have an initial work space to implement the initial
-        // memory of the filter.
-        var workSize = Math.max(feedforward.length, feedback.length);
-        var x = new Float32Array(input.length + workSize);
-
-        // Float64 because we want to match the implementation that uses doubles to minimize
-        // roundoff.
-        var y = new Float64Array(input.length + workSize);
-
-        // Copy the input over.
-        for (var k = 0; k < input.length; ++k)
-          x[k + feedforward.length] = input[k];
+    // Cascade 2 lowpass biquad filters and compare that with the equivalent 4th order IIR
+    // filter.
 
-        // Run the filter
-        for (var n = 0; n < input.length; ++n) {
-          var index = n + workSize;
-          var yn = 0;
-          for (var k = 0; k < feedforward.length; ++k)
-            yn += feedforward[k] * x[index - k];
-          for (var k = 0; k < feedback.length; ++k)
-            yn -= feedback[k] * y[index - k];
+    var nyquist = sampleRate / 2;
+    // Compute the coefficients of a lowpass filter.
 
-          y[index] = yn;
-        }
-
-        return y.slice(workSize).map(Math.fround);
-      }
+    // First some preliminary stuff.  Compute the coefficients of the biquad.  This is used to
+    // figure out how frames to use in the test.
+    var biquadType = "lowpass";
+    var biquadCutoff = 350;
+    var biquadQ = 5;
+    var biquadGain = 1;
 
-      // Cascade the two given biquad filters to create one IIR filter.
-      function cascadeBiquads(f1Coef, f2Coef) {
-        // The biquad filters are:
-        //
-        // f1 = (b10 + b11/z + b12/z^2)/(1 + a11/z + a12/z^2);
-        // f2 = (b20 + b21/z + b22/z^2)/(1 + a21/z + a22/z^2);
-        //
-        // To cascade them, multiply the two transforms together to get a fourth order IIR filter.
+    var coef = createFilter(biquadType,
+      biquadCutoff / nyquist,
+      biquadQ,
+      biquadGain);
 
-        var numProduct = [f1Coef.b0 * f2Coef.b0,
-          f1Coef.b0 * f2Coef.b1 + f1Coef.b1 * f2Coef.b0,
-          f1Coef.b0 * f2Coef.b2 + f1Coef.b1 * f2Coef.b1 + f1Coef.b2 * f2Coef.b0,
-          f1Coef.b1 * f2Coef.b2 + f1Coef.b2 * f2Coef.b1,
-          f1Coef.b2 * f2Coef.b2
-        ];
+    // Cascade the biquads together to create an equivalent IIR filter.
+    var cascade = cascadeBiquads(coef, coef);
 
-        var denProduct = [1,
-          f2Coef.a1 + f1Coef.a1,
-          f2Coef.a2 + f1Coef.a1 * f2Coef.a1 + f1Coef.a2,
-          f1Coef.a1 * f2Coef.a2 + f1Coef.a2 * f2Coef.a1,
-          f1Coef.a2 * f2Coef.a2
-        ];
+    // Since we're cascading two identical biquads, the root of denominator of the IIR filter is
+    // repeated, so the root of the denominator with the largest magnitude occurs twice.  The
+    // impulse response of the IIR filter will be roughly c*(r*r)^n at time n, where r is the
+    // root of largest magnitude.  This approximation gets better as n increases.  We can use
+    // this to get a rough idea of when the response has died down to a small value.
 
-        return {
-          ff: numProduct,
-          fb: denProduct
-        }
-      }
+    // This is the value we will use to determine how many frames to render.  Rendering too many
+    // is a waste of time and also makes it hard to compare the actual result to the expected
+    // because the magnitudes are so small that they could be mostly round-off noise.
+    //
+    // Find magnitude of the root with largest magnitude
+    var rootMagnitude = largestRootMagnitude(coef.a1, coef.a2);
 
-      // Find the magnitude of the root of the quadratic that has the maximum magnitude.
-      //
-      // The quadratic is z^2 + a1 * z + a2 and we want the root z that has the largest magnitude.
-      function largestRootMagnitude(a1, a2) {
-        var discriminant = a1 * a1 - 4 * a2;
-        if (discriminant < 0) {
-          // Complex roots:  -a1/2 +/- i*sqrt(-d)/2.  Thus the magnitude of each root is the same
-          // and is sqrt(a1^2/4 + |d|/4)
-          var d = Math.sqrt(-discriminant);
-          return Math.hypot(a1 / 2, d / 2);
-        } else {
-          // Real roots
-          var d = Math.sqrt(discriminant);
-          return Math.max(Math.abs((-a1 + d) / 2), Math.abs((-a1 - d) / 2));
-        }
-      }
+    // Find n such that |r|^(2*n) <= eps.  That is, n = log(eps)/(2*log(r)).  Somewhat
+    // arbitrarily choose eps = 1e-20;
+    var eps = 1e-20;
+    var framesForTest = Math.floor(Math.log(eps) / (2 * Math.log(rootMagnitude)));
 
-      audit.defineTask("4th-order-iir", function(done) {
-        // Cascade 2 lowpass biquad filters and compare that with the equivalent 4th order IIR
-        // filter.
-
-        var nyquist = sampleRate / 2;
-        // Compute the coefficients of a lowpass filter.
+    // We're ready to create the graph for the test.  The offline context has two channels:
+    // channel 0 is the expected (cascaded biquad) result and channel 1 is the actual IIR filter
+    // result.
+    var context = new OfflineAudioContext(2, framesForTest, sampleRate);
 
-        // First some preliminary stuff.  Compute the coefficients of the biquad.  This is used to
-        // figure out how frames to use in the test.
-        var biquadType = "lowpass";
-        var biquadCutoff = 350;
-        var biquadQ = 5;
-        var biquadGain = 1;
-
-        var coef = createFilter(biquadType,
-          biquadCutoff / nyquist,
-          biquadQ,
-          biquadGain);
-
-        // Cascade the biquads together to create an equivalent IIR filter.
-        var cascade = cascadeBiquads(coef, coef);
+    // Use a simple impulse with a large (arbitrary) amplitude as the source
+    var amplitude = 1;
+    var buffer = context.createBuffer(1, testFrames, sampleRate);
+    buffer.getChannelData(0)[0] = amplitude;
+    var source = context.createBufferSource();
+    source.buffer = buffer;
 
-        // Since we're cascading two identical biquads, the root of denominator of the IIR filter is
-        // repeated, so the root of the denominator with the largest magnitude occurs twice.  The
-        // impulse response of the IIR filter will be roughly c*(r*r)^n at time n, where r is the
-        // root of largest magnitude.  This approximation gets better as n increases.  We can use
-        // this to get a rough idea of when the response has died down to a small value.
+    // Create the two biquad filters.  Doesn't really matter what, but for simplicity we choose
+    // identical lowpass filters with the same parameters.
+    var biquad1 = context.createBiquadFilter();
+    biquad1.type = biquadType;
+    biquad1.frequency.value = biquadCutoff;
+    biquad1.Q.value = biquadQ;
 
-        // This is the value we will use to determine how many frames to render.  Rendering too many
-        // is a waste of time and also makes it hard to compare the actual result to the expected
-        // because the magnitudes are so small that they could be mostly round-off noise.
-        //
-        // Find magnitude of the root with largest magnitude
-        var rootMagnitude = largestRootMagnitude(coef.a1, coef.a2);
+    var biquad2 = context.createBiquadFilter();
+    biquad2.type = biquadType;
+    biquad2.frequency.value = biquadCutoff;
+    biquad2.Q.value = biquadQ;
 
-        // Find n such that |r|^(2*n) <= eps.  That is, n = log(eps)/(2*log(r)).  Somewhat
-        // arbitrarily choose eps = 1e-20;
-        var eps = 1e-20;
-        var framesForTest = Math.floor(Math.log(eps) / (2 * Math.log(rootMagnitude)));
-
-        // We're ready to create the graph for the test.  The offline context has two channels:
-        // channel 0 is the expected (cascaded biquad) result and channel 1 is the actual IIR filter
-        // result.
-        var context = new OfflineAudioContext(2, framesForTest, sampleRate);
+    var iir = context.createIIRFilter(cascade.ff, cascade.fb);
 
-        // Use a simple impulse with a large (arbitrary) amplitude as the source
-        var amplitude = 1;
-        var buffer = context.createBuffer(1, testFrames, sampleRate);
-        buffer.getChannelData(0)[0] = amplitude;
-        var source = context.createBufferSource();
-        source.buffer = buffer;
+    // Create the merger to get the signals into multiple channels
+    var merger = context.createChannelMerger(2);
 
-        // Create the two biquad filters.  Doesn't really matter what, but for simplicity we choose
-        // identical lowpass filters with the same parameters.
-        var biquad1 = context.createBiquadFilter();
-        biquad1.type = biquadType;
-        biquad1.frequency.value = biquadCutoff;
-        biquad1.Q.value = biquadQ;
+    // Create the graph, filtering the source through two biquads.
+    source.connect(biquad1);
+    biquad1.connect(biquad2);
+    biquad2.connect(merger, 0, 0);
 
-        var biquad2 = context.createBiquadFilter();
-        biquad2.type = biquadType;
-        biquad2.frequency.value = biquadCutoff;
-        biquad2.Q.value = biquadQ;
+    source.connect(iir);
+    iir.connect(merger, 0, 1);
 
-        var iir = context.createIIRFilter(cascade.ff, cascade.fb);
-
-        // Create the merger to get the signals into multiple channels
-        var merger = context.createChannelMerger(2);
+    merger.connect(context.destination);
 
-        // Create the graph, filtering the source through two biquads.
-        source.connect(biquad1);
-        biquad1.connect(biquad2);
-        biquad2.connect(merger, 0, 0);
+    // Now filter the source through the IIR filter.
+    var y = iirFilter(buffer.getChannelData(0), cascade.ff, cascade.fb);
 
-        source.connect(iir);
-        iir.connect(merger, 0, 1);
-
-        merger.connect(context.destination);
+    // Rock and roll!
+    source.start();
 
-        // Now filter the source through the IIR filter.
-        var y = iirFilter(buffer.getChannelData(0), cascade.ff, cascade.fb);
+    return context.startRendering().then(function(result) {
+      var expected = result.getChannelData(0);
+      var actual = result.getChannelData(1);
 
-        // Rock and roll!
-        source.start();
+      compareChannels(actual, expected);
 
-        context.startRendering().then(function(result) {
-          var expected = result.getChannelData(0);
-          var actual = result.getChannelData(1);
+    });
+  }());
 
-          Should("4-th order IIRFilter (biquad ref)",
-              actual, {
-                verbose: true,
-                precision: 5
-              })
-            .beCloseToArray(expected, {
-              // Thresholds experimentally determined.
-              absoluteThreshold: 8.4e-8,
-              relativeThreshold: 5e-7,
-            });
-
-          var snr = 10*Math.log10(computeSNR(actual, expected));
-          Should("SNR of 4-th order IIRFilter (biquad ref)", snr)
-            .beGreaterThanOrEqualTo(110.684);
-        }).then(done);
-      });
-
-      audit.defineTask("finish", function (done) {
-        finishJSTest();
-        done();
-      });
-
-      audit.runTasks();
-      successfullyParsed = true;
-    </script>
-  </body>
+  // Wait for all tests
+  Promise.all(testPromises).then(function () {
+    SimpleTest.finish();
+  }, function () {
+    SimpleTest.finish();
+  });
+});
+</script>
+</pre>
+</body>
 </html>
rename from dom/media/webaudio/test/blink/iirfilter-getFrequencyResponse.html
rename to dom/media/webaudio/test/blink/test_iirFilterNodeGetFrequencyResponse.html
--- a/dom/media/webaudio/test/blink/iirfilter-getFrequencyResponse.html
+++ b/dom/media/webaudio/test/blink/test_iirFilterNodeGetFrequencyResponse.html
@@ -1,132 +1,97 @@
-<!doctype html>
+<!DOCTYPE HTML>
 <html>
-  <head>
-    <title>Test IIRFilter getFrequencyResponse() functionality</title>
-    <script src="../resources/js-test.js"></script>
-    <script src="resources/compatibility.js"></script>
-    <script src="resources/audio-testing.js"></script>
-    <script src="resources/biquad-filters.js"></script>
-  </head>
-
-  <body>
-    <script>
-      description("Test IIRFilter getFrequencyResponse() functionality");
-      window.jsTestIsAsync = true;
-
-      var sampleRate = 48000;
-      // Some short duration; we're not actually looking at the rendered output.
-      var testDurationSec = 0.01;
-
-      // Number of frequency samples to take.
-      var numberOfFrequencies = 1000;
-
-      var audit = Audit.createTaskRunner();
-
-
-      // Compute a set of linearly spaced frequencies.
-      function createFrequencies(nFrequencies, sampleRate)
-      {
-          var frequencies = new Float32Array(nFrequencies);
-          var nyquist = sampleRate / 2;
-          var freqDelta = nyquist / nFrequencies;
+<head>
+  <title>Test IIRFilterNode GetFrequencyResponse</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <script type="text/javascript" src="biquad-filters.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  // Modified from WebKit/LayoutTests/webaudio/iirfilter-getFrequencyResponse.html
+  var sampleRate = 48000;
+  var testDurationSec = 0.01;
 
-          for (var k = 0; k < nFrequencies; ++k) {
-              frequencies[k] = k * freqDelta;
-          }
+  // Compute a set of linearly spaced frequencies.
+  function createFrequencies(nFrequencies, sampleRate)
+  {
+    var frequencies = new Float32Array(nFrequencies);
+    var nyquist = sampleRate / 2;
+    var freqDelta = nyquist / nFrequencies;
 
-          return frequencies;
-      }
+    for (var k = 0; k < nFrequencies; ++k) {
+        frequencies[k] = k * freqDelta;
+    }
 
-      audit.defineTask("1-pole IIR", function (done) {
-        var context = new OfflineAudioContext(1, testDurationSec * sampleRate, sampleRate);
+    return frequencies;
+  }
 
-        var iir = context.createIIRFilter([1], [1, -0.9]);
-        var frequencies = createFrequencies(numberOfFrequencies, context.sampleRate);
-        
-        var iirMag = new Float32Array(numberOfFrequencies);
-        var iirPhase = new Float32Array(numberOfFrequencies);
-        var trueMag = new Float32Array(numberOfFrequencies);
-        var truePhase = new Float32Array(numberOfFrequencies);
+  // Number of frequency samples to take.
+  var numberOfFrequencies = 1000;
+
+  var context = new OfflineAudioContext(1, testDurationSec * sampleRate, sampleRate);
+
+  var frequencies = createFrequencies(numberOfFrequencies, context.sampleRate);
 
-        // The IIR filter is
-        //   H(z) = 1/(1 - 0.9*z^(-1)).
-        //
-        // The frequency response is
-        //   H(exp(j*w)) = 1/(1 - 0.9*exp(-j*w)).
-        //
-        // Thus, the magnitude is
-        //   |H(exp(j*w))| = 1/sqrt(1.81-1.8*cos(w)).
-        //
-        // The phase is
-        //   arg(H(exp(j*w)) = atan(0.9*sin(w)/(.9*cos(w)-1))
+  // 1-Pole IIR Filter
+  var iir = context.createIIRFilter([1], [1, -0.9]);
 
-        var frequencyScale = Math.PI / (sampleRate / 2);
+  var iirMag = new Float32Array(numberOfFrequencies);
+  var iirPhase = new Float32Array(numberOfFrequencies);
+  var trueMag = new Float32Array(numberOfFrequencies);
+  var truePhase = new Float32Array(numberOfFrequencies);
 
-        for (var k = 0; k < frequencies.length; ++k) {
-          var omega = frequencyScale * frequencies[k];
-          trueMag[k] = 1/Math.sqrt(1.81-1.8*Math.cos(omega));
-          truePhase[k] = Math.atan(0.9 * Math.sin(omega) / (0.9 * Math.cos(omega) - 1));
-        }
-
-        iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
-
-        var success = true;
+  // The IIR filter is
+  //   H(z) = 1/(1 - 0.9*z^(-1)).
+  //
+  // The frequency response is
+  //   H(exp(j*w)) = 1/(1 - 0.9*exp(-j*w)).
+  //
+  // Thus, the magnitude is
+  //   |H(exp(j*w))| = 1/sqrt(1.81-1.8*cos(w)).
+  //
+  // The phase is
+  //   arg(H(exp(j*w)) = atan(0.9*sin(w)/(.9*cos(w)-1))
 
-        // Thresholds were experimentally determined.
-        success = Should("1-pole IIR Magnitude Response", iirMag).beCloseToArray(trueMag, 2.8611e-6);
-        success = Should("1-pole IIR Phase Response", iirPhase).beCloseToArray(truePhase, 1.7882e-7)
-          && success;
-        if (success)
-          testPassed("1-pole IIR response matched expected response.\n");
-        else
-          testFailed("1-pole IIR response did not match expected response.\n");
+  var frequencyScale = Math.PI / (sampleRate / 2);
 
-        done();
-      });
+  for (var k = 0; k < frequencies.length; ++k) {
+    var omega = frequencyScale * frequencies[k];
+    trueMag[k] = 1/Math.sqrt(1.81-1.8*Math.cos(omega));
+    truePhase[k] = Math.atan(0.9 * Math.sin(omega) / (0.9 * Math.cos(omega) - 1));
+  }
 
-      audit.defineTask("compare IIR and biquad", function(done) {
-        // Create an IIR filter equivalent to the biquad filter. Compute the frequency response for
-        // both and verify that they are the same.
-        var context = new OfflineAudioContext(1, testDurationSec * sampleRate, sampleRate);
-
-        var biquad = context.createBiquadFilter();
-        var coef = createFilter(biquad.type,
-          biquad.frequency.value / (context.sampleRate / 2),
-          biquad.Q.value,
-          biquad.gain.value);
+  iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
+  compareChannels(iirMag, trueMag);
+  compareChannels(iirPhase, truePhase);
 
-        var iir = context.createIIRFilter([coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
-
-        var frequencies = createFrequencies(numberOfFrequencies, context.sampleRate);
-        var biquadMag = new Float32Array(numberOfFrequencies);
-        var biquadPhase = new Float32Array(numberOfFrequencies);
-        var iirMag = new Float32Array(numberOfFrequencies);
-        var iirPhase = new Float32Array(numberOfFrequencies);
+  // Compare IIR and Biquad Filter
+  // Create an IIR filter equivalent to the biquad filter. Compute the frequency response for both and verify that they are the same.
+  var biquad = context.createBiquadFilter();
+  var coef = createFilter(biquad.type,
+                          biquad.frequency.value / (context.sampleRate / 2),
+                          biquad.Q.value,
+                          biquad.gain.value);
 
-        biquad.getFrequencyResponse(frequencies, biquadMag, biquadPhase);
-        iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
-
-        var success = true;
-
-        // Thresholds were experimentally determined.
-        success = Should("IIR Magnitude Response", iirMag).beCloseToArray(biquadMag, 2.7419e-5);
-        success = Should("IIR Phase Response", iirPhase).beCloseToArray(biquadPhase, 2.7657e-5) && success;
+  var iir = context.createIIRFilter([coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
 
-        if (success)
-          testPassed("IIR response matched equivalent " + biquad.type + " Biquad response.\n");
-        else
-          testFailed("IIR response did not equivalent " + biquad.type + " Biquad response.\n");
-
-        done();
-      });
+  var biquadMag = new Float32Array(numberOfFrequencies);
+  var biquadPhase = new Float32Array(numberOfFrequencies);
+  var iirMag = new Float32Array(numberOfFrequencies);
+  var iirPhase = new Float32Array(numberOfFrequencies);
 
-      audit.defineTask("finish", function (done) {
-        finishJSTest();
-        done();
-      });
+  biquad.getFrequencyResponse(frequencies, biquadMag, biquadPhase);
+  iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
+  compareChannels(iirMag, biquadMag);
+  compareChannels(iirPhase, biquadPhase);
 
-      audit.runTasks();
-      successfullyParsed = true;
-    </script>
-  </body>
+  SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
 </html>