Search code examples
javascriptarraysaudiowebogg

Web Audio load both .mp3 and .ogg


I'm building a canvas game using javascript and web audio. To get it to work in Firefox I have a copy of all the audio files in .ogg format. The code to load these files is below. To get the desired audio file I use ' playSound(samplebb[3], channel1); ', I have done it like this as in my app it is useful to choose the sample based on number, for example sounds can be chosen using probability and randomness.

I read on a forum "the loader will accept both [mp3 and ogg] for the same sound, just pass both paths in an array rather than a single string." The 4th line of code is me trying this but it does not work.

Is it possible to load an alternate ogg file for each mp3 like this? (In one bufferlist) Or will I have to detect the browser and build a bufferlist of oggs if the browser is Firefox?

Thanks

function loadSounds() {
bufferLoader = new BufferLoader(audioContext,
    [
        ['sounds/1-KICK.mp3', 'sounds/1-KICK.ogg'],      //0  // Not found
        'sounds/2-BASS.mp3',      //1
        'sounds/3-BASS2.mp3',     //2
        'sounds/4-BASS4.mp3'      //3
        // ...  ...   ...
    ],
    finishedLoading
);
bufferLoader.load();
}


function finishedLoading(bufferList) {
for (var i = 0, l = bufferList.length; i < l; i += 1) {
    var source = audioContext.createBufferSource();
    source.buffer = bufferList[i];
    source.connect(audioContext.destination);
    var note = {
        note: source,
        ready: true
    };
    samplebb.push(note);
}
setTimeout(play, 1000);
}

Solution

  • Are you using BufferLoader from html5rocks? If so, the JS file clearly shows that it only expects strings (not arrays) as url arguments. However you can modify the class so that it works like you want. Use the following BufferLoader.loadBuffer() function instead:

    BufferLoader.prototype.loadBuffer = function(url, index) {
        // Load buffer asynchronously
        var request = new XMLHttpRequest(),
          mult = typeof url != 'string',
          srcInd = 0;
        request.open("GET", mult ? url[srcInd++] : url, true);
        request.responseType = "arraybuffer";
    
        var loader = this;
    
        request.onload = function() {
            // Asynchronously decode the audio file data in request.response
            loader.context.decodeAudioData(
                request.response,
                function(buffer) {
                    if (!buffer) {
                        if(!mult || srcInd == url.length) {
                            console.error('error decoding file data:', url);
                            return;
                        } else {
                            console.info('error decoding file data, trying next source');
                            request.open("GET", url[srcInd++], true);
                            return request.send();
                        }
                    }
                    loader.bufferList[index] = buffer;
                    if (++loader.loadCount == loader.urlList.length)
                        loader.onload(loader.bufferList);
                },
                function(error) {
                    if(!mult || srcInd == url.length) {
                        console.error('decodeAudioData error:', url);
                        return;
                    } else {
                        console.info('decodeAudioData error, trying next source');
                        request.open("GET", url[srcInd++], true);
                        return request.send();
                    }
                }
            );
        }
    
        request.onerror = function() {
            if(!mult || srcInd == url.length) {
                console.error('BufferLoader XHR error:', url);
                return;
            } else {
                console.info('BufferLoader XHR error, trying next source');
                request.open("GET", url[srcInd++], true);
                return request.send();
            }
        }
    
        request.send();
    }