How to Chain Audio Effects in Tone.js
In web audio development, creating rich and complex sounds often
requires routing a sound source through multiple processors. This
article explains how to chain multiple audio effects together in
Tone.js, a powerful framework for the Web Audio API, using both the
streamlined .chain() method and manual routing
connections.
To process an audio signal through several effects in Tone.js, you
must route the output of one node into the input of the next, eventually
routing the final output to the speakers
(Tone.Destination).
The .chain() Method
The most efficient way to connect multiple effects in Tone.js is by
using the .chain() method. This method is available on all
Tone.js audio sources and nodes. It automatically connects the output of
the calling node to the input of the first argument, the output of the
first argument to the second, and so on, down the line.
Here is a practical code example chaining a synthesizer through a distortion effect and a tremolo effect before sending it to the main output:
import * as Tone from 'tone';
// 1. Create the audio source
const synth = new Tone.Synth();
// 2. Create the audio effects
const distortion = new Tone.Distortion(0.4);
const tremolo = new Tone.Tremolo(9, 0.75).start();
// 3. Chain the nodes together
// Synth -> Distortion -> Tremolo -> Destination (Speakers)
synth.chain(distortion, tremolo, Tone.Destination);
// 4. Play a note to hear the chained effects
synth.triggerAttackRelease("C4", "8n");Manual Connections with
.connect()
While .chain() is convenient for linear processing, you
can also use the .connect() method for manual routing. This
is useful if you want to split signals, create auxiliary sends, or build
complex, non-linear audio graphs.
// Connect the synth to the distortion
synth.connect(distortion);
// Connect the distortion to the tremolo
distortion.connect(tremolo);
// Connect the tremolo to the destination
tremolo.connect(Tone.Destination);Important Considerations
- Order Matters: The order in which you chain your effects significantly impacts the final sound. For example, placing a reverb before a distortion effect will distort the reverb tail, whereas placing distortion before reverb will result in a cleaner, more spacious tone.
- Effect State: Some modulation effects, like
Tone.TremoloorTone.Phaser, require you to explicitly call.start()for their internal LFOs (Low-Frequency Oscillators) to begin processing. - Disposing Nodes: To prevent memory leaks in your
web application, always call
.dispose()on your synth and effect nodes when they are no longer needed in the browser session.