API веб-аудио: как мне перезапустить воспроизведение звука?

Я написал базовый скрипт в Chrome, который использует новый Web Audio Api для загрузки 3 звуковых файлов (через XMLHTTPRequest) и воспроизведения каждого из них по отдельности. Я предоставил отдельную кнопку для каждого звука, которая позволяет пользователю запускать и останавливать каждый звук.

Сценарий немедленно загружает все три звуковых файла и, когда это готово, убирает затемнение кнопок воспроизведения, чтобы пользователь мог нажать кнопку воспроизведения только после того, как звуки будут готовы. Кроме того, звуки зацикливаются, поэтому метка на каждой кнопке меняется между «Play» и «Stop» при нажатии кнопки.

Все это прекрасно работает ... Когда вы нажимаете кнопку Play, вы слышите зацикленный звук, а когда вы нажимаете Stop, звук останавливается. Однако, когда вы пытаетесь воспроизвести тот же звук во второй раз, звук больше не воспроизводится. Каждый раз, когда вы нажимаете кнопку Play / Stop, вызывается соответствующая функция 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>

Кроме того, знает ли кто-нибудь о каком-либо событии, которое может сработать после того, как закончится воспроизведение звука без зацикливания? Было бы здорово, если бы я мог установить эти звуки без зацикливания и, как только звук закончится, использовать такое событие, чтобы переключить его метку.Я ничего не вижу в спецификации, но, может быть, есть способ получше?

Спасибо, Брэд.

6
задан Brad Marshall 22 October 2011 в 20:16
поделиться