175 lines
6.1 KiB
HTML
175 lines
6.1 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>
|
|
Test Automation of AudioListener
|
|
</title>
|
|
<script src="../../imported/w3c/web-platform-tests/resources/testharness.js"></script>
|
|
<script src="../../resources/testharnessreport.js"></script>
|
|
<script src="../resources/audit-util.js"></script>
|
|
<script src="../resources/audit.js"></script>
|
|
</head>
|
|
<body>
|
|
<script id="layout-test-code">
|
|
let sampleRate = 48000;
|
|
// These tests are quite slow, so don't run for many frames. 1024 frames
|
|
// should be enough to demonstrate that automations are working.
|
|
let renderFrames = 1024;
|
|
let renderDuration = renderFrames / sampleRate;
|
|
|
|
// End time of the automation. Fairly arbitrary, but must be less than
|
|
// the render duration so that we can verify that the automation did end
|
|
// at the correct time and value.
|
|
let endTime = 0.75 * renderDuration;
|
|
|
|
let audit = Audit.createTaskRunner();
|
|
|
|
// Starting position for the panner
|
|
let defaultStartPosition = {x: 0, y: 0, z: 0};
|
|
|
|
// Ending position for the panner
|
|
let pannerEndPosition = {x: 1000, y: 1000, z: 1000};
|
|
|
|
// Ending position for the listener. It MUST be the the negative of the
|
|
// pannerEndPosition!
|
|
let listenerEndPosition = {
|
|
x: -pannerEndPosition.x,
|
|
y: -pannerEndPosition.y,
|
|
z: -pannerEndPosition.z
|
|
};
|
|
|
|
|
|
// Test the linear, inverse, and exponential distance models when the
|
|
// AudioListener is moving instead of the panner. We take advantage that
|
|
// motion is relative and create a reference by moving the panner in one
|
|
// direction. The resulting output is the expected result. Then we redo
|
|
// the test, but this time move the listener in the opposite direction.
|
|
// The output of this test is compared against the panner result. They
|
|
// should be the same.
|
|
|
|
audit.define('linear', (task, should) => {
|
|
runTest({
|
|
should: should,
|
|
startPosition: defaultStartPosition,
|
|
endPosition: pannerEndPosition,
|
|
distanceModel: {model: 'linear', rolloff: 1}
|
|
}).then(() => task.done());
|
|
});
|
|
|
|
audit.define('exponential', (task, should) => {
|
|
runTest({
|
|
should: should,
|
|
startPosition: defaultStartPosition,
|
|
endPosition: pannerEndPosition,
|
|
distanceModel: {model: 'exponential', rolloff: 1.5}
|
|
}).then(() => task.done());
|
|
});
|
|
|
|
audit.define('inverse', (task, should) => {
|
|
runTest({
|
|
should: should,
|
|
startPosition: defaultStartPosition,
|
|
endPosition: pannerEndPosition,
|
|
distanceModel: {model: 'inverse', rolloff: 1}
|
|
}).then(() => task.done());
|
|
});
|
|
|
|
audit.run();
|
|
|
|
function createGraph() {
|
|
let context = new OfflineAudioContext(2, renderFrames, sampleRate);
|
|
// Stereo source for the panner.
|
|
let source = context.createBufferSource();
|
|
source.buffer = createConstantBuffer(context, renderFrames, [1, 2]);
|
|
|
|
let panner = context.createPanner();
|
|
panner.panningModel = 'equalpower';
|
|
|
|
source.connect(panner);
|
|
panner.connect(context.destination);
|
|
|
|
return {context: context, source: source, panner: panner};
|
|
}
|
|
|
|
// Run a listener test with the given options.
|
|
function runTest(options) {
|
|
let refResult;
|
|
|
|
return runPannerTest(options)
|
|
.then(function(renderedBuffer) {
|
|
refResult = renderedBuffer;
|
|
})
|
|
.then(function() {
|
|
// Move the listener in the opposite direction.
|
|
options.endPosition = listenerEndPosition;
|
|
return runListenerTest(options).then(function(renderedBuffer) {
|
|
compareResults(renderedBuffer, refResult, options);
|
|
});
|
|
});
|
|
}
|
|
|
|
function runPannerTest(options) {
|
|
let graph = createGraph();
|
|
|
|
return runTestCore(graph, options, graph.panner);
|
|
}
|
|
|
|
|
|
function runListenerTest(options) {
|
|
let graph = createGraph();
|
|
|
|
return runTestCore(graph, options, graph.context.listener);
|
|
}
|
|
|
|
function runTestCore(graph, options, audioOjbect) {
|
|
let {context, source, panner} = graph;
|
|
|
|
// Initialize the panner with known values.
|
|
panner.distanceModel = options.distanceModel.model;
|
|
panner.rolloffFactor = options.distanceModel.rolloff;
|
|
panner.panningModel = 'equalpower';
|
|
|
|
// Automate the location. audioObject must be either a PannerNode or
|
|
// the context's AudioListener.
|
|
|
|
audioOjbect.positionX.setValueAtTime(options.startPosition.x, 0);
|
|
audioOjbect.positionY.setValueAtTime(options.startPosition.y, 0);
|
|
audioOjbect.positionZ.setValueAtTime(options.startPosition.z, 0);
|
|
|
|
audioOjbect.positionX.linearRampToValueAtTime(
|
|
options.endPosition.x, endTime);
|
|
audioOjbect.positionY.linearRampToValueAtTime(
|
|
options.endPosition.y, endTime);
|
|
audioOjbect.positionZ.linearRampToValueAtTime(
|
|
options.endPosition.z, endTime);
|
|
|
|
// Start the source, render the graph, and return the resulting promise
|
|
// from rendering.
|
|
source.start();
|
|
|
|
return context.startRendering().then(function(resultBuffer) {
|
|
return resultBuffer;
|
|
});
|
|
}
|
|
|
|
function compareResults(actualResult, expectedResult, options) {
|
|
// Compare the output with the reference output from moving the source
|
|
// in the opposite direction.
|
|
|
|
let expectedLeft = expectedResult.getChannelData(0);
|
|
let expectedRight = expectedResult.getChannelData(1);
|
|
|
|
let actualLeft = actualResult.getChannelData(0);
|
|
let actualRight = actualResult.getChannelData(1);
|
|
|
|
let prefix = 'Distance model: "' + options.distanceModel.model + '"';
|
|
prefix += ', rolloff: ' + options.distanceModel.rolloff;
|
|
options.should(actualLeft, prefix + ': left channel')
|
|
.beCloseToArray(expectedLeft, 0);
|
|
options.should(actualRight, prefix + ': right channel')
|
|
.beCloseToArray(expectedRight, 0);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|