140 lines
4.7 KiB
HTML
140 lines
4.7 KiB
HTML
<!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>
|
|
|