Creating a React audio player
By: Andy Agus
Tags: Javacript, Audio, React

Using the Web Audio Api, here’s my process to leveraging the initial setup to create a React music player. Thank you to Mozilla and Web Audio Api for the wonderful documentation to help me complete this tutorial. This player gives you the ability to pause/play a track, add and remove gain and also pan the audio from left to right. If I have enough time, I will try to implement the drag and drop interface to enable custom sliders. Let’s get started!

First things first, let’s create a new react project

npx create-react-app spatialsound

If you’d like to set up version control you can create a repo through github and then ‘git init’ the folder in the terminal. Once your react app is created enter the directory and open it up in your favorite text editor.

To get started with the Web Audio API, let’s begin by changing our App.js from a function to a class and the first thing we are going to do is add an Audio element to the dom.

<audio src=""></audio>

Since we are anticipating changing this song in the near future, let’s set ‘song’ to state and let source equal the state of song

<audio src={this.state.song}></audio>

Now we’ll need to create a state and let’s also make sure to save a song in the public folder that we can reference in our state. The song I choose is called thedeli.mp3. Once it’s added to the public folder, you can set it to state as follows:

state = {

song: process.env.PUBLIC_URL + 'thedeli.mp3',

}

Awesome, now song is set to state, but how do we play the sound? First I’m going to double check that the song is being properly called as an Audio Element and I’m going to do this by calling console.log(this.state) in the render function…great looks like we’re all set.

Let’s now create a componentDidMount function. Here we have to do an initial set up to make sure our app is properly connected to the framework.

componentDidMount(){

const AudioContext = window.AudioContext || window.webkitAudioContext;

const audioContext = new AudioContext();

}

Here we are creating a new constant that has access to the Web Audio API. Once we have the constant we create a new instance of AudoiContext so that we can use it and play a sound.

Next, save audioContext to state, since we’ll need to access it in future functions and it may need to be altered as we are switching songs. So make sure to add audioContext as an option in state and then set this instance of audioContext to your state

state = {

song: process.env.PUBLIC_URL + 'thedeli.mp3',

audioContext: null

} //componentDidMount

this.setState(audioContext: audioContext)

Now that audio context is set we need to find the audio element, the actual div holding the audio file and connect the audio context to it. In order to do that, we need to access the audio element by using the document query selector and then setting the audioElement to state.

const audioElement = document.querySelector('audio');

this.setState({audioElement:audioElement})

Now we just have to take both the elements that we created a combine them together using the createMediaElementSource. We can conveniently label this section ‘track’ because this is going to be what is playing through the speakers. Then we just connect the track to the destination. And wallah, the sound is ready to be played.

componentDidMount(){

const AudioContext = window.AudioContext || window.webkitAudioContext;

const audioContext = new AudioContext();

this.setState({audioContext: audioContext})

const audioElement = document.querySelector('audio');

this.setState({audioElement:audioElement})

const track = audioContext.createMediaElementSource(audioElement);

track.connect(audioContext.destination);

}

Now we can manipulate the audio element, to pause it and play it

audioElement.play();

audioElement.pause();

But wait…why is it not playing? The reason is because the browser doesn’t allow auto play without the user prompted some form of button to start or stop a track. So because of this, let’s create a play button!

In order to do this we’ll start with a click handler in App.js. I will call it ‘playClickHandler’. Let’s also create a new JS file called PlayClick JS , and import it into App.JS. I’m also going to add a state called ‘playing’ in app.js which will be a boolean to signify if the button has been pressed.

//PlayClick.js import React from React export default class PlayClick extends React.Component{

render(){

return(

<h1> PlayClick </h1>

)

}

}

In App.js

import PlayClick from './PlayClick'

Now let’s add a handler and pass the handler into PlayClick, add a button to PlayClick which will then flip the state of playing to its opposite

playClickHandler = (e) => {

console.log(e)

} render(){

console.log(this.state)

return(

<div>

<h1> Hello </h1>

<audio src={this.state.song}></audio>

<PlayClick playClickHandler={this.playClickHandler}/>

</div> )

}

}

Make sure it’s properly passing

import React from 'react' export default class PlayClick extends React.Component{

render(){

console.log(this.props)

return(

<button> Play </button>

)

}

}

We want to make sure the button says ‘play’ when the song is paused and ‘pause’ when the song is playing. So we’re going to need to use state here.

Add a simple ternary statement that changes the text based on the state…currently its false, but let’s set it so every-time we click it changes and also calls the prop function

<button onClick={

(e) => {

this.setState({playing:!this.state.playing},

this.props.playClickHandler(this.state.playing)

)

}

}>

OnClick we are setting state to the opposite boolean and then we are calling the playClickHandler function and passing it the state of the boolean. Which we will then set in app.js

Now we just need to resume AudioContext which is required in order to initialize a track upon page load

this.state.audioContext.resume();

And let’s add a simple if statement that says if the state is equal to playing then play the sound otherwise pause the sound

if(this.state.playing === false){

console.log("playing")

this.state.audioElement.play()

}else if(this.state.playing === true){

console.log("notplaying")

this.state.audioElement.pause()

}

Now you’re all set! You have audio in your browser and you can pause and play it to your hearts desire! I hope to dive deep further in using effects such as gain and pan, but that is it for now, I hope you enjoyed reading!

Until next time,

Andy