Skip to content

Commit 3b35e97

Browse files
[webaudio-testharness] Migrate audioparam-close.html to testharness.js (#53768)
Convert webaudio/the-audio-api/the-audioparam-interface/audioparam-close.html from the legacy audit.js runner to pure testharness.js Bug: 396477778 Change-Id: Ia54cdbe1fc1621ce586e1604d9c257b756b6dc81 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6680970 Reviewed-by: Michael Wilson <[email protected]> Commit-Queue: Saqlain <[email protected]> Reviewed-by: Hongchan Choi <[email protected]> Cr-Commit-Position: refs/heads/main@{#1497940} Co-authored-by: Saqlain <[email protected]>
1 parent 146144f commit 3b35e97

File tree

2 files changed

+149
-134
lines changed

2 files changed

+149
-134
lines changed

webaudio/resources/audit-util.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,20 @@ function assert_close_to_array(actual, expected, epsilon, desc) {
315315
`${desc}[${i}] |${actual[i]} - ${expected[i]}| = ${diff} > ${epsilon}`);
316316
}
317317
}
318+
319+
/**
320+
* Asserts that all elements of an array are (approximately) equal to a value.
321+
*
322+
* @param {!Array<number>} array - The array to be checked.
323+
* @param {number} constantValue - The expected constant value.
324+
* @param {string} message - Description used for assertion failures.
325+
* @param {number=} epsilon - Allowed tolerance for floating-point comparison.
326+
* Default to 1e-7
327+
*/
328+
function assert_array_constant_value(
329+
array, constantValue, message, epsilon = 1e-7) {
330+
for (let i = 0; i < array.length; ++i) {
331+
assert_approx_equals(
332+
array[i], constantValue, epsilon, `${message} sample[${i}]`);
333+
}
334+
}
Lines changed: 132 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
<!doctype html>
1+
<!DOCTYPE html>
22
<html>
33
<head>
44
<title>Test AudioParam events very close in time</title>
55
<script src="/resources/testharness.js"></script>
66
<script src="/resources/testharnessreport.js"></script>
77
<script src="/webaudio/resources/audit-util.js"></script>
8-
<script src="/webaudio/resources/audit.js"></script>
98
</head>
10-
119
<body>
1210
<script>
13-
const audit = Audit.createTaskRunner();
14-
1511
// Largest sample rate that is required to be supported and is a power of
1612
// two, to eliminate round-off as much as possible.
1713
const sampleRate = 65536;
@@ -27,135 +23,137 @@
2723
// epsneg is the smallest x such that 1 - x != 1
2824
const epsneg = 5.551115123125784e-17;
2925

30-
audit.define(
31-
{label: 'no-nan', description: 'NaN does not occur'},
32-
(task, should) => {
33-
const context = new OfflineAudioContext({
34-
numberOfChannels: 1,
35-
sampleRate: sampleRate,
36-
length: testFrames
37-
});
38-
39-
const src0 = new ConstantSourceNode(context, {offset: 0});
40-
41-
// This should always succeed. We just want to print out a message
42-
// that |src0| is a constant source node for the following
43-
// processing.
44-
should(src0, 'src0 = new ConstantSourceNode(context, {offset: 0})')
45-
.beEqualTo(src0);
46-
47-
src0.connect(context.destination);
48-
49-
// Values for the first event (setValue). |time1| MUST be 0.
50-
const time1 = 0;
51-
const value1 = 10;
52-
53-
// Values for the second event (linearRamp). |value2| must be huge,
54-
// and |time2| must be small enough that 1/|time2| overflows a
55-
// single float. This value is the least positive single float.
56-
const value2 = floatMax;
57-
const time2 = 1.401298464324817e-45;
58-
59-
// These should always succeed; the messages are just informational
60-
// to show the events that we scheduled.
61-
should(
62-
src0.offset.setValueAtTime(value1, time1),
63-
`src0.offset.setValueAtTime(${value1}, ${time1})`)
64-
.beEqualTo(src0.offset);
65-
should(
66-
src0.offset.linearRampToValueAtTime(value2, time2),
67-
`src0.offset.linearRampToValueAtTime(${value2}, ${time2})`)
68-
.beEqualTo(src0.offset);
69-
70-
src0.start();
71-
72-
context.startRendering()
73-
.then(buffer => {
74-
const output = buffer.getChannelData(0);
75-
76-
// Since time1 = 0, the output at frame 0 MUST be value1.
77-
should(output[0], 'output[0]').beEqualTo(value1);
78-
79-
// Since time2 < 1, output from frame 1 and later must be a
80-
// constant.
81-
should(output.slice(1), 'output[1]')
82-
.beConstantValueOf(value2);
83-
})
84-
.then(() => task.done());
85-
});
86-
87-
audit.define(
88-
{label: 'interpolation', description: 'Interpolation of linear ramp'},
89-
(task, should) => {
90-
const context = new OfflineAudioContext({
91-
numberOfChannels: 1,
92-
sampleRate: sampleRate,
93-
length: testFrames
94-
});
95-
96-
const src1 = new ConstantSourceNode(context, {offset: 0});
97-
98-
// This should always succeed. We just want to print out a message
99-
// that |src1| is a constant source node for the following
100-
// processing.
101-
should(src1, 'src1 = new ConstantSourceNode(context, {offset: 0})')
102-
.beEqualTo(src1);
103-
104-
src1.connect(context.destination);
105-
106-
const frame = 1;
107-
108-
// These time values are arranged so that time1 < frame/sampleRate <
109-
// time2. This means we need to interpolate to get a value at given
110-
// frame.
111-
//
112-
// The values are not so important, but |value2| should be huge.
113-
const time1 = frame * (1 - epsneg) / context.sampleRate;
114-
const value1 = 1e15;
115-
116-
const time2 = frame * (1 + epspos) / context.sampleRate;
117-
const value2 = floatMax;
118-
119-
should(
120-
src1.offset.setValueAtTime(value1, time1),
121-
`src1.offset.setValueAtTime(${value1}, ${time1})`)
122-
.beEqualTo(src1.offset);
123-
should(
124-
src1.offset.linearRampToValueAtTime(value2, time2),
125-
`src1.offset.linearRampToValueAtTime(${value2}, ${time2})`)
126-
.beEqualTo(src1.offset);
127-
128-
src1.start();
129-
130-
context.startRendering()
131-
.then(buffer => {
132-
const output = buffer.getChannelData(0);
133-
134-
// Sanity check
135-
should(time2 - time1, 'Event time difference')
136-
.notBeEqualTo(0);
137-
138-
// Because 0 < time1 < 1, output must be 0 at time 0.
139-
should(output[0], 'output[0]').beEqualTo(0);
140-
141-
// Because time1 < 1/sampleRate < time2, we need to
142-
// interpolate the value between these times to determine the
143-
// output at frame 1.
144-
const t = frame / context.sampleRate;
145-
const v = value1 +
146-
(value2 - value1) * (t - time1) / (time2 - time1);
147-
148-
should(output[1], 'output[1]').beCloseTo(v, {threshold: 0});
149-
150-
// Because 1 < time2 < 2, the output at frame 2 and higher is
151-
// constant.
152-
should(output.slice(2), 'output[2:]')
153-
.beConstantValueOf(value2);
154-
})
155-
.then(() => task.done());
156-
});
157-
158-
audit.run();
26+
promise_test(async t => {
27+
const context = new OfflineAudioContext({
28+
numberOfChannels: 1,
29+
sampleRate,
30+
length: testFrames
31+
});
32+
33+
const src0 = new ConstantSourceNode(context, {offset: 0});
34+
35+
// This should always succeed. We just want to print out a message
36+
// that |src0| is a constant source node for the following
37+
// processing.
38+
assert_equals(
39+
src0, src0,
40+
'src0 = new ConstantSourceNode(context, {offset: 0}) ' +
41+
'should succeed');
42+
43+
src0.connect(context.destination);
44+
45+
// Values for the first event (setValue). |time1| MUST be 0.
46+
const time1 = 0;
47+
const value1 = 10;
48+
49+
// Values for the second event (linearRamp). |value2| must be huge,
50+
// and |time2| must be small enough that 1/|time2| overflows a
51+
// single float. This value is the least positive single float.
52+
const time2 = 1.401298464324817e-45;
53+
const value2 = floatMax;
54+
55+
// These should always succeed; the messages are just informational
56+
// to show the events that we scheduled.
57+
assert_equals(
58+
src0.offset.setValueAtTime(value1, time1),
59+
src0.offset,
60+
`src0.offset.setValueAtTime(${value1}, ${time1}) should ` +
61+
`return AudioParam`);
62+
assert_equals(
63+
src0.offset.linearRampToValueAtTime(value2, time2),
64+
src0.offset,
65+
`src0.offset.linearRampToValueAtTime(${value2}, ${time2}) should ` +
66+
`return AudioParam`);
67+
68+
src0.start();
69+
70+
const renderedBuffer = await context.startRendering();
71+
const output = renderedBuffer.getChannelData(0);
72+
73+
// Since time1 = 0, the output at frame 0 MUST be value1.
74+
assert_equals(
75+
output[0], value1, 'Frame 0 should equal initial value set');
76+
77+
// Since time2 < 1, output from frame 1 and later must be a
78+
// constant.
79+
assert_array_constant_value(
80+
output.slice(1),
81+
value2,
82+
'Frames 1+ should equal ramp target value');
83+
}, 'NaN should not occur during extreme linearRampToValueAtTime events');
84+
85+
promise_test(async t => {
86+
const context = new OfflineAudioContext({
87+
numberOfChannels: 1,
88+
sampleRate,
89+
length: testFrames
90+
});
91+
92+
const src1 = new ConstantSourceNode(context, {offset: 0});
93+
94+
// This should always succeed. We just want to print out a message
95+
// that |src1| is a constant source node for the following
96+
// processing.
97+
assert_equals(
98+
src1, src1,
99+
'src1 = new ConstantSourceNode(context, {offset: 0}) ' +
100+
'should succeed');
101+
102+
src1.connect(context.destination);
103+
104+
const frameIndex = 1;
105+
106+
// These time values are arranged so that time1 < frame/sampleRate <
107+
// time2. This means we need to interpolate to get a value at given
108+
// frame.
109+
//
110+
// The values are not so important, but |value2| should be huge.
111+
const time1 = frameIndex * (1 - epsneg) / context.sampleRate;
112+
const value1 = 1e15;
113+
114+
const time2 = frameIndex * (1 + epspos) / context.sampleRate;
115+
const value2 = floatMax;
116+
117+
assert_equals(
118+
src1.offset.setValueAtTime(value1, time1),
119+
src1.offset,
120+
`src1.offset.setValueAtTime(${value1}, ${time1}) should ` +
121+
`return AudioParam`);
122+
assert_equals(
123+
src1.offset.linearRampToValueAtTime(value2, time2),
124+
src1.offset,
125+
`src1.offset.linearRampToValueAtTime(${value2}, ${time2}) should ` +
126+
`return AudioParam`);
127+
128+
src1.start();
129+
130+
const renderedBuffer = await context.startRendering();
131+
const output = renderedBuffer.getChannelData(0);
132+
133+
// Sanity check
134+
assert_not_equals(
135+
time2 - time1, 0,
136+
'Sanity check: time1 and time2 should not be equal');
137+
// Because 0 < time1 < 1, output must be 0 at time 0.
138+
assert_equals(
139+
output[0], 0, 'output[0] should be 0 before any automation');
140+
141+
// Because time1 < 1/sampleRate < time2, we need to
142+
// interpolate the value between these times to determine the
143+
// output at frame 1.
144+
const sampleTime = frameIndex / context.sampleRate;
145+
const interpolated =
146+
value1 + (value2 - value1) * (sampleTime - time1) / (time2 - time1);
147+
assert_approx_equals(
148+
output[1],
149+
interpolated, 0,
150+
'Interpolated value at frame 1 should match ramp');
151+
152+
// Because 1 < time2 < 2, the output at frame 2 and higher is
153+
// constant.
154+
assert_array_constant_value(
155+
output.slice(2), value2, 'output[2:] should be constant at value2');
156+
}, 'Interpolation of linear ramp between very close time values');
159157
</script>
160158
</body>
161159
</html>

0 commit comments

Comments
 (0)