Tone.Sequence vs Tone.Part vs Tone.Pattern in Tone.js
In Tone.js, scheduling events over time is crucial for creating
interactive music and audio applications. This article explains the
differences between Tone.Sequence, Tone.Part,
and Tone.Pattern—three core scheduling classes—detailing
when and how to use each one based on your project’s musical
structure.
Tone.Sequence: The Step Sequencer
Tone.Sequence is designed for repeating, grid-based
loops. It is the ideal choice for building drum machines, step
sequencers, or simple, repetitive synth loops.
- How it works: You provide it with an array of
values (such as note names) and a subdivision (like
"8n"for eighth notes). The sequence automatically steps through the array sequentially, triggering a callback function at every step. - Sub-arrays: It supports nesting. If you pass a
sub-array as an element (e.g.,
["C4", ["E4", "G4"]]), Tone.js will subdivide that step to play the nested notes within the duration of a single step. - Best used for: Drum loops, basslines, and any repeating patterns with a fixed grid.
const seq = new Tone.Sequence((time, note) => {
synth.triggerAttackRelease(note, "8n", time);
}, ["C4", "E4", "G4", "B4"], "4n").start(0);Tone.Part: The Timeline Composer
Tone.Part is designed for precise, absolute timing.
Unlike Tone.Sequence, it does not rely on a fixed step
interval. Instead, it allows you to schedule events at specific,
arbitrary moments along the timeline, making it highly analogous to a
MIDI file or a track in a Digital Audio Workstation (DAW).
- How it works: You pass it an array of objects,
where each object explicitly defines a
timeproperty alongside the musical data (like note, velocity, or duration). - Flexibility: Events can be spaced out unevenly, overlap, or occur at any arbitrary subdivision.
- Best used for: Importing MIDI files, scoring entire songs, or scheduling complex, non-linear musical arrangements.
const part = new Tone.Part((time, event) => {
synth.triggerAttackRelease(event.note, event.dur, time);
}, [
{ time: 0, note: "C4", dur: "4n" },
{ time: "0:2", note: "G4", dur: "8n" },
{ time: "0:3:2", note: "E4", dur: "2n" }
]).start(0);Tone.Pattern: The Arpeggiator
Tone.Pattern is a specialized variation of
Tone.Sequence designed specifically for generative music
and arpeggiation.
- How it works: Instead of stepping through an array
strictly from left to right,
Tone.Patterntraverses the array based on a specified movement pattern. - Patterns types: It supports various playback
algorithms, including
"up"(ascending),"down"(descending),"upDown","random", and"randomWalk". - Best used for: Synthesizer arpeggiators, generative melodies, and creating organic variations from a fixed set of notes.
const pattern = new Tone.Pattern((time, note) => {
synth.triggerAttackRelease(note, "4n", time);
}, ["C4", "E4", "G4", "B4"], "upDown").start(0);Summary of Differences
| Feature | Tone.Sequence | Tone.Part | Tone.Pattern |
|---|---|---|---|
| Primary Use Case | Grid-based loops & step sequencers | Multi-note compositions & MIDI playback | Arpeggiators & generative melodies |
| Timing Structure | Fixed subdivisions (evenly spaced) | Absolute, arbitrary timeline offsets | Fixed subdivisions (evenly spaced) |
| Playback Order | Linear (left to right, supports nesting) | Defined by each event’s timestamp | Algorithmic (up, down, random, etc.) |
| Data Format | Array of notes/values | Array of objects with time
properties |
Array of notes/values |