Fork me on GitHub

lowLag.js: responsive html5 audio

"a simple wrapper for low-latency, high-compatibility,
html5-friendly audio"

Audio on the web is tricky. The <audio> tag is gaining popularity and support, but it is often slow for things that demand quick response (such as games) and on some systems has weak support for playing multiple sounds at once (like in games) . SoundManager2 is comprehensive and awesome (a js/Flash library that falls back to the <audio> tag if it has to) but the lag is notable, especially on Chrome. Finally, WebKit audio is terrific -- on the browsers that support it.

lowLag.js is a wrapper for 3 different best practices:

The interface is meant to be trivial to use, and installation is easy as well.

Download

You need two files:

(You also need jQuery, or a link to it.) I recommend unzipping that into the directory your html file is in. (So that the relative paths sm2/js/ and sm2/swf are available to the script... otherwise you will have to do some configuration, see below.)

Usage

Simplest usage:

lowLag.init();
lowLag.load("pluck.mp3");
lowLag.play("pluck.mp3");
That would be (pretty much) the whole story, except... Firefox doesn't support MP3s. So lowLag.js borrows the concept of a sound group - a set of identical but different format sound URLs that you label and then play via a tag. All 3 modes support this (more or less: Webkit just plays the first one in the group, but you don't have to change any code.) Sample:
lowLag.load(["pluck.mp3","pluck.ogg"],"pluck");
lowLag.play("pluck");
Including an mp3 and ogg version gets you very high percentage coverage across browsers.

Live Demo

In the $(document).ready(), we have run the following:

lowLag.init({'urlPrefix':'plucks/'});
(If we had delayed on the init step, sm2 would have tried to run uninitialized, and panicked if it couldn't find its supporting files.) The urlPrefix tells lowLag to look in the "plucks/" directory for its sound files. We then loaded 2 sound groups and assigned a tag to each one...
lowLag.load(['pluck.mp3','pluck.ogg'],'pluck1');
lowLag.load(['pluck2.mp3','pluck2.ogg'],'pluck2');
We can now play either clip or both of them together:





I have also created a playground page. This page allows you to force different modes (sm2, audio tag, etc) as well as test playback inside a javascript timeout(), and on page load. It also includes a nifty little drum machine demo.

Installation

Unzip the sm2.zip file and move things so its contents can be accessed by the html5 page. Do similar for the file lowLag.js.

Add this to the top of your html file:

<script src="/path/to/lowLag.js"></script>
<script src="/path/to/soundmanager2.js"></script>
<script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
(You don't need the final line if you are already using jQuery on your page.) Finally, if the swf directory is something other than "sm2/swf" relative to your html file, you sill have to set the sm2url parameter when you call lowLag.init().

Command Options

lowLag.init() takes one optional argument, a hash of configuration options:
force
Value can be 'webkitAudio', 'audioTag', or 'sm2'. With no argument, lowLag.js will pick the best for the current browser (webkit for Browser that support that as a feature, the <audio> tag if it detects Firefox (preferred over SoundManager2 for performance reasons) and finally SoundManager2, which will first try Flash and fallback to the <audio> tag.)
urlPrefix
The value of this key will be directly prefixed to URLs when loading sound files. (Default "", i.e. same directory as the html file)
audioTagTimeToLive
To allow for simultaneous sounds, <audio> tags are cloned and then destroyed. This value is the time (in millis) before the file is destroyed. Default is 5000, or 5 seconds: if your clips are longer than that you may wish to adjust this value accordingly.
sm2url
Location of the directory for Soundmanager2's .swf files... defaults to 'sm2/swf/'
debug
Values can be 'console', 'page', 'both' or 'none'-- determines where information gets sent. Default to 'console'.

lowLag.load(urls,tag) "urls" can be a string (containing a single sound file URL) or an array (containing a group of the same sound in different file formats) Tag is optional: if present, it will be used by the "play()" command. If absent, "urls" as a string will be used, or the first entry in the urls array. (Note: webkit Audio will only use the first file in a urls group, so order things accordingly. (i.e. start with .mp3))

lowLag.play(tag) Play the sound associated with this tag.

Caveats

History/Rationale

As you may have guess from the introduction, I wanted sound effects for my HTML5 games,and was frustrated by a lack of a one-stop-shopping low-lag audio solution.

Anyway, here is a table showing browsers I've tested various audio solutions on, and what file formats they support:

<audio>SM2webAudioFormat: .mp3.ogg.m4a.wav
ChromeGOOD*SLOWGOOD (webAudio)YYYY
FirefoxGOOD SLOW-- (audioTag)NYNY
IE9SLOWOK-- (sm2 flash)YNNN
Safari (OSX)SLOWOKGOOD (webkit) YNYY
iOS 5TERRIBLETERRIBLE-- (sm2 html5) YNYY
iOS 6GOODSLOWGOOD (webkit)YNYY
* Initially Chrome had a weird glitch where it would play two sounds sequentially instead of simultaneously-- that's what inspired this project in part, though after a reboot the glitch disappeared.

Acknowledgements

Thanks to Darius Kazemi for pointing me to SoundManager2 and providing example Webkit code and Kabir Hemrajani for running a test on an iOS6 simulator for me. I got the implementation of <audio> cloning from http://html5doctor.com/native-audio-in-the-browser/. And of course many thanks to the SoundManager 2 project for being so cool.