Tone.MonoSynth vs Tone.DuoSynth in Tone.js

In web audio development with Tone.js, choosing the right synthesizer is crucial for shaping your application’s sound design and managing performance. This article compares Tone.MonoSynth and Tone.DuoSynth, detailing their structural differences, parameter controls, and performance impacts to help you decide which synthesizer best fits your project’s needs.

Architectural Differences

The primary difference between Tone.MonoSynth and Tone.DuoSynth lies in their internal signal routing and voice architecture. While both are strictly monophonic (meaning they can only play one note at a time), they generate sound using different numbers of internal engines.

Tone.MonoSynth

Tone.MonoSynth is a classic, single-voice subtractive synthesizer. Its architecture is straightforward and consists of: * One Oscillator: Generates the raw waveform (e.g., sine, square, triangle, sawtooth). * One Amplitude Envelope (ADSR): Controls the volume of the sound over time. * One Filter: Shapes the frequency spectrum. * One Filter Envelope: Dynamically modulates the filter’s cutoff frequency over time.

Because of this single-oscillator signal path, Tone.MonoSynth produces a clean, focused, and traditional synthesizer sound.

Tone.DuoSynth

Tone.DuoSynth is a more complex monophonic synthesizer composed of two separate MonoSynth voices (internally labeled as voice0 and voice1) routed in parallel into a single output. Its architecture features: * Two independent Oscillators, Filters, and Envelopes: You have complete control over two distinct sound sources within a single instrument interface. * Harmonicity Control: A dedicated parameter that sets the pitch ratio between voice0 and voice1. * Vibrato Control: An integrated LFO (Low-Frequency Oscillator) that applies frequency modulation to both voices for pitch-bend effects.

This dual-voice setup allows you to create rich, layered, detuned, or chorused sounds that are impossible to achieve with a standard MonoSynth.

Key Parameters and Code Comparison

Understanding how to control these instruments in your code highlights their practical differences.

MonoSynth Implementation

Configuring a Tone.MonoSynth is simple because you are managing only one voice:

const monoSynth = new Tone.MonoSynth({
  oscillator: {
    type: "sawtooth"
  },
  envelope: {
    attack: 0.1,
    decay: 0.2,
    sustain: 0.5,
    release: 0.8
  },
  filter: {
    Q: 6,
    type: "lowpass",
    frequency: 350
  },
  filterEnvelope: {
    attack: 0.05,
    decay: 0.2,
    sustain: 0.2,
    release: 1,
    baseFrequency: 350,
    octaves: 4
  }
}).toDestination();

DuoSynth Implementation

Configuring a Tone.DuoSynth requires defining properties for both internal voices, alongside global settings like harmonicity and vibratoAmount:

const duoSynth = new Tone.DuoSynth({
  harmonicity: 1.5, // Sets the pitch ratio between voice0 and voice1
  vibratoAmount: 0.5,
  vibratoRate: 5,
  voice0: {
    oscillator: { type: "sine" },
    envelope: { attack: 0.1, decay: 0.5 }
  },
  voice1: {
    oscillator: { type: "sawtooth" },
    envelope: { attack: 0.2, decay: 0.8 },
    filterEnvelope: { attack: 0.01 }
  }
}).toDestination();

Performance and CPU Usage

Because Tone.DuoSynth runs two complete synthesizers under the hood plus additional LFO modulation, it is significantly more CPU-intensive than Tone.MonoSynth.

If your application requires triggering multiple synthesizer instances simultaneously, or if you are targeting mobile devices with limited processing power, Tone.MonoSynth is the highly preferred, lightweight option.

Summary: When to Use Which?