How to Release a Sustained Note in Tone.js

Controlling the duration of notes is fundamental to creating dynamic web audio applications. This guide explains how to programmatically trigger and release sustained notes in Tone.js using the triggerAttack and triggerRelease methods, allowing you to sustain sounds indefinitely until an event, such as a user interaction, stops them.

To sustain a note indefinitely, you must split the synthesizer’s activation into two distinct phases: triggering the attack to start the sound, and triggering the release to stop it. This is different from the common triggerAttackRelease() method, which automatically schedules a release after a predefined duration.

Step 1: Initializing the Synthesizer

First, create an instance of a synthesizer (such as Tone.Synth) and connect it to the master output.

import * as Tone from 'tone';

const synth = new Tone.Synth().toDestination();

Step 2: Triggering the Sustained Note

To start playing a note and keep it sustaining, use the triggerAttack method. This triggers the attack and decay portion of the ADSR envelope, holding the sound at the sustain level.

// Start playing a C4 note indefinitely
synth.triggerAttack("C4");

Step 3: Programmatically Releasing the Note

To stop the sustained note, call the triggerRelease method. This triggers the release phase of the envelope, fading the sound out to silence.

// Stop the currently playing note
synth.triggerRelease();

Handling Multiple Notes (PolySynth)

If you are using Tone.PolySynth to play chords, you must specify which pitch to release so the synthesizer knows which active note to stop.

const polySynth = new Tone.PolySynth().toDestination();

// Play a C major chord
polySynth.triggerAttack(["C4", "E4", "G4"]);

// Release only the E4 note programmatically
polySynth.triggerRelease(["E4"]);

// Release the remaining notes later
polySynth.triggerRelease(["C4", "G4"]);

Interactive Example (Keyboard / Mouse Events)

In real-world applications, you will often want to bind these methods to user interface events, such as pointer down and pointer up actions on a virtual piano key.

const playButton = document.getElementById("play-button");

// Start note when the button is pressed
playButton.addEventListener("mousedown", () => {
  Tone.start(); // Ensure AudioContext is resumed
  synth.triggerAttack("A4");
});

// Release note when the button is released
playButton.addEventListener("mouseup", () => {
  synth.triggerRelease();
});