Change Tone.js Instrument Volume Dynamically

This article explains how to dynamically adjust the volume of a Tone.js instrument during playback. You will learn how to manipulate the volume property using decibels, perform smooth volume transitions to avoid audio artifacts, and use ramping methods for real-time control.

Understanding the Volume Property in Tone.js

In Tone.js, instruments have a built-in volume property which is a Tone.Signal object. Unlike standard Web Audio nodes that use linear gain (0 to 1), Tone.js measures volume in decibels (dB).

Because the volume property is a signal, you should not assign a number directly to instrument.volume. Instead, you must manipulate its .value property or use signal methods.

Method 1: Changing Volume Immediately

To change the volume instantly, update the .value of the instrument’s volume signal.

// Create a synth and connect it to the main output
const synth = new Tone.Synth().toDestination();

// Set the volume to -12 decibels instantly
synth.volume.value = -12;

Note: Changing the volume instantly while a note is playing can cause an audible click or pop in the audio.

To avoid audio artifacts like pops and clicks, you should ramp the volume over a short period of time. Tone.js provides helper methods on its signal objects to make this easy.

Using rampTo()

The rampTo method smoothly transitions the volume from its current level to a new level over a specified duration (in seconds).

// Smoothly fade the volume to -20 dB over 2 seconds
synth.volume.rampTo(-20, 2);

Using AudioParam Scheduling

For precise scheduling relative to the Tone.js transport timeline, you can use standard AudioParam automation methods:

const now = Tone.now();

// Ramp to -30 dB exponentially over 1 second, starting from the current time
synth.volume.exponentialRampToValueAtTime(-30, now + 1);

Practical Example: Linking Volume to an HTML Slider

A common use case is controlling an instrument’s volume using an HTML <input type="range"> slider.

HTML

<input type="range" id="volume-slider" min="-60" max="0" value="-10" step="1">

JavaScript

const synth = new Tone.Synth().toDestination();
const slider = document.getElementById('volume-slider');

// Set initial volume based on slider value
synth.volume.value = parseFloat(slider.value);

// Update volume dynamically on input
slider.addEventListener('input', (e) => {
  const dbValue = parseFloat(e.target.value);
  
  // Use a tiny ramp time (0.05s) to prevent clicking during rapid slider movement
  synth.volume.rampTo(dbValue, 0.05);
});