Tone.js

repository·dev·Indexed 12 days ago

https://github.com/tonejs/tone.js

A Web Audio framework for creating interactive music in the browser. Version 15.5.36 provides high-level DAW-like features including a Transport for scheduling, various synthesizers (such as Tone.Synth, Tone.PolySynth, and Tone.FMSynth), and a wide array of audio effects. It includes utilities for converting between musical and technical units, audio-rate signal control for automation, and tools for loading and playing audio samples via Tone.Player and Tone.Sampler.

Tokens
4.3K
Snippets
20
Records
24
Agent score
96%

What's inside Tone.js

  1. Schedule events with the Transport

    dev

    Tone.getTransport() returns the main timekeeper, similar to an arrangement view in a DAW. It can be started, stopped, looped, and adjusted independently of the AudioContext clock.

    To ensure sample-accurate timing, always use the time value passed into a Tone.Loop callback to schedule your events.

    // create two monophonic synths
    const synthA = new Tone.FMSynth().toDestination();
    const synthB = new Tone.AMSynth().toDestination();
    
    //play a note every quarter-note
    const loopA = new Tone.Loop((time) => {
    	synthA.triggerAttackRelease("C2", "8n", time);
    }, "4n").start(0);
    
    //play another note every off quarter-note, by starting it "8n"
    const loopB = new Tone.Loop((time) => {
    	synthB.triggerAttackRelease("C4", "8n", time);
    }, "4n").start("8n");
    
    // all loops start when the Transport is started
    Tone.getTransport().start();
    
    // ramp up to 800 bpm over 10 seconds
    Tone.getTransport().bpm.rampTo(800, 10);
  2. Automate parameters with Signals

    dev

    Tone.js uses audio-rate signal control for parameters, allowing for sample-accurate automation. Many properties (like frequency on an Oscillator) are Signal objects. You can use methods like rampTo to create smooth automation curves.

    const osc = new Tone.Oscillator().toDestination();
    // start at "C4"
    osc.frequency.value = "C4";
    // ramp to "C2" over 2 seconds
    osc.frequency.rampTo("C2", 2);
    // start the oscillator for 2 seconds
    osc.start().stop("+3");
  3. Understand Time and tempo-relative values

    dev

    Tone.js uses the Web Audio API's AudioContext time, which starts at 0 when the page loads and counts up in seconds.

    • Tone.now(): Returns the current AudioContext time.
    • Tempo-relative values: Tone.js abstracts seconds by allowing strings like "4n" (quarter-note), "8t" (eighth-note triplet), or "1m" (one measure) as arguments for time-based methods.
    //get the current AudioContext time
    setInterval(() => console.log(Tone.now()), 100);
  4. Route audio through effects

    dev

    You can route the output of a source (like a synth or player) through one or more effects before it reaches the Destination. Connections can be serial or parallel.

    • Serial: source.connect(effect).toDestination()
    • Parallel: source.connect(effect1); source.connect(effect2);
    const player = new Tone.Player({
    	url: "https://tonejs.github.io/audio/drum-samples/loops/ominous.mp3",
    	autostart: true,
    });
    const filter = new Tone.Filter(400, "lowpass").toDestination();
    const feedbackDelay = new Tone.FeedbackDelay(0.125, 0.5).toDestination();
    
    // connect the player to the feedback delay and filter in parallel
    player.connect(filter);
    player.connect(feedbackDelay);
  5. Start audio with Tone.start()

    dev

    Browsers prevent audio from playing until a user interaction occurs (like a click or keydown). To enable audio, you must call Tone.start() inside an event listener triggered by a user action. Tone.start() returns a promise that resolves when the AudioContext is ready.

    Warning: Scheduling or playing audio before this promise resolves may result in silence or incorrect scheduling.

    //attach a click listener to a play button
    document.querySelector("button")?.addEventListener("click", async () => {
    	await Tone.start();
    	console.log("audio is ready");
    });
  6. Add new examples to the repository

    dev
    If you are contributing new examples to the Tone.js repository, ensure you follow the existing style of the current examples. To make your new example visible on the index page, you must register its title and filename in the js/ExampleList.json file.
  7. Install Tone.js via npm or unpkg

    dev

    You can incorporate Tone.js into your project using npm for local development or by including it directly in an HTML document via unpkg.com.

    Using npm

    Install the latest stable version:

    npm install tone

    Or install the 'next' version:

    npm install tone@next

    Then import it in your JavaScript files:

    import * as Tone from "tone";

    Using unpkg (CDN)

    Add the script tag to your HTML document. Ensure it precedes any of your project's scripts:

    <script src="http://unpkg.com/tone"></script>
  8. Run Tone.js examples locally

    dev

    To run the official Tone.js examples on your local machine, follow these steps:

    1. Install dependencies and build the project from the repository root:
      npm install
      npm run build
    2. Start a local development server using http-server:
      npx http-server -e html -p 8000
    3. Open your browser and navigate to http://localhost:8000/examples.

    Note: These examples utilize web components (such as <tone-example>) defined in the Tonejs/ui repository.

    npm install
    npm run build
    npx http-server -e html -p 8000
  9. Core Audio Engine Entrypoint

    dev

    The tone package provides the core audio engine, including the global Context, Transport, and various audio nodes. It serves as the central hub for managing the Web Audio API lifecycle, scheduling, and audio processing. Key components include:

    • Contexts: Context (standard real-time audio) and OfflineContext (for rendering audio to a buffer).
    • Audio Nodes: Base classes for audio processing like Gain, Delay, and ToneAudioNode.
    • Time & Scheduling: Utilities for handling Time, Midi, Ticks, and TransportTime.
    • Conversions: Mathematical utilities for translating between musical and technical units.
  10. Use Tone.Synth for basic synthesis

    dev

    Tone.Synth is a basic monophonic synthesizer with a single oscillator and an ADSR envelope.

    triggerAttack / triggerRelease

    • triggerAttack(note, time): Starts the note (amplitude rises).
    • triggerRelease(time): Ends the note (amplitude returns to 0).

    triggerAttackRelease

    A convenience method that combines attack and release.

    • Argument 1 (note): A frequency in hertz (e.g., 440) or pitch-octave notation (e.g., "D#2").
    • Argument 2 (duration): How long the note is held. Can be in seconds or tempo-relative values (e.g., "8n").
    • Argument 3 (time, optional): When to play the note along the AudioContext time.
    //create a synth and connect it to the main output (your speakers)
    const synth = new Tone.Synth().toDestination();
    
    //play a middle 'C' for the duration of an 8th note
    synth.triggerAttackRelease("C4", "8n");
  11. Create polyphonic instruments with Tone.PolySynth

    dev

    Most standard synths (like Tone.FMSynth, Tone.AMSynth, and Tone.NoiseSynth) are monophonic, meaning they can only play one note at a time.

    To play multiple notes simultaneously, wrap a monophonic synth in Tone.PolySynth. The API is similar, but triggerRelease must be provided with a note or an array of notes.

    const synth = new Tone.PolySynth(Tone.Synth).toDestination();
    const now = Tone.now();
    synth.triggerAttack("D4", now);
    synth.triggerAttack("F4", now + 0.5);
    synth.triggerAttack("A4", now + 1);
    synth.triggerAttack("C5", now + 1.5);
    synth.triggerAttack("E5", now + 2);
    synth.triggerRelease(["D4", "F4", "A4", "C5", "E5"], now + 4);
  12. Play audio samples with Tone.Player and Tone.Sampler

    dev

    Tone.Player

    Used to load and play back a single audio file.

    Tone.Sampler

    Used to create a polyphonic instrument from multiple samples. If you provide samples for specific notes, Tone.Sampler will pitch-shift them to fill the gaps between notes.

    Loading Assets

    Use Tone.loaded() to return a promise that resolves when all audio files are loaded, which is safer than managing individual onload events.

    // Using Tone.Player
    const player = new Tone.Player(
    	"https://tonejs.github.io/audio/berklee/gong_1.mp3"
    ).toDestination();
    Tone.loaded().then(() => {
    	player.start();
    });
    
    // Using Tone.Sampler
    const sampler = new Tone.Sampler({
    	urls: {
    		C4: "C4.mp3",
    		"D#4": "Ds4.mp3",
    		"F#4": "Fs4.mp3",
    		A4: "A4.mp3",
    	},
    	release: 1,
    	baseUrl: "https://tonejs.github.io/audio/salamander/",
    }).toDestination();
    
    Tone.loaded().then(() => {
    	sampler.triggerAttackRelease(["Eb4", "G4", "Bb4"], 4);
    });