代码之家  ›  专栏  ›  技术社区  ›  Doohyeon Won

使用Web audio API实现360度旋转音频

  •  0
  • Doohyeon Won  · 技术社区  · 4 年前

    我目前正在尝试使用PannerNode实现360度旋转音频(我不知道它的确切术语——也许是8d音频?)。

    就我所想,我需要做的只是围绕y轴旋转PannerNode的位置,AudioListener位于(0,0,0)。

    但结果听起来音频根本没有改变。下面是我的代码。

    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();
    });
    
    0 回复  |  直到 4 年前
        1
  •  0
  •   Doohyeon Won    4 年前
    // 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;
    }
    

    我将PannerNode.positionX设置为1,因为为了使PannerNode围绕AudioListener旋转,PannerNode需要与AudioListener有一定距离。

    我改变了 for 声明,因为我想要一个快速、平稳的变化效果。