Record Audio Output from Tone.js to a File
This article provides a quick guide on how to capture and save the
audio output generated by a Tone.js project directly into an audio file.
You will learn how to set up the Tone.Recorder class,
connect it to your audio graph, start and stop the recording, and
trigger a browser download of the resulting audio file.
Step 1: Create and Connect the Recorder
Tone.js includes a built-in Tone.Recorder utility
designed specifically for capturing audio. To record everything playing
in your project, you must connect the global output
(Tone.Destination) to a new instance of
Tone.Recorder.
// Create a new instance of the Tone.js Recorder
const recorder = new Tone.Recorder();
// Connect the main output to the recorder
Tone.Destination.connect(recorder);If you only want to record a specific instrument or effect instead of
the entire project, connect that specific node directly to the recorder
instead of Tone.Destination.
Step 2: Start the Recording
Before you start playing any audio or scheduling events, you must
start the recorder. The start() method prepares the
recorder to capture incoming audio signals.
// Start recording audio
recorder.start();
// Start your synthesizers, players, or transport
synth.triggerAttackRelease("C4", "8n");Step 3: Stop the Recording and Download the File
The stop() method is an asynchronous operation that
stops the recording and returns a Promise. This Promise resolves to a
Blob containing the recorded audio data (typically in WebM
or WAV format, depending on browser support).
To save this file directly to the user’s device, convert the
Blob into an object URL and trigger a virtual click on an
anchor (<a>) element.
async function stopAndSaveRecording() {
// Stop the recorder and retrieve the audio Blob
const recording = await recorder.stop();
// Create a temporary URL pointing to the Blob
const url = URL.createObjectURL(recording);
// Create a temporary anchor element to trigger the download
const anchor = document.createElement("a");
anchor.download = "tonejs-recording.webm";
anchor.href = url;
// Trigger the download in the browser
anchor.click();
// Clean up the object URL from memory
URL.revokeObjectURL(url);
}Complete Implementation Example
Here is how to combine these steps into a simple, functional implementation with start and stop buttons:
import * as Tone from "tone";
const synth = new Tone.Synth().toDestination();
const recorder = new Tone.Recorder();
Tone.Destination.connect(recorder);
document.getElementById("start-btn").addEventListener("click", async () => {
await Tone.start(); // Ensure the audio context is active
recorder.start();
// Play a demo note
synth.triggerAttackRelease("E4", "1m");
});
document.getElementById("stop-btn").addEventListener("click", async () => {
const recording = await recorder.stop();
const url = URL.createObjectURL(recording);
const anchor = document.createElement("a");
anchor.download = "my-tonejs-track.webm";
anchor.href = url;
anchor.click();
URL.revokeObjectURL(url);
});