Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Unified Diff: third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html

Issue 2895963003: Apply layout-test-tidy to LayoutTests/webaudio (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
diff --git a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
index bee1559964bcad5d729947c688c1d7fcd927321a..4c6d573b14cbd1e8c788aeaa32772cb5dcfe0de3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
+++ b/third_party/WebKit/LayoutTests/webaudio/IIRFilter/iirfilter.html
@@ -1,75 +1,75 @@
-<!doctype html>
+<!DOCTYPE html>
<html>
<head>
- <title>Test Basic IIRFilterNode Operation</title>
+ <title>
+ Test Basic IIRFilterNode Operation
+ </title>
<script src="../../resources/testharness.js"></script>
- <script src="../../resources/testharnessreport.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
<script src="../resources/audit-util.js"></script>
<script src="../resources/audit.js"></script>
<script src="../resources/biquad-filters.js"></script>
</head>
-
<body>
- <script>
- var sampleRate = 24000;
- var testDurationSec = 0.25;
- var testFrames = testDurationSec * sampleRate;
+ <script id="layout-test-code">
+ let sampleRate = 24000;
+ let testDurationSec = 0.25;
+ let testFrames = testDurationSec * sampleRate;
- var audit = Audit.createTaskRunner();
+ let audit = Audit.createTaskRunner();
- audit.define("coefficient-normalization", (task, should) => {
- // 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);
+ audit.define('coefficient-normalization', (task, should) => {
+ // 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.
+ let context = new OfflineAudioContext(2, testFrames, sampleRate);
// Use a simple impulse as the source.
- var buffer = context.createBuffer(1, 1, sampleRate);
+ let buffer = context.createBuffer(1, 1, sampleRate);
buffer.getChannelData(0)[0] = 1;
- var source = context.createBufferSource();
+ let source = context.createBufferSource();
source.buffer = buffer;
// Gain node for computing the difference between the filters.
- var gain = context.createGain();
+ let gain = context.createGain();
gain.gain.value = -1;
// The IIR filters. Use a common feedforward array.
- var ff = [1];
+ let ff = [1];
- var fb1 = [1, .9];
+ let fb1 = [1, .9];
- var fb2 = new Float64Array(2);
+ let fb2 = new Float64Array(2);
// Scale the feedback coefficients by an arbitrary factor.
- var coefScaleFactor = 2;
- for (var k = 0; k < fb2.length; ++k) {
+ let coefScaleFactor = 2;
+ for (let k = 0; k < fb2.length; ++k) {
fb2[k] = coefScaleFactor * fb1[k];
}
- var iir1;
- var iir2;
+ let iir1;
+ let iir2;
- should(function () {
- iir1 = context.createIIRFilter(ff, fb1);
- },
- "createIIRFilter with normalized coefficients")
- .notThrow();
+ should(function() {
+ iir1 = context.createIIRFilter(ff, fb1);
+ }, 'createIIRFilter with normalized coefficients').notThrow();
- should(function () {
- iir2 = context.createIIRFilter(ff, fb2);
- },
- "createIIRFilter with unnormalized coefficients").notThrow();
+ should(function() {
+ iir2 = context.createIIRFilter(ff, fb2);
+ }, 'createIIRFilter with unnormalized coefficients').notThrow();
- // 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);
+ // 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.
+ let merger = context.createChannelMerger(2);
source.connect(iir1);
source.connect(iir2);
iir1.connect(merger, 0, 0);
iir2.connect(gain);
- // 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.
+ // 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);
@@ -79,35 +79,37 @@
// 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);
-
- // Threshold isn't exactly zero because the arithmetic is done differently between the
- // IIRFilterNode and the BiquadFilterNode.
- should(iir2Data,
- "Output of IIR filter with unnormalized coefficients")
- .beCloseToArray(iir1Data, {
- absoluteThreshold: 2.1958e-38
- });
- }).then(() => task.done());
+ context.startRendering()
+ .then(function(result) {
+ // Find the max amplitude of the result, which should be near
+ // zero.
+ let iir1Data = result.getChannelData(0);
+ let iir2Data = result.getChannelData(1);
+
+ // Threshold isn't exactly zero because the arithmetic is done
+ // differently between the IIRFilterNode and the BiquadFilterNode.
+ should(
+ iir2Data,
+ 'Output of IIR filter with unnormalized coefficients')
+ .beCloseToArray(iir1Data, {absoluteThreshold: 2.1958e-38});
+ })
+ .then(() => task.done());
});
- audit.define("one-zero", (task, should) => {
+ audit.define('one-zero', (task, should) => {
// Create a simple 1-zero filter and compare with the expected output.
- var context = new OfflineAudioContext(1, testFrames, sampleRate);
+ let context = new OfflineAudioContext(1, testFrames, sampleRate);
// Use a simple impulse as the source
- var buffer = context.createBuffer(1, 1, sampleRate);
+ let buffer = context.createBuffer(1, 1, sampleRate);
buffer.getChannelData(0)[0] = 1;
- var source = context.createBufferSource();
+ let source = context.createBufferSource();
source.buffer = buffer;
- // 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.
+ // 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.
- var iir = context.createIIRFilter([0.5, 0.5], [1]);
+ let iir = context.createIIRFilter([0.5, 0.5], [1]);
// Create the graph
source.connect(iir);
@@ -116,37 +118,39 @@
// Rock and roll!
source.start();
- 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(actual, 'IIR 1-zero output')
- .beCloseToArray(expected, {
- absoluteThreshold: 0
- });
- }).then(() => task.done());
+ context.startRendering()
+ .then(function(result) {
+ let actual = result.getChannelData(0);
+ let 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(actual, 'IIR 1-zero output').beCloseToArray(expected, {
+ absoluteThreshold: 0
+ });
+ })
+ .then(() => task.done());
});
- audit.define("one-pole", (task, should) => {
+ audit.define('one-pole', (task, should) => {
// 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);
+ // 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.
+ let c = 0.9;
+ let eps = 1e-20;
+ let duration = Math.floor(Math.log(eps) / Math.log(Math.abs(c)));
+ let context = new OfflineAudioContext(1, duration, sampleRate);
// Use a simple impulse as the source
- var buffer = context.createBuffer(1, 1, sampleRate);
+ let buffer = context.createBuffer(1, 1, sampleRate);
buffer.getChannelData(0)[0] = 1;
- var source = context.createBufferSource();
+ let source = context.createBufferSource();
source.buffer = buffer;
- var iir = context.createIIRFilter([1], [1, c]);
+ let iir = context.createIIRFilter([1], [1, c]);
// Create the graph
source.connect(iir);
@@ -155,57 +159,60 @@
// Rock and roll!
source.start();
- context.startRendering().then(function (result) {
- var actual = result.getChannelData(0);
- var expected = new Float64Array(actual.length);
-
- // 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];
- }
-
- // Threshold isn't exactly zero due to round-off in the single-precision IIRFilterNode
- // computations versus the double-precision Javascript computations.
- should(actual, 'IIR 1-pole output')
- .beCloseToArray(expected, {
- absoluteThreshold: 2.7657e-8
- });
- }).then(() => task.done());
+ context.startRendering()
+ .then(function(result) {
+ let actual = result.getChannelData(0);
+ let expected = new Float64Array(actual.length);
+
+ // 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];
+ }
+
+ // Threshold isn't exactly zero due to round-off in the
+ // single-precision IIRFilterNode computations versus the
+ // double-precision Javascript computations.
+ should(actual, 'IIR 1-pole output').beCloseToArray(expected, {
+ absoluteThreshold: 2.7657e-8
+ });
+ })
+ .then(() => task.done());
});
- // 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 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 (task, should) => {
- var context = new OfflineAudioContext(2, testFrames, sampleRate);
+ let context = new OfflineAudioContext(2, testFrames, sampleRate);
// Use a constant (step function) as the source
- var buffer = createConstantBuffer(context, testFrames, 1);
- var source = context.createBufferSource();
+ let buffer = createConstantBuffer(context, testFrames, 1);
+ let 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();
+
+ // Create the biquad. Choose some rather arbitrary values for Q and
+ // gain for the biquad so that the shelf filters aren't identical.
+ let 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);
+ // Create the equivalent IIR Filter node by computing the coefficients
+ // of the given biquad filter type.
+ let nyquist = sampleRate / 2;
+ let 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]);
+ let iir = context.createIIRFilter(
+ [coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
- var merger = context.createChannelMerger(2);
+ let merger = context.createChannelMerger(2);
// Create the graph
source.connect(biquad);
source.connect(iir);
@@ -218,125 +225,118 @@
// Rock and roll!
source.start();
- 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);
-
- // 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(actual, "IIRFilter for Biquad " + filterType)
- .beCloseToArray(expected, errorThreshold);
-
- var snr = 10*Math.log10(computeSNR(actual, expected));
- should(snr,
- "SNR for IIRFIlter for Biquad " + filterType)
- .beGreaterThanOrEqualTo(snrThreshold);
- }).then(() => task.done());
+ context.startRendering()
+ .then(function(result) {
+ // Find the max amplitude of the result, which should be near
+ // zero.
+ let expected = result.getChannelData(0);
+ let actual = result.getChannelData(1);
+
+ // 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(actual, 'IIRFilter for Biquad ' + filterType)
+ .beCloseToArray(expected, errorThreshold);
+
+ let snr = 10 * Math.log10(computeSNR(actual, expected));
+ should(snr, 'SNR for IIRFIlter for Biquad ' + filterType)
+ .beGreaterThanOrEqualTo(snrThreshold);
+ })
+ .then(() => task.done());
};
}
// Thresholds here are experimentally determined.
- var biquadTestConfigs = [{
- filterType: "lowpass",
- snrThreshold: 91.221,
- errorThreshold: {
- relativeThreshold: 4.9834e-5
- }
- }, {
- filterType: "highpass",
- snrThreshold: 105.4590,
- 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
+ let biquadTestConfigs = [
+ {
+ filterType: 'lowpass',
+ snrThreshold: 91.221,
+ errorThreshold: {relativeThreshold: 4.9834e-5}
+ },
+ {
+ filterType: 'highpass',
+ snrThreshold: 105.4590,
+ 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}
}
- }, {
- filterType: "peaking",
- snrThreshold: 91.504,
- errorThreshold: {
- absoluteThreshold: 0,
- relativeThreshold: 5.05e-5
- }
- }];
+ ];
// 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.define(name, testWithBiquadFilter(config.filterType, config.errorThreshold,
- config.snrThreshold));
+ let config = biquadTestConfigs[k];
+ let name = k + ': ' + config.filterType;
+ audit.define(
+ name,
+ testWithBiquadFilter(
+ config.filterType, config.errorThreshold, config.snrThreshold));
}
- audit.define("multi-channel", (task, should) => {
- // 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);
+ audit.define('multi-channel', (task, should) => {
+ // Multi-channel test. Create a biquad filter and the equivalent IIR
+ // filter. Filter the same multichannel signal and compare the results.
+ let nChannels = 3;
+ let context =
+ new OfflineAudioContext(nChannels, testFrames, sampleRate);
// Create a set of oscillators as the multi-channel source.
- var source = [];
+ let source = [];
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].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);
+ let merger = context.createChannelMerger(3);
- var biquad = context.createBiquadFilter();
+ let 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();
+ let nyquist = sampleRate / 2;
+ let coef = createFilter(
+ biquad.type, biquad.frequency.value / nyquist, biquad.Q.value,
+ biquad.gain.value);
+ let fb = [1, coef.a1, coef.a2];
+ let ff = [coef.b0, coef.b1, coef.b2];
+
+ let iir = context.createIIRFilter(ff, fb);
+ // Gain node to compute the difference between the IIR and biquad
+ // filter.
+ let gain = context.createGain();
gain.gain.value = -1;
// Create the graph.
@@ -352,23 +352,29 @@
for (k = 0; k < nChannels; ++k)
source[k].start();
- 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));
- });
-
- should(maxError,
- "Max difference between IIR and Biquad on channel " + channel)
- .beLessThanOrEqualTo(errorThresholds[channel]);
- }
-
- }).then(() => task.done());
+ context.startRendering()
+ .then(function(result) {
+ let 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.
+ let data = result.getChannelData(channel);
+ let maxError =
+ data.reduce(function(reducedValue, currentValue) {
+ return Math.max(reducedValue, Math.abs(currentValue));
+ });
+
+ should(
+ maxError,
+ 'Max difference between IIR and Biquad on channel ' +
+ channel)
+ .beLessThanOrEqualTo(errorThresholds[channel]);
+ }
+
+ })
+ .then(() => task.done());
});
// Apply an IIRFilter to the given input signal.
@@ -378,27 +384,27 @@
// 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);
+ // 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.
+ let workSize = Math.max(feedforward.length, feedback.length);
+ let 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);
+ // Float64 because we want to match the implementation that uses doubles
+ // to minimize roundoff.
+ let y = new Float64Array(input.length + workSize);
// Copy the input over.
- for (var k = 0; k < input.length; ++k)
+ for (let 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)
+ for (let n = 0; n < input.length; ++n) {
+ let index = n + workSize;
+ let yn = 0;
+ for (let k = 0; k < feedforward.length; ++k)
yn += feedforward[k] * x[index - k];
- for (var k = 0; k < feedback.length; ++k)
+ for (let k = 0; k < feedback.length; ++k)
yn -= feedback[k] * y[index - k];
y[index] = yn;
@@ -414,113 +420,116 @@
// 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.
+ // To cascade them, multiply the two transforms together to get a fourth
+ // order IIR filter.
- var numProduct = [f1Coef.b0 * f2Coef.b0,
- f1Coef.b0 * f2Coef.b1 + f1Coef.b1 * f2Coef.b0,
+ let 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
+ f1Coef.b1 * f2Coef.b2 + f1Coef.b2 * f2Coef.b1, f1Coef.b2 * f2Coef.b2
];
- var denProduct = [1,
- f2Coef.a1 + f1Coef.a1,
+ let 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
+ f1Coef.a1 * f2Coef.a2 + f1Coef.a2 * f2Coef.a1, f1Coef.a2 * f2Coef.a2
];
return {
- ff: numProduct,
- fb: denProduct
+ ff: numProduct, fb: denProduct
}
}
- // Find the magnitude of the root of the quadratic that has the maximum magnitude.
+ // 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.
+ // 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;
+ let 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);
+ // 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)
+ let d = Math.sqrt(-discriminant);
return Math.hypot(a1 / 2, d / 2);
} else {
// Real roots
- var d = Math.sqrt(discriminant);
+ let d = Math.sqrt(discriminant);
return Math.max(Math.abs((-a1 + d) / 2), Math.abs((-a1 - d) / 2));
}
}
- audit.define("4th-order-iir", (task, should) => {
- // Cascade 2 lowpass biquad filters and compare that with the equivalent 4th order IIR
- // filter.
+ audit.define('4th-order-iir', (task, should) => {
+ // Cascade 2 lowpass biquad filters and compare that with the equivalent
+ // 4th order IIR filter.
- var nyquist = sampleRate / 2;
+ let nyquist = sampleRate / 2;
// Compute the coefficients of a lowpass filter.
- // 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;
+ // First some preliminary stuff. Compute the coefficients of the
+ // biquad. This is used to figure out how frames to use in the test.
+ let biquadType = 'lowpass';
+ let biquadCutoff = 350;
+ let biquadQ = 5;
+ let biquadGain = 1;
- var coef = createFilter(biquadType,
- biquadCutoff / nyquist,
- biquadQ,
- biquadGain);
+ let coef = createFilter(
+ biquadType, biquadCutoff / nyquist, biquadQ, biquadGain);
// Cascade the biquads together to create an equivalent IIR filter.
- var cascade = cascadeBiquads(coef, coef);
-
- // 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.
-
- // 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.
+ let cascade = cascadeBiquads(coef, coef);
+
+ // 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.
+
+ // 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);
+ let rootMagnitude = largestRootMagnitude(coef.a1, coef.a2);
- // 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)));
+ // Find n such that |r|^(2*n) <= eps. That is, n = log(eps)/(2*log(r)).
+ // Somewhat arbitrarily choose eps = 1e-20;
+ let eps = 1e-20;
+ let 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);
+ // 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.
+ let context = new OfflineAudioContext(2, framesForTest, sampleRate);
// Use a simple impulse with a large (arbitrary) amplitude as the source
- var amplitude = 1;
- var buffer = context.createBuffer(1, testFrames, sampleRate);
+ let amplitude = 1;
+ let buffer = context.createBuffer(1, testFrames, sampleRate);
buffer.getChannelData(0)[0] = amplitude;
- var source = context.createBufferSource();
+ let source = context.createBufferSource();
source.buffer = buffer;
- // 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();
+ // Create the two biquad filters. Doesn't really matter what, but for
+ // simplicity we choose identical lowpass filters with the same
+ // parameters.
+ let biquad1 = context.createBiquadFilter();
biquad1.type = biquadType;
biquad1.frequency.value = biquadCutoff;
biquad1.Q.value = biquadQ;
- var biquad2 = context.createBiquadFilter();
+ let biquad2 = context.createBiquadFilter();
biquad2.type = biquadType;
biquad2.frequency.value = biquadCutoff;
biquad2.Q.value = biquadQ;
- var iir = context.createIIRFilter(cascade.ff, cascade.fb);
+ let iir = context.createIIRFilter(cascade.ff, cascade.fb);
// Create the merger to get the signals into multiple channels
- var merger = context.createChannelMerger(2);
+ let merger = context.createChannelMerger(2);
// Create the graph, filtering the source through two biquads.
source.connect(biquad1);
@@ -533,26 +542,28 @@
merger.connect(context.destination);
// Now filter the source through the IIR filter.
- var y = iirFilter(buffer.getChannelData(0), cascade.ff, cascade.fb);
+ let y = iirFilter(buffer.getChannelData(0), cascade.ff, cascade.fb);
// Rock and roll!
source.start();
- context.startRendering().then(function(result) {
- var expected = result.getChannelData(0);
- var actual = result.getChannelData(1);
-
- should(actual, "4-th order IIRFilter (biquad ref)")
- .beCloseToArray(expected, {
- // Thresholds experimentally determined.
- absoluteThreshold: 1.59e-7,
- relativeThreshold: 2.11e-5,
- });
-
- var snr = 10*Math.log10(computeSNR(actual, expected));
- should(snr, "SNR of 4-th order IIRFilter (biquad ref)")
- .beGreaterThanOrEqualTo(108.947);
- }).then(() => task.done());
+ context.startRendering()
+ .then(function(result) {
+ let expected = result.getChannelData(0);
+ let actual = result.getChannelData(1);
+
+ should(actual, '4-th order IIRFilter (biquad ref)')
+ .beCloseToArray(expected, {
+ // Thresholds experimentally determined.
+ absoluteThreshold: 1.59e-7,
+ relativeThreshold: 2.11e-5,
+ });
+
+ let snr = 10 * Math.log10(computeSNR(actual, expected));
+ should(snr, 'SNR of 4-th order IIRFilter (biquad ref)')
+ .beGreaterThanOrEqualTo(108.947);
+ })
+ .then(() => task.done());
});
audit.run();

Powered by Google App Engine
This is Rietveld 408576698