I'm experimenting with the WebAudio API and am attempting to build an analyser that a user can interact with and ultimately turn on and off different frequencies within the music to isolate different beats within the track, i.e bass, kick etc.
I'm visualising the frequency data using the Canvas, and would like the user to be able to highlight parts of the visualisation, and in-turn muting frequencies.
By default the visualisation would look like this and the user would hear all frequencies.
But when the user selects several bars, the greyed out ones would mute the related frequencies:
My thinking is can I reverse-engineer the frequencyData array and essentially mute the associated frequencies?
** Update **
So I've been playing around by adding several biquadFilter
s with a type of notch
in series, and then adjusting their frequency and Q values. This does sort of help isolate pats of the music, but not exactly how I want. This is the code I'm using so far...
const audioContext = new window.AudioContext();
const source = audioContext.createMediaElementSource(element);
const biquadFilter1 = audioContext.createBiquadFilter();
const biquadFilter2 = audioContext.createBiquadFilter();
const biquadFilter3 = audioContext.createBiquadFilter();
const analyser = audioContext.createAnalyser();
biquadFilter1.connect(analyser);
biquadFilter2.connect(analyser);
biquadFilter3.connect(analyser);
source
.connect(biquadFilter1)
.connect(biquadFilter2)
.connect(biquadFilter3);
analyser.connect(audioContext.destination);
I'm not sure if I've set this up correctly, but it does allow me to very roughly manipulate the frequencies, but it feels like there is no accurate science to doing it this way.
Is what I'm attempting possible, and if so, any suggestions are really appreciated :)
What you are looking for is a band pass filter.
A band-pass filter (also bandpass filter, BPF) is a device that passes frequencies within a certain range and rejects (attenuates) frequencies outside that range. https://en.wikipedia.org/wiki/Band-pass_filter
And we are lucky, the web audio api provide it via the BiquadFilterNode.
https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode
So, based on the demo code provided, to apply a band pass filter at the 400Hz frequency range to an html audio player.
The html audio element must be created by js then inserted into the DOM, or it won't works with the web audio api.
<div id="hello"></div>
<script>
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// Create new player
var a = document.createElement("audio");
// Give a source song
a.src = "vorbis.ogg";
// Show the controls
a.setAttribute("controls", "");
// Append to the DOM
hello.appendChild(a);
// Player now ready for the web audio api
var mediaElement = a;
//set up the different audio nodes we will use for the app
var gainNode = audioCtx.createGain();
var biquadFilter = audioCtx.createBiquadFilter();
// connect the nodes together
source = audioCtx.createMediaElementSource(mediaElement);
source.connect(biquadFilter);
biquadFilter.connect(gainNode);
gainNode.connect(audioCtx.destination);
// Manipulate the Biquad filter
biquadFilter.type = "bandpass";
biquadFilter.frequency.value = 400;
biquadFilter.gain.value = 25;
</script>
The biquadFilter.frequency.value represent the center of the range frequencies. The range expands with the gain value.
This filters can be chained just like this example with some other GainNode, see https://developer.mozilla.org/en-US/docs/Web/API/GainNode
In a similar way, using two filters, a lowpass and a highpass, for the range 1000hz to 1500hz.
<div id="hello"></div> <script> var audioCtx = new (window.AudioContext)() var a = document.createElement("audio") a.src = "vorbis.ogg" a.setAttribute("controls", "") hello.appendChild(a) var mediaElement = a var gainNode = audioCtx.createGain() var lowpass = audioCtx.createBiquadFilter() var highpass = audioCtx.createBiquadFilter() source = audioCtx.createMediaElementSource(mediaElement) source.connect(lowpass) lowpass.connect(highpass) highpass.connect(gainNode) gainNode.connect(audioCtx.destination) lowpass.type = "lowpass" lowpass.frequency.value = 1000 lowpass.gain.value = -1 highpass.type = "highpass" highpass.frequency.value = 1500 highpass.gain.value = -1 </script>
You’re working with audio, so what you need is a band-pass filter. That will allow you to play only certain frequencies.
I can see you’re already using FFT to get the frequencies. From there, you have two options. One is to remove the frequencies you want from that array obtained after you do the FFT. Then, in order to get the sound you need the signal in the time domain, so you will need an Inverse FFT. The other option is to make your filter in the time domain, and then make convolution with the original signal.
I’m not posting code since I’ve just made this in C, but I’m pretty sure there are many libraries to do these operations easily (Convolution/IFFT).
:)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With