Build Custom Audio Player With Audio Waveform In Angular

If you are working on a platform that needs to play some audio to a user, for example to sell an audio file, it's awesome to show its wave form. That way, the user will be impressed about the structure of the audio and of what your platform can do. To extract the information from the audio file, Web Audio API can be used. This allows you to extract frequency, waveform and other data from the audio file. Then, the received data from the audio source can be visualized as audio-waves. While dealing with the huge data that an audio waveform will have, drawing waveform smoothly and more quickly without lagging the web page is essential. As a developer, the performance of the page matters a lot, irrespective of the content shown on the page to the developer. So, I'm using CanvasJS chart to visualize the waveform. Note: CanvasJS can draw millions of datapoints in few milliseconds.

This tutorial shows how to create simple MP3 player using web audio API, and how to visualize audio files using CanvasJS. The underlying techniques work within plain JavaScript, Angular, React or any other JavaScript framework. In this case, I'm using Angular to create waveforms.

Audio Player with Waveform using CanvasJS Angular Chart

Browse & Read Audio File

The first step to play audio and visualize waveforms is to get the audio file. Let's add an input field to accept MP3 files. Here I've restricted it to allow the user to browse just MP3 files. However, web audio API supports WAV, MP3, AAC, OGG and other formats.

<input type="file" class="file-input"
	   accept="audio/mp3"
       change)="onFileSelected($event)" #fileUpload>

Read Audio File

To fetch audio using the Web Audio API, we need to get an ArrayBuffer of audio data and pass it to a BufferSource. To get an audio buffer of the sound, you need to use the AudioContext.decodeAudioData method. The decoded AudioBuffer is resampled to the AudioContext's sampling rate, then passed to a callback or promise.

let margin = 10,
    chunkSize = 50,
    scaleFactor = (150 - margin * 2) / 2;
let audioContext = new AudioContext(),
    buffer = await file.arrayBuffer(),
    audioBuffer = await audioContext.decodeAudioData(buffer),
    float32Array = audioBuffer.getChannelData(0);
let array = [],
    i = 0,
    length = float32Array.length;
while (i < length) {
    array.push(float32Array.slice(i, i += chunkSize).reduce(function(total, value) {
        return Math.max(total, Math.abs(value));
    }));
}

Add Play / Pause & Stop Buttons

Add two buttons, one for play/pause and another to stop. When the audio is playing, the icon should show what the user can do by clicking that button. So, it will show the "Pause" icon when the audio is playing and "Play" icon when the audio is paused. To do this, we need to toggle between the play and pause states. In Web Audio API, you can check for the state of the audio-context, and based on the current state either resume the audio or suspend it.

togglePlaying = (event: any) => {	
	if(audioContext.state === 'running') {
		audioContext.suspend().then(() => {
		  buttonStatus = "Play";
		});
	}
	else if(audioContext.state === 'suspended') {
		audioContext.resume().then(() => {
		  buttonStatus = "Pause";
		});
	}
}

When it comes to the stop option, this is pretty simple. Web Audio API has option to stop the source by calling stop() method.

stopPlaying = (event: any) => {
	source.stop();
}

Generate Datapoints from the Audio Data

CanvasJS supports varieties of chart types for different sets of data, including line, area, pie, range, and financial charts, etc. For our case, range-area suits well - it looks like audio waves. The only task for us to do is to generate datapoints, pass it to datapoints and call chart.render(). CanvasJS draws wave graphs like a charm.

let dps = []
for (let index in array) {
	dps.push({ x: margin + Number(index), y: [50 - array[index] * scaleFactor, 50 + array[index] * scaleFactor]});
}

this.chart.options.data[0].dataPoints = dps;
this.chart.render();

Add Audio Playing Effect to the Wave

When audio begins playing, it is an excellent idea to shade the region that has already played in the waveform. Add a stripline to show the shaded region in the chart and keep updating it every few milliseconds or second. Stop updating it once the audio stops playing.

source.onended = () => {
	chart.axisX[0].stripLines[0].set("endValue", chart.axisX[0].get("maximum"));
    clearInterval(intervalId);
}
let intervalId = setInterval(() => {
	chart.axisX[0].stripLines[0].set("endValue", audioContext.currentTime * (chart.data[0].dataPoints.length / audioBuffer.duration));
}, 250);

Yippee! You just built a custom audio player with play, pause and stop options, along with the audio waveform generated using CanvasJS range-area chart. You can also use column chart, range-column chart to show waves differently. You can even customize the look and feel of the audio player using simple CSS properties, and can match the same with the waveform by changing CanvasJS chart properties.

This waveform generated by CanvasJS chart can be integrated with an audio/video player to make it more appealing to the user. Library has more customization options to change the look and feel, which gives you more flexibility to customize the chart look and feel to match with your website/player theme. In this tutorial, I have disabled chart interactivity so as to showcase only the waveform. However, CanvasJS supports interactivity where it shows tooltip and highlights when you hover over the chart.