mirror of
https://github.com/servo/servo.git
synced 2025-08-11 00:15:32 +01:00
Update web-platform-tests to revision b7ee88243f64e6c7f2d00c163bd3bc501e4db7ef
This commit is contained in:
parent
804b4b3db6
commit
a4b4c8e015
134 changed files with 2918 additions and 388 deletions
|
@ -0,0 +1,193 @@
|
|||
let sampleRate = 44100.0;
|
||||
|
||||
// How many panner nodes to create for the test.
|
||||
let nodesToCreate = 100;
|
||||
|
||||
// Time step when each panner node starts.
|
||||
let timeStep = 0.001;
|
||||
|
||||
// Make sure we render long enough to get all of our nodes.
|
||||
let renderLengthSeconds = timeStep * (nodesToCreate + 1);
|
||||
|
||||
// Length of an impulse signal.
|
||||
let pulseLengthFrames = Math.round(timeStep * sampleRate);
|
||||
|
||||
// Globals to make debugging a little easier.
|
||||
let context;
|
||||
let impulse;
|
||||
let bufferSource;
|
||||
let panner;
|
||||
let position;
|
||||
let time;
|
||||
|
||||
// For the record, these distance formulas were taken from the OpenAL
|
||||
// spec
|
||||
// (http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.pdf),
|
||||
// not the code. The Web Audio spec follows the OpenAL formulas.
|
||||
|
||||
function linearDistance(panner, x, y, z) {
|
||||
let distance = Math.sqrt(x * x + y * y + z * z);
|
||||
distance = Math.min(distance, panner.maxDistance);
|
||||
let rolloff = panner.rolloffFactor;
|
||||
let gain =
|
||||
(1 -
|
||||
rolloff * (distance - panner.refDistance) /
|
||||
(panner.maxDistance - panner.refDistance));
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
function inverseDistance(panner, x, y, z) {
|
||||
let distance = Math.sqrt(x * x + y * y + z * z);
|
||||
distance = Math.min(distance, panner.maxDistance);
|
||||
let rolloff = panner.rolloffFactor;
|
||||
let gain = panner.refDistance /
|
||||
(panner.refDistance + rolloff * (distance - panner.refDistance));
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
function exponentialDistance(panner, x, y, z) {
|
||||
let distance = Math.sqrt(x * x + y * y + z * z);
|
||||
distance = Math.min(distance, panner.maxDistance);
|
||||
let rolloff = panner.rolloffFactor;
|
||||
let gain = Math.pow(distance / panner.refDistance, -rolloff);
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
// Map the distance model to the function that implements the model
|
||||
let distanceModelFunction = {
|
||||
'linear': linearDistance,
|
||||
'inverse': inverseDistance,
|
||||
'exponential': exponentialDistance
|
||||
};
|
||||
|
||||
function createGraph(context, distanceModel, nodeCount) {
|
||||
bufferSource = new Array(nodeCount);
|
||||
panner = new Array(nodeCount);
|
||||
position = new Array(nodeCount);
|
||||
time = new Array(nodesToCreate);
|
||||
|
||||
impulse = createImpulseBuffer(context, pulseLengthFrames);
|
||||
|
||||
// Create all the sources and panners.
|
||||
//
|
||||
// We MUST use the EQUALPOWER panning model so that we can easily
|
||||
// figure out the gain introduced by the panner.
|
||||
//
|
||||
// We want to stay in the middle of the panning range, which means
|
||||
// we want to stay on the z-axis. If we don't, then the effect of
|
||||
// panning model will be much more complicated. We're not testing
|
||||
// the panner, but the distance model, so we want the panner effect
|
||||
// to be simple.
|
||||
//
|
||||
// The panners are placed at a uniform intervals between the panner
|
||||
// reference distance and the panner max distance. The source is
|
||||
// also started at regular intervals.
|
||||
for (let k = 0; k < nodeCount; ++k) {
|
||||
bufferSource[k] = context.createBufferSource();
|
||||
bufferSource[k].buffer = impulse;
|
||||
|
||||
panner[k] = context.createPanner();
|
||||
panner[k].panningModel = 'equalpower';
|
||||
panner[k].distanceModel = distanceModel;
|
||||
|
||||
let distanceStep =
|
||||
(panner[k].maxDistance - panner[k].refDistance) / nodeCount;
|
||||
position[k] = distanceStep * k + panner[k].refDistance;
|
||||
panner[k].setPosition(0, 0, position[k]);
|
||||
|
||||
bufferSource[k].connect(panner[k]);
|
||||
panner[k].connect(context.destination);
|
||||
|
||||
time[k] = k * timeStep;
|
||||
bufferSource[k].start(time[k]);
|
||||
}
|
||||
}
|
||||
|
||||
// distanceModel should be the distance model string like
|
||||
// "linear", "inverse", or "exponential".
|
||||
function createTestAndRun(context, distanceModel, should) {
|
||||
// To test the distance models, we create a number of panners at
|
||||
// uniformly spaced intervals on the z-axis. Each of these are
|
||||
// started at equally spaced time intervals. After rendering the
|
||||
// signals, we examine where each impulse is located and the
|
||||
// attenuation of the impulse. The attenuation is compared
|
||||
// against our expected attenuation.
|
||||
|
||||
createGraph(context, distanceModel, nodesToCreate);
|
||||
|
||||
return context.startRendering().then(
|
||||
buffer => checkDistanceResult(buffer, distanceModel, should));
|
||||
}
|
||||
|
||||
// The gain caused by the EQUALPOWER panning model, if we stay on the
|
||||
// z axis, with the default orientations.
|
||||
function equalPowerGain() {
|
||||
return Math.SQRT1_2;
|
||||
}
|
||||
|
||||
function checkDistanceResult(renderedBuffer, model, should) {
|
||||
renderedData = renderedBuffer.getChannelData(0);
|
||||
|
||||
// The max allowed error between the actual gain and the expected
|
||||
// value. This is determined experimentally. Set to 0 to see
|
||||
// what the actual errors are.
|
||||
let maxAllowedError = 3.3e-6;
|
||||
|
||||
let success = true;
|
||||
|
||||
// Number of impulses we found in the rendered result.
|
||||
let impulseCount = 0;
|
||||
|
||||
// Maximum relative error in the gain of the impulses.
|
||||
let maxError = 0;
|
||||
|
||||
// Array of locations of the impulses that were not at the
|
||||
// expected location. (Contains the actual and expected frame
|
||||
// of the impulse.)
|
||||
let impulsePositionErrors = new Array();
|
||||
|
||||
// Step through the rendered data to find all the non-zero points
|
||||
// so we can find where our distance-attenuated impulses are.
|
||||
// These are tested against the expected attenuations at that
|
||||
// distance.
|
||||
for (let k = 0; k < renderedData.length; ++k) {
|
||||
if (renderedData[k] != 0) {
|
||||
// Convert from string to index.
|
||||
let distanceFunction = distanceModelFunction[model];
|
||||
let expected =
|
||||
distanceFunction(panner[impulseCount], 0, 0, position[impulseCount]);
|
||||
|
||||
// Adjust for the center-panning of the EQUALPOWER panning
|
||||
// model that we're using.
|
||||
expected *= equalPowerGain();
|
||||
|
||||
let error = Math.abs(renderedData[k] - expected) / Math.abs(expected);
|
||||
|
||||
maxError = Math.max(maxError, Math.abs(error));
|
||||
|
||||
should(renderedData[k]).beCloseTo(expected, {threshold: maxAllowedError});
|
||||
|
||||
// Keep track of any impulses that aren't where we expect them
|
||||
// to be.
|
||||
let expectedOffset = timeToSampleFrame(time[impulseCount], sampleRate);
|
||||
if (k != expectedOffset) {
|
||||
impulsePositionErrors.push({actual: k, expected: expectedOffset});
|
||||
}
|
||||
++impulseCount;
|
||||
}
|
||||
}
|
||||
should(impulseCount, 'Number of impulses').beEqualTo(nodesToCreate);
|
||||
|
||||
should(maxError, 'Max error in distance gains')
|
||||
.beLessThanOrEqualTo(maxAllowedError);
|
||||
|
||||
// Display any timing errors that we found.
|
||||
if (impulsePositionErrors.length > 0) {
|
||||
let actual = impulsePositionErrors.map(x => x.actual);
|
||||
let expected = impulsePositionErrors.map(x => x.expected);
|
||||
should(actual, 'Actual impulse positions found').beEqualToArray(expected);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue