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:
- harmonicity: This is the ratio between the modulator frequency and the carrier frequency (\(f_{modulator} / f_{carrier}\)). For example, if the carrier pitch is 440 Hz and the harmonicity is set to 2, the modulator will run at 880 Hz. Whole numbers generate harmonic, consonant sounds, while decimal values (like 1.414) generate inharmonic, metallic, or bell-like sounds.
- modulationIndex: This value determines the amplitude of the modulator. In practical terms, the modulation index controls the depth of the modulation. A low modulation index produces a mellow, simple sound (close to a pure sine wave), while a high modulation index adds more sidebands, creating a brighter, harsher, and more complex sound.
- oscillator and modulation: You can define the type of waveform for both the carrier and modulator (e.g., sine, square, triangle, or sawtooth).
- envelope and modulationEnvelope: These control the
Amplitude Envelope (attack, decay, sustain, release) for the carrier and
modulator respectively. Adjusting the
modulationEnvelopeallows the timbre of the sound to evolve over the duration of a note.
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.