Create Stereo Movement with Tone.AutoFilter in Tone.js
This article explains how to create dynamic stereo filter sweeps in
Tone.js by leveraging Tone.AutoFilter. You will learn how
to split an audio signal, apply independent auto-filters with offset LFO
phases to the left and right channels, and merge them back together to
achieve a wide, moving stereo effect.
The Logic Behind Stereo Auto-Filtering
By default, a single Tone.AutoFilter processes both the
left and right channels of a stereo signal identically. While this
creates a great moving filter effect, it remains monophonic in terms of
movement because both ears hear the same filter frequency at the same
time.
To create true stereo movement—where the filter sweeps up in the left
ear while sweeping down in the right ear—you must split your audio
source into separate left and right channels, apply an individual
Tone.AutoFilter to each channel with offset LFO phases, and
then merge the channels back into a single stereo stream.
Step-by-Step Implementation
To implement this stereo movement, follow these steps:
- Create the Sound Source: Generate or load the sound you want to filter.
- Create Splitter and Merger Nodes: Use
Tone.Splitto separate the stereo channels andTone.Mergeto recombine them. - Instantiate Two AutoFilters: Create one filter for the left channel and another for the right channel.
- Offset the Phases: Set the phase of the left
filter’s LFO to
0and the right filter’s LFO to180(or any offset value of your choice). - Connect the Routing Chain: Route the left split output to the left filter, the right split output to the right filter, and connect both filter outputs back to the merger.
Code Example
Here is a complete, ready-to-use JavaScript example using Tone.js:
import * as Tone from 'tone';
// 1. Create a sound source (e.g., a rich synthesizer sound)
const synth = new Tone.PolySynth(Tone.Synth, {
oscillator: { type: "sawtooth" }
});
// 2. Create the Split and Merge nodes
const splitter = new Tone.Split();
const merger = new Tone.Merge();
// 3. Create the Left AutoFilter (Phase = 0 degrees)
const autoFilterL = new Tone.AutoFilter({
frequency: "2n", // Speed of the sweep (e.g., a half note)
baseFrequency: 200, // Lower boundary of the filter
octaves: 4, // How far above the base frequency the filter sweeps
phase: 0 // Starts at the beginning of the LFO cycle
}).start(); // Crucial: AutoFilter's internal LFO must be started
// 4. Create the Right AutoFilter (Phase = 180 degrees)
const autoFilterR = new Tone.AutoFilter({
frequency: "2n",
baseFrequency: 200,
octaves: 4,
phase: 180 // 180 degrees out of phase for maximum stereo width
}).start();
// 5. Connect the audio routing chain
synth.connect(splitter);
// Left Channel Routing (Index 0)
splitter.connect(autoFilterL, 0, 0); // Split output 0 -> Filter input
autoFilterL.connect(merger, 0, 0); // Filter output -> Merge input 0 (Left)
// Right Channel Routing (Index 1)
splitter.connect(autoFilterR, 1, 0); // Split output 1 -> Filter input
autoFilterR.connect(merger, 0, 1); // Filter output -> Merge input 1 (Right)
// Connect the merged stereo signal to the master output
merger.toDestination();
// Play a chord to hear the stereo sweep
Tone.loaded().then(() => {
synth.triggerAttackRelease(["C4", "E4", "G4", "B4"], "4m");
});Key Parameters to Customize
frequency: Controls the speed of the stereo movement. You can use Hertz (e.g.,1.5) or tempo-relative values (e.g.,"4n"for quarter notes).phase: This is the angle of the LFO. Keeping one filter at0and the other at180results in a perfectly mirrored movement. Setting them closer (e.g.,0and90) creates a circular, panning-like filter effect.type: Changes the shape of the LFO waveform modulating the filter. By default, it is a"sine"wave, but you can change it to"triangle","sawtooth", or"square"for different modulation characteristics.