What I'm currently trying to implement is 360 degree rotation audio (I don't know the exact term for it--maybe 8d audio?) using PannerNode.
As far as I think, what I need to do is just rotate the position of PannerNode around y axis, with AudioListener being at (0, 0, 0).
But the result sounds like the audio is not changed at all. The below is my code.
const $fileInput = document.createElement('input');
$fileInput.setAttribute('type', 'file');
document.body.appendChild($fileInput);
const $audio = document.createElement('audio');
$audio.setAttribute('controls', true);
document.body.appendChild($audio);
$fileInput.addEventListener('change', async (e) => {
const file = $fileInput.files[0];
const arrayBuffered = await file.arrayBuffer();
const actx = new (window.AudioContext || window.webkitAudioContext)({ latencyHint: 'interactive', sampleRate: 44100 });
const decoded = await actx.decodeAudioData(arrayBuffered);
const oactx = new OfflineAudioContext({ numberOfChannels: 2, length: decoded.length, sampleRate: actx.sampleRate });
const absn = new AudioBufferSourceNode(oactx, { buffer: decoded });
const pn = new PannerNode(oactx, {
panningModel: 'equalpower',
distanceModel: 'inverse',
positionX: 0,
positionY: 0,
positionZ: 0,
orientationX: 1,
orientationY: 0,
orientationZ: 0,
refDistance: 1,
maxDistance: 10000,
rolloffFactor: 1,
coneInnerAngle: 360,
coneOuterAngle: 360,
coneOuterGain: 0
});
oactx.listener.positionX.value = 0;
oactx.listener.positionY.value = 0;
oactx.listener.positionZ.value = 0;
oactx.listener.forwardX.value = 0;
oactx.listener.forwardY.value = 0;
oactx.listener.forwardZ.value = -1;
oactx.listener.upX.value = 0;
oactx.listener.upY.value = 1;
oactx.listener.upZ.value = 0;
// rotation
for (let t = 0; t < decoded.duration; t++) {
const rad = t * Math.PI / 180;
const x = pn.positionX.value * Math.cos(rad) - pn.positionZ.value * Math.sin(rad);
const z = pn.positionX.value * Math.sin(rad) + pn.positionZ.value * Math.cos(rad);
pn.positionX.setValueAtTime(x, t);
pn.positionZ.setValueAtTime(z, t);
}
absn.connect(pn);
pn.connect(oactx.destination);
absn.start();
const resultBuffer = await oactx.startRendering();
const test = new AudioBufferSourceNode(actx, { buffer: resultBuffer });
test.connect(actx.destination);
test.start();
});