So Firefox 3.5 recently hit the streets and brought some new toys for we designers and developers, including support for HTML5′s <audio> and <video> tags. The Ogg Vorbis and Theora codecs are supported for audio and video respectively. I tinkered with them a little bit with an earlier beta, but didn’t get too fancy. Now that 3.5 is available and more folks have it, I’ve put together a little demo I’ve been thinking about for a couple months.
Presenting, you’re going to hate me for this, karaoke in Javascript! Or, as I like to call it, Jaraoke! Cheeky, eh?
Head over to http://randallagordon.com/jaraoke/ and check it out. Just hit play, and then you’re able to toggle the lyrics in the audio on and off. The song is “Discipline” by Nine Inch Nails, chosen because of the great forward-thinking license chosen for the song, a Creative Commons Attribution-Noncommercial Share Alike license. The lyrics start 24 seconds in, so be patient.
Other Browsers
It is also worth noting that this works in Safari 4 using MP3 sources instead of Ogg Vorbis. Unfortunately the codec playing field is not a level one and Apple refuses to support Ogg on grounds that a patent could crop up out of nowhere…
Chrome should also support this, a <video> tag demo I link to below works just fine. I just simply haven’t done any debugging to see why Chrome doesn’t like it at this point. If anyone catches the problem, please let me know. Determined that this was a server config problem—gzip and Chrome’s Ogg playback don’t play nice together. Adding “SetEnv no-gzip dont-vary” to .htaccess makes everyone happy. So, Jaraoke now works properly in Chrome.
The Markup
The guts are really quite simple. I’m loading up two separate audio files to be played simultaneously, one with the lyrics present and one which is instrumental. Here you’ll also see the two separate source declarations, one for Ogg Vorbis and another for MP3. Beyond that there are two links, one for play control and one to toggle between the vocal and instrumental tracks, and an unordered list element to insert the lyrics into. Here’s the markup:
<audio id='apN' autobuffer="true">
<source src='audio/discipline_mixdown-nvocal.ogg' type='audio/ogg; codecs="vorbis"'>
<source src='audio/discipline_mixdown-nvocal.mp3' type='audio/mp3; codecs="mp3"'>
A custom message can go here for browsers which don't support the <code>audio</code> HTML5 element.
</audio>
<audio id='apW' autobuffer="true">
<source src='audio/discipline_mixdown-wvocal.ogg' type='audio/ogg; codecs="vorbis"'>
<source src='audio/discipline_mixdown-wvocal.mp3' type='audio/mp3; codecs="mp3"'>
</audio>
<a id="togglePlay" href="#">Play/Pause</a>
<a id="toggleVocal" href="#">Toggle Vocals</a>
<ul id="lyricsList"></ul>
The Javascript
When the DOM is loaded, the Javascript does some minimal setup. The volume for the vocal track is set to 0 and the instrumental to 1. These settings are floats with a value of 0, volume completely off, to 1, volume completely on. This, of course, let’s the two files play simultaneously without interfering. By calling play and pause during setup, it forces the files to play perfectly synchronized (at least on my system…) so there is no “skipping” when the vocals are toggled. The lyrics and cue times are simply hard coded into arrays and really should be imported from an XML file.
(UPDATE: Newer versions of Chrome no longer play the files in sync; I’ve yet to find another solution. If you have a solution, please leave a comment! Thanks!)
The grunt work is done by setting up an event listener on the audio element’s “timeupdate” event. The callback just checks the current playback time against a set of cue times. If the playback time is past the current cue’s time then it displays the current lyric and increments to the next cue. Here’s the relevant code:
var currCue = 0;
var cues = [ 24.78, 26.81, 29.69, 34.88, ... ];
var lyrics = [ "Am I...",
"Am I still tough enough?",
"Feels like I'm wearing down, down, down, down, down...",
"Is my viciousness", ... ];
this.apN.addEventListener("timeupdate", timeUpdate, true);
function timeUpdate() {
if(jaraoke.apN.currentTime > (cues[currCue] - CUEOFFSET)) {
var el = $(document.createElement('li'));
el.update(lyrics[currCue++]);
$('lyricsList').insertBefore(el, $('lyricsList').firstChild);
}
}
Taking the Concept Further
Please, let me know what you think, I would love to get some feedback on this. If there is enough interest I figure I’ll take the concept a little further. Such as getting the cue data moved into an XML file, adding some effects (the classic “follow the bouncing ball”, for instance) and, possibly, an editor to create the XML cue data. Perhaps give it a proper design…
Links and Other Resources
Here’s the <video> tag demo that gave me the idea in the first place: STS-116 Launch Profile. As the title implies, it shows a video of the STS-116 launch along with drawing graphs of the speed, altitude and downrange data in sync with the playback time of video.
Also be sure to check out Hyper-Metrix’s jai – javascript audio interface [http://hyper-metrix.com/misc/jai/]. It takes beautifully semantic markup and turns it into an elegant, Flash-free media player GUI. Also puts the <canvas> tag to work, showing off another great new feature.

If you’re going to be tinkering with these elements, don’t forget the best reference—the HTML5 draft spec! Here’s a link to the audio element section.
Update – Examples In the Wild
David Friedman of Ironic Sans used Jaraoke’s code along with other sources to come up with a unique take on traditional volume control. Instead of simply going from quiet to loud, this control adjusts the volume from “whisper to shout”! Check it out and enjoy a laugh over here and also read his blog post about it.