blob: 8aa73552aab5e1639ac95e4ae7e06c725c9cad0c [file] [log] [blame]
<!doctype html>
<html>
<head>
<title>Panner Node Automation</title>
<script src="/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>
// Use a power-of-two to eliminate some round-off; otherwise, this isn't
// really important.
const sampleRate = 16384;
// Render enough for the test; we don't need a lot.
const renderFrames = 2048;
// Initial panner positionX and final positionX for listener.
const positionX = 2000;
const audit = Audit.createTaskRunner();
// Test that listener.positionX.value setter does the right thing.
audit.define('Set Listener.positionX.value', (task, should) => {
const context = new OfflineAudioContext(2, renderFrames, sampleRate);
createGraph(context);
// Frame at which the listener instantaneously moves to a new location.
const moveFrame = 512;
context.suspend(moveFrame / context.sampleRate)
.then(() => {
context.listener.positionX.value = positionX;
})
.then(() => context.resume());
verifyOutput(context, moveFrame, should, 'listenr.positionX.value')
.then(() => task.done());
});
// Test that listener.positionX.setValueAtTime() does the right thing.
audit.define('Listener.positionX.setValue', (task, should) => {
const context = new OfflineAudioContext(2, renderFrames, sampleRate);
createGraph(context);
// Frame at which the listener instantaneously moves to a new location.
const moveFrame = 512;
context.listener.positionX.setValueAtTime(
positionX, moveFrame / context.sampleRate);
verifyOutput(
context, moveFrame, should, 'listener.positionX.setValueATTime')
.then(() => task.done());
});
// Test that listener.setPosition() does the right thing.
audit.define('Listener.setPosition', (task, should) => {
const context = new OfflineAudioContext(2, renderFrames, sampleRate);
createGraph(context);
// Frame at which the listener instantaneously moves to a new location.
const moveFrame = 512;
context.suspend(moveFrame / context.sampleRate)
.then(() => {
context.listener.setPosition(positionX, 0, 0);
})
.then(() => context.resume());
verifyOutput(context, moveFrame, should, 'listener.setPostion')
.then(() => task.done());
});
audit.run();
// Create the basic graph for testing which consists of an oscillator node
// connected to a panner node.
function createGraph(context) {
const listener = context.listener;
listener.positionX.value = 0;
listener.positionY.value = 0;
listener.positionZ.value = 0;
const src = new OscillatorNode(context);
const panner = new PannerNode(context, {
distanceModel: 'linear',
refDistance: 1,
maxDistance: 3000,
positionX: positionX,
positionY: 0,
positionZ: 0
});
src.connect(panner).connect(context.destination);
src.start();
}
// Verify the output from the panner is correct.
function verifyOutput(context, moveFrame, should, prefix) {
return context.startRendering().then(resultBuffer => {
// Get the outputs (left and right)
const c0 = resultBuffer.getChannelData(0);
const c1 = resultBuffer.getChannelData(1);
// The src/listener set up is such that audio should only come
// from the right for until |moveFrame|. Hence the left channel
// should be 0 (or very nearly 0).
const zero = new Float32Array(moveFrame);
should(
c0.slice(0, moveFrame), `${prefix}: output0[0:${moveFrame - 1}]`)
.beCloseToArray(zero, {absoluteThreshold: 1e-16});
should(
c1.slice(0, moveFrame), `${prefix}: output1[0:${moveFrame - 1}]`)
.notBeConstantValueOf(0);
// At |moveFrame| and beyond, the listener and source are at the
// same position, so the outputs from the left and right should be
// identical, and the left channel should not be 0 anymore.
should(c0.slice(moveFrame), `${prefix}: output0[${moveFrame}:]`)
.notBeConstantValueOf(0);
should(c1.slice(moveFrame), `${prefix}: output1[${moveFrame}:]`)
.beCloseToArray(c0.slice(moveFrame));
});
}
</script>
</body>
</html>