It uses six BiquadFilter nodes with type="peaking".
HTML:
<html lang="en">
<head>
<title>Equalizer made with the Web Audio API</title>
</head>
<body>
<h2>Equalizer made with the Web Audio API</h2>
<div class="eq">
<audio id="player" controls crossorigin="anonymous" loop>
<source src="https://mainline.i3s.unice.fr/mooc/guitarRiff1.mp3">
Your browser does not support the audio tag.
</audio>
<div class="controls">
<label>60Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 0);"></input>
<output id="gain0">0 dB</output>
</div>
<div class="controls">
<label>170Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 1);"></input>
<output id="gain1">0 dB</output>
</div>
<div class="controls">
<label>350Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 2);"></input>
<output id="gain2">0 dB</output>
</div>
<div class="controls">
<label>1000Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 3);"></input>
<output id="gain3">0 dB</output>
</div>
<div class="controls">
<label>3500Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 4);"></input>
<output id="gain4">0 dB</output>
</div>
<div class="controls">
<label>10000Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 5);"></input>
<output id="gain5">0 dB</output>
</div>
</div>
</body>
</html>
CSS:
div audio {
display: block;
margin-bottom:10px;
}
.eq {
margin: 32px;
border:1px solid;
border-radius:15px;
background-color:lightGrey;
padding:10px;
width:300px;
box-shadow: 10px 10px 5px grey;
text-align:center;
font-family: "Open Sans";
font-size: 12px;
}
div.controls:hover {
color:blue;
font-weight:bold;
}
div.controls label {
display: inline-block;
text-align: center;
width: 50px;
}
div.controls label, div.controls input, output {
vertical-align: middle;
padding: 0;
margin: 0;
font-family: "Open Sans",Verdana,Geneva,sans-serif,sans-serif;
font-size: 12px;
}
JavaScript:
let context = new AudioContext();
let mediaElement = document.getElementById('player');
let sourceNode = context.createMediaElementSource(mediaElement);
mediaElement.onplay = () => {
context.resume();
}
// create the equalizer. It's a set of biquad Filters
var filters = [];
// Set filters
[60, 170, 350, 1000, 3500, 10000].forEach(function(freq, i) {
var eq = context.createBiquadFilter();
eq.frequency.value = freq;
eq.type = "peaking";
eq.gain.value = 0;
filters.push(eq);
});
// Connect filters in serie
sourceNode.connect(filters[0]);
for(var i = 0; i < filters.length - 1; i++) {
filters[i].connect(filters[i+1]);
}
// connect the last filter to the speakers
filters[filters.length - 1].connect(context.destination);
function changeGain(sliderVal,nbFilter) {
var value = parseFloat(sliderVal);
filters[nbFilter].gain.value = value;
// update output labels
var output = document.querySelector("#gain"+nbFilter);
output.value = value + " dB";
}
If you read the description of this filter type: "Frequencies inside the range get a boost or an attenuation; frequencies outside it are unchanged." This is exactly what we need to write a multi band equalizer! We're going to use several sliders, each of which boosts one range of frequency values.
The definition says that:
the frequency property value of a filter will indicate the middle of the frequency range getting a boost or an attenuation, each slider corresponds to a filter whose frequency will be set to 60Hz, 170Hz, 350Hz, 1000Hz, 3500Hz, or 10000Hz.
the gain property value of a filter corresponds to the boost, in dB, to be applied; if negative, it will be an attenuation. We will code the sliders' event listeners to change the gain value of the corresponding filter.
the Q property values control the width of the frequency band. The greater the Q value, the smaller the frequency band. We'll ignore it for the purposes of this example.
Here is the final audio graph (picture taken with the now discontinued FireFox WebAudio debugger, you should get similar results with the Chrome Audion extension):
Example #2: equalizer with a <video> element
We cloned the previous example and simply changed the <audio>...</audio> part of the HTML code by:
<video id="player" width="320" height="240" controls crossOrigin="anonymous">
<source src="https://mainline.i3s.unice.fr/mooc/elephants-dream-medium.mp4" >
</video>
And the example works in the same way, but this time with a video. Try moving the sliders to change the sound!
HTML:
<html lang="en">
<head>
<title>Equalizer made with the Web Audio API</title>
</head>
<body>
<h2>Equalizer made with the Web Audio API</h2>
<div class="eq">
<video id="player" width="320" height="240" controls crossorigin="anonymous">
<source src="https://mainline.i3s.unice.fr/mooc/elephants-dream-medium.mp4" >
</video>
<div class="controls">
<label>60Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 0);"></input>
<output id="gain0">0 dB</output>
</div>
<div class="controls">
<label>170Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 1);"></input>
<output id="gain1">0 dB</output>
</div>
<div class="controls">
<label>350Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 2);"></input>
<output id="gain2">0 dB</output>
</div>
<div class="controls">
<label>1000Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 3);"></input>
<output id="gain3">0 dB</output>
</div>
<div class="controls">
<label>3500Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 4);"></input>
<output id="gain4">0 dB</output>
</div>
<div class="controls">
<label>10000Hz</label>
<input type="range" value="0" step="1" min="-30" max="30" oninput="changeGain(this.value, 5);"></input>
<output id="gain5">0 dB</output>
</div>
</div>
</body>
</html>
CSS:
div video {
display: block;
margin-bottom:10px;
}
.eq {
margin: 32px;
border:1px solid;
border-radius:15px;
background-color:lightGrey;
padding:10px;
width:320px;
box-shadow: 10px 10px 5px grey;
text-align:center;
font-family: "Open Sans";
font-size: 12px;
}
div.controls:hover {
color:blue;
font-weight:bold;
}
div.controls label {
display: inline-block;
text-align: center;
width: 50px;
}
div.controls label, div.controls input, output {
vertical-align: middle;
padding: 0;
margin: 0;
font-family: "Open Sans",Verdana,Geneva,sans-serif,sans-serif;
font-size: 12px;
}
JavaScript:
let context = new AudioContext();
let mediaElement = document.getElementById('player');
let sourceNode = context.createMediaElementSource(mediaElement);
mediaElement.onplay = () => {
context.resume();
}
// create the equalizer. It's a set of biquad Filters
let filters = [];
// Set filters
[60, 170, 350, 1000, 3500, 10000].forEach(function(freq, i) {
let eq = context.createBiquadFilter();
eq.frequency.value = freq;
eq.type = "peaking";
eq.gain.value = 0;
filters.push(eq);
});
// Connect filters in serie
sourceNode.connect(filters[0]);
for(let i = 0; i < filters.length - 1; i++) {
filters[i].connect(filters[i+1]);
}
// connect the last filter to the speakers
filters[filters.length - 1].connect(context.destination);
function changeGain(sliderVal,nbFilter) {
let value = parseFloat(sliderVal);
filters[nbFilter].gain.value = value;
// update output labels
let output = document.querySelector("#gain"+nbFilter);
output.value = value + " dB";
}