How to Mute Tracks with Tone.Transport in Tone.js

This article explains how to mute and unmute specific audio tracks in Tone.js by combining track-level volume controls with the timing capabilities of Tone.Transport. You will learn how to set up individual audio channels, control their mute states, and schedule mute/unmute events to happen automatically at specific points along the playback timeline.

Understanding Tone.Transport and Audio Tracks

In Tone.js, Tone.Transport acts as the master timeline and sequencer, governing playback, tempo, and scheduling. It does not handle audio routing directly. To mute or unmute specific tracks, you must route your sound sources (like synthesizers or players) through individual Tone.Channel nodes. You can then manipulate the mute property of these channels, either in real-time or by scheduling the actions on the Tone.Transport timeline.

Step 1: Set Up Your Tracks Using Tone.Channel

To control individual tracks, route each audio source through its own Tone.Channel.

// Create audio sources
const synthTrack = new Tone.Synth().toDestination();
const drumTrack = new Tone.Player("drums.wav");

// Create channels for independent control
const synthChannel = new Tone.Channel().toDestination();
const drumChannel = new Tone.Channel().toDestination();

// Connect the sources to their respective channels
synthTrack.connect(synthChannel);
drumTrack.connect(drumChannel);

Step 2: Manually Muting and Unmuting Tracks

Each Tone.Channel has a boolean mute property. You can toggle this property at any time during playback to instantly mute or unmute the track.

// Mute the drum track
drumChannel.mute = true;

// Unmute the drum track
drumChannel.mute = false;

Step 3: Scheduling Mute and Unmute Events with Tone.Transport

To automate the muting and unmuting of tracks at precise times during playback, use Tone.Transport.schedule(). This method allows you to queue state changes at specific measures, beats, or seconds.

// Start the transport
Tone.Transport.start();

// Schedule the drum track to mute at the beginning of measure 4
Tone.Transport.schedule((time) => {
    // Draw changes on the next animation frame for UI synchronization if needed
    Tone.Draw.schedule(() => {
        drumChannel.mute = true;
        console.log("Drums muted at measure 4");
    }, time);
}, "4:0:0");

// Schedule the drum track to unmute at the beginning of measure 8
Tone.Transport.schedule((time) => {
    Tone.Draw.schedule(() => {
        drumChannel.mute = false;
        console.log("Drums unmuted at measure 8");
    }, time);
}, "8:0:0");

Step 4: Toggling Mute via User Interaction

If you want to allow users to mute or unmute tracks interactively while Tone.Transport is running, bind the channel’s mute property directly to a button event listener:

const muteButton = document.getElementById("mute-drums-btn");

muteButton.addEventListener("click", () => {
    // Toggle the mute state
    drumChannel.mute = !drumChannel.mute;
    
    // Update button text to reflect current state
    muteButton.innerText = drumChannel.mute ? "Unmute Drums" : "Mute Drums";
});