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
"AudioNodes".
In Max, we connect objects together using patch cords; with Web Audio API, we
connect AudioNodes together using the
.connect()
method. Finally, whereas in Max, all objects live in a "patch", with Web Audio
API, all AudioNodes 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 AudioNodes: 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 AudioNodes. 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 AudioNodes 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
AudioNodes: as long as you remember to stop each one (which triggers the
garbage collector), your program will run just fine.