How Tone.js Sampler Handles Pitch Shifting

This article explains how Tone.Sampler handles pitch-shifting when triggering samples in the Tone.js web audio library. You will learn how the sampler uses playback rate manipulation to alter pitch, how it interpolates between mapped audio files, and how to optimize your sample maps to maintain high-quality audio playback across different notes.

The Core Mechanism: Playback Rate Manipulation

Unlike real-time pitch-shifting effects that alter pitch while preserving the original duration (such as phase vocoders), Tone.Sampler shifts pitch by adjusting the playback rate of the audio buffer. This is the digital equivalent of speeding up or slowing down a vinyl record or tape machine.

The relationship between the pitch shift in semitones (\(n\)) and the playback rate is exponential, calculated using the formula:

\[\text{Playback Rate} = 2^{(n / 12)}\]

For example, triggering a note one octave higher (+12 semitones) doubles the playback rate (2.0), while triggering a note one octave lower (-12 semitones) halves the playback rate (0.5).

Multisampling and Nearest-Neighbor Interpolation

To prevent the unnatural sound stretching (often called the “chipmunk effect”) that occurs when a single sample is pitched too far from its original frequency, Tone.Sampler utilizes multisampling.

When you instantiate a Tone.Sampler, you pass it an object mapping specific midi notes to audio files:

const sampler = new Tone.Sampler({
    urls: {
        A1: "A1.mp3",
        A2: "A2.mp3",
        A3: "A3.mp3",
        A4: "A4.mp3",
    },
    baseUrl: "https://tonejs.github.io/audio/salamander/",
    onload: () => {
        sampler.triggerAttackRelease("C3", "4n");
    }
}).toDestination();

When you trigger a note that does not have an explicit sample mapped to it (like C3 in the example above), Tone.Sampler performs the following steps:

  1. Finds the Closest Sample: It looks through the mapped keys and identifies the closest available sample (in this case, A2 or A3).
  2. Calculates the Interval: It determines the interval distance in semitones between the target note (C3) and the source sample.
  3. Applies the Playback Rate: It loads the closest sample’s buffer and adjusts its playback rate based on that interval distance. If it chooses A2 (110 Hz) to play C3 (130.81 Hz), it speeds up the playback of A2 by 3 semitones.

Best Practices for Clean Pitch Shifting

Because Tone.Sampler relies on playback rate changes, pitch-shifting over wide intervals can degrade audio quality. To achieve the most natural sound: