The Web Audio API is an abstraction layer which aims to simplify audio programming for the web.
In this short introduction, you’ll learn about the Web Audio API’s AudioContext
, and the ability of AudioContext
instances to create simple oscillators which can be used to transform your browser into a retro synthesizer! This tutorial’s code snippets have been tested in Chrome, but you can probably follow along using the console
of your favorite browser’s developer tools.
As mentioned, support for the Web Audio API is not universal, so it’s best to verify that the API is available in the user’s browser:
let audioContext;
try {
audioContext =
new (window.AudioContext || window.webkitAudioContext)();
} catch (error) {
window.alert(
`Sorry, but your browser doesn't support the Web Audio API!`
);
}
if (audioContext !== undefined) {
/* Our code goes here */
}
After this simple check, we’re safe to use the Web Audio API’s functionality.
It might be helpful to imagine audioContext
--our instance of the AudioContext
--as a sort of DJ: it coordinates a collection of audio sources and ensures that the sources play through the user’s speakers at the right time and with the right “sound.” And like a DJ, we can think of audioContext
as a mediator between sources of sound and a “sound system,” the host machine’s audio hardware. Here are some more things to keep in mind when working with the AudioContext
:
AudioContext
is a master “time-keeper.” All signals should be scheduled relative to audioContext.currentTime
.AudioContext
can create audio sources from scratch.To see what sorts of sounds it can generate on its own, let’s use audioContext
to create an OscillatorNode
:
const oscillator = audioContext.createOscillator();
This is all we need to make sound with the browser–an AudioContext
and an OscillatorNode
. But first, we need to “wire” the oscillator
to our audioContext
:
oscillator.connect(audioContext.destination);
The Web Audio API attempts to mimic an analog signal chain. We pipe our input signal (the oscillator
) into a digital power amp (the audioContext
), which then passes the signal to the speakers (the destination
).
Let’s make some noise:
oscillator.start();
You should hear a sound comparable to a dial tone. Congratulations, you’re making music with the Web Audio API! Of course, no one wants to hear the same pitch forever and ever. You can stop our oscillator
this way:
oscillator.stop();
Once an AudioNode has been stopped, it cannot be started again! A new AudioNode will need to be created to resume playback.
The start
and stop
methods both accept a single parameter of type number
. The parameter value is used to schedule the start/stop events:
/* Emit a signal 10 seconds from now */
oscillator.start(audioContext.currentTime + 10);
/* Cancel the signal 10 seconds after that */
oscillator.stop(audioContext.currentTime + 20);
Let’s conclude by manipulating our oscillator
to make different sounds.
Logging the oscillator
object, we get something like this (specific property values are omitted as they may be different depending on the device/browser):
console.log(oscillator);
/*
{
channelCount: number,
context: AudioContext,
detune: AudioParam,
type: 'sine' | 'sawtooth' | 'triangle' | 'square'
frequency: AudioParam,
numberOfInputs: number,
numberOfOutputs: number,
onended: function
...
}
*/
The property that matters most for our purposes is oscillator.frequency
:
console.log(oscillator.frequency);
/*
{
defaultValue: number,
maxValue: number,
minValue: number,
value: number // Probably 440 (A4)
}
*/
The frequency
value of our oscillator
implements the AudioParam
interface. The sound of an AudioNode
such as oscillator
can be manipulated via its AudioParam
properties. However, direct reassignment to the AudioParam
value
property has been deprecated in favor of helper methods.
/* Don't do this */
oscillator.frequency.value = 500;
If we want our oscillator
to emit a “Bb” instead of an “A”, we should do something like this:
/* The frequency (in Hz) of Bb4 is 466.16 */
oscillator
.frequency
.setValueAtTime(466.16, audioContext.currentTime);
or
/* Slowly transition to Bb4 over the span of 10 seconds */
oscillator
.frequency
.exponentialRampToValueAtTime(
466.16,
audioContext.currentTime + 10
);
Our oscillator
uses a periodic waveform to emit its tone. The waveform is represented by the type
property of the OscillatorNode
interface. By default, the type
is 'sine'
. Most browsers support at least three other options: 'sawtooth'
, 'triangle'
, and 'square'
. So, changing the “tone” of our oscillator
is as simple as:
oscillator.type = 'triangle';
Generating and manipulating audio in the browser is easier than ever thanks to the Web Audio API. With its help, web developers can recreate retro synth tones with 3-5 lines of code.
🎶 CHALLENGE: Use the Web Audio API to program the riff from Funkytown!
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!