« New Google Doodle uses Web Audio API | Home | A tone generator built using the Web Audio API »

May 23, 2012

Google's Moog Doodle falls back to Flash

Moog doodle

As reported yesterday, Google created a doodle in honor of Bob Moog's 78th birthday.  The doodle caused a sensation throughout the Internet as Google users enjoyed a fully capable synthesizer embedded directly within their web browser.

What intrigued me, however, was the fact that an initial look at Google's JavaScript code indicated they were utilizing the new Web Audio API, which has yet to be supported anywhere other than Google's own Chrome browser.  Yet, reports came in that the doodle works great pretty much everywhere.  (It doesn't work on my iPad, though.  I would have to assume that Android devices also are similarly mute, although I'd love to hear confirmation of this from Ice Cream Sandwich users who have the Android version of Chrome.)

So the big question is how did Google make this work on browsers that don't yet support the Web Audio API?  After all, the <audio> tag is not functional enough to do anything even approaching the level of sophistication being demonstrated here.

The answer is simple:  the doodle employs a Flash fallback.  Google tests to see which browser you're using, as well as which version of Flash is present, and utilizes the appropriate option.  Hence the reason why I was unable to use the doodle in Safari or Firefox, as Click2Flash and FlashBlock, respectively, were preventing the invisible Flash object from launching.

If the browser supports webkitAudioContext(), it is used.  If an error is generated, an <iframe> is created and an HTML page containing an embedded Flash swf is written into that <iframe>.

You can see the beautified code here:

var Td = function (a) {
		this.b = [];
		this.k = a;
		if (this.e = "function" === typeof webkitAudioContext) a: {
			try {
				var b = new webkitAudioContext
			} catch (c) {
				break a
			}
			for (a = 0; 4 > a; a++) {
				var d = [new Bb(b, 0.46, 4, 4, 0, i, l, l, 0, i, 0.05, 0, 0.4, 1),
						new Bb(b, 0.82, 4, 16, 0, i, l, l, 0, i, 0.05, 0, 0.4, 1),
						new Bb(b, 0.46, 4, 2, 0, i, l, i, 0.6, i, 0.05, 0, 0.4, 1)],
					e = new xb(b, 2100, 7, 0, 0.8, 0);
				this.b.push(new Ac(b, d, e, 0.82))
			}
			a = new Rd(b, 20, 2E4);
			this.c = new yb(b, this.b, a);
			Sd(this)
		} else if (qb = u(this.l, this), mb && 0 <= na(nb, "10.0.0.0")) {
			D = document.createElement("iframe");
			D.name = "doodle-moog";
			D.style.position = "absolute";
			D.style.top = "-150px";
			D.style.border = 0;
			D.style.width = "1px";
			D.style.height = "1px";
			document.getElementById("hplogo").appendChild(D);
			E = D.contentDocument;
			if (E == g || E == j) E = D.contentWindow.document;
			E.open();
			E.write('<html><head></head><body><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="0" height="0" id="doodle-moog-flash-1" type="application/x-shockwave-flash"><param name="movie" value="/logos/swf/moog12-2.swf"><param name="allowScriptAccess" value="always"><object id="doodle-moog-flash-2" type="application/x-shockwave-flash" data="/logos/swf/moog12-2.swf" width="0" height="0"><param name="allowScriptAccess" value="always"></object></object></body></html>');
			E.close()
		}
	};

So, there you have it. Mystery solved. If you'd like to peruse the code yourself, you can skip all the tracing and just go straight to this page.