HTML5 Canvas [136]
Iteration #2: Creating Unlimited Dynamic Sound Objects
So, we almost got what we wanted with the first iteration, but we ran into some oddities when calling the play() function on a single HTMLAudioElement multiple times before the sound had finished playing.
For our second iteration, we are going to try something different. Let’s see what happens when you simply create a new HTMLAudioElement object every time you want to play a sound. If this doesn’t sound like an efficient use of memory or resources in the web browser, you are a keen observer. It’s actually a horrible idea. However, let’s proceed just to see what happens.
Figure 7-7. Space Raiders playing sounds from two objects
In canvasApp(), we will create a couple constants that represent the filenames of the sounds we want to play, but without the associated extension. We will still retrieve the extension with a call to supportedAudioFormat(), just as we did in the first iteration, and store that value in the audioType variable.
We will also create an array named sounds that we will use to hold all the HTMLAudioElement objects we create. This array will tell us how many objects we have created so we can visually see when all hell breaks loose:
const SOUND_EXPLODE = "explode1";
const SOUND_SHOOT = "shoot1";
var sounds = new Array();
Instead of calling the play() function of each sound directly, we are going to create a function named playSound(). This function accepts two parameters:
sound
One of the constants we created above that contains the name of the sound file
volume
A number between 0 and 1 that represents the volume of the sound to play
The function here creates a new sound object every time it is called by calling the createElement() function of the document DOM object. It then sets the properties (src, loop, volume) and attempts to play the sound. Just for fun, let’s push the object into the sounds array:
function playSound(sound,volume) {
var tempSound = document.createElement("audio");
tempSound.setAttribute("src", sound + "." + audioType);
tempSound.loop = false;
tempSound.volume = volume;
tempSound.play();
sounds.push(tempSound);
}
To play the sounds, we call playSound(), passing the proper parameters.
The call in eventMouseUp() looks like this:
playSound(SOUND_SHOOT,.5);
And in drawScreen() it looks like this:
playSound(SOUND_EXPLODE,.5);
To display on the canvas how many sounds we have created, we add this code to the drawScreen() function:
context.fillStyle = "#FFFFFF";
context.fillText ("Active Sounds: " + sounds.length, 200 ,480);
Now, go ahead and try this example (CH7EX7.html in the code distribution). Figure 7-8 shows what Space Raiders iteration #2 looks like. Notice we have added some display text at the bottom of the screen to show how many sounds are in the sounds array. You will discover two issues with this iteration:
The sounds play with almost no pauses when loaded from a local drive. But when the page is loaded from a remote website, there is a defined pause before each sound is loaded and played.
The number of sound objects created is a huge problem. For some browsers, such as Chrome, the number of active sounds caps out at about 50. After that, no sounds play at all.
Figure 7-8. Space Raiders creating sounds on the fly
Iteration #3: Creating a Sound Pool
So, now we know we don’t want to play