Passing Options to Tone.js Synth on Initialization

When working with the Tone.js web audio framework, customizing the sound of a synthesizer at the moment of creation is crucial for clean and efficient code. This article explains how to pass options and configuration objects directly into a Tone.js synth during its initialization, detailing the syntax for setting oscillators, envelopes, and other nested properties using practical code examples.

The Configuration Object Syntax

To configure a Tone.js synth during initialization, you pass a single configuration object as an argument to the constructor. This object contains key-value pairs that correspond to the properties of the synthesizer you want to customize, such as the oscillator, envelope, and volume.

Here is a basic template for initializing a standard Tone.Synth with custom options:

const synth = new Tone.Synth({
  volume: -6, // Volume in decibels
  detune: 0, // Detune in cents
  oscillator: {
    type: "triangle" // Change the default sine wave to a triangle wave
  },
  envelope: {
    attack: 0.05,
    decay: 0.2,
    sustain: 0.6,
    release: 1.2
  }
}).toDestination();

In this example, the nested objects oscillator and envelope target specific sub-components of the synthesizer, allowing you to define the waveform and ADSR envelope boundaries immediately.

Configuring Complex Synths

Different types of synths in Tone.js (such as MonoSynth, DuoSynth, or FMSynth) have different internal structures. When initializing these advanced synthesizers, your configuration object must reflect their specific architecture.

For example, a Tone.MonoSynth includes a filter in its signal chain. You can configure the filter type and frequency alongside the oscillator and envelope:

const monoSynth = new Tone.MonoSynth({
  oscillator: {
    type: "sawtooth"
  },
  filter: {
    Q: 2,
    type: "lowpass",
    frequency: 300
  },
  envelope: {
    attack: 0.1,
    decay: 0.3,
    sustain: 0.4,
    release: 0.8
  },
  filterEnvelope: {
    attack: 0.06,
    decay: 0.2,
    sustain: 0.5,
    release: 2,
    baseFrequency: 200,
    octaves: 3,
    exponent: 2
  }
}).toDestination();

Passing Options to PolySynth

When using Tone.PolySynth, the initialization process is slightly different. A PolySynth manages multiple voices of a simpler synth type (by default, Tone.Synth). To pass options to these underlying voices, you specify the voice type as the first argument and the configuration object as the second argument:

const polySynth = new Tone.PolySynth(Tone.Synth, {
  oscillator: {
    type: "sine"
  },
  envelope: {
    attack: 0.1,
    release: 1
  }
}).toDestination();

This ensures that every voice generated by the polyphonic synthesizer inherits the defined configuration.