UPDATED ON: December 20, 2014
Play a Sound with Web Audio API is a tutorial that explains some common methods of triggering and toggling buffered sounds with the Web Audio API. It will build on what we’ve covered in Web Audio API Basics and Web Audio API Audio Buffer. You should understand the basics of the Web Audio API as well as how to buffer sounds before moving on. If not, please refer to the previous tutorials. After mastering these concepts, you should be able to follow along.
So, I’ve compiled various methods of triggering and toggling sounds with the Web Audio API. We’ll use a few simple scenarios of accessing and controlling buffered audio assets to detail these methods. We’ll also cover how to create start and stop functions. But first, let’s talk about Event Listeners.
Event Listeners
The easiest way to trigger a sound is on page load. However, this technique is not very practical for most applications. Can you imagine having to reload the web page every time you wanted to hear a sound? For all of the scenarios in this tutorial, we’ll have some kind of interface bound to a JavaScript Event Listener that changes a parameter or runs a function in response to signals sent from the interface. First, let’s break them down by the type of Event Listener, starting with the most important. Then we’ll look at some different scenarios for each one.
Mouse Event
The Mouse Event Listener “listens” for a signal from the mouse. This can be triggered by mousedown, mouseup, click, dblclick, mousemove, mouseover and mouseout. Clicking on the interface element or alternatively, hovering the pointer over the interface element are the two most common ways to initiate an action in a web browser. These are the two methods people are most accustomed to using.
<dl> <dt>click</dt> <dd>The click event occurs when the pointing device button is clicked over an element. A click is defined as a mousedown and mouseup over the same screen location. The sequence of these events is: <ol> <li>mousedown</li> <li>mouseup</li> <li>click</li> </ol> </dd> <dt>mousedown</dt> <dd>The mousedown event occurs when the pointing device button is pressed over an element.</dd> <dt>mouseup</dt> <dd>The mouseup event occurs when the pointing device button is released over an element.</dd> <dt>mouseover</dt> <dd>The mouseover event occurs when the pointing device is moved onto an element.</dd> <dt>mousemove</dt> <dd>The mousemove event occurs when the pointing device is moved while it is over an element.</dd> <dt>mouseout</dt> <dd>The mouseout event occurs when the pointing device is moved away from an element.</dd> </dl>
Keyboard Event
The Keyboard Event Listener “listens” for a signal from the computer keyboard. This can be triggered in three different ways. KeyDown happens when a key is first pressed down. KeyPress happens when a key is pressed down and then released. KeyUp happens when the key is released. All three events occur in this order when a key is pressed and then released.
<dl> <dt>keydown</dt> <dd>The keydown event occurs when the key is pressed.</dd> <dt>keypress</dt> <dd>The keypress event occurs when the key is pressed, after the keydown event.</dd> <dt>keyup</dt> <dd>The keyup event occurs when the key is released.</dd> </dl>
Other Ways to Trigger Sounds
Besides Mouse and Keyboard Events, there are several other ways to trigger or play a sound. Of course, touchscreen devices make use of Touch Events. With the recent growth of smart phones and other mobile devices, this one will surely gain importance in the future. The Web Audio API gives us the ability to fire off sounds at timed intervals with a high degree of accuracy. Also we have the ability to append or concatenate AudioBuffers and even loop an entire, or specific portions of an AudioBuffer. A related API called the Web MIDI API helps us use music devices, such as synthesizers, keyboard controllers, and drum machines to trigger sounds. I’ll probably cover each of these topics in a tutorial in the near future, but for now, let’s settle for Mouse and Keyboard Events.
Start and Stop Functions
Before getting into the applied scenarios, let’s think about the functions that will be called by our Event Listeners. We need a start function that runs when the user activates the play interface. We also need a stop function that runs when the user activates the stop interface. The stop function is easy so we’ll start with that one.
Stop Function
We create a function called stop. This function, when activated, tells the buffered audio source to stop immediately.
function stop() { source.stop(context.currentTime); // stop the source immediately }
UPDATE: As of July 2014, source.stop() should be used instead of source.noteOff().
Start Function
The start function can be a bit trickier. In order to allow for flexibility later, we’ll take a more advanced approach and actually create three different functions to handle this. First of all, the start function asynchronously reads an audio file into an arraybuffer as binary data. It then passes the data to a function called audioRouting.
// Load the Sound with XMLHttpRequest function start() { // Note: this will load asynchronously var request = new XMLHttpRequest(); request.open("GET", url, true); request.responseType = "arraybuffer"; // Read as binary data // Asynchronous callback request.onload = function() { var data = request.response; audioRouting(data); }; request.send(); }
The audioRouting function creates a sound source, creates a source buffer from the raw binary, adds the buffered data to the source, connects the sound source to the output, and finally passes the source to the playSound function.
// Create Buffered Sound Source function audioRouting(data) { source = context.createBufferSource(); // Create sound source context.decodeAudioData(data, function(buffer){ // Create source buffer from raw binary source.buffer = buffer; // Add buffered data to object source.connect(context.destination); // Connect sound source to output playSound(source); // Pass the object to the play function }); }
UPDATE: As of July 2014, context.decodeAudioData(data, function(buffer){}); should be used instead of buffer = context.createBuffer(data, true);.
The playSound function simply tells the buffered audio source to play immediately.
// Tell the Source when to play function playSound() { source.start(context.currentTime); // play the source immediately }
UPDATE: As of July 2014, source.start() should be used instead of source.noteOn().
Applied Scenarios
To play a sound with Web Audio API, it must be buffered first. If a buffered sound is very short and isn’t being looped, there’s probably no need for a stop function. However, if a buffered sound is longer than a few seconds or looped, please consider the sanity of your users and include a stop function. Because the sample we’re using for all the buffered sound scenarios is a bit longer, we’ve included stop functions.
Speaking of sanity, I’d like to add one quick note about the simple functions used in this tutorial. There’s nothing to prevent the sound from being triggered rapidly multiple times, but the stop function will only stop the first occurrence! This is not really a glitch or a bug. It’s just me being lazy. The Web Audio API was designed to allow this behavior. After all, it could be useful. It’s not useful to us in this tutorial though. To make it smarter, we could have it check to see if the sound is currently playing, and only trigger the sound again if it’s not currently playing. More on that in the future. Please just be aware that if things get too crazy, you can always stop the sound by reloading or refreshing the page in your browser.
Click real button elements to trigger or stop the buffered sound
In this scenario, our buffered sound can be activated by clicking with the mouse on the play button. It can be stopped by clicking on the stop button. By using real button elements we can ensure better accessibility.
document.querySelector('.play-button').addEventListener('click', start); document.querySelector('.stop-button').addEventListener('click', stop);
Click images to trigger or stop the buffered sound
Again, our buffered sound can be activated by clicking with the mouse on the play button. This time however, the play button is actually an image element. While not as good for accessibility as the button element, the image element is bit more flexible. We could have created fancy graphics for our controls and set them as the image source. Instead, we’ve created custom shapes with CSS that give visual cues to the function of each image. One benefit of using CSS shapes instead of actual images is reduced load time for the page.
document.querySelector('.play').addEventListener('click', start); document.querySelector('.stop').addEventListener('click', stop);
.play { display:inline-block; margin:5px 20px 5px 10px; width: 0; height: 0; border-left: 50px solid #444; border-top: 25px solid transparent; border-bottom: 25px solid transparent; text-indent: -200px; } .stop { display:inline-block; background: #444; margin:5px; width: 50px; height: 50px; text-indent: -200px; }
Mouseover paragraphs to trigger or stop the buffered sound
Sometimes it might be desirable to have the sound play when a user hovers over an element instead of clicking on it. Here, we use the paragraph element to show that these techniques can be used on elements besides buttons and images. Whatever element is used, make sure it gives the user visual cues to ensure ease of use. In this case, the paragraphs are color coded and include instructional text. Also, because the start and stop functions are triggered upon mouseover, the color of each paragraph changes to yellow when the mouse is hovered over it.
Hover your mouse pointer over this paragraph to PLAY the buffered sound.
Hover your mouse pointer over this paragraph to STOP the buffered sound.
document.querySelector('.play2').addEventListener('mouseover', start); document.querySelector('.stop2').addEventListener('mouseover', stop);
Press separate QWERTY keyboard keys to trigger and stop the buffered sound
A buffered sound can also be activated by pressing keys on a QWERTY keyboard. Here, we’d like to activate the sound by pressing [Q] and stop the sound by pressing [W]. This can be achieved by using the keydown Event Listener and the proper keyCodes for the letter Q and the letter W.
$(document).on("keydown", function(e) { console.log(e); switch (e.keyCode) { case 81: // Q start(); break; case 87: // W stop(); break; } })
Press and release a single QWERTY keyboard key to trigger and stop the buffered sound
This time, we’d like to start and stop the buffered sound with only one key. We’ll activate the sound by pressing down [F] and stop the sound by releasing [F]. Again, we use the keydown Event Listener. This time we use the keyCode for the letter F to call the start function.
$(document).on("keydown", function(e) { console.log(e); switch (e.keyCode) { case 70: // F start(); break; } })
We use the keyup Event Listener with the keyCode for the letter F to call the stop function.
$(document).on("keyup", function(e) { console.log(e); switch (e.keyCode) { case 70: // F stop(); break; } })
Play a Sound with Web Audio API
Well, there you have it. That should be more than enough to get you going. I’ve shown you a bunch of different ways to play a sound with Web Audio API. Now it’s up to you to implement them in your next project. How will you use these techniques to make the web awesome? Please drop me a comment below if you have any questions about these methods.
Other tutorials in this series
- Web Audio API Basics
- Web Audio API Oscillators
- Web Audio API Audio Buffer
- Controlling Web Audio API Oscillators
- Web Audio API BufferLoader
- Timed Rhythms with Web Audio API and JavaScript
Leave a Reply