1

如何将 decodeAudioData 中创建的缓冲区分配给 soundBuffer 以便稍后播放?

请注意,在 decodeAudioData 函数调用中对 playSound() 的调用成功地播放了缓冲区,但从 Play 按钮调用返回“值不是 ArrayBuffer 类型的值”,并且在测试时,soundBuffer 仍然未定义。

我假设深层嵌套函数在最外层函数中失去了 soundBuffer 的范围,但我似乎可以将 soundBuffer 包装在一个闭包中,以便它成功传入。

$(function () {
  var soundBuffer, context;
  try {
      context = new webkitAudioContext();
  }
  catch (e) {     
      console.log("Error setting up webaudiocontext: " + e);
  }    

  loadSound("https://dl.dropboxusercontent.com/u/9780255/counting-coins-3.mp3",soundBuffer);

  $("#playSound").click(function () {
     playSound(soundBuffer);
  });

  function loadSound(url, buffer) {
      var rq = new XMLHttpRequest();
      rq.open("GET", url, true);
      rq.responseType = "arraybuffer";
      rq.onload = function () {
          context.decodeAudioData(rq.response,
              function (b) {
                  buffer = b;
                  console.log("buffer loaded...");
                  playSound(buffer);
              });
      };

      rq.onerror = function (e) {
          console.log("error loading audio:"+e);
      };
      rq.send();
  }   


  function playSound(s) {
     var sn= context.createBufferSource();
     sn.buffer = s;
     sn.connect(context.destination);
     sn.start(0);
  }         

});

此来源在 jsfiddle 上:http: //jsfiddle.net/karasutengu/qA5Nb/8/它可能仅适用于识别 webkitAudioContext 的 chrome。

4

2 回答 2

1

您需要提供回调以在当前范围内设置 soundBuffer。

将 loadSound 更改为:

loadSound("https://dl.dropboxusercontent.com/u/9780255/counting-coins-3.mp3", function(buffer) {
    soundBuffer = buffer;
});

加载声音的函数def:

function loadSound(url, callback) {

和成功功能:

function (b) {
  buffer = b;
  console.log("buffer loaded...");
  callback(buffer);
});

http://jsfiddle.net/karasutengu/qA5Nb/8

于 2013-08-23T06:12:57.587 回答
1

这很棘手,但请阅读JavaScript 是按引用传递还是按值传递语言?了解为什么 soundBuffer 不保留其值。

这是带有回调函数的代码,该函数正确使用闭包来保持 PlaySound 函数中缓冲区的值http://jsfiddle.net/qA5Nb/9/

var Player = $(function () {
   var soundBuffer, context;

    try {
        context = new webkitAudioContext();
    }
    catch (e) {     
        console.log("Error setting up webaudiocontext: " + e);
    }    


    var registerPlayButton = function(buffer){    
       $("#playSound").click(function () {
           playSound(buffer);
       });
    }


   loadSound("https://dl.dropboxusercontent.com/u/9780255/counting-coins-3.mp3",soundBuffer, registerPlayButton);

  function loadSound(url, buffer, callbackFn) {
        var rq = new XMLHttpRequest();
        rq.open("GET", url, true);
        rq.responseType = "arraybuffer";
        rq.onload = function () {
            context.decodeAudioData(rq.response,
                function (b) {
                    buffer = b;
                    console.log("buffer loaded...");
                    playSound(buffer);
                    callbackFn(buffer);
                });
        };

        rq.onerror = function (e) {
            console.log("error loading audio:"+e);
        };
        rq.send();
    }   


   function playSound(soundBuffer) {
       var sn= context.createBufferSource();
       sn.buffer = soundBuffer;
       sn.connect(context.destination);
       sn.start(0);
    }     



});

添加:

简单解释一下,soundBuffer是一个引用类型,是按值传入loadSound的(所以是引用的值,是一个未初始化的指针)。

如果您的 soundBuffer 被初始化为像 的对象var soundBuffer ={b:null};,并被传递给loadSound,那么您要将缓冲区分配给b对象的属性{b};你的代码会工作。

您仍将按值传递 soundBuffer,该指针的值是指向存储 {buffer:null} 的同一内存位置的指针,外部 soundBuffer 也指向该内存位置。

因此,如果您要在 中分配loadSound一个缓冲区到 soundBuffer,例如

        context.decodeAudioData(rq.response,
            function (b) {
                buffer.b = b;
                console.log("buffer loaded...");
                playSound(buffer.b);

            });

实际上,您会将解码后的缓冲区分配到外部变量soundBuffer和内部buffer变量都指向的相同内存位置,然后您playSound就可以工作了。

于 2013-08-23T06:48:30.680 回答