Audio | Part 2 — Playing Accurately Timed Beats with Tone.js
Creating music in a web browser has never been as accessible as it is now, thanks to the power of libraries like Tone.js. This JavaScript framework allows us to work with audio in the browser, providing a level of control and flexibility that opens a whole new world of possibilities. In this blog post, we'll dive into how to play a beat with accurate timing using Tone.js.
Setting the Stage
First and foremost, we need to ensure Tone.js is included in our project. You can either include it directly in your HTML file from a CDN or install it using npm for a more development-oriented setup.
Here's how to include it via a CDN:
<script src="https://cdn.tonejs.io/14.7.58/Tone.js"></script>
Or install it with npm:
npm install tone
And import it in your JavaScript file:
import * as Tone from 'tone';
Building and Timing a Beat
To create a beat, we'll need samples of the sounds we wish to play, such as a kick, snare, or hi-hat. For the sake of this tutorial, we'll assume you have three audio samples available: kick.mp3, snare.mp3, and hihat.mp3. We'll load these files into Tone.Player
objects and create a function to play them at the correct times.
Here's a simple implementation:
const kick = new Tone.Player("./path/to/your/kick.mp3").toDestination();
const snare = new Tone.Player("./path/to/your/snare.mp3").toDestination();
const hihat = new Tone.Player("./path/to/your/hihat.mp3").toDestination();
const playBeat = () => {
Tone.Transport.scheduleRepeat((time) => {
kick.start(time);
hihat.start(time + 0.5);
snare.start(time + 1);
hihat.start(time + 1.5);
}, "2n");
Tone.Transport.start();
};
document.querySelector('button').addEventListener('click', () => {
Tone.start().then(() => {
playBeat();
});
});
Let's break this down:
-
new Tone.Player("x").toDestination();
: We're creating newPlayer
objects for each sample and routing their output to the default audio output. -
Tone.Transport.scheduleRepeat(t => {...}, "2n");
: Tone.js provides us with aTransport
object, which we can think of as our song's timeline. ThescheduleRepeat
method allows us to schedule repeating events. Here, we're telling it to play our samples at different times within a 2-beat (or "2n") cycle. -
sample.start(time + [offset]);
: We're starting each sample at a specific time within our cycle. The start method accepts a time parameter, which can be an offset from the currentTransport
time. This allows us to create our beat pattern. -
Tone.Transport.start();
: Finally, we're starting theTransport
, which will begin our cycle. -
The
addEventListener
on the button: Since browsers typically require a user interaction before starting audio playback, we've wrapped our playBeat function in a button click event.
Demo
That's it! You've created your first accurately timed beat using Tone.js! Try out the demo below. Download the native HTML / JS code below as well to run the demo locally.
Wrapping Up
And there you have it! You've created a simple beat in the browser with accurate timing. Tone.js offers much more to explore, so don't hesitate to dive deeper and create complex rhythms, melodies, and even complete songs.