Sound Manager

The Sound Manager was one of the last things I built, and involved a while wading through the HTML5 spec document.

The resulting code is actually pretty simple, but took me a while to figure out that this was the best way to do it.  My requirments were;

  • Ability to adjust volume
  • Ability to stop all the sounds at once
  • Able to play multiple instances of the same sound
  • Don’t want to be reloading the sound every time!
  • Not kill my frame rate!!

The core of the class is an Array called Channels which holds all sounds which are playing/ have been played through the manager.

PlaySound(HTML5AudioElement sound, Bool loop, Float volume)

The PlaySound method is where the meat is- You pass in a reference to an actual HTML5 Sound element (which I’m pulling straight out of the resource manager – so no reloading), a boolean to say if you want to loop and the volume (between 0.0 and 1.0).

The code loops through the Channels array to see if this sound is already loaded into the array; if it is it checks to see if the “ended” flag is set- this flag is part of the HTMLMediaElement interface which the Audio and Video tag both implement so should exist in both, and is set automatically when playback is complete.  If ended is set, then it simply adjusts the volume of that element as needed and tell’s it to start again with .play().

If the audio element doesn’t exist in the array, or it does but it’s still playing, then we need to add an additional instance.  I do this using the DOM function cloneNode() on the sound element which is passed into the method- this creates a “deep-copy” of the element which we can play and stop and adjust totally independantly of any other instances, and also allows us to avoid having to load a totally new instance from the disk.

StopAll

Really simple one which loops through the Channels array calling pause() on each element.  There is, at present, no stop() method defined in the HTML5 Spec.

Future Expansion

I got the volume adjust working, but in the end never implemented it in the game- I was going to make it so you could hear the bad guys foot steps as you approached, but realised it sounded rubbish.

The Loop switch at present also does nothing- this was because there is, at present from my testing, no way to seemlessly loop a sound using HTML5 Audio yet.

The Code

// 2010.07.15SY - loop disabled as, at present, there is no way to reliably loop sounds without there being a break inbetween loop cycles.  gash.
function SoundManager() {
    this.Channels = new Array();
}
SoundManager.prototype.PlaySound = function (sound, loop, volume) {
    //is this sound already loaded into the stack?
    for (var i = 0; i < this.Channels.length; i++) {
        if (this.Channels[i].currentSrc == sound.currentSrc && this.Channels[i].ended) {
            if (volume) this.Channels[i].volume = volume;
            this.Channels[i].play();
            return;
        }
    }

    // https://developer.mozilla.org/en/CloneNode
    var new_id = this.Channels.length;
    this.Channels[new_id] = sound.cloneNode(true); // perform a deep copy so we get a totally seperate instance of the sound!
    if (volume) this.Channels[new_id].volume = volume;
    this.Channels[new_id].play();
}

SoundManager.prototype.StopAll = function () {
    for (var i = 0; i < this.Channels.length; i++) {
        if (this.Channels[i] != null) 
            this.Channels[i].pause();
    }
}
  1. #1 by Olivier on September 16, 2010 - 07:52

    Hi Shawson,

    While browsing the web looking for an alternative to the cloneNode function, I found your page, and saw that you also used it for your games. On my side, that’s the only way I found to play the same sounds (almost) simultaneously on different “channels” (for SFX in games), and while this is working perfectly in Chrome, I got some troubles with Safari (as mp3 are then refetched from the server each time a call to cloneNode is done).

    So my question is: did you tested this under recent version of Safari (5.0.x) and since this (that seems to date a little now) did you figured it any other/better way to do that ?

    thank you,
    Olivier.

  2. #2 by shawson on September 17, 2010 - 10:34

    Hi Olivier,

    Thanks for posting- no I didn’t do any extensive testing or profiling on Sarafi, aside from a quick 15 minutes to make sure it roughly worked- I was mainly targetting Firefox and Chrome. Sorry I can’t be of more help!

(will not be published)