Skip to content

Commit 16dc3ae

Browse files
[webaudio] Migrate k-rate-delay-connections.html to testharness.js (#53763)
Convert webaudio/the-audio-api/the-audioparam-interface /k-rate-delay-connections.html from the legacy audit.js runner to pure testharness.js Bug: 396477778 Change-Id: I02abc222b5b999d1a0c5072ab55e252dc1869a85 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6683140 Reviewed-by: Alvin Ji <[email protected]> Reviewed-by: Hongchan Choi <[email protected]> Commit-Queue: Saqlain <[email protected]> Cr-Commit-Position: refs/heads/main@{#1486738} Co-authored-by: Saqlain <[email protected]>
1 parent afaf31a commit 16dc3ae

File tree

2 files changed

+133
-143
lines changed

2 files changed

+133
-143
lines changed

webaudio/resources/audit-util.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,39 @@ function assert_constant_value(array, value, messagePrefix = '') {
218218
);
219219
}
220220
}
221-
}
221+
}
222+
223+
/**
224+
* Asserts that two arrays are exactly equal, element by element.
225+
* @param {!Array<number>} actual The actual array of values.
226+
* @param {!Array<number>} expected The expected array of values.
227+
* @param {string} message Description used for assertion failures.
228+
*/
229+
function assert_array_equals_exact(actual, expected, message) {
230+
assert_equals(actual.length, expected.length, 'Buffers must be same length');
231+
for (let i = 0; i < actual.length; ++i) {
232+
assert_equals(actual[i], expected[i], `${message} (at index ${i})`);
233+
}
234+
}
235+
236+
/**
237+
* Asserts that an array is not a constant array (i.e., not all values are equal to the given constant).
238+
* @param {!Array<number>} array The array to be checked.
239+
* @param {number} constantValue The constant value to compare against.
240+
* @param {string} message Description used for assertion failures.
241+
*/
242+
function assert_not_constant_value(array, constantValue, message) {
243+
const notAllSame = array.some(value => value !== constantValue);
244+
assert_true(notAllSame, message);
245+
}
246+
247+
/**
248+
* Asserts that all elements of an array are exactly equal to a constant value.
249+
* @param {!Array<number>} array The array to be checked.
250+
* @param {number} constantValue The expected constant value.
251+
* @param {string} message Description used for assertion failures.
252+
*/
253+
function assert_strict_constant_value(array, constantValue, message) {
254+
const allSame = array.every(value => value === constantValue);
255+
assert_true(allSame, message);
256+
}
Lines changed: 97 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,156 +1,111 @@
11
<!doctype html>
22
<html>
33
<head>
4-
<title>k-rate AudioParams with inputs for DelayNode</title>
4+
<title>DelayNode delayTime with k-rate input should match automation</title>
55
<script src="/resources/testharness.js"></script>
66
<script src="/resources/testharnessreport.js"></script>
7-
<script src="/webaudio/resources/audit.js"></script>
87
<script src="/webaudio/resources/audit-util.js"></script>
98
</head>
109

1110
<body>
1211
<script>
13-
let audit = Audit.createTaskRunner();
14-
15-
// Power-of-two to eliminate round-off in computing time and frames, but
16-
// is otherwise arbitrary.
12+
// Power-of-two sample rate to eliminate round-off errors.
1713
const sampleRate = 8192;
1814

19-
// Arbitrary duration except it must be greater than or equal to 1.
20-
const testDuration = 1.5;
21-
22-
audit.define(
23-
{label: 'delayTime', description: `DelayNode delayTime k-rate input`},
24-
async (task, should) => {
25-
// Two channels: 0 = test result, 1 = expected result.
26-
let context = new OfflineAudioContext({
27-
numberOfChannels: 2,
28-
sampleRate: sampleRate,
29-
length: testDuration * sampleRate
30-
});
31-
32-
let merger = new ChannelMergerNode(
33-
context, {numberOfInputs: context.destination.channelCount});
34-
merger.connect(context.destination);
35-
36-
// Test the DelayNode by having a reference node (refNode) that uses
37-
// k-rate automations of delayTime. The test node (testNode) sets
38-
// delayTime to k-rate with a connected input that has the same
39-
// automation vlaues as the reference node. The test passes if the
40-
// output from each node is identical to each other.
41-
42-
// Just some non-constant source.
43-
let src = new OscillatorNode(context);
44-
45-
// The end value and time for the linear ramp. These values are
46-
// chosen so that the delay advances faster than real time.
47-
let endValue = 1.125;
48-
let endTime = 1;
49-
50-
let refNode;
51-
52-
should(
53-
() => refNode = new DelayNode(context),
54-
`refNode = new DelayNode(context)`)
55-
.notThrow();
56-
57-
should(
58-
() => refNode.delayTime.automationRate = 'k-rate',
59-
`refNode.delayTime.automationRate = 'k-rate'`)
60-
.notThrow();
61-
62-
should(
63-
() => refNode.delayTime.setValueAtTime(0, 0),
64-
`refNode.delayTime.setValueAtTime(0, 0)`)
65-
.notThrow();
66-
67-
should(
68-
() => refNode.delayTime.linearRampToValueAtTime(
69-
endValue, endTime),
70-
`refNode.delayTime.linearRampToValueAtTime(${endValue}, ${
71-
endTime})`)
72-
.notThrow();
73-
74-
let testNode;
75-
76-
should(
77-
() => testNode = new DelayNode(context),
78-
`testNode = new DelayNode(context)`)
79-
.notThrow();
80-
81-
should(
82-
() => testNode.delayTime.automationRate = 'k-rate',
83-
`testNode.delayTime.automationRate = 'k-rate'`)
84-
.notThrow();
85-
86-
let testMod;
87-
88-
should(
89-
() => testMod = new ConstantSourceNode(context),
90-
`testMod = new ConstantSourceNode(context)`)
91-
.notThrow();
92-
93-
should(
94-
() => testMod.offset.setValueAtTime(0, 0),
95-
`testMod.offset.setValueAtTime(0, 0)`)
96-
.notThrow();
97-
98-
should(
99-
() => testMod.offset.linearRampToValueAtTime(endValue, endTime),
100-
`testMod.offset.linearRampToValueAtTime(${endValue}, ${
101-
endTime})`)
102-
.notThrow();
103-
104-
should(
105-
() => testMod.connect(testNode.delayTime),
106-
`testMod.connect(testNode.delayTime)`)
107-
.notThrow();
108-
109-
// Connect up everything and go!
110-
src.connect(testNode).connect(merger, 0, 0);
111-
src.connect(refNode).connect(merger, 0, 1);
112-
113-
src.start();
114-
testMod.start();
115-
116-
const buffer = await context.startRendering();
117-
let expected = buffer.getChannelData(0);
118-
let actual = buffer.getChannelData(1);
119-
120-
// Quick sanity check that output isn't zero. This means we messed
121-
// up the connections or automations or the buffer source.
122-
should(expected, `Expected k-rate delayTime AudioParam with input`)
123-
.notBeConstantValueOf(0);
124-
should(actual, `Actual k-rate delayTime AudioParam with input`)
125-
.notBeConstantValueOf(0);
126-
127-
// Quick sanity check. The amount of delay after one render is
128-
// endValue * 128 / sampleRate. But after 1 render, time has
129-
// advanced 128/sampleRate. Hence, the delay exceeds the time by
130-
// (endValue - 1)*128/sampleRate sec or (endValue - 1)*128 frames.
131-
// This means the output must be EXACTLY zero for this many frames
132-
// in the second render.
133-
let zeroFrames = (endValue - 1) * RENDER_QUANTUM_FRAMES;
134-
should(
135-
actual.slice(
136-
RENDER_QUANTUM_FRAMES, RENDER_QUANTUM_FRAMES + zeroFrames),
137-
`output[${RENDER_QUANTUM_FRAMES}, ${
138-
RENDER_QUANTUM_FRAMES + zeroFrames - 1}]`)
139-
.beConstantValueOf(0);
140-
should(
141-
actual.slice(
142-
RENDER_QUANTUM_FRAMES + zeroFrames,
143-
2 * RENDER_QUANTUM_FRAMES),
144-
`output[${RENDER_QUANTUM_FRAMES + zeroFrames}, ${
145-
2 * RENDER_QUANTUM_FRAMES - 1}]`)
146-
.notBeConstantValueOf(0);
147-
148-
// The expected and actual results must be EXACTLY the same.
149-
should(actual, `k-rate delayTime AudioParam with input`)
150-
.beCloseToArray(expected, {absoluteThreshold: 0});
151-
});
152-
153-
audit.run();
15+
// Arbitrary test duration (must be ≥ 1s).
16+
const testDurationSeconds = 1.5;
17+
18+
// Total number of frames based on sample rate and duration.
19+
const totalFrames = sampleRate * testDurationSeconds;
20+
21+
promise_test(async t => {
22+
// Two channels: 0 = test result, 1 = expected result.
23+
const context = new OfflineAudioContext({
24+
numberOfChannels: 2,
25+
sampleRate: sampleRate,
26+
length: totalFrames
27+
});
28+
29+
const merger = new ChannelMergerNode(context, {
30+
numberOfInputs: context.destination.channelCount
31+
});
32+
merger.connect(context.destination);
33+
34+
// Test the DelayNode by having a reference node (refNode) that uses
35+
// k-rate automations of delayTime. The test node (testNode) sets
36+
// delayTime to k-rate with a connected input that has the same
37+
// automation vlaues as the reference node. The test passes if the
38+
// output from each node is identical to each other.
39+
40+
const oscillator = new OscillatorNode(context);
41+
42+
// The end value and time for the linear ramp. These values are
43+
// chosen so that the delay advances faster than real time.
44+
const rampEndValue = 1.125;
45+
const rampEndTime = 1;
46+
47+
const refNode = new DelayNode(context);
48+
refNode.delayTime.automationRate = 'k-rate';
49+
refNode.delayTime.setValueAtTime(0, 0);
50+
refNode.delayTime.linearRampToValueAtTime(rampEndValue, rampEndTime);
51+
52+
const testNode = new DelayNode(context);
53+
testNode.delayTime.automationRate = 'k-rate';
54+
55+
const modulator = new ConstantSourceNode(context);
56+
modulator.offset.setValueAtTime(0, 0);
57+
modulator.offset.linearRampToValueAtTime(rampEndValue, rampEndTime);
58+
modulator.connect(testNode.delayTime);
59+
60+
oscillator.connect(testNode).connect(merger, 0, 0);
61+
oscillator.connect(refNode).connect(merger, 0, 1);
62+
63+
oscillator.start();
64+
modulator.start();
65+
66+
const renderedBuffer = await context.startRendering();
67+
const actual = renderedBuffer.getChannelData(0);
68+
const expected = renderedBuffer.getChannelData(1);
69+
70+
// Quick sanity check that output isn't zero. This means we messed
71+
// up the connections or automations or the buffer source.
72+
assert_not_constant_value(
73+
expected, 0, 'Expected output should not be constant zero');
74+
assert_not_constant_value(
75+
actual, 0, 'Actual output should not be constant zero');
76+
77+
// Quick sanity check. The amount of delay after one render is
78+
// endValue * 128 / sampleRate. But after 1 render, time has
79+
// advanced 128/sampleRate. Hence, the delay exceeds the time by
80+
// (endValue - 1)*128/sampleRate sec or (endValue - 1)*128 frames.
81+
// This means the output must be EXACTLY zero for this many frames
82+
// in the second render.
83+
const silentFrames = (rampEndValue - 1) * RENDER_QUANTUM_FRAMES;
84+
85+
assert_strict_constant_value(
86+
actual.slice(
87+
RENDER_QUANTUM_FRAMES, RENDER_QUANTUM_FRAMES + silentFrames),
88+
0,
89+
`output[${RENDER_QUANTUM_FRAMES}` +
90+
`..${RENDER_QUANTUM_FRAMES + silentFrames - 1}] must be silent`
91+
);
92+
93+
// Next quantum should NOT be silent
94+
assert_not_constant_value(
95+
actual.slice(
96+
RENDER_QUANTUM_FRAMES + silentFrames,
97+
2 * RENDER_QUANTUM_FRAMES),
98+
0,
99+
`output[${RENDER_QUANTUM_FRAMES + silentFrames}` +
100+
`..${2 * RENDER_QUANTUM_FRAMES - 1}] must have signal`
101+
);
102+
103+
// Compare actual vs expected output
104+
assert_array_equals_exact(
105+
actual,
106+
expected,
107+
'Output from testNode should exactly match reference');
108+
}, 'k-rate DelayNode.delayTime with input matches automation behavior');
154109
</script>
155110
</body>
156-
</html>
111+
</html>

0 commit comments

Comments
 (0)