Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(336)

Side by Side Diff: third_party/WebKit/LayoutTests/webaudio/resources/audioparam-testing.js

Issue 1377903002: Use frames instead of time for running AudioParam timelines. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 var sampleRate = 44100; 1 var sampleRate = 44100;
hongchan 2015/09/30 22:14:18 Not relevant to this CL, but this test can be sepa
Raymond Toy 2015/09/30 22:30:18 Sorry, I don't understand this comment. What test
hongchan 2015/09/30 22:47:59 First, this file is a bit bloated now. I thought w
Raymond Toy 2015/10/01 18:05:55 Ok. But I did remove createConstantBuffer in favo
2 2
3 // Information about the starting/ending times and starting/ending values for ea ch time interval. 3 // Information about the starting/ending times and starting/ending values for ea ch time interval.
4 var timeValueInfo; 4 var timeValueInfo;
5 5
6 // The difference between starting values between each time interval. 6 // The difference between starting values between each time interval.
7 var startingValueDelta; 7 var startingValueDelta;
8 8
9 // For any automation function that has an end or target value, the end value is based the starting 9 // For any automation function that has an end or target value, the end value is based the starting
10 // value of the time interval. The starting value will be increased or decrease d by 10 // value of the time interval. The starting value will be increased or decrease d by
11 // |startEndValueChange|. We choose half of |startingValueDelta| so that the end ing value will be 11 // |startEndValueChange|. We choose half of |startingValueDelta| so that the end ing value will be
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 { 53 {
54 var startFrame = timeToSampleFrame(startTime, sampleRate); 54 var startFrame = timeToSampleFrame(startTime, sampleRate);
55 var endFrame = timeToSampleFrame(endTime, sampleRate); 55 var endFrame = timeToSampleFrame(endTime, sampleRate);
56 var length = endFrame - startFrame; 56 var length = endFrame - startFrame;
57 57
58 var buffer = createConstantBuffer(context, value, length); 58 var buffer = createConstantBuffer(context, value, length);
59 59
60 return buffer.getChannelData(0); 60 return buffer.getChannelData(0);
61 } 61 }
62 62
63 function getStartEndFrames(startTime, endTime, sampleRate)
64 {
65 // Start frame is the ceiling of the start time because the ramp
66 // starts at or after the sample frame. End frame is the ceiling
67 // because it's the exclusive ending frame of the automation.
68 var startFrame = Math.ceil(startTime * sampleRate);
69 var endFrame = Math.ceil(endTime * sampleRate);
70
71 return {startFrame: startFrame, endFrame: endFrame};
72 }
73
63 // Create a linear ramp starting at |startValue| and ending at |endValue|. The ramp starts at time 74 // Create a linear ramp starting at |startValue| and ending at |endValue|. The ramp starts at time
64 // |startTime| and ends at |endTime|. (The start and end times are only used to compute how many 75 // |startTime| and ends at |endTime|. (The start and end times are only used to compute how many
65 // samples to return.) 76 // samples to return.)
66 function createLinearRampArray(startTime, endTime, startValue, endValue, sampleR ate) 77 function createLinearRampArray(startTime, endTime, startValue, endValue, sampleR ate)
67 { 78 {
68 var startFrame = timeToSampleFrame(startTime, sampleRate); 79 var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
69 var endFrame = timeToSampleFrame(endTime, sampleRate); 80 var startFrame = frameInfo.startFrame;
81 var endFrame = frameInfo.endFrame;
70 var length = endFrame - startFrame; 82 var length = endFrame - startFrame;
71 var array = new Array(length); 83 var array = new Array(length);
72 84
73 var step = (endValue - startValue) / length; 85 var step = Math.fround((endValue - startValue) / (endTime - startTime) / sam pleRate);
86 var start = Math.fround(startValue + (endValue - startValue) * (startFrame / sampleRate - startTime) / (endTime - startTime));
74 87
88 var slope = (endValue - startValue) / (endTime - startTime);
89
90 // v(t) = v0 + (v1 - v0)*(t-t0)/(t1-t0)
75 for (k = 0; k < length; ++k) { 91 for (k = 0; k < length; ++k) {
76 array[k] = startValue + k * step; 92 //array[k] = Math.fround(start + k * step);
93 var t = (startFrame + k) / sampleRate;
94 array[k] = startValue + slope * (t - startTime);
77 } 95 }
78 96
79 return array; 97 return array;
80 } 98 }
81 99
82 // Create an exponential ramp starting at |startValue| and ending at |endValue|. The ramp starts at 100 // Create an exponential ramp starting at |startValue| and ending at |endValue|. The ramp starts at
83 // time |startTime| and ends at |endTime|. (The start and end times are only us ed to compute how 101 // time |startTime| and ends at |endTime|. (The start and end times are only us ed to compute how
84 // many samples to return.) 102 // many samples to return.)
85 function createExponentialRampArray(startTime, endTime, startValue, endValue, sa mpleRate) 103 function createExponentialRampArray(startTime, endTime, startValue, endValue, sa mpleRate)
86 { 104 {
87 var startFrame = timeToSampleFrame(startTime, sampleRate); 105 var deltaTime = endTime - startTime;
88 var endFrame = timeToSampleFrame(endTime, sampleRate); 106
107 var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
108 var startFrame = frameInfo.startFrame;
109 var endFrame = frameInfo.endFrame;
89 var length = endFrame - startFrame; 110 var length = endFrame - startFrame;
90 var array = new Array(length); 111 var array = new Array(length);
91 112
92 var multiplier = Math.pow(endValue / startValue, 1 / length); 113 var ratio = endValue / startValue;
93 114
115 // v(t) = v0*(v1/v0)^((t-t0)/(t1-t0))
94 for (var k = 0; k < length; ++k) { 116 for (var k = 0; k < length; ++k) {
95 array[k] = startValue * Math.pow(multiplier, k); 117 var t = Math.fround((startFrame + k) / sampleRate);
118 array[k] = Math.fround(startValue * Math.pow(ratio, (t - startTime) / de ltaTime));
96 } 119 }
97 120
98 return array; 121 return array;
99 } 122 }
100 123
101 function discreteTimeConstantForSampleRate(timeConstant, sampleRate) 124 function discreteTimeConstantForSampleRate(timeConstant, sampleRate)
102 { 125 {
103 return 1 - Math.exp(-1 / (sampleRate * timeConstant)); 126 return 1 - Math.exp(-1 / (sampleRate * timeConstant));
104 } 127 }
105 128
106 // Create a signal that starts at |startValue| and exponentially approaches the target value of 129 // Create a signal that starts at |startValue| and exponentially approaches the target value of
107 // |targetValue|, using a time constant of |timeConstant|. The ramp starts at t ime |startTime| and 130 // |targetValue|, using a time constant of |timeConstant|. The ramp starts at t ime |startTime| and
108 // ends at |endTime|. (The start and end times are only used to compute how man y samples to 131 // ends at |endTime|. (The start and end times are only used to compute how man y samples to
109 // return.) 132 // return.)
110 function createExponentialApproachArray(startTime, endTime, startValue, targetVa lue, sampleRate, timeConstant) 133 function createExponentialApproachArray(startTime, endTime, startValue, targetVa lue, sampleRate, timeConstant)
111 { 134 {
112 var startFrame = timeToSampleFrame(startTime, sampleRate); 135 var startFrameFloat = startTime * sampleRate;
113 var endFrame = timeToSampleFrame(endTime, sampleRate); 136 var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
114 var length = endFrame - startFrame; 137 var startFrame = frameInfo.startFrame;
138 var endFrame = frameInfo.endFrame;
139 var length = Math.floor(endFrame - startFrame);
115 var array = new Array(length); 140 var array = new Array(length);
116 var c = discreteTimeConstantForSampleRate(timeConstant, sampleRate); 141 var c = discreteTimeConstantForSampleRate(timeConstant, sampleRate);
117 142
118 var value = startValue; 143 var delta = startValue - targetValue;
119 144
145 // v(t) = v1 + (v0 - v1) * exp(-(t-t0)/tau)
120 for (var k = 0; k < length; ++k) { 146 for (var k = 0; k < length; ++k) {
147 var t = (startFrame + k) / sampleRate;
148 var value = targetValue + delta * Math.exp(-(t - startTime) / timeConsta nt);
121 array[k] = value; 149 array[k] = value;
122 value += (targetValue - value) * c;
123 } 150 }
124 151
125 return array; 152 return array;
153 }
154
155 // Create a sine wave of the specified duration.
156 function createReferenceSineArray(startTime, endTime, startValue, endValue, samp leRate)
157 {
158 // Ignore |startValue| and |endValue| for the sine wave.
159 var curve = createSineWaveArray(endTime - startTime, freqHz, sineAmplitude, sampleRate);
160 // Sample the curve appropriately.
161 var frameInfo = getStartEndFrames(startTime, endTime, sampleRate);
162 var startFrame = frameInfo.startFrame;
163 var endFrame = frameInfo.endFrame;
164 var length = Math.floor(endFrame - startFrame);
165 var array = new Array(length);
166
167 // v(t) = linearly interpolate between V[k] and V[k + 1] where k = floor(N/d uration*(t - t0))
168 var f = length / (endTime - startTime);
169
170 for (var k = 0; k < length; ++k) {
171 var t = (startFrame + k) / sampleRate;
172 var indexFloat = f * (t - startTime);
173 var index = Math.floor(indexFloat);
174 if (index + 1 < length) {
175 var v0 = curve[index];
176 var v1 = curve[index + 1];
177 array[k] = v0 + (v1 - v0) * (indexFloat - index);
178 } else {
179 array[k] = curve[length - 1];
180 }
181 }
182
183 return array;
126 } 184 }
127 185
128 // Create a sine wave of the given frequency and amplitude. The sine wave is of fset by half the 186 // Create a sine wave of the given frequency and amplitude. The sine wave is of fset by half the
129 // amplitude so that result is always positive. 187 // amplitude so that result is always positive.
130 function createSineWaveArray(durationSeconds, freqHz, amplitude, sampleRate) 188 function createSineWaveArray(durationSeconds, freqHz, amplitude, sampleRate)
131 { 189 {
132 var length = timeToSampleFrame(durationSeconds, sampleRate); 190 var length = timeToSampleFrame(durationSeconds, sampleRate);
133 var signal = new Float32Array(length); 191 var signal = new Float32Array(length);
134 var omega = 2 * Math.PI * freqHz / sampleRate; 192 var omega = 2 * Math.PI * freqHz / sampleRate;
135 var halfAmplitude = amplitude / 2; 193 var halfAmplitude = amplitude / 2;
(...skipping 10 matching lines...) Expand all
146 // value. 204 // value.
147 function endValueDelta(timeIntervalIndex) 205 function endValueDelta(timeIntervalIndex)
148 { 206 {
149 if (timeIntervalIndex & 1) { 207 if (timeIntervalIndex & 1) {
150 return -startEndValueChange; 208 return -startEndValueChange;
151 } else { 209 } else {
152 return startEndValueChange; 210 return startEndValueChange;
153 } 211 }
154 } 212 }
155 213
214 // Relative error metric
215 function relativeErrorMetric(actual, expected)
216 {
217 return (actual - expected) / Math.abs(expected);
218 }
219
220 // Difference metric
221 function differenceErrorMetric(actual, expected)
222 {
223 return actual - expected;
224 }
225
156 // Return the difference between the starting value at |timeIntervalIndex| and t he starting value at 226 // Return the difference between the starting value at |timeIntervalIndex| and t he starting value at
157 // the next time interval. Since we started at a large initial value, we decrea se the value at each 227 // the next time interval. Since we started at a large initial value, we decrea se the value at each
158 // time interval. 228 // time interval.
159 function valueUpdate(timeIntervalIndex) 229 function valueUpdate(timeIntervalIndex)
160 { 230 {
161 return -startingValueDelta; 231 return -startingValueDelta;
162 } 232 }
163 233
164 // Compare a section of the rendered data against our expected signal. 234 // Compare a section of the rendered data against our expected signal.
165 function comparePartialSignals(rendered, expectedFunction, startTime, endTime, v alueInfo, sampleRate) 235 function comparePartialSignals(rendered, expectedFunction, startTime, endTime, v alueInfo, sampleRate, errorMetric)
166 { 236 {
167 var startSample = timeToSampleFrame(startTime, sampleRate); 237 var startSample = timeToSampleFrame(startTime, sampleRate);
168 var expected = expectedFunction(startTime, endTime, valueInfo.startValue, va lueInfo.endValue, sampleRate, timeConstant); 238 var expected = expectedFunction(startTime, endTime, valueInfo.startValue, va lueInfo.endValue, sampleRate, timeConstant);
169 239
170 var n = expected.length; 240 var n = expected.length;
171 var maxError = -1; 241 var maxError = -1;
172 var maxErrorIndex = -1; 242 var maxErrorIndex = -1;
173 243
174 for (var k = 0; k < n; ++k) { 244 for (var k = 0; k < n; ++k) {
175 // Make sure we don't pass these tests because a NaN has been generated in either the 245 // Make sure we don't pass these tests because a NaN has been generated in either the
176 // rendered data or the reference data. 246 // rendered data or the reference data.
177 if (!isValidNumber(rendered[startSample + k])) { 247 if (!isValidNumber(rendered[startSample + k])) {
178 maxError = Infinity; 248 maxError = Infinity;
179 maxErrorIndex = startSample + k; 249 maxErrorIndex = startSample + k;
180 testFailed("NaN or infinity for rendered data at " + maxErrorIndex); 250 testFailed("NaN or infinity for rendered data at " + maxErrorIndex);
181 break; 251 break;
182 } 252 }
183 if (!isValidNumber(expected[k])) { 253 if (!isValidNumber(expected[k])) {
184 maxError = Infinity; 254 maxError = Infinity;
185 maxErrorIndex = startSample + k; 255 maxErrorIndex = startSample + k;
186 testFailed("Nan or infinity for reference data at " + maxErrorIndex) ; 256 testFailed("Nan or infinity for reference data at " + maxErrorIndex) ;
187 break; 257 break;
188 } 258 }
189 var error = Math.abs(rendered[startSample + k] - expected[k]); 259 var error = Math.abs(errorMetric(rendered[startSample + k], expected[k]) );
190 if (error > maxError) { 260 if (error > maxError) {
191 maxError = error; 261 maxError = error;
192 maxErrorIndex = k; 262 maxErrorIndex = k;
193 } 263 }
194 } 264 }
195 265
196 return {maxError : maxError, index : maxErrorIndex}; 266 return {maxError : maxError, index : maxErrorIndex, expected: expected};
197 } 267 }
198 268
199 // Find the discontinuities in the data and compare the locations of the discont inuities with the 269 // Find the discontinuities in the data and compare the locations of the discont inuities with the
200 // times that define the time intervals. There is a discontinuity if the differe nce between 270 // times that define the time intervals. There is a discontinuity if the differe nce between
201 // successive samples exceeds the threshold. 271 // successive samples exceeds the threshold.
202 function verifyDiscontinuities(values, times, threshold) 272 function verifyDiscontinuities(values, times, threshold)
203 { 273 {
204 var n = values.length; 274 var n = values.length;
205 var success = true; 275 var success = true;
206 var badLocations = 0; 276 var badLocations = 0;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 // maxError - maximum allowed difference between the rendered data and the expec ted data 333 // maxError - maximum allowed difference between the rendered data and the expec ted data
264 // 334 //
265 // rendererdData - array containing the rendered (actual) data 335 // rendererdData - array containing the rendered (actual) data
266 // 336 //
267 // expectedFunction - function to compute the expected data 337 // expectedFunction - function to compute the expected data
268 // 338 //
269 // timeValueInfo - array containing information about the start and end times an d the start and end 339 // timeValueInfo - array containing information about the start and end times an d the start and end
270 // values of each interval. 340 // values of each interval.
271 // 341 //
272 // breakThreshold - threshold to use for determining discontinuities. 342 // breakThreshold - threshold to use for determining discontinuities.
273 function compareSignals(testName, maxError, renderedData, expectedFunction, time ValueInfo, breakThreshold) 343 function compareSignals(testName, maxError, renderedData, expectedFunction, time ValueInfo, breakThreshold, errorMetric)
274 { 344 {
275 var success = true; 345 var success = true;
276 var failedTestCount = 0; 346 var failedTestCount = 0;
277 var times = timeValueInfo.times; 347 var times = timeValueInfo.times;
278 var values = timeValueInfo.values; 348 var values = timeValueInfo.values;
279 var n = values.length; 349 var n = values.length;
350 var expectedSignal = [];
280 351
281 success = verifyDiscontinuities(renderedData, times, breakThreshold); 352 success = verifyDiscontinuities(renderedData, times, breakThreshold);
282 353
283 for (var k = 0; k < n; ++k) { 354 for (var k = 0; k < n; ++k) {
284 var result = comparePartialSignals(renderedData, expectedFunction, times [k], times[k + 1], values[k], sampleRate); 355 var result = comparePartialSignals(renderedData, expectedFunction, times [k], times[k + 1], values[k], sampleRate, errorMetric);
356
357 expectedSignal = expectedSignal.concat(Array.prototype.slice.call(result .expected));
285 358
286 if (result.maxError > maxError) { 359 if (result.maxError > maxError) {
287 testFailed("Incorrect value for test " + k + ". Max error = " + resu lt.maxError + " at offset " + (result.index + timeToSampleFrame(times[k], sample Rate))); 360 var offset = result.index + timeToSampleFrame(times[k], sampleRate);
361 testFailed("Incorrect value for test " + k + ". Max error = " + resu lt.maxError
362 + " at offset " + offset
363 + ": actual = " + renderedData[offset]
364 + ", expected = " + expectedSignal[offset] + ".");
288 ++failedTestCount; 365 ++failedTestCount;
289 } 366 }
290 } 367 }
291 368
292 if (failedTestCount) { 369 if (failedTestCount) {
293 testFailed(failedTestCount + " tests failed out of " + n); 370 testFailed(failedTestCount + " tests failed out of " + n);
294 success = false; 371 success = false;
295 } else { 372 } else {
296 testPassed("All " + n + " tests passed within an acceptable tolerance.") ; 373 testPassed("All " + n + " tests passed within an acceptable relative tol erance of " + maxError + ".");
297 } 374 }
298 375
299 if (success) { 376 if (success) {
300 testPassed("AudioParam " + testName + " test passed."); 377 testPassed("AudioParam " + testName + " test passed.");
301 } else { 378 } else {
302 testFailed("AudioParam " + testName + " test failed."); 379 testFailed("AudioParam " + testName + " test failed.");
303 } 380 }
304 } 381 }
305 382
306 // Create a function to test the rendered data with the reference data. 383 // Create a function to test the rendered data with the reference data.
307 // 384 //
308 // testName - string describing the test 385 // testName - string describing the test
309 // 386 //
310 // error - max allowed error between rendered data and the reference data. 387 // error - max allowed error between rendered data and the reference data.
311 // 388 //
312 // referenceFunction - function that generates the reference data to be compared with the rendered 389 // referenceFunction - function that generates the reference data to be compared with the rendered
313 // data. 390 // data.
314 // 391 //
315 // jumpThreshold - optional parameter that specifies the threshold to use for de tecting 392 // jumpThreshold - optional parameter that specifies the threshold to use for de tecting
316 // discontinuities. If not specified, defaults to discontinuityThreshold. 393 // discontinuities. If not specified, defaults to discontinuityThreshold.
317 // 394 //
318 function checkResultFunction(testName, error, referenceFunction, jumpThreshold) 395 function checkResultFunction(testName, error, referenceFunction, jumpThreshold, errorMetric)
319 { 396 {
320 return function(event) { 397 return function(event) {
321 var buffer = event.renderedBuffer; 398 var buffer = event.renderedBuffer;
322 renderedData = buffer.getChannelData(0); 399 renderedData = buffer.getChannelData(0);
323 400
324 var threshold; 401 var threshold;
325 402
326 if (!jumpThreshold) { 403 if (!jumpThreshold) {
327 threshold = discontinuityThreshold; 404 threshold = discontinuityThreshold;
328 } else { 405 } else {
329 threshold = jumpThreshold; 406 threshold = jumpThreshold;
330 } 407 }
331 408
332 compareSignals(testName, error, renderedData, referenceFunction, timeVal ueInfo, threshold); 409 compareSignals(testName, error, renderedData, referenceFunction, timeVal ueInfo, threshold, errorMetric);
333 410
334 finishJSTest(); 411 finishJSTest();
335 } 412 }
336 } 413 }
337 414
338 // Run all the automation tests. 415 // Run all the automation tests.
339 // 416 //
340 // numberOfTests - number of tests (time intervals) to run. 417 // numberOfTests - number of tests (time intervals) to run.
341 // 418 //
342 // initialValue - The initial value of the first time interval. 419 // initialValue - The initial value of the first time interval.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 // testName - string indicating the test that is being run. 465 // testName - string indicating the test that is being run.
389 // 466 //
390 // maxError - maximum allowed error between the rendered data and the reference data 467 // maxError - maximum allowed error between the rendered data and the reference data
391 // 468 //
392 // referenceFunction - function that generates the reference data to be compared against the 469 // referenceFunction - function that generates the reference data to be compared against the
393 // rendered data. 470 // rendered data.
394 // 471 //
395 // jumpThreshold - optional parameter that specifies the threshold to use for de tecting 472 // jumpThreshold - optional parameter that specifies the threshold to use for de tecting
396 // discontinuities. If not specified, defaults to discontinuityThreshold. 473 // discontinuities. If not specified, defaults to discontinuityThreshold.
397 // 474 //
398 function createAudioGraphAndTest(numberOfTests, initialValue, setValueFunction, automationFunction, testName, maxError, referenceFunction, jumpThreshold) 475 function createAudioGraphAndTest(numberOfTests, initialValue, setValueFunction, automationFunction, testName, maxError, referenceFunction, jumpThreshold, errorM etric)
399 { 476 {
400 if (window.testRunner) { 477 if (window.testRunner) {
401 testRunner.dumpAsText(); 478 testRunner.dumpAsText();
402 testRunner.waitUntilDone(); 479 testRunner.waitUntilDone();
403 } 480 }
404 481
405 window.jsTestIsAsync = true; 482 window.jsTestIsAsync = true;
406 483
407 // Create offline audio context. 484 // Create offline audio context.
408 context = new OfflineAudioContext(2, renderLength(numberOfTests), sampleRate ); 485 context = new OfflineAudioContext(2, renderLength(numberOfTests), sampleRate );
(...skipping 19 matching lines...) Expand all
428 // Run the automation tests. 505 // Run the automation tests.
429 timeValueInfo = doAutomation(numberOfTests, 506 timeValueInfo = doAutomation(numberOfTests,
430 initialValue, 507 initialValue,
431 setValueFunction, 508 setValueFunction,
432 automationFunction); 509 automationFunction);
433 bufferSource.start(0); 510 bufferSource.start(0);
434 511
435 context.oncomplete = checkResultFunction(testName, 512 context.oncomplete = checkResultFunction(testName,
436 maxError, 513 maxError,
437 referenceFunction, 514 referenceFunction,
438 jumpThreshold); 515 jumpThreshold,
516 errorMetric || relativeErrorMetric) ;
439 context.startRendering(); 517 context.startRendering();
440 } 518 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698