How to Loop a Specific Timeline Section in Tone.js
This article explains how to loop a specific section of the timeline
in Tone.js using the Tone.Transport API. You will learn how
to enable looping, define the exact start and end points of your loop
using various time formats, and control playback to create repeating
musical patterns.
Enabling and Configuring the Loop
In Tone.js, timeline playback is managed by
Tone.Transport. To loop a specific section of your
timeline, you need to configure three primary properties on the
Transport object: loop, loopStart, and
loopEnd.
Tone.Transport.loop: A boolean value that must be set totrueto enable looping.Tone.Transport.loopStart: The position on the timeline where the loop begins.Tone.Transport.loopEnd: The position on the timeline where the loop ends and jumps back toloopStart.
Defining Time Formats
Tone.js is highly flexible and accepts several time formats for
loopStart and loopEnd:
- Bars/Beats/Sixteenths (BMT): Represented as a
string like
"1:0:0"(Measure 1, Beat 0, Sixteenth 0). This is the most common format for musical projects. - Measures: Represented as notation strings, such as
"2m"for two measures. - Seconds: Represented as numbers, such as
4for four seconds.
Practical Code Example
The following code demonstrates how to set up a loop between measure 1 and measure 3 using a simple synthesizer to play a repeating note.
import * as Tone from "tone";
// Create a simple synth and connect it to the main output
const synth = new Tone.Synth().toDestination();
// Schedule a note to play at the start of measure 1
Tone.Transport.schedule((time) => {
synth.triggerAttackRelease("C4", "8n", time);
}, "1:0:0");
// Schedule a note to play at measure 2
Tone.Transport.schedule((time) => {
synth.triggerAttackRelease("E4", "8n", time);
}, "2:0:0");
// Configure the loop settings
Tone.Transport.loop = true;
Tone.Transport.loopStart = "1:0:0"; // Loop starts at measure 1
Tone.Transport.loopEnd = "3:0:0"; // Loop ends at measure 3 (then repeats)
// Start the audio context and the transport on user interaction
document.getElementById("startButton").addEventListener("click", async () => {
await Tone.start();
Tone.Transport.start();
});In this setup, when the transport starts playing, it will progress
normally until it reaches measure 3 ("3:0:0"). It will then
immediately jump back to measure 1 ("1:0:0") and repeat
that two-measure section indefinitely.