mirror of
https://github.com/servo/servo.git
synced 2025-09-03 03:28:20 +01:00
Update web-platform-tests to revision 68a256f49be380ca4add535ce8ece9de28820e6b
This commit is contained in:
parent
e54935c25a
commit
cd5bf022bd
178 changed files with 6082 additions and 795 deletions
|
@ -0,0 +1,203 @@
|
|||
let StereoPannerTest = (function() {
|
||||
|
||||
// Constants
|
||||
let PI_OVER_TWO = Math.PI * 0.5;
|
||||
|
||||
let gSampleRate = 44100;
|
||||
|
||||
// Time step when each panner node starts.
|
||||
let gTimeStep = 0.001;
|
||||
|
||||
// How many panner nodes to create for the test
|
||||
let gNodesToCreate = 100;
|
||||
|
||||
// Total render length for all of our nodes.
|
||||
let gRenderLength = gTimeStep * (gNodesToCreate + 1) + gSampleRate;
|
||||
|
||||
// Calculates channel gains based on equal power panning model.
|
||||
// See: http://webaudio.github.io/web-audio-api/#panning-algorithm
|
||||
function getChannelGain(pan, numberOfChannels) {
|
||||
// The internal panning clips the pan value between -1, 1.
|
||||
pan = Math.min(Math.max(pan, -1), 1);
|
||||
let gainL, gainR;
|
||||
// Consider number of channels and pan value's polarity.
|
||||
if (numberOfChannels == 1) {
|
||||
let panRadian = (pan * 0.5 + 0.5) * PI_OVER_TWO;
|
||||
gainL = Math.cos(panRadian);
|
||||
gainR = Math.sin(panRadian);
|
||||
} else {
|
||||
let panRadian = (pan <= 0 ? pan + 1 : pan) * PI_OVER_TWO;
|
||||
if (pan <= 0) {
|
||||
gainL = 1 + Math.cos(panRadian);
|
||||
gainR = Math.sin(panRadian);
|
||||
} else {
|
||||
gainL = Math.cos(panRadian);
|
||||
gainR = 1 + Math.sin(panRadian);
|
||||
}
|
||||
}
|
||||
return {gainL: gainL, gainR: gainR};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test implementation class.
|
||||
* @param {Object} options Test options
|
||||
* @param {Object} options.description Test description
|
||||
* @param {Object} options.numberOfInputChannels Number of input channels
|
||||
*/
|
||||
function Test(should, options) {
|
||||
// Primary test flag.
|
||||
this.success = true;
|
||||
|
||||
this.should = should;
|
||||
this.context = null;
|
||||
this.prefix = options.prefix;
|
||||
this.numberOfInputChannels = (options.numberOfInputChannels || 1);
|
||||
switch (this.numberOfInputChannels) {
|
||||
case 1:
|
||||
this.description = 'Test for mono input';
|
||||
break;
|
||||
case 2:
|
||||
this.description = 'Test for stereo input';
|
||||
break;
|
||||
}
|
||||
|
||||
// Onset time position of each impulse.
|
||||
this.onsets = [];
|
||||
|
||||
// Pan position value of each impulse.
|
||||
this.panPositions = [];
|
||||
|
||||
// Locations of where the impulses aren't at the expected locations.
|
||||
this.errors = [];
|
||||
|
||||
// The index of the current impulse being verified.
|
||||
this.impulseIndex = 0;
|
||||
|
||||
// The max error we allow between the rendered impulse and the
|
||||
// expected value. This value is experimentally determined. Set
|
||||
// to 0 to make the test fail to see what the actual error is.
|
||||
this.maxAllowedError = 1.3e-6;
|
||||
|
||||
// Max (absolute) error and the index of the maxima for the left
|
||||
// and right channels.
|
||||
this.maxErrorL = 0;
|
||||
this.maxErrorR = 0;
|
||||
this.maxErrorIndexL = 0;
|
||||
this.maxErrorIndexR = 0;
|
||||
|
||||
// The maximum value to use for panner pan value. The value will range from
|
||||
// -panLimit to +panLimit.
|
||||
this.panLimit = 1.0625;
|
||||
}
|
||||
|
||||
|
||||
Test.prototype.init = function() {
|
||||
this.context = new OfflineAudioContext(2, gRenderLength, gSampleRate);
|
||||
};
|
||||
|
||||
// Prepare an audio graph for testing. Create multiple impulse generators and
|
||||
// panner nodes, then play them sequentially while varying the pan position.
|
||||
Test.prototype.prepare = function() {
|
||||
let impulse;
|
||||
let impulseLength = Math.round(gTimeStep * gSampleRate);
|
||||
let sources = [];
|
||||
let panners = [];
|
||||
|
||||
// Moves the pan value for each panner by pan step unit from -2 to 2.
|
||||
// This is to check if the internal panning value is clipped properly.
|
||||
let panStep = (2 * this.panLimit) / (gNodesToCreate - 1);
|
||||
|
||||
if (this.numberOfInputChannels === 1) {
|
||||
impulse = createImpulseBuffer(this.context, impulseLength);
|
||||
} else {
|
||||
impulse = createStereoImpulseBuffer(this.context, impulseLength);
|
||||
}
|
||||
|
||||
for (let i = 0; i < gNodesToCreate; i++) {
|
||||
sources[i] = this.context.createBufferSource();
|
||||
panners[i] = this.context.createStereoPanner();
|
||||
sources[i].connect(panners[i]);
|
||||
panners[i].connect(this.context.destination);
|
||||
sources[i].buffer = impulse;
|
||||
panners[i].pan.value = this.panPositions[i] = panStep * i - this.panLimit;
|
||||
|
||||
// Store the onset time position of impulse.
|
||||
this.onsets[i] = gTimeStep * i;
|
||||
|
||||
sources[i].start(this.onsets[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Test.prototype.verify = function() {
|
||||
let chanL = this.renderedBufferL;
|
||||
let chanR = this.renderedBufferR;
|
||||
for (let i = 0; i < chanL.length; i++) {
|
||||
// Left and right channels must start at the same instant.
|
||||
if (chanL[i] !== 0 || chanR[i] !== 0) {
|
||||
// Get amount of error between actual and expected gain.
|
||||
let expected = getChannelGain(
|
||||
this.panPositions[this.impulseIndex], this.numberOfInputChannels);
|
||||
let errorL = Math.abs(chanL[i] - expected.gainL);
|
||||
let errorR = Math.abs(chanR[i] - expected.gainR);
|
||||
|
||||
if (errorL > this.maxErrorL) {
|
||||
this.maxErrorL = errorL;
|
||||
this.maxErrorIndexL = this.impulseIndex;
|
||||
}
|
||||
if (errorR > this.maxErrorR) {
|
||||
this.maxErrorR = errorR;
|
||||
this.maxErrorIndexR = this.impulseIndex;
|
||||
}
|
||||
|
||||
// Keep track of the impulses that didn't show up where we expected
|
||||
// them to be.
|
||||
let expectedOffset =
|
||||
timeToSampleFrame(this.onsets[this.impulseIndex], gSampleRate);
|
||||
if (i != expectedOffset) {
|
||||
this.errors.push({actual: i, expected: expectedOffset});
|
||||
}
|
||||
|
||||
this.impulseIndex++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Test.prototype.showResult = function() {
|
||||
this.should(this.impulseIndex, this.prefix + 'Number of impulses found')
|
||||
.beEqualTo(gNodesToCreate);
|
||||
|
||||
this.should(
|
||||
this.errors.length,
|
||||
this.prefix + 'Number of impulse at the wrong offset')
|
||||
.beEqualTo(0);
|
||||
|
||||
this.should(this.maxErrorL, this.prefix + 'Left channel error magnitude')
|
||||
.beLessThanOrEqualTo(this.maxAllowedError);
|
||||
|
||||
this.should(this.maxErrorR, this.prefix + 'Right channel error magnitude')
|
||||
.beLessThanOrEqualTo(this.maxAllowedError);
|
||||
};
|
||||
|
||||
Test.prototype.run = function() {
|
||||
|
||||
this.init();
|
||||
this.prepare();
|
||||
|
||||
return this.context.startRendering().then(renderedBuffer => {
|
||||
this.renderedBufferL = renderedBuffer.getChannelData(0);
|
||||
this.renderedBufferR = renderedBuffer.getChannelData(1);
|
||||
this.verify();
|
||||
this.showResult();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
create: function(should, options) {
|
||||
return new Test(should, options);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue