2013-08-23 2 views
1

Как я могу назначить буфер, созданный в decodeAudioData, для soundBuffer для воспроизведения позже?Я не могу понять, закрытие для этого

Обратите внимание, что вызов функции playSound() в вызове функции decodeAudioData успешно воспроизводит буфер, но вызовы с кнопки воспроизведения возвращают «значение не типа ArrayBuffer», и при тестировании 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.

ответ

1

Вам необходимо предоставить обратный вызов для установки soundBuffer в вашей текущей области.

Изменить LoadSound на:

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

Функция четкости звука нагрузки на:

function loadSound(url, callback) { 

и функция успех:

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

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

+0

Я хотел бы не жестко указывать, какой буфер я загружаю, поэтому я пытаюсь назначить его по ссылке, чтобы повторно использовать подпрограмму для других звуковых файлов. – Kenji

+0

, что могло бы ввести в заблуждение, я должен был, вероятно, сделать вызовы playSound (s); – Kenji

+0

Правильно, неправильно понял вопрос. –

1

Это сложно, но прочитайте Is JavaScript a pass-by-reference or pass-by-value language?, чтобы понять, почему 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}, к которому также относится внешний звуковой буфер.

Так что, если вы должны были назначить в loadSound, буфер в soundBuffer как

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

      }); 

вы фактически назначить декодированного буфер в том же месте памяти, что и внешний soundBuffer и внутренние buffer переменные point to and you playSound будет работать.

+0

спасибо. Это очень интересный нюанс для оценки/ссылки, о котором я не знал. – Kenji

+0

отличное объяснение, полностью имеет смысл сейчас, спасибо, что нашли время! – Kenji

Смежные вопросы