OLD | NEW |
| (Empty) |
1 <!doctype html> | |
2 <html> | |
3 <head> | |
4 <script src="../resources/js-test.js"></script> | |
5 <script src="resources/compatibility.js"></script> | |
6 <script src="resources/audit-util.js"></script> | |
7 <script src="resources/audio-testing.js"></script> | |
8 <title>Test Clamping of Automations</title> | |
9 </head> | |
10 | |
11 <body> | |
12 <script> | |
13 description("Test Clamping of Automations."); | |
14 window.jsTestIsAsync = true; | |
15 | |
16 // Some arbitrary sample rate for the offline context. | |
17 var sampleRate = 48000; | |
18 | |
19 // Duration of test (fairly arbitrary). | |
20 var renderDuration = 1; | |
21 var renderFrames = renderDuration * sampleRate; | |
22 | |
23 var audit = Audit.createTaskRunner(); | |
24 | |
25 audit.defineTask("clamp", function (done) { | |
26 // Test clamping of automations. Most AudioParam limits are essentially | |
27 // unbounded, so clamping doesn't happen. For most other AudioParams, | |
28 // the behavior is sufficiently complicated with complicated outputs | |
29 // that testing them is hard. However the output behavior of the | |
30 // frequency parameter for a BiquadFilter is relatively simple. Use | |
31 // that as the test. | |
32 var context = new OfflineAudioContext(1, renderFrames, sampleRate); | |
33 | |
34 var source = context.createBufferSource(); | |
35 source.buffer = createConstantBuffer(context, 1, 1); | |
36 source.loop = true; | |
37 | |
38 var filter = context.createBiquadFilter(); | |
39 filter.type = "lowpass"; | |
40 | |
41 source.connect(filter); | |
42 filter.connect(context.destination); | |
43 | |
44 var V0 = 880; | |
45 var T0 = 0; | |
46 filter.frequency.setValueAtTime(V0, T0); | |
47 | |
48 var V1 = -1000; | |
49 var T1 = renderDuration / 4; | |
50 filter.frequency.linearRampToValueAtTime(V1, T1); | |
51 | |
52 var V2 = 880; | |
53 var T2 = renderDuration / 2; | |
54 filter.frequency.linearRampToValueAtTime(V2, T2); | |
55 | |
56 source.start(); | |
57 | |
58 context.startRendering().then(function (buffer) { | |
59 var result = buffer.getChannelData(0); | |
60 var success = true; | |
61 | |
62 // When the cutoff frequency of a lowpass filter is 0, nothing gets | |
63 // through. Hence the output of the filter between the clamping | |
64 // period should be exactly zero. This tests passes if the output is 0 | |
65 // during the expected range. | |
66 // | |
67 // Compute when the frequency value of the biquad goes to 0. In | |
68 // general, t = (T0*V1 -T1*V0)/(V1-V0) (using the notation from the | |
69 // spec.) | |
70 var clampStartTime = solveLinearRamp(0, V0, T0, V1, T1); | |
71 var clampEndTime = solveLinearRamp(0, V1, T1, V2, T2); | |
72 | |
73 var clampStartFrame = Math.ceil(clampStartTime * sampleRate); | |
74 var clampEndFrame = Math.floor(clampEndTime * sampleRate); | |
75 | |
76 var clampedSignal = result.slice(clampStartFrame, clampEndFrame + 1); | |
77 var expectedSignal = new Float32Array(clampedSignal.length); | |
78 expectedSignal.fill(0); | |
79 | |
80 // Output should be zero. | |
81 success = Should("Clamped signal in frame range [" + clampStartFrame +
", " + | |
82 clampEndFrame + "]", | |
83 clampedSignal, { | |
84 verbose: true, | |
85 }).beCloseToArray(expectedSignal, 0); | |
86 | |
87 // Find the actual clamp range based on the output values. | |
88 var actualClampStart = result.findIndex(x => x === 0); | |
89 var actualClampEnd = actualClampStart + result.slice(actualClampStart)
.findIndex( | |
90 x => x != 0); | |
91 | |
92 // Verify that the expected clamping range is a subset of the actual r
ange. | |
93 success = Should("Actual Clamp start", | |
94 actualClampStart).beLessThanOrEqualTo(clampStartFrame) && success; | |
95 success == Should("Actual Clamp end", | |
96 actualClampEnd).beGreaterThanOrEqualTo(clampEndFrame) && success; | |
97 | |
98 if (success) | |
99 testPassed("Clamping of BiquadFilter.frequency automation performed
correctly.") | |
100 else | |
101 testFailed( | |
102 "Clamping of BiquadFilter.frequency automation performed incorrect
ly.") | |
103 | |
104 }).then(done); | |
105 }); | |
106 | |
107 // All done! | |
108 audit.defineTask("finish", function (done) { | |
109 finishJSTest(); | |
110 done(); | |
111 }); | |
112 | |
113 audit.runTasks(); | |
114 | |
115 function solveLinearRamp(v, v0, t0, v1, t1) { | |
116 // Solve the linear ramp equation for the time t at which the ramp | |
117 // reaches the value v. The linear ramp equation (from the spec) is | |
118 // | |
119 // v(t) = v0 + (v1 - v0) * (t - t0)/(t1 - t0) | |
120 // | |
121 // Find t such that | |
122 // | |
123 // v = v0 + (v1 - v0) * (t - t0)/(t1 - t0) | |
124 // | |
125 // Then | |
126 // | |
127 // t = (t0 * v1 - t1 * v0 + (t1 - t0) * v) / (v1 - v0) | |
128 // | |
129 return (t0 * v1 - t1 * v0 + (t1 - t0) * v) / (v1 - v0); | |
130 } | |
131 </script> | |
132 </body> | |
133 </html> | |
OLD | NEW |