Update Tone.Sequence Grid Dynamically in Tone.js
This article explains how to dynamically alter the subdivision, grid,
and playback speed of a Tone.Sequence in Tone.js during
runtime. You will learn how to directly modify the subdivision property,
utilize the playback rate for relative timing adjustments, and update
the events array to keep your synthesizers and samplers perfectly in
sync with changing musical rhythms.
In Tone.js, a Tone.Sequence stepped loop is driven by a
specific subdivision (such as "4n", "8n", or
"16n"). Adjusting this grid dynamically allows you to
create build-ups, tempo-halving effects, or complex generative rhythms
without stopping the Tone.Transport.
There are two primary methods to dynamically update the grid of an active sequence.
Method 1:
Directly Updating the subdivision Property
The most straightforward way to change the grid of a
Tone.Sequence is by directly reassigning its
subdivision property. Tone.js handles this update smoothly
in real-time.
// Initialize a sequence with eighth notes
const seq = new Tone.Sequence((time, note) => {
synth.triggerAttackRelease(note, "0.1", time);
}, ["C4", "E4", "G4", "B4"], "8n").start(0);
// Dynamically change the grid to sixteenth notes
function speedUpGrid() {
seq.subdivision = "16n";
}
// Dynamically change the grid to quarter notes
function slowDownGrid() {
seq.subdivision = "4n";
}When you update the .subdivision property, Tone.js
recalculates the interval between each step of the sequence on the next
tick, maintaining the overall timing of your application.
Method 2: Adjusting the
playbackRate
If you want to speed up or slow down the grid relatively without
hardcoding a new subdivision string, you can modify the
playbackRate property. This property acts as a multiplier
for the sequence’s progress.
// A playbackRate of 1.0 is the default speed
seq.playbackRate = 1.0;
// Double the speed of the sequence (e.g., "8n" plays at the speed of "16n")
seq.playbackRate = 2.0;
// Halve the speed of the sequence (e.g., "8n" plays at the speed of "4n")
seq.playbackRate = 0.5;Using playbackRate is ideal for gradual accelerandos,
ritardandos, or when you want to shift the grid relative to the master
tempo using a slider control.
Updating the Events Array alongside the Grid
When changing subdivisions, the length of your sequence may no longer
match the time signature or loop length you desire. You can dynamically
update the .events array at the same time to match the new
grid size.
// Change grid to 16th notes and expand the sequence array to match
function changeGridAndPattern() {
seq.subdivision = "16n";
seq.events = ["C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5"];
}Updating both properties simultaneously ensures your sequence remains musically coherent and fits perfectly within your grid structure.