1

I'm trying to use the Web Audio API in JavaScript to load a sound into a buffer and play it. Unfortunately it doesn't work and I get the following error:

Uncaught TypeError: Failed to set the 'buffer' property on 'AudioBufferSourceNode':
The provided value is not of type 'AudioBuffer'.

I can pinpoint which line is giving me the error, but I don't know why. Here is the relevant code if it helps:

var audioContext;
var playSoundBuffer;

function init() {
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    audioContext = new AudioContext();

    loadNote();
}

function loadNote() {
    var request = new XMLHttpRequest();
    request.open("GET", "./sounds/topE.wav", true);
    request.responseType = "arraybuffer";
    request.onload = function() {
        audioContext.decodeAudioData(request.response, function(buffer) {
            playSoundBuffer = buffer;
        }, function(error) {
            console.error("decodeAudioData error", error);
        });
    };
    request.send();

    playSound();
}

function playSound() {
    var source = audioContext.createBufferSource();
    source.buffer = playSoundBuffer;       // This is the line that generates the error
    source.connect(audioContext.destination);
    source.start(0);
}

I believe the decodeAudioData method returns an AudioBuffer to its first callback function (its second parameter). I tried to save this AudioBuffer to the "playSoundBuffer" and then play it, but I get that error and I'm not sure why. Any help would be greatly appreciated.

hashahid
  • 179
  • 1
  • 2
  • 7

1 Answers1

8

The reason you get that error is because you are ignoring the asynchronous nature of your code and treat it as if it were synchronous. If you always log the contents of all relevant parts as the first step in debugging you will realize that at the time you try to process your buffer it's undefined and not an AudioBuffer at all. Tip: Always console.log everything until you know exactly how it behaves at any point.

function loadNote() {
    var request = new XMLHttpRequest();
    request.open("GET", "./sounds/topE.wav", true);
    request.responseType = "arraybuffer";
    request.onload = function() {
        audioContext.decodeAudioData(request.response, function(buffer) {
            playSoundBuffer = buffer;
            playSound(); // don't start processing it before the response is there!
        }, function(error) {
            console.error("decodeAudioData error", error);
        });
    };
    request.send();//start doing something async


}
Winchestro
  • 2,138
  • 14
  • 18
  • 1
    Thanks so much for your response! The edits you suggested made the sound play properly. Unfortunately I don't really understand how asynchronous functions work. Was the playSound() method being executed at the same time as the decodeAudioData method? Was that what was causing the error specifically? Thanks again for your help! – hashahid Oct 19 '14 at 07:36
  • 2
    Here is an article https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests in your case you exectuted the `playSound()` method actually way before the `decodeAudioData` method, basically right after you sent the request (which is async) and before the request arrived, and before you started decoding it (which is also async) – Winchestro Oct 19 '14 at 07:48