Last modified on 18 August 2013, at 20:23

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 ExampleEdit

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; ">
    <font color="white">A canvas element cannot be displayed.</font>
 
    <audio id="hello"> 
      <source src="grouphello.wav" type="audio/wav">
    </audio>
  </body>
</html>

Loading SoundsEdit

The easiest way to load sounds is to define an audio element in the body element:

  <audio id="hello"> 
    <source 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 SoundsEdit

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 SoundsEdit

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.


< Canvas 2D Web Apps

Unless stated otherwise, all example source code on this page is granted to the public domain.