时间:2011-10-22 20:16:08

标签: javascript google-chrome html5-audio

我在Chrome中编写了一个基本脚本,它使用新的Web Audio Api加载3个声音文件(通过XMLHTTPRequest)并逐个播放它们。我为每个声音提供了一个单独的按钮,允许用户启动和停止每个声音。

脚本会立即加载所有三个声音文件,完成后,取消调暗播放按钮,这样用户只有在声音准备好后才能播放。此外,声音循环播放,因此当点击按钮时,每个按钮上的标签在“播放”和“停止”之间变化。

这一切都很有效...当您点击播放按钮时,您会听到循环声音,当您点击停止时声音会停止。但是,当您尝试第二次重新播放相同的声音时,声音将不会再次开始播放。每次单击播放/停止按钮时,都会调用相应的playSound()或stopSound()函数并传入适当的参数但由于某种原因我无法再次播放声音。我做错了吗?

这是我的代码:

<body>

<label for="playBtn1">Moog:</label>
<input id="playBtn1" type="button" value="Play" disabled />
<label for="playBtn1">Drums:</label>
<input id="playBtn2" type="button" value="Play" disabled />
<label for="playBtn1">Choir:</label>
<input id="playBtn3" type="button" value="Play" disabled />

<script>
  var playBtn1 = document.getElementById("playBtn1");
  var playBtn2 = document.getElementById("playBtn2");
  var playBtn3 = document.getElementById("playBtn3");

  var context = new webkitAudioContext();

  var soundBuffer1 = null;
  var soundBuffer2 = null;
  var soundBuffer3 = null;

  var soundBufferSourceNode1 = context.createBufferSource();
  soundBufferSourceNode1.looping = true;
  var soundBufferSourceNode2 = context.createBufferSource();
  soundBufferSourceNode2.looping = true;
  var soundBufferSourceNode3 = context.createBufferSource();
  soundBufferSourceNode3.looping = true;

  loadSound('micromoog.wav', 1);
  loadSound('breakbeat-drum-loop.wav', 2);
  loadSound('choir.wav', 3);

  playBtn1.addEventListener("click", function(e) {
    if(this.value == "Play") {
      this.value = "Stop";
      playSound(soundBuffer1, soundBufferSourceNode1);
    } else if(this.value == "Stop") {
      this.value = "Play";
      stopSound(soundBufferSourceNode1);
    }
  }, false);
  playBtn2.addEventListener("click", function(e) {
    if(this.value == "Play") {
      this.value = "Stop";
      playSound(soundBuffer2, soundBufferSourceNode2);
    } else if(this.value == "Stop") {
      this.value = "Play";
      stopSound(soundBufferSourceNode2);
    }
  }, false);
  playBtn3.addEventListener("click", function(e) {
    if(this.value == "Play") {
      this.value = "Stop";
      playSound(soundBuffer3, soundBufferSourceNode3);
    } else if(this.value == "Stop") {
      this.value = "Play";
      stopSound(soundBufferSourceNode3);
    }
  }, false);

  function loadSound(url, bufferNum) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.responseType = 'arraybuffer';

    // Decode asynchronously
    request.onload = function() {
      var successCallback = function(buffer) {
        switch(bufferNum) {
          case 1:
            soundBuffer1 = buffer;
            playBtn1.disabled = false;
          break;
          case 2:
                soundBuffer2 = buffer;
            playBtn2.disabled = false;
          break;
          case 3:
            soundBuffer3 = buffer;
            playBtn3.disabled = false;
          break;
        }
      }
      var errorCallback = function(e) {
      console.log(e);
      }
      context.decodeAudioData(request.response, successCallback, errorCallback);
    }

    request.send();
  }

  function playSound(buffer, bufferSourceNode) {
    bufferSourceNode.buffer = buffer;
    bufferSourceNode.connect(context.destination);
    bufferSourceNode.noteOn(0);
  }

  function stopSound(bufferSourceNode) {
    bufferSourceNode.noteOff(0);
  }
</script>

</body>

此外,是否有人知道在播放非循环声音后可能触发的任何事件?如果我可以将这些声音设置为非循环并且一旦声音播放完毕就会很酷,使用这样的事件来切换它的标签。我在规范中没有看到任何内容,但也许有更好的方法?

谢谢, 布拉德。

2 个答案:

答案 0 :(得分:6)

我知道这已经晚了一年,但我遇到了类似的问题,做了一些快速搜索,这就是我发现的:

在此页面中:http://updates.html5rocks.com/2012/01/Web-Audio-FAQ

然后参考问题:

  • “如何检查AudioSourceNode何时播放完毕?”
  • “我有一个AudioBufferSourceNode,我刚刚用noteOn()回放,我想再玩一次,但是noteOn()没有做任何事!帮助!”

据我所知:从createBufferSource()创建的源只能播放一次。一旦你停止它,你必须创建一个新的。如果您想知道特定声音何时停止播放,则不会发送任何事件;所以你必须使用超时。

希望这有帮助!

答案 1 :(得分:5)

自己学习Web Audio API。乍一看我会说这是因为你每次播放声音都应该创建BoufferSource,看起来你只是第一次这样做。在这里查看示例:http://www.html5rocks.com/en/tutorials/webaudio/intro/