JavaScript's Web Audio API shares a number of characteristics with Max. In
Max, we create and alter sounds using objects with tildes; in Web Audio API, we
create and alter sounds using
"AudioNode
s".
In Max, we connect objects together using patch cords; with Web Audio API, we
connect AudioNode
s together using the
.connect()
method. Finally, whereas in Max, all objects live in a "patch", with Web Audio
API, all AudioNode
s exist inside of an
AudioContext
.
This is the Max equivalent of a "hello world": playing a sine tone through a
dac~. Here, the sine tone is 300 Hz, and it's being fed through a *~
at half gain. How would we build the equivalent program with Web Audio API?
The first thing we do is create an AudioContext
, which is the equivalent of
starting a new patch. Then we create our three AudioNode
s: an oscillator, a
gain, and the dac. Note that AudioContext
has a built-in dac, which we can
access with audioCtx.destination
.
const audioCtx = new AudioContext();
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
const dac = audioCtx.destination;
Now, we can customize our AudioNode
s. To set an oscillator's frequency, we
set the osc.frequency.value
property. To set a gain's gain, we set the
gain.gain.value
property. Technically, osc.frequency
and gain.gain
are
implementations of the
AudioParam
interface. This interface contains useful methods like
.linearRampToValueAtTime()
and
.setValueCurveAtTime()
that allow you to smoothly interpolate between a parameter's values.
osc.frequency.value = 300;
gain.gain.value = 0.5
Finally, we connect the AudioNode
s together, just like we would connect
objects with patch cords. The last line of code tells the oscillator to start
producing sound.
osc.connect(gain);
gain.connect(dac);
osc.start();
One significant difference between Max and Web Audio API is that in Max, an
object is not at risk of deletion once it stops producing sound. In Web Audio
API, on the other hand, once an AudioNode
stops producing sound, it goes away
forever. As a result, to create multiple simultaneous or successive sounds,
you may have to instantiate an AudioNode
for each one. Don't feel weird if
you're writing a program that creates hundreds or even thousands of
AudioNode
s: as long as you remember to stop each one (which triggers the
garbage collector), your program will run just fine.