Skip to content

Commit 7e374fd

Browse files
chromium-wpt-export-botpunithbnayak
authored andcommitted
[webaudio-testharness] Migrate iirfilter-getFrequencyResponse.html (#53950)
This CL rewrites the IIRFilterNode getFrequencyResponse() test to use testharness.js instead of the legacy audit.js framework. The logic and thresholds remain unchanged, preserving test validity. This migration helps reduce dependencies on audit.js and aligns with Web Platform Test standards. Bug: 396477778 Change-Id: I093a0ccd8792a5813c47e46148b09c7410474e1f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6688066 Reviewed-by: Hongchan Choi <[email protected]> Auto-Submit: Punith Nayak <[email protected]> Reviewed-by: Michael Wilson <[email protected]> Commit-Queue: Punith Nayak <[email protected]> Cr-Commit-Position: refs/heads/main@{#1491212} Co-authored-by: punithbnayak <[email protected]>
1 parent d5af45b commit 7e374fd

File tree

2 files changed

+107
-102
lines changed

2 files changed

+107
-102
lines changed

webaudio/resources/audit-util.js

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -278,13 +278,40 @@ function assert_strict_constant_value(array, constantValue, message) {
278278
*/
279279
function assert_array_approximately_equals(
280280
actual, expected, threshold, message) {
281-
assert_equals(
282-
actual.length,
283-
expected.length,
284-
`${message} - buffer lengths must match`);
285-
for (let i = 0; i < actual.length; ++i) {
286-
assert_approx_equals(
287-
actual[i], expected[i], threshold,
288-
`${message} at index ${i}`);
289-
}
281+
assert_equals(
282+
actual.length,
283+
expected.length,
284+
`${message} - buffer lengths must match`);
285+
for (let i = 0; i < actual.length; ++i) {
286+
assert_approx_equals(
287+
actual[i], expected[i], threshold,
288+
`${message} at index ${i}`);
289+
}
290+
}
291+
292+
/**
293+
* Asserts that two arrays are of equal length and that each corresponding
294+
* element is within a specified epsilon of each other. Throws an assertion
295+
* error if any element pair differs by more than epsilon or if the arrays
296+
* have different lengths.
297+
*
298+
* @param {Array<number>} actual - The array of actual values to test.
299+
* @param {Array<number>} expected - The array of expected values to compare
300+
* against.
301+
* @param {number} epsilon - The maximum allowed difference between
302+
* corresponding elements.
303+
* @param {string} desc - Description used in assertion error messages.
304+
*/
305+
function assert_close_to_array(actual, expected, epsilon, desc) {
306+
assert_equals(
307+
actual.length,
308+
expected.length,
309+
`${desc}: length mismatch`);
310+
for (let i = 0; i < actual.length; ++i) {
311+
const diff = Math.abs(actual[i] - expected[i]);
312+
assert_less_than_equal(
313+
diff,
314+
epsilon,
315+
`${desc}[${i}] |${actual[i]} - ${expected[i]}| = ${diff} > ${epsilon}`);
316+
}
290317
}

webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html

Lines changed: 71 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,17 @@
77
<script src="/resources/testharness.js"></script>
88
<script src="/resources/testharnessreport.js"></script>
99
<script src="../../resources/audit-util.js"></script>
10-
<script src="../../resources/audit.js"></script>
1110
<script src="../../resources/biquad-filters.js"></script>
1211
</head>
1312
<body>
14-
<script id="layout-test-code">
15-
let sampleRate = 48000;
13+
<script>
14+
15+
const sampleRate = 48000;
1616
// Some short duration; we're not actually looking at the rendered output.
17-
let testDurationSec = 0.01;
17+
const testDurationSec = 0.01;
1818

1919
// Number of frequency samples to take.
20-
let numberOfFrequencies = 1000;
21-
22-
let audit = Audit.createTaskRunner();
23-
20+
const numberOfFrequencies = 1000;
2421

2522
// Compute a set of linearly spaced frequencies.
2623
function createFrequencies(nFrequencies, sampleRate) {
@@ -35,18 +32,17 @@
3532
return frequencies;
3633
}
3734

38-
audit.define('1-pole IIR', (task, should) => {
39-
let context = new OfflineAudioContext(
35+
test(t => {
36+
const context = new OfflineAudioContext(
4037
1, testDurationSec * sampleRate, sampleRate);
38+
const iir = context.createIIRFilter([1], [1, -0.9]);
4139

42-
let iir = context.createIIRFilter([1], [1, -0.9]);
43-
let frequencies =
44-
createFrequencies(numberOfFrequencies, context.sampleRate);
45-
46-
let iirMag = new Float32Array(numberOfFrequencies);
47-
let iirPhase = new Float32Array(numberOfFrequencies);
48-
let trueMag = new Float32Array(numberOfFrequencies);
49-
let truePhase = new Float32Array(numberOfFrequencies);
40+
const frequencies = createFrequencies(
41+
numberOfFrequencies, context.sampleRate);
42+
const iirMag = new Float32Array(numberOfFrequencies);
43+
const iirPhase = new Float32Array(numberOfFrequencies);
44+
const trueMag = new Float32Array(numberOfFrequencies);
45+
const truePhase = new Float32Array(numberOfFrequencies);
5046

5147
// The IIR filter is
5248
// H(z) = 1/(1 - 0.9*z^(-1)).
@@ -60,10 +56,9 @@
6056
// The phase is
6157
// arg(H(exp(j*w)) = atan(0.9*sin(w)/(.9*cos(w)-1))
6258

63-
let frequencyScale = Math.PI / (sampleRate / 2);
64-
59+
const frequencyScale = Math.PI / (sampleRate / 2);
6560
for (let k = 0; k < frequencies.length; ++k) {
66-
let omega = frequencyScale * frequencies[k];
61+
const omega = frequencyScale * frequencies[k];
6762
trueMag[k] = 1 / Math.sqrt(1.81 - 1.8 * Math.cos(omega));
6863
truePhase[k] =
6964
Math.atan(0.9 * Math.sin(omega) / (0.9 * Math.cos(omega) - 1));
@@ -72,88 +67,71 @@
7267
iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
7368

7469
// Thresholds were experimentally determined.
75-
should(iirMag, '1-pole IIR Magnitude Response')
76-
.beCloseToArray(trueMag, {absoluteThreshold: 2.8611e-6});
77-
should(iirPhase, '1-pole IIR Phase Response')
78-
.beCloseToArray(truePhase, {absoluteThreshold: 1.7882e-7});
79-
80-
task.done();
81-
});
82-
83-
audit.define('compare IIR and biquad', (task, should) => {
70+
assert_close_to_array(
71+
iirMag, trueMag, 2.8611e-6, '1‑pole IIR magnitude response ' +
72+
'should be closed to calculated magnitude response');
73+
assert_close_to_array(
74+
iirPhase, truePhase, 1.7882e-7, '1‑pole IIR phase response ' +
75+
' should be closed to calculated phase response');
76+
}, '1‑pole IIR getFrequencyResponse() matches analytic response');
77+
78+
test(t => {
8479
// Create an IIR filter equivalent to the biquad filter. Compute the
8580
// frequency response for both and verify that they are the same.
86-
let context = new OfflineAudioContext(
81+
const context = new OfflineAudioContext(
8782
1, testDurationSec * sampleRate, sampleRate);
8883

89-
let biquad = context.createBiquadFilter();
90-
let coef = createFilter(
91-
biquad.type, biquad.frequency.value / (context.sampleRate / 2),
92-
biquad.Q.value, biquad.gain.value);
84+
const biquad = context.createBiquadFilter();
85+
const coef = createFilter(
86+
biquad.type,
87+
biquad.frequency.value / (context.sampleRate / 2),
88+
biquad.Q.value,
89+
biquad.gain.value);
9390

94-
let iir = context.createIIRFilter(
91+
const iir = context.createIIRFilter(
9592
[coef.b0, coef.b1, coef.b2], [1, coef.a1, coef.a2]);
9693

97-
let frequencies =
98-
createFrequencies(numberOfFrequencies, context.sampleRate);
99-
let biquadMag = new Float32Array(numberOfFrequencies);
100-
let biquadPhase = new Float32Array(numberOfFrequencies);
101-
let iirMag = new Float32Array(numberOfFrequencies);
102-
let iirPhase = new Float32Array(numberOfFrequencies);
94+
const frequencies = createFrequencies(
95+
numberOfFrequencies, context.sampleRate);
96+
const biquadMag = new Float32Array(numberOfFrequencies);
97+
const biquadPhase = new Float32Array(numberOfFrequencies);
98+
const iirMag = new Float32Array(numberOfFrequencies);
99+
const iirPhase = new Float32Array(numberOfFrequencies);
103100

104101
biquad.getFrequencyResponse(frequencies, biquadMag, biquadPhase);
105102
iir.getFrequencyResponse(frequencies, iirMag, iirPhase);
106-
107-
// Thresholds were experimentally determined.
108-
should(iirMag, 'IIR Magnitude Response').beCloseToArray(biquadMag, {
109-
absoluteThreshold: 2.7419e-5
110-
});
111-
should(iirPhase, 'IIR Phase Response').beCloseToArray(biquadPhase, {
112-
absoluteThreshold: 2.7657e-5
113-
});
114-
115-
task.done();
116-
});
117-
118-
audit.define(
119-
{
120-
label: 'getFrequencyResponse',
121-
description: 'Test out-of-bounds frequency values'
122-
},
123-
(task, should) => {
124-
let context = new OfflineAudioContext(1, 1, sampleRate);
125-
let filter = new IIRFilterNode(
126-
context, {feedforward: [1], feedback: [1, -.9]});
127-
128-
// Frequencies to test. These are all outside the valid range of
129-
// frequencies of 0 to Nyquist.
130-
let freq = new Float32Array(2);
131-
freq[0] = -1;
132-
freq[1] = context.sampleRate / 2 + 1;
133-
134-
let mag = new Float32Array(freq.length);
135-
let phase = new Float32Array(freq.length);
136-
137-
filter.getFrequencyResponse(freq, mag, phase);
138-
139-
// Verify that the returned magnitude and phase entries are alL NaN
140-
// since the frequencies are outside the valid range
141-
for (let k = 0; k < mag.length; ++k) {
142-
should(mag[k],
143-
'Magnitude response at frequency ' + freq[k])
144-
.beNaN();
145-
}
146-
147-
for (let k = 0; k < phase.length; ++k) {
148-
should(phase[k],
149-
'Phase response at frequency ' + freq[k])
150-
.beNaN();
151-
}
152-
153-
task.done();
154-
});
155-
156-
audit.run();
103+
// Thresholds were experimentally determined.
104+
assert_close_to_array(
105+
iirMag, biquadMag, 2.7419e-5, 'IIR magnitude response should be' +
106+
'close to Biquad magnitude response');
107+
assert_close_to_array(
108+
iirPhase, biquadPhase, 2.7657e-5, 'IIR phase response should be' +
109+
'close to Biquad phase response');
110+
}, 'IIR filter equivalent to biquad has matching frequency response');
111+
112+
test(t => {
113+
const context = new OfflineAudioContext(1, 1, sampleRate);
114+
const filter = new IIRFilterNode(
115+
context, {feedforward: [1], feedback: [1, -0.9]});
116+
// Frequencies to test. These are all outside the valid range of
117+
// frequencies of 0 to Nyquist.
118+
const freq = new Float32Array([-1, context.sampleRate / 2 + 1]);
119+
const mag = new Float32Array(freq.length);
120+
const phase = new Float32Array(freq.length);
121+
122+
filter.getFrequencyResponse(freq, mag, phase);
123+
124+
// Verify that the returned magnitude and phase entries are all NaN
125+
// since the frequencies are outside the valid range
126+
for (let k = 0; k < freq.length; ++k) {
127+
assert_true(
128+
Number.isNaN(mag[k]),
129+
`Magnitude response at f=${freq[k]} should be NaN`);
130+
assert_true(
131+
Number.isNaN(phase[k]),
132+
`Phase response at f=${freq[k]} should be NaN`);
133+
}
134+
}, 'Out‑of‑range frequency values yield NaN responses');
157135
</script>
158136
</body>
159137
</html>

0 commit comments

Comments
 (0)