【问题标题】:Web audio API, problem using the panNode, the sounds only play onceWeb 音频 API,使用 panNode 的问题,声音只播放一次
【发布时间】:2020-07-03 19:38:30
【问题描述】:

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

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

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() 函数,它就再也不会播放了。

谁能帮我解决这个问题?

【问题讨论】:

  • 有什么会阻止您使用 AudioBuffers?对于您正在做的事情,这听起来更自然。
  • 我不确定。我昨天才知道这个,所以显然有很多我不知道的。 AudioBuffers 能解决问题吗?我将研究 AudioBuffers 比。谢谢!

标签: javascript audio web-audio-api


【解决方案1】:

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

未捕获的 InvalidStateError:无法在“AudioContext”上执行“createMediaElementSource”:HTMLMediaElement 之前已连接到不同的 MediaElementSourceNode。

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

为避免这种情况,您必须断开MediaElementMediaElementSourceNode,但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>

【讨论】:

  • 好的,非常感谢!我将对此进行调查,尝试了解发生了什么,将其实施到我的代码中,并在我设法使其工作后立即回到这里接受这个答案。谢谢!
  • 嘿,它有效!惊人的。但我不确定如何用几种声音来处理它。我试过了,但只能有 1 个 AudioContext。我会尝试从中推断,但无论如何,你应该得到奖励 :) 谢谢!
  • 预取所有资产并将其存储在您的代码可以访问的地方,我个人可能会使用字典或数组来存储它们。无论如何只创建audioContext。您可以让自己成为一个预加载器助手,它将从 url 返回 AudioBuffer(基本上是我答案顶部的 5 行,但作为一个函数。
  • 好的,明白了!你可以fetch 尽可能多的声音!它有效:) 我很高兴
  • 哦,抱歉,它直接通过 id 获取
猜你喜欢
  • 2012-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多