网络音频 API,使用 panNode 时出现问题,声音只播放一次

Web audio API, problem using the panNode, the sounds only play once

我正在尝试将一些声相效果集成到一个小型测试应用程序中的一些声音中。它工作正常,除了一个重要问题:每个声音只播放一次!

我尝试了多种方法试图绕过该问题,但均未成功。问题是,我无法确定问题出在哪里。这是我的代码,下面是一些解释。

const audio = new Audio('audio/background.mp3');
const footstep = new Audio('audio/footstep1.mp3');
const bumpWall1 = new Audio(`audio/bump-wall1.mp3`);
const bumpWall2 = new Audio(`audio/bump-wall2.mp3`);
const bumpWall3 = new Audio(`audio/bump-wall3.mp3`);
const bumpWall4 = new Audio(`audio/bump-wall4.mp3`);
const bumpWallArray = [bumpWall1, bumpWall2, bumpWall3, bumpWall4];

audio.volume = 0.5;

function play(sound, dir) {
  let audioContext = new AudioContext();
  let pre = document.querySelector('pre');
  let myScript = document.querySelector('script');

  let source = audioContext.createMediaElementSource(sound);

  let panNode = audioContext.createStereoPanner();
  source.connect(panNode);
  panNode.connect(audioContext.destination);
  if (dir === "left") {
    panNode.pan.value = -0.8
  } else if (dir === "right") {
    panNode.pan.value = 0.8;
  } else {
    panNode.pan.value = 0;
  }
  sound.play();
}

基本上,当您调用 play() 函数时,它会在左侧、右侧或中间播放声音。但是每个声音只播放一次。例如,如果足迹播放了一次,如果我调用它的 play() 函数,它就再也不会播放了。

有人可以帮我吗?

在您的 developer console 中,您应该有一条消息说明

Uncaught InvalidStateError: Failed to execute 'createMediaElementSource' on 'AudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode.

(至少在 Chrome,)你不能多次将 MediaElement 连接到 MediaElementSourceNode

为避免这种情况,您必须从 MediaElementSourceNode 断开 这个 MediaElement,但是 this isn't possible...

在你的情况下最好的可能是直接使用 AudioBuffers 而不是 HTMLAudioElements,而且如果你不将它们附加到文档中。

let audio;
const sel = document.getElementById( 'sel' );
// create a single AudioContext, these are not small objects
const audioContext = new AudioContext();
fetch( 'https://dl.dropboxusercontent.com/s/agepbh2agnduknz/camera.mp3' ).then( resp => resp.arrayBuffer() )
.then( buf => audioContext.decodeAudioData( buf ) )
.then( audioBuffer => audio = audioBuffer )
.then( () => sel.disabled = false )
.catch( console.error );

function play(sound, dir) {

  let source = audioContext.createBufferSource();
  source.buffer = sound;
  
  let panNode = audioContext.createStereoPanner();
  source.connect( panNode );
  panNode.connect( audioContext.destination );
  if (dir === "left") {
    panNode.pan.value = -0.8
  } else if (dir === "right") {
    panNode.pan.value = 0.8;
  } else {
    panNode.pan.value = 0;
  }
  source.start( 0 );
  
}

sel.onchange = evt => play( audio, sel.value );
<select id="sel" disabled>
  <option>left</option>
  <option>center</option>
  <option>right</option>
</select>