hostmonster-Host Unlimited Domains on 1 Account   coolhandle offering reliable webhosting since 2001
Unlimited Hosting Space - FREE Site Builder   Smart Website Solutions for Your Small Business=

How To Create A Responsive 8-Bit Drum Machine Using Web Audio, SVG And Multitouch

Sponsored Post
How To Create A Responsive 8-Bit Drum Machine Using Web Audio, SVG And Multitouch

In this little tutorial, I’m going to share some tips I recently followed to build a fun demo for the Build 20161 conference. The idea was to create a small 8-bit drum machine2, with 8-bit sounds and graphics:

You can click on the black drums to make some noise (make sure sound is on). However, please note that the demo may not work on certain devices. (Demo3)

This small web app was used in one of our demos to illustrate how you can easily provide a temporary offline experience when your hosted web app4 loses Internet connectivity.

Building this drum machine might sound trivial, but it raises some interesting questions. For instance, how do you handle the hit testing for the various pads of this bitmap image? How do you guarantee the same experience across all devices and browsers, accounting for resolution and touch support?

Options To Handle Hit Testing Link

Consider the image used in the demo just below. I built it by degrading the original image to 8-bit, as part of our little retro joke. The full online experience would provide the best graphics and sounds, while the offline experience would offer a degraded 8-bit version.

You’ll probably be tempted to press on the various black circles to make some noises. Let’s figure out how to handle clicks on those parts of the image using HTML.

The older folks among us might be tempted to use an image map, with the map and area tags. We can define areas of the image with various geometric shapes, including ellipses and circles. That might do the trick.

Unfortunately, this approach has two problems, the first one being major:

  • It’s pixel-based, so it won’t scale across resolutions and devices. Suppose your bitmap image had a fixed size of 600 × 400 pixels. If you defined areas inside it, you would build them based on this 600 × 400 resolution. As soon as you expand or contract the image to match the device’s resolution, the areas wouldn’t match the image any longer. The jQuery RWD Image Maps5 plugin will compute the area’s coordinates dynamically. But I thought that adding the jQuery library and this plugin just for this simple hit-testing demo would be too much. I was looking for something simpler.
  • The feature was originally defined to enable navigation to URLs. I’d rather call a JavaScript function to use web audio to play the sounds. Still, you could use this trick by defining an href="#" and registering the click event in the area.

My next idea was to put it in a 2D canvas, which I could stretch to the current resolution using CSS. This solution might work, but it would be a really complex implementation for such a simple web app. Indeed, this would entail:

  • manually defining the hit zones by code;
  • handling the click event on the canvas, finding the exact x and y mouse coordinates of the click, and scaling that to the current resolution;
  • computing the hit-testing algorithm by checking whether those 2D coordinates are in one of the ellipses that we have defined in the code.

It’s not tremendously complex, but it’s a fair bit of math for something that should be simple to build. Also, if you’d like to keep the aspect ratio of the image, the 2D canvas method also entails resizing the canvas’ size by computing in the code the ratio during the loading phase and inside the onresize event.

Finally, I thought of what should be the most obvious solution. When you think about what scales across devices, facilitates hit-testing and handles aspect ratios, the answer is naturally SVG. The “S” stands for “scalable” — we can define a viewbox with some parameters to lock the aspect ratio.

Sure, but you’re probably going to say, “How does that help us define the hit zones in the image?” Not to mention that we’re working with a bitmap image, not a vector?

Let me show you what I’ve done. Follow these very same steps for any similar experience you’d like to build on top of a bitmap image.

Save the image above of the 8-bit drum machine on your computer.

We need a tool that will generate an XML of our SVG content. I’ll use InkScape6, a free application, but you can probably do the same thing with SVG Edit7 in the browser.

Open Inkscape, go to “File” → “Document Properties,” and change the “Custom size” values to 160 × 90.

Go to “File” → “Import,” and choose the 8bitsdrummachine.jpg file that you’ve saved. Choose “Link” as the import type, and leave the other options as is. Then, stretch the image to map our drawing zone:

Creating A Small 8-bit Responsive Drum Machine Using Web Audio, SVG  Multi-Touches Image8

We’re now going to draw ellipses on top on our image. Choose red, and make sure that your ellipses perfectly cover the black drums:

Creating A Small 8-bit Responsive Drum Machine Using Web Audio, SVG  Multi-Touches Image9

Those seven ellipses will be our hit zones.

To be able to find those SVG forms easily in our code, right-click on each of them, choose “Object Properties” and change its “ID” and “Label” properties to button1 (up to button7) and #button1 (up to #button7), respectively:

Creating A Small 8-bit Responsive Drum Machine Using Web Audio, SVG  Multi-Touches Image10

Now that we have defined the hit zones precisely, let’s make them transparent, rather than hiding them under the image. Right-click on each of them, choose “Fill and Stroke,” and set the alpha value (“A”) to 0:

Creating A Small 8-bit Responsive Drum Machine Using Web Audio, SVG  Multi-Touches Image11

Note: We’re using simple ellipses here, but you could draw any complex shape allowed by SVG on top of the image to achieve a similar result.

Save the result on your hard drive by going to “File” → “Save as…” in the menu.

Open this file with your favorite editor (Notepad++, Sublime, Visual Studio Code, whatever), and add the following line of XML just after the viewBox attribute:

preserveAspectRatio="xMidYMin meet"

Mozilla’s documentation explains what this SVG attribute does12.

You’re done with this part. This piece of SVG will embed the bitmap image, add a layer of a transparent vector form that can be clicked on, and scale across resolutions, keeping the aspect ratio, thanks to the preserveAspectRatio attribute.

Now, we need to set the code to tie those SVG ellipses to our event handler.

What About Web Audio? Link

I’ve already covered web audio elsewhere13 in detail. I’m reusing part of that code, including the Sound object:

var Sound = (function () {
    function Sound(url, audioContext, masterGain, loop, callback) {
        this.url = url;
        this.audioContext = audioContext;
        this.masterGain = masterGain;
        this.loop = loop;
        this.callback = callback;
        this.gain = this.audioContext.createGain();
        this.isReadyToPlay = false;
    Sound.prototype.loadSoundFile = function () {
        if (canUseWebAudio) {
            var that = this;
            // make XMLHttpRequest (AJAX) on server
            var xhr = new XMLHttpRequest();
  'GET', this.url, true);
            xhr.responseType = 'arraybuffer';
            xhr.onload = function (e) {
                // decoded binary response
                function (decodedArrayBuffer) {
                    // get decoded buffer
                    that.buffer = decodedArrayBuffer;
                    that.isReadyToPlay = true;
                    if (that.callback) {
                }, function (e) {
                    console.log('Error decoding file', e);
    }; = function () {
        if (canUseWebAudio amp;amp;amp;amp; this.isReadyToPlay) {
            // make source
            this.source = this.audioContext.createBufferSource();
            // connect buffer to source
            this.source.buffer = this.buffer;
            this.source.loop = this.loop;
            // connect source to receiver
            // play
    return Sound;

Then, as I’ve also explained elsewhere14, we need to handle web audio in a special way for iOS, by unlocking the AudioContext:

try {
    if (typeof AudioContext !== 'undefined') {
        audioContext = new AudioContext();
        canUseWebAudio = true;
    } else if (typeof webkitAudioContext !== 'undefined') {
        audioContext = new webkitAudioContext();
        canUseWebAudio = true;
    if (/iPad|iPhone|iPod/.test(navigator.platform)) {
    else {
        audioUnlocked = true;
15.} catch (e) {
    console.error("Web Audio: " + e.message);
19.function unlockiOSaudio() {
    var unlockaudio = function () {
        var buffer = audioContext.createBuffer(1, 1, 22050);
        var source = audioContext.createBufferSource();
        source.buffer = buffer;
        setTimeout(function () {
            if ((source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE)) {
                audioUnlocked = true;
                window.removeEventListener('touchend', unlockaudio, false);
        }, 0);
    window.addEventListener('touchend', unlockaudio, false);

Handling Multitouch Across Devices Link

In my opinion, the best touch specification for the web is pointer events15. I’ve already covered the specification in detail16. We’ll use it to wire our event handler to our SVG shapes.

In the code below, we’re referring to all of the SVG shapes that we built with InkScape — shapes with which we’ve associated IDs (button1, button2, etc.). Then, we’re loading the various 8-bit sounds from the web server and decoding them via our Sound object. Finally, using the pointerdown event, we’re playing each sound associated with each SVG shape:

var soundsCollection = [];
var buttonsCollection = [];

if (canUseWebAudio) {
    masterGain = audioContext.createGain();
    soundsCollection.push(new Sound("./8bits_sounds/clap.wav", audioContext, masterGain, false, newSoundLoaded));
    soundsCollection.push(new Sound("./8bits_sounds/cowbell.wav", audioContext, masterGain, false, newSoundLoaded));
    soundsCollection.push(new Sound("./8bits_sounds/hihat1.wav", audioContext, masterGain, false, newSoundLoaded));
    soundsCollection.push(new Sound("./8bits_sounds/kick1.wav", audioContext, masterGain, false, newSoundLoaded));
    soundsCollection.push(new Sound("./8bits_sounds/snare1.wav", audioContext, masterGain, false, newSoundLoaded));
    soundsCollection.push(new Sound("./8bits_sounds/tom1.wav", audioContext, masterGain, false, newSoundLoaded));
    soundsCollection.push(new Sound("./8bits_sounds/kick3.wav", audioContext, masterGain, false, newSoundLoaded));
var soundsLoaded = 0;
function newSoundLoaded() {
    if (soundsLoaded == 7) {
        // Ready to rock amp;amp; roll!
        for (var i = 0; i 

With this code, we’re supporting multitouch in a simple way. But it has one drawback: it only works in the Microsoft Edge browser. To support all browsers and devices, you can use the jQuery-based Pointer Events Polyfill17.

script src=""/script

Add the following property to the HTML element that contains the relevant UI (the body element in our demo):


Going Further With Synthesizing Link

In this small demo, I’ve downloaded recorded samples of 8-bit sounds. But web audio has some great features that could help you generate sounds via oscillators, for example, as Chris Lowis explains on Dev.Opera18.

I hope that you’ve enjoyed this little tutorial and that it helps you solve some of your issues or create cool experiences.

This article is part of the web development series from Microsoft tech evangelists and engineers on practical JavaScript learning, open source projects, and interoperability best practices including Microsoft Edge19 browser.

We encourage you to test across browsers and devices including Microsoft Edge – the default browser for Windows 10 – with free tools on dev.microsoftedge.com20, including F12 developer tools21 — seven distinct, fully-documented tools to help you debug, test, and speed up your webpages. Also, visit the Edge blog22 to stay updated and informed from Microsoft developers and experts.

(ms, il, al)

Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
SmashingConf New York

Hold on, Tiger! Thank you for reading the article. Did you know that we also publish printed books and run friendly conferences – crafted for pros like you? Like SmashingConf Barcelona, on October 25–26, with smart design patterns and front-end techniques.

↑ Back to top
Tweet itShare on Facebook

Article source:


Submit a Review

If you want a picture to show with your review, go get a Gravatar.

1&1 has shared hosting and dedicated hosting solutions for every budget and free domains with all hosting packages!  StartLogic - Affordable hosting: Free setup/domain, unlimited emails, PHP, mySQL, CGI, FrontPage. As low as $3.95/month
Cloud ecommerce platform delivers more traffic, higher conversion and unmatched performance

© Copyright 2008 Tyconia International, Inc. All Rights Reserved.