Home of the Ranbot 3000

randallagordon.com

Jaraoke – An HTML5

July 19, 2009

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 “Disciple” 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.

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.
jai

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.

3 Responses to “Jaraoke – An HTML5

  1. Richard H

    cool but i thought it was playing 2 different audio tracks in sync. from what i can tell its just swapping out one track for another. Was looking for a way for javascript to play 2 separate tracks at the same/offset time i specify. essentially doing what smil does with javascript.

  2. randallagordon

    There are indeed two playing simultaneously. The handleToggle function that gets called when you click “Toggle Vocals” simply sets the volume on one to 0 and the other to 1, effectively muting one (although technically mute is a separate state). I will note that there are all sorts of issues with synchronization. I attempted to write some crossfade functions, which worked fine, but threw the files out of sync… One of these days I may get around to tinkering with the concept more and figuring out why they get out of sync. Sample-level synchronization would be ideal for creating browser based music apps.

  3. Jaraoke – An HTML5 Tag Demo · HTML5 App

    [...] Jaraoke – An HTML5 <audio> Tag Demo [...]

Leave a Reply

All content, excluding the work in my Portfolio, is licensed CC-BY-SA, unless otherwise noted. Museo and Museo Sans fonts by Jos Buivenga. Thank you!

Other Attributions   •   Entries (RSS)   •   Comments (RSS)

Free the web