OLD | NEW |
---|---|
(Empty) | |
1 <!doctype html> | |
2 <html> | |
3 <head> | |
4 <title>Test Interpolation for AudioParam.setValueCurveAtTime</title> | |
5 <script src="resources/compatibility.js"></script> | |
6 <script src="resources/audio-testing.js"></script> | |
7 <script src="../resources/js-test.js"></script> | |
hongchan
2015/08/07 17:32:51
js-test.js should be the first.
Raymond Toy
2015/08/07 18:58:32
Done.
| |
8 </head> | |
9 | |
10 <body> | |
11 <script> | |
12 description("Test Interpolation for AudioParam.setValueCurveAtTime"); | |
13 | |
14 // Play a constant signal through a gain node that is automated using setV alueCurveAtTime with | |
15 // a 2-element curve. The output should be a linear change. | |
16 | |
17 // Chose a sample rate that is a multiple of 128, the rendering quantum si ze. This makes the | |
hongchan
2015/08/07 17:32:51
Chose -> Choose
Raymond Toy
2015/08/07 18:58:32
Done.
| |
18 // math work out to be nice numbers. | |
19 var sampleRate = 25600; | |
20 var testDurationSec = 1; | |
21 var testDurationFrames = testDurationSec * sampleRate; | |
22 | |
23 // Where the curve starts and its duration. This MUST be less than the to tal rendering time. | |
24 var curveStartTime = 256 / sampleRate; | |
25 var curveDuration = 300 / sampleRate;; | |
26 var curveValue = 0.75; | |
27 | |
28 // At this time, the gain node goes to gain 1. This is used to make sure the value curve is | |
29 // propagated correctly until the next event. | |
30 var fullGainTime = 0.75; | |
31 | |
32 // Thresholds use to determine if the test passes; these are experimentall y determined. The | |
33 // SNR between the actual and expected result should be at least |snrThres hold|. The maximum | |
34 // difference betwen them should not exceed |maxErrorThreshold|. | |
35 var snrThreshold = 10000; | |
36 var maxErrorThreshold = 0; | |
37 | |
38 var context; | |
39 var actualResult; | |
40 var expectedResult; | |
41 | |
42 var audit = Audit.createTaskRunner(); | |
43 | |
44 audit.defineTask("initialize", function (done) { | |
45 window.jsTestIsAsync = true; | |
hongchan
2015/08/07 17:32:51
This can be done right after description() method.
Raymond Toy
2015/08/07 18:58:33
Done. And initialize task deleted.
| |
46 done(); | |
47 }); | |
48 | |
49 | |
50 // Array of test configs. Each config must specify curveStartTime, curveD uration, | |
51 // curveLength, fullGainTime, maxErrorThreshold, and snrThreshold. | |
52 var testConfigs = [ | |
hongchan
2015/08/07 17:32:51
This can be re-written:
var testConfig = [{
/
Raymond Toy
2015/08/07 18:58:32
Done.
| |
53 // The main test | |
54 { | |
55 curveStartTime: 256 / sampleRate, | |
56 curveDuration: 300 / sampleRate, | |
57 curveLength: 2, | |
58 fullGainTime: 0.75, | |
59 maxErrorThreshold: 0, | |
60 snrThreshold: 10000 | |
61 }, | |
62 // Increase the curve length | |
63 { | |
64 curveStartTime: 256 / sampleRate, | |
65 curveDuration: 300 / sampleRate, | |
66 curveLength: 3, | |
67 fullGainTime: 0.75, | |
68 maxErrorThreshold: 0, | |
69 snrThreshold: 10000 | |
70 }, | |
71 // Increase the curve length | |
72 { | |
73 curveStartTime: 256 / sampleRate, | |
74 curveDuration: 300 / sampleRate, | |
75 curveLength: 16, | |
76 fullGainTime: 0.75, | |
77 maxErrorThreshold: 0, | |
78 snrThreshold: 10000 | |
79 }, | |
80 // Increase the curve length | |
81 { | |
82 curveStartTime: 256 / sampleRate, | |
83 curveDuration: 300 / sampleRate, | |
84 curveLength: 100, | |
85 fullGainTime: 0.75, | |
86 maxErrorThreshold: 0, | |
87 snrThreshold: 10000 | |
88 }, | |
89 // Corner case with duration less than a frame! | |
90 { | |
91 curveStartTime: 256 / sampleRate, | |
92 curveDuration: 0.25 / sampleRate, | |
93 curveLength: 2, | |
94 fullGainTime: 0.75, | |
95 maxErrorThreshold: 0, | |
96 snrThreshold: 10000 | |
97 }, | |
98 // Short duration test | |
99 { | |
100 curveStartTime: 256 / sampleRate, | |
101 curveDuration: 2 / sampleRate, | |
102 curveLength: 2, | |
103 fullGainTime: 0.75, | |
104 maxErrorThreshold: 0, | |
105 snrThreshold: 10000 | |
106 }, | |
107 // Short duration test with many points. | |
108 { | |
109 curveStartTime: 256 / sampleRate, | |
110 curveDuration: 2 / sampleRate, | |
111 curveLength: 8, | |
112 fullGainTime: 0.75, | |
113 maxErrorThreshold: 0, | |
114 snrThreshold: 10000 | |
115 }, | |
116 // Long duration, big curve | |
117 { | |
118 curveStartTime: 256 / sampleRate, | |
119 curveDuration: .5, | |
120 curveLength: 1000, | |
121 fullGainTime: 0.75, | |
122 maxErrorThreshold: 0, | |
123 snrThreshold: 10000 | |
124 } | |
125 ]; | |
126 | |
127 // Creates a function based on the test config that is suitable for use by defineTask(). | |
128 function createTaskFunction (config) { | |
hongchan
2015/08/07 17:32:51
[Optional] Usually the named function does not hav
Raymond Toy
2015/08/07 18:58:33
Done.
| |
129 return function (done) { | |
hongchan
2015/08/07 17:32:51
The anonymous function can have a space between th
Raymond Toy
2015/08/07 18:58:33
Acknowledged.
| |
130 runTest(config).then(done); | |
131 }; | |
132 } | |
133 | |
134 // Define a task for each config, in the order listed in testConfigs. | |
135 for (var k = 0; k < testConfigs.length; ++k) { | |
136 var config = testConfigs[k]; | |
137 var name = k + ":curve=" + config.curveLength + ",duration=" + (config.c urveDuration * sampleRate); | |
138 audit.defineTask(name, createTaskFunction(config)); | |
139 } | |
140 | |
141 // Must be the last defined task. | |
142 audit.defineTask("end", function (done) { | |
143 finishJSTest(); | |
144 done(); | |
145 }); | |
146 | |
147 function runTest (config) { | |
hongchan
2015/08/07 17:32:51
No space between the name in the parentheses. The
Raymond Toy
2015/08/07 18:58:32
Done.
| |
148 context = new OfflineAudioContext(1, testDurationFrames, sampleRate); | |
149 | |
150 // A constant audio source of value 1. | |
151 var source = context.createBufferSource(); | |
152 source.buffer = createConstantBuffer(context, 1, 1); | |
153 source.loop = true; | |
154 | |
155 // The value curve for testing. Just to make things easy for testing, m ake the curve a | |
156 // simple ramp up to curveValue. | |
157 // TODO: Maybe allow more complicated curves? | |
hongchan
2015/08/07 17:32:51
TODO(rtoy)
Raymond Toy
2015/08/07 18:58:32
Done.
| |
158 var curve = new Float32Array(config.curveLength); | |
159 for (var k = 0; k < config.curveLength; ++k) { | |
160 curve[k] = curveValue / (config.curveLength - 1) * k; | |
161 } | |
162 | |
163 // A gain node that is to be automated using setValueCurveAtTime. | |
164 var gain = context.createGain(); | |
165 gain.gain.value = 0; | |
166 gain.gain.setValueCurveAtTime(curve, config.curveStartTime, config.curve Duration); | |
167 // This is to verify that setValueCurveAtTime ends appropriately. | |
168 gain.gain.setValueAtTime(1, config.fullGainTime); | |
169 | |
170 source.connect(gain); | |
171 gain.connect(context.destination); | |
172 source.start(); | |
173 | |
174 // Some consistency checks on the test parameters | |
175 Should("Check: Curve end time", config.curveStartTime + config.curveDura tion) | |
176 .beLessThanOrEqualTo(testDurationSec); | |
177 Should("Check: Full gain start time", config.fullGainTime).beLessThanOrE qualTo(testDurationSec); | |
178 Should("Check: Full gain start time", config.fullGainTime).beGreaterThan OrEqualTo(config.curveStartTime + config.curveDuration); | |
179 | |
180 // Rock and roll! | |
181 return context.startRendering().then(checkResult(config)); | |
182 } | |
183 | |
184 // Return a function to check that the rendered result matches the expecte d result. | |
185 function checkResult(config) | |
hongchan
2015/08/07 17:32:51
Let's move the curly brace one line up.
Raymond Toy
2015/08/07 18:58:33
Done.
| |
186 { | |
187 return function (renderedBuffer) { | |
188 var success = true; | |
189 | |
190 actualResult = renderedBuffer.getChannelData(0); | |
191 expectedResult = computeExpectedResult(config); | |
192 | |
193 // Compute the SNR and max absolute difference between the actual and expected result. | |
194 var SNR = 10*Math.log10(computeSNR(actualResult, expectedResult)); | |
195 var maxDiff = -1; | |
196 var posn = -1; | |
197 | |
198 for (var k = 0; k < actualResult.length; ++k) { | |
199 var diff = Math.abs(actualResult[k] - expectedResult[k]); | |
200 if (maxDiff < diff) { | |
201 maxDiff = diff; | |
202 posn = k; | |
203 } | |
204 } | |
205 | |
206 success = success && Should("SNR", SNR).beGreaterThanOrEqualTo(config. snrThreshold); | |
207 | |
208 if (maxDiff <= config.maxErrorThreshold) { | |
209 testPassed("Max difference is less than or equal to " + config.maxEr rorThreshold + "."); | |
210 } else { | |
211 testFailed("Max difference (" + maxDiff + ") NOT less than or equal to " + | |
212 config.maxErrorThreshold + " at frame " + posn + "."); | |
213 success = false; | |
214 } | |
215 | |
216 var message = "Test: curve length = " + config.curveLength + "; durati on frames = " + | |
217 config.curveDuration * sampleRate + ".\n"; | |
218 | |
219 if (success) | |
220 testPassed(message); | |
221 else | |
222 testFailed(message); | |
223 } | |
224 } | |
225 | |
226 // Compute the expected result based on the config settings. | |
227 function computeExpectedResult(config) | |
228 { | |
229 // The automation curve starts at |curveStartTime| and has duration |cu rveDuration|. So, | |
230 // the output should be zero until curveStartTime, linearly ramp up fro m there to | |
231 // |curveValue|, and then be constant 1 from then to the end of the buf fer. | |
232 | |
233 var expected = new Float32Array(testDurationFrames); | |
234 | |
235 var curveStartFrame = config.curveStartTime * sampleRate; | |
236 var curveEndFrame = Math.floor((config.curveStartTime + config.curveDur ation) * sampleRate); | |
237 var fullGainFrame = config.fullGainTime * sampleRate; | |
238 | |
239 // TODO(crbug.com/517491): setValueAtTime is off by one rendering quant um. | |
240 fullGainFrame += 128; | |
241 | |
242 var k; | |
243 | |
244 // Zero out the start. | |
245 for (k = 0; k < curveStartFrame; ++k) { | |
hongchan
2015/08/07 17:32:51
One-line loop block does not curly embraces around
Raymond Toy
2015/08/07 18:58:32
Done.
| |
246 expected[k] = 0; | |
247 } | |
248 | |
249 // Linearly ramp now. This assumes that the actual curve used is a lin ear ramp, even if | |
250 // there are many curve points. | |
251 var stepSize = curveValue / (config.curveDuration * sampleRate - 1); | |
252 for (; k < curveEndFrame; ++k) { | |
hongchan
2015/08/07 17:32:51
ditto.
Raymond Toy
2015/08/07 18:58:32
Done.
| |
253 expected[k] = stepSize * (k - curveStartFrame); | |
254 } | |
255 | |
256 // Hold it constant until the next event | |
257 for (; k < fullGainFrame; ++k) { | |
hongchan
2015/08/07 17:32:51
ditto.
Raymond Toy
2015/08/07 18:58:32
Done.
| |
258 expected[k] = curveValue; | |
259 } | |
260 | |
261 // Amplitude is one for the rest of the test. | |
262 for (; k < testDurationFrames; ++k) { | |
hongchan
2015/08/07 17:32:51
ditto.
Raymond Toy
2015/08/07 18:58:32
Done.
| |
263 expected[k] = 1; | |
264 } | |
265 | |
266 return expected; | |
267 } | |
268 | |
269 //runTest(); | |
hongchan
2015/08/07 17:32:51
Why is this commented out? Let's remove if this is
Raymond Toy
2015/08/07 18:58:33
Done.
| |
270 | |
271 audit.runTasks(); | |
272 | |
273 successfullyParsed = true; | |
274 </script> | |
275 </body> | |
276 </html> | |
OLD | NEW |