UPDATED ON: December 20, 2014
Web Audio API BufferLoader is a tutorial that shares how the Web Audio API Audio Buffer loading process can be abstracted into a custom function called BufferLoader. This allows us to reduce the amount of code needed when loading audio assets. The BufferLoader class is especially important for applications that require many different audio assets. You should understand the basics of the Web Audio API as well as how to buffer and play audio files. If not, please refer to the previous tutorials.
The AudioBuffer
With the Web Audio API, audio files can be played only after they’ve been loaded into a buffer. We use an XMLHttpRequest to load data into a buffer from an audio file. Next, we make an asynchronous callback and send the actual request to load. Once a sound has been buffered and decoded, it can be triggered instantly. Each time it is triggered, a different instance of the buffered sound is created.
The BufferLoader Class
Wouldn’t it be great if we didn’t have to hard-code the buffer loading process for each audio file? The process can be abstracted into a custom function called BufferLoader. This allows us to reduce the amount of code needed when loading each audio asset. There’s not much benefit if an application uses only a couple audio assets. However, the BufferLoader class quickly proves it’s worth when dealing with many audio assets or multiple sets of audio assets.
Create Web Audio API BufferLoader
Create a file called “buffer-loader.js” in your project directory. Copy the following code into the file and save it. This code contains the BufferLoader class.
function BufferLoader(context, urlList, callback) { this.context = context; this.urlList = urlList; this.onload = callback; this.bufferList = new Array(); this.loadCount = 0; } BufferLoader.prototype.loadBuffer = function(url, index) { var request = new XMLHttpRequest(); request.open("GET", url, true); request.responseType = "arraybuffer"; var loader = this; request.onload = function() { loader.context.decodeAudioData( request.response, function(buffer) { if (!buffer) { alert('error decoding file data: ' + url); return; } loader.bufferList[index] = buffer; if (++loader.loadCount == loader.urlList.length) loader.onload(loader.bufferList); } ); } request.onerror = function() { alert('BufferLoader: XHR error'); } request.send(); } BufferLoader.prototype.load = function() { for (var i = 0; i < this.urlList.length; ++i) this.loadBuffer(this.urlList[i], i); }
Include Web Audio API BufferLoader
To function properly, the BufferLoader class must be included in your page before the Web Audio API script. Although it can be included directly, I would recommend keeping it separated from the rest of your script. Use the following to include it.
<script type="text/javascript" src="buffer-loader.js"></script>
A Working Example
Now let’s combine what we’ve learned so far into a working example of how you can use the BufferLoader class. We want to load three drum sounds, a kick, snare, and hihat. We also want the option to play all three sounds together or staggered.
Trigger Events
To accomplish this, we use the inline binding technique on input elements with their type attribute set to button. One calls the loadAndPlay function which loads and plays all three buffered sounds together. The other calls the loadAndPlayStaggered function which loads all three buffered sounds and plays them at slightly different times.
<h2>Load multiple sounds with a BufferLoader class.</h2> <h3>Play all the audio buffers together.</h3> <input type="button" value="Play" onclick="loadAndPlay();" /> <h3>Play all the audio buffers staggered.</h3> <input type="button" value="Play" onclick="loadAndPlayStaggered();" />
Play the Sounds
First we create the global variables context and bufferLoader. Then we create the loadAndPlay function that creates an audio context, gives the BufferLoader an array of urls to buffer, and calls the finishedLoading function.
The finishedLoading function is responsible for creating BufferSourceNodes and BufferNodes for our buffered sounds, connecting them to the speakers, and telling them when to begin playing.
Then we create similar functions called loadAndPlayStaggered and finishedLoadingStaggered which will make the second button work as desired.
Full Code for Web Audio API BufferLoader Example
Here’s the full code to load and play audio with the Web Audio API BufferLoader. Change the path and filename of the audio files to match yours and you’ve got it!
var context; var bufferLoader; function loadAndPlay() { try { context = new AudioContext(); } catch(e) { alert("Web Audio API is not supported in this browser"); } bufferLoader = new BufferLoader( context, [ "sounds/kick.wav", "sounds/snare.wav", "sounds/hihat.wav", ], finishedLoading ); bufferLoader.load(); } function loadAndPlayStaggered() { try { context = new AudioContext(); } catch(e) { alert("Web Audio API is not supported in this browser"); } bufferLoader = new BufferLoader( context, [ "sounds/kick.wav", "sounds/snare.wav", "sounds/hihat.wav", ], finishedLoadingStaggered ); bufferLoader.load(); } function finishedLoading(bufferList) { // Create three sources and buffers var kick = context.createBufferSource(); var snare = context.createBufferSource(); var hihat = context.createBufferSource(); kick.buffer = bufferList[0]; snare.buffer = bufferList[1]; hihat.buffer = bufferList[2]; kick.connect(context.destination); snare.connect(context.destination); hihat.connect(context.destination); // Play them together kick.start(0); snare.start(0); hihat.start(0); } function finishedLoadingStaggered(bufferList) { // Create three sources and buffers var kick = context.createBufferSource(); var snare = context.createBufferSource(); var hihat = context.createBufferSource(); kick.buffer = bufferList[0]; snare.buffer = bufferList[1]; hihat.buffer = bufferList[2]; kick.connect(context.destination); snare.connect(context.destination); hihat.connect(context.destination); // Play them staggered kick.start(0); snare.start(0.125); hihat.start(0.25); }
Web Audio API BufferLoader
I’ve shown you how to load multiple sounds with a BufferLoader class, and how to play them simultaneously or staggered. Now, let’s see what you can do with your new found knowledge. Be creative! How will you use the Web Audio API BufferLoader to make the web awesome?
Also, you could try Abbey Load, a clever little music asset loader by Stuart Memo.
Other tutorials in this series
- Web Audio API Basics
- Web Audio API Oscillators
- Web Audio API Audio Buffer
- Play a Sound with Web Audio API
- Controlling Web Audio API Oscillators
- Timed Rhythms with Web Audio API and JavaScript
Leave a Reply