Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / webaudio / resources / audioparam-testing.js
blob3df3083d1a58ab9b635424046fda7041f064c712
1 var sampleRate = 44100;
3 // Information about the starting/ending times and starting/ending values for each time interval.
4 var timeValueInfo;
6 // The difference between starting values between each time interval.
7 var startingValueDelta;
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 decreased by
11 // |startEndValueChange|. We choose half of |startingValueDelta| so that the ending value will be
12 // distinct from the starting value for next time interval. This allows us to detect where the ramp
13 // begins and ends.
14 var startEndValueChange;
16 // Default threshold to use for detecting discontinuities that should appear at each time interval.
17 var discontinuityThreshold;
19 // Time interval between value changes. It is best if 1 / numberOfTests is not close to timeInterval.
20 var timeInterval = .03;
22 // Some suitable time constant so that we can see a significant change over a timeInterval. This is
23 // only needed by setTargetAtTime() which needs a time constant.
24 var timeConstant = timeInterval / 3;
26 var gainNode;
28 var context;
30 // Make sure we render long enough to capture all of our test data.
31 function renderLength(numberOfTests)
33 return timeToSampleFrame((numberOfTests + 1) * timeInterval, sampleRate);
36 // Create a buffer containing the same constant value.
37 function createConstantBuffer(context, constant, length) {
38 var buffer = context.createBuffer(1, length, context.sampleRate);
39 var n = buffer.length;
40 var data = buffer.getChannelData(0);
42 for (var k = 0; k < n; ++k) {
43 data[k] = constant;
46 return buffer;
49 // Create a constant reference signal with the given |value|. Basically the same as
50 // |createConstantBuffer|, but with the parameters to match the other create functions. The
51 // |endValue| is ignored.
52 function createConstantArray(startTime, endTime, value, endValue, sampleRate)
54 var startFrame = timeToSampleFrame(startTime, sampleRate);
55 var endFrame = timeToSampleFrame(endTime, sampleRate);
56 var length = endFrame - startFrame;
58 var buffer = createConstantBuffer(context, value, length);
60 return buffer.getChannelData(0);
63 // 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
65 // samples to return.)
66 function createLinearRampArray(startTime, endTime, startValue, endValue, sampleRate)
68 var startFrame = timeToSampleFrame(startTime, sampleRate);
69 var endFrame = timeToSampleFrame(endTime, sampleRate);
70 var length = endFrame - startFrame;
71 var array = new Array(length);
73 var step = (endValue - startValue) / length;
75 for (k = 0; k < length; ++k) {
76 array[k] = startValue + k * step;
79 return array;
82 // 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 used to compute how
84 // many samples to return.)
85 function createExponentialRampArray(startTime, endTime, startValue, endValue, sampleRate)
87 var startFrame = timeToSampleFrame(startTime, sampleRate);
88 var endFrame = timeToSampleFrame(endTime, sampleRate);
89 var length = endFrame - startFrame;
90 var array = new Array(length);
92 var multiplier = Math.pow(endValue / startValue, 1 / length);
94 for (var k = 0; k < length; ++k) {
95 array[k] = startValue * Math.pow(multiplier, k);
98 return array;
101 function discreteTimeConstantForSampleRate(timeConstant, sampleRate)
103 return 1 - Math.exp(-1 / (sampleRate * timeConstant));
106 // 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 time |startTime| and
108 // ends at |endTime|. (The start and end times are only used to compute how many samples to
109 // return.)
110 function createExponentialApproachArray(startTime, endTime, startValue, targetValue, sampleRate, timeConstant)
112 var startFrame = timeToSampleFrame(startTime, sampleRate);
113 var endFrame = timeToSampleFrame(endTime, sampleRate);
114 var length = endFrame - startFrame;
115 var array = new Array(length);
116 var c = discreteTimeConstantForSampleRate(timeConstant, sampleRate);
118 var value = startValue;
120 for (var k = 0; k < length; ++k) {
121 array[k] = value;
122 value += (targetValue - value) * c;
125 return array;
128 // Create a sine wave of the given frequency and amplitude. The sine wave is offset by half the
129 // amplitude so that result is always positive.
130 function createSineWaveArray(durationSeconds, freqHz, amplitude, sampleRate)
132 var length = timeToSampleFrame(durationSeconds, sampleRate);
133 var signal = new Float32Array(length);
134 var omega = 2 * Math.PI * freqHz / sampleRate;
135 var halfAmplitude = amplitude / 2;
137 for (var k = 0; k < length; ++k) {
138 signal[k] = halfAmplitude + halfAmplitude * Math.sin(omega * k);
141 return signal;
144 // Return the difference between the starting value and the ending value for time interval
145 // |timeIntervalIndex|. We alternate between an end value that is above or below the starting
146 // value.
147 function endValueDelta(timeIntervalIndex)
149 if (timeIntervalIndex & 1) {
150 return -startEndValueChange;
151 } else {
152 return startEndValueChange;
156 // Return the difference between the starting value at |timeIntervalIndex| and the starting value at
157 // the next time interval. Since we started at a large initial value, we decrease the value at each
158 // time interval.
159 function valueUpdate(timeIntervalIndex)
161 return -startingValueDelta;
164 // Compare a section of the rendered data against our expected signal.
165 function comparePartialSignals(rendered, expectedFunction, startTime, endTime, valueInfo, sampleRate)
167 var startSample = timeToSampleFrame(startTime, sampleRate);
168 var expected = expectedFunction(startTime, endTime, valueInfo.startValue, valueInfo.endValue, sampleRate, timeConstant);
170 var n = expected.length;
171 var maxError = -1;
172 var maxErrorIndex = -1;
174 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
176 // rendered data or the reference data.
177 if (!isValidNumber(rendered[startSample + k])) {
178 maxError = Infinity;
179 maxErrorIndex = startSample + k;
180 testFailed("NaN or infinity for rendered data at " + maxErrorIndex);
181 break;
183 if (!isValidNumber(expected[k])) {
184 maxError = Infinity;
185 maxErrorIndex = startSample + k;
186 testFailed("Nan or infinity for reference data at " + maxErrorIndex);
187 break;
189 var error = Math.abs(rendered[startSample + k] - expected[k]);
190 if (error > maxError) {
191 maxError = error;
192 maxErrorIndex = k;
196 return {maxError : maxError, index : maxErrorIndex};
199 // Find the discontinuities in the data and compare the locations of the discontinuities with the
200 // times that define the time intervals. There is a discontinuity if the difference between
201 // successive samples exceeds the threshold.
202 function verifyDiscontinuities(values, times, threshold)
204 var n = values.length;
205 var success = true;
206 var badLocations = 0;
207 var breaks = [];
209 // Find discontinuities.
210 for (var k = 1; k < n; ++k) {
211 if (Math.abs(values[k] - values[k - 1]) > threshold) {
212 breaks.push(k);
216 var testCount;
218 // If there are numberOfTests intervals, there are only numberOfTests - 1 internal interval
219 // boundaries. Hence the maximum number of discontinuties we expect to find is numberOfTests -
220 // 1. If we find more than that, we have no reference to compare against. We also assume that
221 // the actual discontinuities are close to the expected ones.
223 // This is just a sanity check when something goes really wrong. For example, if the threshold
224 // is too low, every sample frame looks like a discontinuity.
225 if (breaks.length >= numberOfTests) {
226 testCount = numberOfTests - 1;
227 testFailed("Found more discontinuities (" + breaks.length + ") than expected. Only comparing first " + testCount + "discontinuities.");
228 success = false;
229 } else {
230 testCount = breaks.length;
233 // Compare the location of each discontinuity with the end time of each interval. (There is no
234 // discontinuity at the start of the signal.)
235 for (var k = 0; k < testCount; ++k) {
236 var expectedSampleFrame = timeToSampleFrame(times[k + 1], sampleRate);
237 if (breaks[k] != expectedSampleFrame) {
238 success = false;
239 ++badLocations;
240 testFailed("Expected discontinuity at " + expectedSampleFrame + " but got " + breaks[k]);
244 if (badLocations) {
245 testFailed(badLocations + " discontinuities at incorrect locations");
246 success = false;
247 } else {
248 if (breaks.length == numberOfTests - 1) {
249 testPassed("All " + numberOfTests + " tests started and ended at the correct time.");
250 } else {
251 testFailed("Found " + breaks.length + " discontinuities but expected " + (numberOfTests - 1));
252 success = false;
256 return success;
259 // Compare the rendered data with the expected data.
261 // testName - string describing the test
263 // maxError - maximum allowed difference between the rendered data and the expected data
265 // rendererdData - array containing the rendered (actual) data
267 // expectedFunction - function to compute the expected data
269 // timeValueInfo - array containing information about the start and end times and the start and end
270 // values of each interval.
272 // breakThreshold - threshold to use for determining discontinuities.
273 function compareSignals(testName, maxError, renderedData, expectedFunction, timeValueInfo, breakThreshold)
275 var success = true;
276 var failedTestCount = 0;
277 var times = timeValueInfo.times;
278 var values = timeValueInfo.values;
279 var n = values.length;
281 success = verifyDiscontinuities(renderedData, times, breakThreshold);
283 for (var k = 0; k < n; ++k) {
284 var result = comparePartialSignals(renderedData, expectedFunction, times[k], times[k + 1], values[k], sampleRate);
286 if (result.maxError > maxError) {
287 testFailed("Incorrect value for test " + k + ". Max error = " + result.maxError + " at offset " + (result.index + timeToSampleFrame(times[k], sampleRate)));
288 ++failedTestCount;
292 if (failedTestCount) {
293 testFailed(failedTestCount + " tests failed out of " + n);
294 success = false;
295 } else {
296 testPassed("All " + n + " tests passed within an acceptable tolerance.");
299 if (success) {
300 testPassed("AudioParam " + testName + " test passed.");
301 } else {
302 testFailed("AudioParam " + testName + " test failed.");
306 // Create a function to test the rendered data with the reference data.
308 // testName - string describing the test
310 // error - max allowed error between rendered data and the reference data.
312 // referenceFunction - function that generates the reference data to be compared with the rendered
313 // data.
315 // jumpThreshold - optional parameter that specifies the threshold to use for detecting
316 // discontinuities. If not specified, defaults to discontinuityThreshold.
318 function checkResultFunction(testName, error, referenceFunction, jumpThreshold)
320 return function(event) {
321 var buffer = event.renderedBuffer;
322 renderedData = buffer.getChannelData(0);
324 var threshold;
326 if (!jumpThreshold) {
327 threshold = discontinuityThreshold;
328 } else {
329 threshold = jumpThreshold;
332 compareSignals(testName, error, renderedData, referenceFunction, timeValueInfo, threshold);
334 finishJSTest();
338 // Run all the automation tests.
340 // numberOfTests - number of tests (time intervals) to run.
342 // initialValue - The initial value of the first time interval.
344 // setValueFunction - function that sets the specified value at the start of a time interval.
346 // automationFunction - function that sets the end value for the time interval. It specifies how
347 // the value approaches the end value.
349 // An object is returned containing an array of start times for each time interval, and an array
350 // giving the start and end values for the interval.
351 function doAutomation(numberOfTests, initialValue, setValueFunction, automationFunction)
353 var timeInfo = [0];
354 var valueInfo = [];
355 var value = initialValue;
357 for (var k = 0; k < numberOfTests; ++k) {
358 var startTime = k * timeInterval;
359 var endTime = (k + 1) * timeInterval;
360 var endValue = value + endValueDelta(k);
362 // Set the value at the start of the time interval.
363 setValueFunction(value, startTime);
365 // Specify the end or target value, and how we should approach it.
366 automationFunction(endValue, startTime, endTime);
368 // Keep track of the start times, and the start and end values for each time interval.
369 timeInfo.push(endTime);
370 valueInfo.push({startValue: value, endValue : endValue});
372 value += valueUpdate(k);
375 return {times : timeInfo, values : valueInfo};
378 // Create the audio graph for the test and then run the test.
380 // numberOfTests - number of time intervals (tests) to run.
382 // initialValue - the initial value of the gain at time 0.
384 // setValueFunction - function to set the value at the beginning of each time interval.
386 // automationFunction - the AudioParamTimeline automation function
388 // testName - string indicating the test that is being run.
390 // maxError - maximum allowed error between the rendered data and the reference data
392 // referenceFunction - function that generates the reference data to be compared against the
393 // rendered data.
395 // jumpThreshold - optional parameter that specifies the threshold to use for detecting
396 // discontinuities. If not specified, defaults to discontinuityThreshold.
398 function createAudioGraphAndTest(numberOfTests, initialValue, setValueFunction, automationFunction, testName, maxError, referenceFunction, jumpThreshold)
400 if (window.testRunner) {
401 testRunner.dumpAsText();
402 testRunner.waitUntilDone();
405 window.jsTestIsAsync = true;
407 // Create offline audio context.
408 context = new OfflineAudioContext(2, renderLength(numberOfTests), sampleRate);
409 var constantBuffer = createConstantBuffer(context, 1, renderLength(numberOfTests));
411 // We use an AudioGainNode here simply as a convenient way to test the AudioParam
412 // automation, since it's easy to pass a constant value through the node, automate the
413 // .gain attribute and observe the resulting values.
415 gainNode = context.createGain();
417 var bufferSource = context.createBufferSource();
418 bufferSource.buffer = constantBuffer;
419 bufferSource.connect(gainNode);
420 gainNode.connect(context.destination);
422 // Set up default values for the parameters that control how the automation test values progress
423 // for each time interval.
424 startingValueDelta = initialValue / numberOfTests;
425 startEndValueChange = startingValueDelta / 2;
426 discontinuityThreshold = startEndValueChange / 2;
428 // Run the automation tests.
429 timeValueInfo = doAutomation(numberOfTests,
430 initialValue,
431 setValueFunction,
432 automationFunction);
433 bufferSource.start(0);
435 context.oncomplete = checkResultFunction(testName,
436 maxError,
437 referenceFunction,
438 jumpThreshold);
439 context.startRendering();