Bug 1265408 - Use blink IIRFilterNode tests; r=padenot
authorDan Minor <dminor@mozilla.com>
Fri, 06 May 2016 15:07:11 -0400
changeset 300933 492d7b059416cd528596516fe727d55a9635b4aa
parent 300932 49a685db15355f7a404ecf0f50938850981a4663
child 300934 021ffc7c02e67aaf8d8afaea80403450923f44a6
push id19599
push usercbook@mozilla.com
push dateWed, 08 Jun 2016 10:16:21 +0000
treeherderfx-team@81f4cc3f6f4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1265408
milestone50.0a1
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>