Audio Synthesis in JavaScript

This is something I’ve wanted to play with for a long time. So the other day I buckled down and started searching around.

Yes, you can create sound in JavaScript. In some browsers. Supposedly, it works in Chrome 14, Firefox 23, Opera 15 and Safari 6. Not IE. But, I’ve only tested this in Chrome. So for now, consider this something experimental and fun to lay with, not for your super awesome works-in-every-browser game.

I found several sites that had build up complex libraries based on the Web Audio API. These weren’t the greatest things to learn the basics from, but I eventually was able to pare some of the code down to the bare minimum needed to create some sounds in the browser. There’s also the MDN documentation here: https://developer.mozilla.org/en-US/docs/Web_Audio_API, which is a great reference, but not a step-by-step tutorial for creating sounds. There are a few tutorials linked to from there as well, but none really covered what I was interested in.

So, to get down to it, let’s create some noise.

First you need to create an AudioContext object. This is similar in concept to HTML5’s 2D graphics context for canvas. The context is the overarching object that you’ll use to create all the pieces that will create the sound you’re going to make. For Webkit-based browsers, you get an AudioContext like so:

[php lang=”javascript”]

var context =
new window.webkitAudioContext();

[/php]

The AudioContext has a few properties, the most important one being “destination”. The destination is basically the output of the context, where the sound goes. You can think of it as your speakers.

audiocontext

The next thing you need to know about the Web Audio API is that it is a node based system. You use the AudioContext to create various nodes that are used to create and shape sounds. Nodes have inputs and outputs that you can use to hook various nodes together into different configurations.

The most direct way to create a sound is to create an oscillator node. An oscillator node has zero inputs and one output. You can hook that output to the destination of your context. You’ll also need to specify a frequency for the oscillator. 440 hz will create the musical note, A. Here’s the code:

[php lang=”javascript”]
var context = new window.webkitAudioContext();

var osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);

[/php]

And here’s how this looks from a node view:

oscillator

Yeah, it says “frequency: 500”. My goof. Not changing it. Live with it.

You have an oscillator node with a frequency of 440 connected to the destination of the AudioContext. Call start(0) and you should get an annoying sound coming out of your speaker.

The oscillator node has a couple of other properties. One is “type”. This is the type of wave it uses to generate the sound. It defaults to “sine”. But, you can try “square”, “sawtooth” or “triangle” and see how they sound by doing this:

[php lang=”javascript”]
osc.type = “sawtooth”;
[/php]

There’s also a “custom” type, but that involves creating and setting a custom wave table. If you’re into it, go for it.

Anyway, wasn’t that easy? Let’s expand on it and create another oscillator that messes with the first one.

To do this, you’ll create two new nodes, an oscillator node and a gain node. A gain node is usually used to change the volume of a sound, but you’ll be using it here to alter the frequency of the original oscillator node. You’ll also create another, slower oscillator node. This new oscillator node’s output will be connected to the gain node. A gain node has a single input and a single output. As the new oscillator goes up and down at a frequency of 1 hz (once per second), it will affect the output of the gain node. A gain node also has a value property. If you set that to 100, then the gain node’s output will cycle from +100 to -100 as the new oscillator slowly cycles.

Now you need to hook this +/- 100 gain node output to the original oscillator. But remember that oscillator nodes don’t have any inputs, so you can’t connect it directly to the oscillator node. Instead, you connect it directly to the frequency property of the node. Now that gain output will change the original frequency of 440 hz + or – 100 hz as it cycles. A picture is worth several hundred words.

oscillator2

One oscillator is connected to the gain node, which is directly connected to the other oscillator’s frequency. That oscillator is connected to the destination. Here’s the code:

[php lang=”javascript”]
var context = new window.webkitAudioContext();

var osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);

var gain = context.createGain();
gain.gain.value = 100;
gain.connect(osc.frequency);

var osc2 = context.createOscillator();
osc2.frequency.value = 1;
osc2.connect(gain);
osc2.start(0);
[/php]

Run that and you should hear a siren like sound.

You can also change the type of the second oscillator. Try making that a square wave:

[php lang=”javascript”]
osc2.type = “square”;
[/php]

square

Now, instead of cycling smoothly from +100 to -100, the gain’s output will be exactly +100 for half the cycle than jump to exactly -100 for the second half. The result is more like a siren you’d hear in Europe or the UK. It also drives my dog crazy.

Anyway, that’s the bare minimum. Check out the API at the link mentioned previously. There’s a lot more you can do with it from here.

This entry was posted in JavaScript. Bookmark the permalink.