Have you ever wanted to make some noise in your browser? I wanted to generate some sound effects, and it made me curious about what tools are available in the browser.
What I found is the Web Audio API. I’m going to show how to play basic sounds, and lay the groundwork for building more advanced sound generators.
The WebAudio API is built around a “node” system. It somewhat parallels how you would connect sound modules or effects pedals together in real life.
The base object you need to work with is the AudioContext, created with
new AudioContext() (or
new webkitAudioContext() for Webkit-based browsers). This context object has factory methods to create the other nodes you use.
Here’s how you output a simple tone (Warning, this is rather loud if run directly):
We already learned about the audioContext, and the rest is fairly straightforward as well. The
audioContext.createOscillator() creates an OscillatorNode instance, which generates a tone. OscillatorNodes has AudioParam properties to control frequency (directly, and via a “detune” value, which seems to be more suitable for note-based music generation) and wave-shape.
OscillatorNode implement AudioNode, which is the base class. AudioNodes use the AudioParam interface for properties, which gives controls like
setValueAtTime() used above. So an oscillator has a
oscillator.frequency.value, and you can either write to the
value property or use the time-based methods such as
.setValueAtTime(). Generally, using the time-based methods is better, because they will overwrite any value written to the value property directly.
To use the output of an AudioNode, you call the
.connect() method and pass the target, which can be another AudioNode, an AudioParam (for dynamic input), or
audioContext.destination which represents the browser’s sound output (speakers, headphones). We connect our oscillator to audioContext.destination so we can hear the output.
audioContext.currentTime, which says we want a frequency of 440hz, and we want that to be applied now. To sets value in the future, you add time in seconds to the currentTime value.
To start the oscillator sound output we call
.start(). After a 1 second we stop the output with
.stop(). These are not start/pause controls like you might expect. Once you call
.stop(), an OscillatorNode can not be re-started. For repeatedly doing something, you either need to use multiple oscillators, or use a single oscillator and disconnect it’s output or set the output volume to zero using a GainNode before the destination.
By default, the oscillator output is rather loud. Lets fix that by adding a GainNode.
Now, instead of connecting the oscillator to the output directly, we connect it to a GainNode which then connects to the destination. The GainNode has a gain AudioParam which takes a float value and multiplies the amplitude. So a value of 1 would be no change, .5 would be half, and 2 would be double. .2 (or 20%) makes for a fairly reasonable volume.
Lets make a button that plays a sound!
Our button click handler creates a new oscillator, connects it, sets the frequency, starts it, and then stops and disconnects it after 500ms.
This is the basis for how you play sounds on a trigger. Just create your oscillator, play it, and destroy it. Notice that if you click the button again before the sound stops, it does create a new oscillator and plays them both, which you can usually hear as a louder sound.
So far, we’ve only made boring single-frequency sounds. Lets do something a bit more interesting. If we just wanted to change the pitch played on the button press, that would be as simple as changing “440” to the desired frequency. This could be set from a dynamic input as well.
More interesting would be to play a series of sounds. Lets make a varying wave-form.
Instead of just setting a frequency and calling it done, we run over an array of 1000 frequency values, setting them at intervals of 1ms so that we get a (to human perception) smooth variation of pitch. Any AudioParams can be set like this, so you can create arrays of frequency and volume (gain) values to play over time.
Naturally, this is just the tip of the iceberg. Besides gain and oscillators, you can do other types of filtering and effects, including reverberation, delays, and distortion; you can use microphone input and uploaded audio files; and you can even do visualizations of the waveform output. A good place to start for more in-depth study is the MDN Web Audio API Guide. Especially look through the types of AudioNodes listed in Related pages for Web Audio API.