Schedule Events with Tone.Transport.schedule in Tone.js

This article provides a concise guide on how to schedule a one-time event at a precise moment in Tone.js using the Tone.Transport.schedule method. You will learn how to write the basic syntax, pass the correct time parameters, and ensure your event fires accurately when the audio timeline runs.

The Basic Syntax

To schedule a single-use event on the timeline, you use Tone.Transport.schedule(callback, time). This method takes a callback function to execute and a time at which to execute it.

const eventId = Tone.Transport.schedule((time) => {
    // Your code to execute at the scheduled time
}, "2:0:0");

1. The Callback Function

The callback function receives a time argument. It is crucial to pass this time parameter into any audio nodes or synthesizers you trigger inside the callback to ensure sample-accurate playback, rather than relying on the slightly delayed JavaScript main thread.

2. The Time Argument

The second argument defines when the event should occur. Tone.js accepts several time formats: * Seconds: 2 (starts at exactly 2 seconds) * Bars/Beats/Sixteenths: "1:2:0" (starts at measure 1, beat 2) * Notation: "4n" (starts at a quarter-note duration from the beginning)


Step-by-Step Implementation

Here is a complete example of how to schedule a synthesizer note to play at exactly 2 seconds into the transport timeline.

import * as Tone from 'tone';

// 1. Create an audio source and connect it to the master output
const synth = new Tone.Synth().toDestination();

// 2. Schedule the event
const eventId = Tone.Transport.schedule((time) => {
    // Play a C4 note for an 8th note duration at the precise scheduled time
    synth.triggerAttackRelease("C4", "8n", time);
}, 2); // 2 seconds

// 3. Start the transport to begin playback
Tone.Transport.start();

Ensuring the Event is Strictly “Single-Use”

By default, an event scheduled with Tone.Transport.schedule will fire every time the Transport timeline passes that specific time stamp. If your Transport loops, or if you stop and restart the Transport, the event will trigger again.

If you want the event to destroy itself after firing once so that it never plays again, you can clear it inside its own callback using Tone.Transport.clear():

const eventId = Tone.Transport.schedule((time) => {
    // Trigger your audio event
    synth.triggerAttackRelease("E4", "8n", time);

    // Remove this event from the timeline immediately after it fires
    Tone.Transport.clear(eventId);
}, "0:3:0");