Trigger ADSR Envelope with Tone.Synth in Tone.js

Controlling the volume of a sound over time is essential for creating realistic or expressive synthesizer sounds. This article explains how to configure and trigger an Attack-Decay-Sustain-Release (ADSR) envelope using the Tone.Synth instrument in the Tone.js framework, allowing you to easily shape the dynamics of your web audio projects.

Understanding ADSR in Tone.Synth

In Tone.js, Tone.Synth comes pre-packaged with an amplitude envelope. You can customize the envelope by passing an envelope configuration object when instantiating the synth.

Configuring the ADSR Envelope

To set custom ADSR values, pass them into the envelope property of the Tone.Synth constructor:

const synth = new Tone.Synth({
  oscillator: {
    type: "sine" // Choose oscillator type (sine, square, triangle, saw)
  },
  envelope: {
    attack: 0.1,   // 100ms fade-in
    decay: 0.2,    // 200ms decay
    sustain: 0.5,  // hold at 50% volume
    release: 1.2   // 1.2 seconds fade-out
  }
}).toDestination();

Triggering the Envelope

There are two primary methods to trigger the ADSR envelope: automatically scheduling both the attack and release, or triggering them manually with separate events.

Method 1: Automatic Triggering (triggerAttackRelease)

The most common way to trigger a note is using triggerAttackRelease(). This method plays a note for a set duration, automatically handling the transition from the sustain phase to the release phase.

// Start Tone.js audio context on user interaction
document.body.addEventListener('click', async () => {
  await Tone.start();
  
  // Play note C4 for the duration of a quarter note ("4n")
  synth.triggerAttackRelease("C4", "4n");
});

Method 2: Manual Triggering (triggerAttack and triggerRelease)

For interactive applications like a MIDI keyboard, you need to start the sound when a key is pressed and stop it when the key is released. You achieve this using separate triggerAttack() and triggerRelease() calls.

// Trigger the attack phase (initiates attack, decay, and holds at sustain)
synth.triggerAttack("E4");

// Trigger the release phase (initiates release fade-out) after 2 seconds
setTimeout(() => {
  synth.triggerRelease();
}, 2000);