Guide to Tone.FMSynth and Tone.js Frequency Modulation

This article explores Tone.FMSynth, a powerful synthesizer class in the Tone.js web audio library. You will learn the core concepts of frequency modulation (FM) synthesis, how the carrier and modulator oscillators interact, and how to configure and use Tone.FMSynth to create dynamic, metallic, and complex digital sounds in your web applications.

What is Frequency Modulation Synthesis?

Frequency Modulation (FM) synthesis is a method of audio synthesis where the frequency of a simple waveform (called the carrier) is modulated by the frequency of another waveform (called the modulator).

When the modulator’s frequency is low (typically below 20 Hz), the result is a vibrato effect. However, when the modulator’s frequency enters the audible range (above 20 Hz), our ears no longer perceive it as a pitch shift. Instead, the modulation creates new frequencies called sidebands, resulting in a rich, complex timbre. FM synthesis is famous for producing bright, metallic, bell-like tones, brass instruments, and deep, digital basslines.

Understanding Tone.FMSynth

In Tone.js, Tone.FMSynth is a pre-packaged instrument that simplifies FM synthesis. It coordinates two internal synthesizers: 1. The Carrier: The main synthesizer that generates the audible output. 2. The Modulator: The secondary synthesizer that modulates the frequency of the carrier.

Both the carrier and the modulator have their own independent envelopes, allowing you to shape how the timbre changes over time.

Key Parameters of Tone.FMSynth

To control the timbre of Tone.FMSynth, Tone.js exposes several crucial properties:

Implementing Tone.FMSynth in Code

To use Tone.FMSynth, you instantiate the synthesizer, configure its properties, connect it to the main audio output, and trigger a note.

// Create and configure Tone.FMSynth
const fmSynth = new Tone.FMSynth({
  harmonicity: 3,
  modulationIndex: 10,
  detune: 0,
  oscillator: {
    type: "sine"
  },
  envelope: {
    attack: 0.01,
    decay: 0.3,
    sustain: 0.1,
    release: 1.2
  },
  modulation: {
    type: "square"
  },
  modulationEnvelope: {
    attack: 0.5,
    decay: 0.1,
    sustain: 1,
    release: 0.5
  }
}).toDestination();

// Trigger a C4 note for the duration of a quarter note
fmSynth.triggerAttackRelease("C4", "4n");

In this example, because the modulationEnvelope has a longer attack time (0.5 seconds) than the carrier’s envelope (0.01 seconds), the sound will start as a clean sine wave and gradually grow brighter and more complex as the modulator’s output level rises.