This is a great tutorial for anyone who has some Javascript and audio experience, but is looking into how to utilize the two together. The Web Audio API, maintained by Mozilla, is (to be frank) not the most intuitively written API out there. I wrote this tutorial to give audio-interested programmers a way to get their toes wet in Web Audio.
Convolution reverb simulates reverberation by placing performing a mathematical operation on the source audio file using a recording of the Impulse Response, which illustrates how a sound travels through a physical space. Here's a link to a YouTube video that explains the process in greater detail: Convolution Reverb Explained
This is what we'll be building today
Here are the steps we'll go through:
<html> <head> <title>Convolution Reverb App</title> </head> <body> </body> </html>
<body> <div id="asdf"> <div><p id="a">Press 'a' for kick</p></div> <div><p id="s">Press 's' for snare</p></div> <div><p id="d">Press 'd' for hat</p></div> <div><p id="f">Press 'f' for clap</p></div> </div> <div id="impulses"> <button type="button" onclick="boom()">boom</button> <button type="button" onclick="echo()">echo</button> <button type="button" onclick="space()">space</button> <button type="button" onclick="hall()">hall</button> </div> </body>
<script type="text/javascript" src="buffer-loader.js"></script>
var context; //audio context var bufferLoader; var impulseResponse = "./assets/impulse1.wav" //set default IR
function getImpulse() { context = new AudioContext(); //initializes audio context convolver = context.createConvolver(); console.log("convolver Started") ajaxRequest = new XMLHttpRequest(); //requests sound from server ajaxRequest.open('GET', impulseResponse, true); console.log(impulseResponse) ajaxRequest.responseType = 'arraybuffer'; ajaxRequest.onload = function() { var impulseData = ajaxRequest.response; context.decodeAudioData(impulseData, function(buffer) { myImpulseBuffer = buffer; convolver.buffer = myImpulseBuffer; convolver.loop = false; convolver.normalize = true; convolver.connect(context.destination); }, function(e){"Error with decoding audio data" + e.err}); } ajaxRequest.send(); } getImpulse();
function loadAndPlayKick() { bufferLoader = new BufferLoader( context, [ "./assets/kick.wav", ], finishedLoadingKick ); bufferLoader.load(); } function loadAndPlaySnare() { bufferLoader = new BufferLoader( context, [ "./assets/snare.wav", ], finishedLoadingSnare ); bufferLoader.load(); } function loadAndPlayHat() { bufferLoader = new BufferLoader( context, [ "./assets/hat.wav", ], finishedLoadingHat ); bufferLoader.load(); } function loadAndPlayClap() { bufferLoader = new BufferLoader( context, [ "./assets/clap.wav", ], finishedLoadingClap ); bufferLoader.load(); }
document.body.onkeydown = function() {keyCode(event)}; function keyCode(event) { var x = event.keyCode; if (x == 65) { loadAndPlayKick(); //trigger kick } if (x == 83) { loadAndPlaySnare(); } if (x == 68) { loadAndPlayHat(); } if (x == 70) { loadAndPlayClap(); } }
function finishedLoadingKick(bufferList) { var snd1 = context.createBufferSource(); snd1.buffer = bufferList[0]; snd1.connect(convolver); snd1.start(0); } function finishedLoadingSnare(bufferList) { var snd2 = context.createBufferSource(); snd2.buffer = bufferList[0]; snd2.connect(convolver); snd2.start(0); } function finishedLoadingHat(bufferList) { var snd3 = context.createBufferSource(); snd3.buffer = bufferList[0]; snd3.connect(convolver); snd3.start(0); } function finishedLoadingClap(bufferList) { var snd4 = context.createBufferSource(); snd4.buffer = bufferList[0]; snd4.connect(convolver); snd4.start(0); }
function boom(){ impulseResponse="./assets/impulse1.wav"; getImpulse(); //changes impulse response } function echo(){ impulseResponse="./assets/impulse2.wav"; getImpulse(); } function space(){ impulseResponse="./assets/impulse3.wav"; getImpulse(); } function hall(){ impulseResponse="./assets/impulse4.wav"; getImpulse(); }
There are many different resources you can find online of different impulse responses. I’ve included the download to the four I used for this project in the assets folder above, but feel free to find your own to use! The same goes for the included source sounds.
Finally, because of the usage of a file system, we need to serve this app on a server. You can do this by opening up your terminal, navigating to the folder you’ve stored the project in, and writing the following code:
python -m SimpleHTTPServer 5000.
Then you’ll be able to navigate to:
localhost:5000/index.html
and see the working script. Alternatively, you can host it on a website and it should work perfectly.
If you'd like to find other impulse responses, there are plenty of free online resources for that. Here's an example of one: OpenAir.
If you'd like to download the full project (though I advise against this) you can do so here: Full Project Download
Thank you for following this tutorial, I hope you enjoyed it!
Feel free to contact me at lucas@lucwhite.com with any and all questions you have!