Playing notes with the Web Audio API Part 1 - Monophonic Synthesis
The Web Audio API turns your browser into a powerful synthesizer. One question I’ve been asked about the Web Audio API is how to play single, one-shot sounds using the oscillators, in other words how to play notes or tunes. I’ll show one approach in this post and along the way we’ll look at how some early analogue monophonic synths worked.
If you’re new to the Web Audio API there’s a good introduction over on HTML5 Rocks. The first couple of sections should be all you need to follow this tutorial.
Playing a sound
We start by creating some sound. This could be considered the “hello world” of Web Audio applications - we’ll generate music’s purest tone, the sine wave, and make it play.
If you open a javascript console on this page and enter the code
above, assuming your browser supports the Web Audio API1, you
should hear a tone at 200Hz. We’ve created an AudioContext
, added an
oscillator and told it to start playing immediately. If you don’t set
the frequency the default is 440Hz, or an A above middle C. Why 440Hz?
I thought you’d never ask!
We can stop the tone with
At this point, you might be tempted to start the oscillator again
but you’ll find, if you try, that this doesn’t work. For performance reasons the Web Audio API is designed so that oscillator, and other nodes such as AudioBufferSourceNode can only be “used” once. So if we want to play a sequence of notes, or attach notes to the keys of a virtual keyboard, how do we proceed? To answer this question, let’s consider how analogue synth designers tackled the problem.
Monophonic Synthesis
One classic monophonic synthesizer is Robert Moog’s “Minimoog”. This was a monophonic synthesizer - that is, it could only play a single note at a time. Here’s the control panel from the Minimoog:
The sections we are interested in here are the “oscillator bank”2 and the “loudness contour” controls, also known as the VCO (Voltage Controlled Oscillator) and VCA (Voltage Controlled Amplifier) respectively3.
The VCO, as it’s name suggests, is an oscillator whose frequency can
be set by sending a specific voltage - typically from the keyboard of
the instrument. In our code above, this is equivalent to the
oscillator.frequency.value =
.
The VCA is an amplifier which varies its gain depending on a supplied voltage. For simplicity, let’s assume that when it receives a positive voltage it sets its gain to 1, and when it receives a negative voltage it sets its gain to zero.
When a musician presses a key on the keyboard, two things happen. Firstly a voltage is sent to the VCO to set its frequency. Secondly, the same key press sets the gain of the VCA. The oscillator is connected to the amplifier so pressing the key makes a sound. When the key is released, the VCA is set to zero and the sound stops.
Armed with this knowledge, we can simulate this using the Web Audio API.
A simple Web Audio monosynth
To recreate the simple Minimoog described above we need two nodes from the Web Audio API, connected together like so:
We also need a mechanism to send messages to the nodes using key-presses. We’ll use Stuart Memo’s very useful Qwerty Hancock library for this. It turns a given DOM element into an interactive vector keyboard!
A little bit of glue code, and we have
When a key on our virtual keyboard is pressed, the keyDown event is fired. We set the frequency of the oscillator and turn the gain of the amplifier up to 1. When the key is lifted we set the gain to zero.
Here’s the simple synthesiser in action:
There’s a few tweaks we should make here, as I’ve deliberately kept the code very simple. For example, if you press two keys at the same time and then release one, the gain will be set to zero. This can be avoided by keeping track of the keys that are pressed using an object
The completed code is in this gist.
The other thing you might hear when playing with this demo is the
“slide” between each note. When setting the value of some parameters
directly in the API, as we do here with frequency
, the spec
recommends that changes are made smoothly to avoid clicks or glitches.
We’ll see how to control this effect in a future post when we look at
parameter automation and envelopes.
Next
We’ve seen how to play notes using the Web Audio API using code influenced by the design of classic monophonic synthesizers. Next time we’ll have a look at techniques for playing multiple notes at the same time: polyphonic synthesis.
Footnotes
AudioContext monkeypatch
on this page so that I can use AudioContext
instead of the
vendor-prefixed webkitAudioContext
on Chrome. The code examples here
match the Web Audio spec and can work in non-webkit browsers, such as
Firefox, as well. If you’re trying these examples in a page that
doesn’t have the patch loaded, you’ll need to replace AudioContext
with webkitAudioContext
.
oscillators - the Minimoog could mix together the sound of three oscillators, but only to combine them into a single “note” - they couldn’t be triggered by independent keys on the keyboard.