OLD | NEW |
1 <!doctype html> | 1 <!DOCTYPE html> |
2 <html> | 2 <html> |
3 <head> | 3 <head> |
| 4 <title> |
| 5 Updating of Value Attribute from Timeline |
| 6 </title> |
4 <script src="../../resources/testharness.js"></script> | 7 <script src="../../resources/testharness.js"></script> |
5 <script src="../../resources/testharnessreport.js"></script> | 8 <script src="../../resources/testharnessreport.js"></script> |
6 <script src="../resources/audit-util.js"></script> | 9 <script src="../resources/audit-util.js"></script> |
7 <script src="../resources/audit.js"></script> | 10 <script src="../resources/audit.js"></script> |
8 <script src="../resources/audio-param.js"></script> | 11 <script src="../resources/audio-param.js"></script> |
9 <title>Updating of Value Attribute from Timeline</title> | |
10 </head> | 12 </head> |
| 13 <body> |
| 14 <script id="layout-test-code"> |
| 15 // This should be a power of two so that all time computations have no |
| 16 // round-off errors. |
| 17 let sampleRate = 32768; |
| 18 let renderQuantumSize = 128; |
| 19 // How many tests to run. |
| 20 let renderLoops = 20; |
| 21 let renderFrames = renderLoops * renderQuantumSize; |
| 22 let renderDuration = renderFrames / sampleRate; |
11 | 23 |
12 <body> | 24 let audit = Audit.createTaskRunner(); |
13 <script> | |
14 | 25 |
15 // This should be a power of two so that all time computations have no rou
nd-off errors. | 26 audit.define('linear', (task, should) => { |
16 var sampleRate = 32768; | |
17 var renderQuantumSize = 128; | |
18 // How many tests to run. | |
19 var renderLoops = 20; | |
20 var renderFrames = renderLoops * renderQuantumSize; | |
21 var renderDuration = renderFrames / sampleRate; | |
22 | |
23 var audit = Audit.createTaskRunner(); | |
24 | |
25 audit.define("linear", (task, should) => { | |
26 // Test the value attribute from a linearRamp event | 27 // Test the value attribute from a linearRamp event |
27 runTest(should, function (g, v0, t0, v1, t1) { | 28 runTest(should, function(g, v0, t0, v1, t1) { |
28 g.gain.linearRampToValueAtTime(v1, t1); | 29 g.gain.linearRampToValueAtTime(v1, t1); |
29 return { | 30 return { |
30 expectedValue: function (testTime) { | 31 expectedValue: function(testTime) { |
31 return audioParamLinearRamp(testTime, v0, t0, v1, t1); | 32 return audioParamLinearRamp(testTime, v0, t0, v1, t1); |
32 }, | 33 }, |
33 message: "linearRamp(" + v1 + ", " + t1 + ")", | 34 message: 'linearRamp(' + v1 + ', ' + t1 + ')', |
34 errorThreshold: 1.1650e-6 | 35 errorThreshold: 1.1650e-6 |
35 }; | 36 }; |
36 }).then(() => task.done()); | 37 }).then(() => task.done()); |
37 }); | 38 }); |
38 | 39 |
39 audit.define("exponential", (task, should) => { | 40 audit.define('exponential', (task, should) => { |
40 // Test the value attribute from an exponentialRamp event | 41 // Test the value attribute from an exponentialRamp event |
41 runTest(should, function (g, v0, t0, v1, t1) { | 42 runTest(should, function(g, v0, t0, v1, t1) { |
42 g.gain.exponentialRampToValueAtTime(v1, t1); | 43 g.gain.exponentialRampToValueAtTime(v1, t1); |
43 return { | 44 return { |
44 expectedValue: function (testTime) { | 45 expectedValue: function(testTime) { |
45 return audioParamExponentialRamp(testTime, v0, t0, v1, t1); | 46 return audioParamExponentialRamp(testTime, v0, t0, v1, t1); |
46 }, | 47 }, |
47 message: "exponentialRamp(" + v1 + ", " + t1 + ")", | 48 message: 'exponentialRamp(' + v1 + ', ' + t1 + ')', |
48 errorThreshold: 7.4601e-7 | 49 errorThreshold: 7.4601e-7 |
49 }; | 50 }; |
50 }).then(() => task.done()); | 51 }).then(() => task.done()); |
51 }); | 52 }); |
52 | 53 |
53 audit.define("setTarget", (task, should) => { | 54 audit.define('setTarget', (task, should) => { |
54 // Test the value attribute from a setTargetAtTime event | 55 // Test the value attribute from a setTargetAtTime event |
55 runTest(should, function (g, v0, t0, v1, t1) { | 56 runTest(should, function(g, v0, t0, v1, t1) { |
56 var timeConstant = 0.1; | 57 let timeConstant = 0.1; |
57 var vFinal = 0; | 58 let vFinal = 0; |
58 g.gain.setTargetAtTime(vFinal, t0, timeConstant); | 59 g.gain.setTargetAtTime(vFinal, t0, timeConstant); |
59 return { | 60 return { |
60 expectedValue: function (testTime) { | 61 expectedValue: function(testTime) { |
61 return audioParamSetTarget(testTime, v0, t0, vFinal, timeConstant)
; | 62 return audioParamSetTarget( |
| 63 testTime, v0, t0, vFinal, timeConstant); |
62 }, | 64 }, |
63 message: "setTargetAtTime(" + vFinal + ", " + t0 + ", " + timeConsta
nt + ")", | 65 message: 'setTargetAtTime(' + vFinal + ', ' + t0 + ', ' + |
| 66 timeConstant + ')', |
64 errorThreshold: 2.2599e-6 | 67 errorThreshold: 2.2599e-6 |
65 }; | 68 }; |
66 }).then(() => task.done()); | 69 }).then(() => task.done()); |
67 }); | 70 }); |
68 | 71 |
69 audit.define("setValueCurve", (task, should) => { | 72 audit.define('setValueCurve', (task, should) => { |
70 // Test the value attribute from a setValueCurve event | 73 // Test the value attribute from a setValueCurve event |
71 runTest(should, function (g, v0, t0, v1, t1) { | 74 runTest(should, function(g, v0, t0, v1, t1) { |
72 var curve = [1, 1.5, 4]; | 75 let curve = [1, 1.5, 4]; |
73 var duration = t1 - t0; | 76 let duration = t1 - t0; |
74 g.gain.setValueCurveAtTime(Float32Array.from(curve), t0, duration); | 77 g.gain.setValueCurveAtTime(Float32Array.from(curve), t0, duration); |
75 return { | 78 return { |
76 expectedValue: function (testTime) { | 79 expectedValue: function(testTime) { |
77 return audioParamSetValueCurve(testTime, curve, t0, duration); | 80 return audioParamSetValueCurve(testTime, curve, t0, duration); |
78 }, | 81 }, |
79 message: "setValueCurveAtTime([" + curve + "], " + t0 + ", " + durat
ion + ")", | 82 message: 'setValueCurveAtTime([' + curve + '], ' + t0 + ', ' + |
| 83 duration + ')', |
80 errorThreshold: 7.9577e-8 | 84 errorThreshold: 7.9577e-8 |
81 }; | 85 }; |
82 }).then(() => task.done()); | 86 }).then(() => task.done()); |
83 }); | 87 }); |
84 | 88 |
85 audit.run(); | 89 audit.run(); |
86 | 90 |
87 // Test that the .value getter has the correct value when a timeline is ru
nning. | 91 // Test that the .value getter has the correct value when a timeline is |
88 // The |testFunction| is the underlying test to be run. | 92 // running. The |testFunction| is the underlying test to be run. |
89 function runTest(should, testFunction) { | 93 function runTest(should, testFunction) { |
90 // Create a simple graph consisting of a constant source and a gain node
where the | 94 // Create a simple graph consisting of a constant source and a gain node |
91 // automations are run. A setValueAtTime event starts things off. | 95 // where the automations are run. A setValueAtTime event starts things |
92 var context = new OfflineAudioContext(1, renderFrames, sampleRate); | 96 // off. |
93 var source = context.createBufferSource(); | 97 let context = new OfflineAudioContext(1, renderFrames, sampleRate); |
| 98 let source = context.createBufferSource(); |
94 source.buffer = createConstantBuffer(context, 1, 1); | 99 source.buffer = createConstantBuffer(context, 1, 1); |
95 source.loop = true; | 100 source.loop = true; |
96 var gain = context.createGain(); | 101 let gain = context.createGain(); |
97 | 102 |
98 source.connect(gain); | 103 source.connect(gain); |
99 gain.connect(context.destination); | 104 gain.connect(context.destination); |
100 | 105 |
101 // Start the timeline with setValueAtTime(v0, t0). | 106 // Start the timeline with setValueAtTime(v0, t0). |
102 var v0 = 0.25; | 107 let v0 = 0.25; |
103 var t0 = 0; | 108 let t0 = 0; |
104 // End value and time, for those that need it. The end time is less tha
n the rendering | 109 // End value and time, for those that need it. The end time is less |
105 // duration so we can test that the final values of the automation (if a
ny) are also | 110 // than the rendering duration so we can test that the final values of |
106 // correct. | 111 // the automation (if any) are also correct. |
107 var v1 = 100; | 112 let v1 = 100; |
108 var t1 = renderDuration - 5 * renderQuantumSize / sampleRate; | 113 let t1 = renderDuration - 5 * renderQuantumSize / sampleRate; |
109 | 114 |
110 gain.gain.setValueAtTime(v0, t0); | 115 gain.gain.setValueAtTime(v0, t0); |
111 | 116 |
112 // Run the desired automation test. The test function returns a diction
ary consisting of | 117 // Run the desired automation test. The test function returns a |
113 // the following properties: | 118 // dictionary consisting of the following properties: |
114 // | 119 // |
115 // |message| an informative message about the automation being te
sted. | 120 // |message| an informative message about the automation being |
116 // |errorThreshold| error threshold to determine if the test passes or n
ot. | 121 // tested. |errorThreshold| error threshold to determine if the test |
117 // |expectedValue| a function that compute the expected value at time |
t|. | 122 // passes or not. |expectedValue| a function that compute the expected |
118 var test = testFunction(gain, v0, t0, v1, t1); | 123 // value at time |t|. |
| 124 let test = testFunction(gain, v0, t0, v1, t1); |
119 | 125 |
120 // Print an informative message about the test being run. | 126 // Print an informative message about the test being run. |
121 //testPassed("Initialize " + test.message + " with setValueAtTime(" + v0
+ ", " + t0 + ")."); | 127 // testPassed("Initialize " + test.message + " with setValueAtTime(" + |
122 should(true, "Initialize") | 128 // v0 + ", " + t0 + ")."); |
123 .message(test.message + " with setValueAtTime(" + v0 + ", " + t0 + ")"
, | 129 should(true, 'Initialize') |
124 ""); | 130 .message( |
125 | 131 test.message + ' with setValueAtTime(' + v0 + ', ' + t0 + ')', |
126 var success = true; | 132 ''); |
127 | 133 |
128 // Max relative error found for this test. This is printed if the test f
ails so that setting | 134 let success = true; |
129 // the thresholds is easier. | |
130 var maxError = 0; | |
131 | 135 |
132 // For every rendering quantum (except the first), suspend the context s
o the we can inspect | 136 // Max relative error found for this test. This is printed if the test |
133 // the value attribute and compare it with the expected value. | 137 // fails so that setting the thresholds is easier. |
134 for (var k = 1; k < renderLoops; ++k) { | 138 let maxError = 0; |
135 var time = k * renderQuantumSize / sampleRate; | |
136 context.suspend(time).then(function () { | |
137 // The context is supsended at time |time|, which is just before the
rendering quantum | |
138 // starts. Thus, the value of the attribute is actually 1 frame bef
ore the current | |
139 // context time. | |
140 var sampleTime = context.currentTime - 1 / sampleRate; | |
141 | 139 |
142 // Compute the max relative error | 140 // For every rendering quantum (except the first), suspend the context |
143 var expected = test.expectedValue(sampleTime); | 141 // so the we can inspect the value attribute and compare it with the |
144 var relError = Math.abs(expected - gain.gain.value) / Math.abs(expec
ted); | 142 // expected value. |
145 maxError = Math.max(relError, maxError); | 143 for (let k = 1; k < renderLoops; ++k) { |
| 144 let time = k * renderQuantumSize / sampleRate; |
| 145 context.suspend(time) |
| 146 .then(function() { |
| 147 // The context is supsended at time |time|, which is just before |
| 148 // the rendering quantum starts. Thus, the value of the |
| 149 // attribute is actually 1 frame before the current context |
| 150 // time. |
| 151 let sampleTime = context.currentTime - 1 / sampleRate; |
146 | 152 |
147 success = should(gain.gain.value, test.message + " at frame " + (sam
pleRate * sampleTime)) | 153 // Compute the max relative error |
148 .beCloseTo(expected, {threshold: test.errorThreshold || 0}); | 154 let expected = test.expectedValue(sampleTime); |
149 }).then(context.resume.bind(context)); | 155 let relError = |
| 156 Math.abs(expected - gain.gain.value) / Math.abs(expected); |
| 157 maxError = Math.max(relError, maxError); |
| 158 |
| 159 success = |
| 160 should( |
| 161 gain.gain.value, |
| 162 test.message + ' at frame ' + (sampleRate * sampleTime)) |
| 163 .beCloseTo( |
| 164 expected, {threshold: test.errorThreshold || 0}); |
| 165 }) |
| 166 .then(context.resume.bind(context)); |
150 } | 167 } |
151 | 168 |
152 source.start(); | 169 source.start(); |
153 | 170 |
154 return context.startRendering().then(function (resultBuffer) { | 171 return context.startRendering().then(function(resultBuffer) { |
155 // Just print a final pass (or fail) message. | 172 // Just print a final pass (or fail) message. |
156 should(success, "Gain .value attribute for " + test.message) | 173 should(success, 'Gain .value attribute for ' + test.message) |
157 .message("correctly updated during automation", | 174 .message( |
158 "not correctly updated during automation; max error = " + m
axError); | 175 'correctly updated during automation', |
| 176 'not correctly updated during automation; max error = ' + |
| 177 maxError); |
159 }); | 178 }); |
160 } | 179 } |
161 </script> | 180 </script> |
162 </body> | 181 </body> |
163 </html> | 182 </html> |
OLD | NEW |