Making Music in React

Rob Egeland
5 min readFeb 3, 2023

--

Calling all music lovers! If you are like me and would love to see your developer life and your musical life come together, I have found the web framework of your dreams. Tone.js makes creating musical apps and websites powerful and fun. This framework allowed my projects not to go down the path of endless Spotify clones but make music in the browser.

I will introduce a little bit of the Web Audio API, the core building block of Tone.js. Then Tone itself, how to install/import it, how to use it, and some pitfalls of using it in React.

Web Audio API

MDN describes the Web Audio API as a powerful and versatile system for controlling audio on the Web, allowing developers to choose audio sources, add effects to audio, create audio visualizations, apply spatial effects (such as panning) and much more”. The API uses audio context with modular routing that allows you to create a sound source, add effects, and plug into the sound’s destination aka. The users’ speakers.

This workflow will get more complicated as you add effects more effects or audio sources but at its root, this is how it works, this is important knowledge because this is also how Tone.js works as well.

Tone.js

Tone is described as a web audio framework that aims to be familiar to programmers as well as musicians. You can think of Tone as a library for the Web Audio API adding more effects, different oscillators, multi oscillator synth, and sequencers.

Usage

To show you how Tone works I’ll be building a simple React app with a MonoSynth, a button to play a note, a dropdown menu to change the oscillator type, and plus and minus buttons to change the amount of volume, build along with me if you like!

After I’ve created the project I'm gonna use npm to install Tone into the project’s dependencies.

I then want to create a React component for the synth and import Tone into the component.

Now we need to create a variable, we’ll call it synth, and set it equal to Tones’ Monosynth. Notice I’m tagging on the .toDestination() function this allows the sound to make it to the users’ speakers, it is needed on any sound-producing object in Tone as well as any effects that will be added to the sound. We then need to set the initial state of the sound.

We then need to import and use state to keep track of the oscillator type and the volume.

Next, we need to build out a front end to be able to change and display the data, don’t forget to make the inputs controlled!

Notice when I initialized the synth I didn’t set the values to the state variables, this is one of the biggest pitfalls when working with Tone in React, at least for me it was. As you may know when state changes in a component it causes the component to re-render, but as these re-renders keep happing they are also resetting the synth values which causes the sound to diminish in quality until you get what I can only describe as the worst static sounding noise you’ve ever heard coming out of your speakers. So how do we combat this? There are a couple of ways, If your sound is static you can use React Context and pass the sound down from the context component to any other that needs it avoiding the React render cycle. But what if you want your sound to be dynamic? Like our example, we want the sound to change as the user changes input values. For this, a simple useEffect will do the trick we can wrap our synth value assignments in a useEffect with the corresponding state variable in the dependency array allowing it to only change when our specified state changes and protecting it from the unneeded re-renders.

Now we just need it to play something when the user hits play! For this, I’m going to use Tones triggerAttackRelease method. This method takes two arguments and a third optional one, the first is the pitch the note will play at and can be expressed as either a frequency in hertz or an actual note ex. 261hz or C4. The second argument is the duration of the note, either in seconds or tempo-relative values ex. 2 seconds or quarter note(4n). The third optional argument is when the note should play usually for scheduling a note to play in advance, note — this argument can also help with getting better performance in an app if you set it a few milliseconds in advance. For our project we are gonna have the synth play middle C(C4) for a quarter note(4n)

Conclusion

Tone.js is a great framework for music lovers or even people interested and want to upgrade their portfolio projects. It’s simple enough to jump in and mess around with, but also powerful enough to make some really incredible creations. For anyone familiar with the DAW Ableton they have an interactive lesson in making music on their website that was built in Tone.js. I will also link to Tones’ page with other cool examples here.

--

--