0

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();
});

1 Answer 1

0
// from
PannerNode.positionX: 0
// to
PannerNode.positionX: 1

// from
for (let t = 0; t < decoded.duration; t++) {
  const rad = t * Math.PI / 180;
}
// to
for (let t = 0; t < decoded.duration; t += 0.01) {
  const rad = 100 * t * Math.PI / 180;
}

I set PannerNode.positionX to 1 because in order for PannerNode to rotate around AudioListener, PannerNode needs to be have some distance from AudioListener.

I change for statement because I want a fast, smoothly changing effect.

Sign up to request clarification or add additional context in comments.

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.