Canvas 2D Web Apps/Sounds
This chapter presents one way to play audio files in web apps using the HTML5 audio
element. There are alternatives (e.g. W3C's Web Audio API) but the HTML5 audio
element appears to be the most widely supported standard.
The Example
[edit | edit source]The example of this chapter (which is also available online; also as downloadable version) uses three buttons to call the play()
, load()
, and play()
or pause()
methods of the audio
element. In fact, this is about all you can do with audio
elements (more specifically with media elements, see the W3C's specification of media elements). The example can also be used to test whether a specific audio file can be played on a specific platform. For example, I had problems using the load
method more than once with the WAV file on an iPad. (The iPad would stop playing the file until I reloaded the web page.)
The following sections will discuss the sound-specific parts of the code; see the chapter on responsive buttons and previous chapters for discussions of other parts.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no">
<script src="cui2d.js"></script>
<script>
function init() {
// get images
imageNormalButton.src = "normal.png";
imageNormalButton.onload = cuiRepaint;
imageFocusedButton.src = "selected.png";
imageFocusedButton.onload = cuiRepaint;
imagePressedButton.src = "depressed.png";
imagePressedButton.onload = cuiRepaint;
// get audio
audioHello = document.getElementById("hello");
audioHello.load();
// initialize and start cui2d
cuiInit(myPage);
}
// audio clip
var audioHello;
// create images
var imageNormalButton = new Image();
var imageFocusedButton = new Image();
var imagePressedButton = new Image();
// create buttons
var button0 = new cuiButton();
var button1 = new cuiButton();
var button2 = new cuiButton();
// create page
var myPage = new cuiPage(400, 300, myPageProcess);
function myPageProcess(event) {
if (button0.process(event, 20, 50, 80, 50, "play",
imageNormalButton, imageFocusedButton, imagePressedButton)) {
if (button0.isClicked()) {
audioHello.play();
}
return true;
}
if (button1.process(event, 100, 50, 80, 50, "load",
imageNormalButton, imageFocusedButton, imagePressedButton)) {
if (button1.isClicked()) {
audioHello.load();
}
return true;
}
if (button2.process(event, 180, 50, 140, 50, "play/pause",
imageNormalButton, imageFocusedButton, imagePressedButton)) {
if (button2.isClicked()) {
if (audioHello.paused || audioHello.ended) {
audioHello.play();
}
else {
audioHello.pause();
}
}
return true;
}
if (null == event) {
// draw background
cuiContext.fillStyle = "#A0A0AF";
cuiContext.fillRect(0, 0, this.width, this.height);
}
return false; // event has not been processed
}
</script>
</head>
<body bgcolor="#000000" onload="init()"
style="-webkit-user-drag:none; -webkit-user-select:none; ">
<span style="color:white;">A canvas element cannot be displayed.</span>
<audio id="hello">
<syntaxhighlight src="grouphello.wav" type="audio/wav">
</audio>
</body>
</html>
Loading Sounds
[edit | edit source]The easiest way to load sounds is to define an audio
element in the body
element:
<audio id="hello">
<syntaxhighlight src="grouphello.wav" type="audio/wav">
</audio>
This specifies a audio
element with the name “hello
” and the audio file (the source) “group hello.wav
” of type “audio/wav
.” Note that:
- You should specify multiple
source
elements with the same audio content in different formats such that all web browser find one that they can play. (See here for an overview of supported formats by various browsers; Apple developers should see here for formats supported on iOS.) - You should specify the type of each audio file because some browsers (in particular Safari on iOS) appear to need this information in some cases.
In order to access the audio
element, a global variable should be defined, e.g.:
var audioHello;
This variable should be set in the init
function; in the example:
audioHello = document.getElementById("hello");
audioHello.load();
This uses the name “hello
” which was defined in the audio
tag and requests the web browser to load the audio file.
Playing Sounds
[edit | edit source]The update
function uses one button to call play()
:
if (button0.process(event, 20, 50, 80, 50, "play",
imageNormalButton, imageFocusedButton, imagePressedButton)) {
if (button0.isClicked()) {
audioHello.play();
}
return true;
}
There is a second button to call load()
again (which usually rewinds the file to the beginning but might lead to problems for some combinations of audio file formats and web browsers):
if (button1.process(event, 100, 50, 80, 50, "load",
imageNormalButton, imageFocusedButton, imagePressedButton)) {
if (button1.isClicked()) {
audioHello.load();
}
return true;
}
The third button checks whether the audio file is paused
or has ended
. In this case, it calls play()
, otherwise pause()
:
if (button2.process(event, 180, 50, 140, 50, "play/pause",
imageNormalButton, imageFocusedButton, imagePressedButton)) {
if (button2.isClicked()) {
if (audioHello.paused || audioHello.ended) {
audioHello.play();
}
else {
audioHello.pause();
}
}
return true;
The example can also be used to test audio files with particular web browsers, which is often necessary as described next.
Testing Sounds
[edit | edit source]Since support for audio file formats strongly depends on the web browser (not only for technical reasons but also because of legal issues), it is important to test web apps with sounds on as many platforms as possible. If there is an issue, the same content should be provided in multiple formats in order to support as many browsers as possible. It might also make sense to avoid calling the load
function more than once, e.g. if the audio clip is very short and restarting before it ends doesn't make much sense anyways. (Also note that the load
function in Safari on iOS appears to be rather slow.)
For iBooks widgets, Apple recommends to use AAC audio in an MPEG-4 container with an “.m4a
” file extension.