Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web Audio Api : How do I add a working convolver?

What I am trying to learn / do: How to set up a simple working convolver (reverb) into my code sandbox below using an impulse response. I thought it was similar to setting a filter but things seem quite different.

What I tried: As with all new technologies things change at a fast pace making it difficult to know which implementation is correct and what is not. I looked at countless WebAudio Api Convolver Tutorials, many were old and others were working but far too "bloated" making it hard to understand what is going on. I tried to implement some of the examples from the mozilla documentation:

I already had a look at: https://developer.mozilla.org/en-US/docs/Web/API/ConvolverNode/buffer

My question: How do I integrate a convolver properly in the context below? As you can see I tried but cant figure this out.

 window.addEventListener('load', init, false);

function init() {
    setupWebAudio();
}

function setupWebAudio() {
    var audio = document.getElementById('music');
    var context = new AudioContext();
    var source = context.createMediaElementSource(audio);
    var filter = context.createBiquadFilter();
    var convolver = context.createConvolver();
    var inpulseRes = "hall.mp3";

    var hallBuffer = inpulseRes;
    soundSource = context.createBufferSource();
    soundSource.buffer = hallBuffer;
    convolver.buffer = hallBuffer;

    filter.type = 'lowpass';
    filter.frequency.value = 400;

var theParent = document.getElementById("test");
    theParent.addEventListener("mousedown", doSomething, false);
    function doSomething(e) {
        if (e.target !== e.currentTarget) {
            if(e.target == theParent.children[0]){
                filter.frequency.value += 200;
            }
            else if(e.target == theParent.children[1]){
                 filter.frequency.value -= 200;
            }
            else if(e.target == theParent.children[2]){
                 filter.type = 'highpass';
            }               
        }
        e.stopPropagation();
    }

    source.connect(filter);
    source.connect(convolver);
    filter.connect(context.destination);
    audio.play();
}
like image 415
Asperger Avatar asked Dec 27 '15 16:12

Asperger


2 Answers

This is a pretty open-ended question; what have you tried that hasn't worked, or is the piece you're missing what the "impulse response" is supposed to be? If the latter, search for "impulse response files" and you'll find tons of free files you can use. You can also generate noise on a logarithmic decay curve into a buffer, and you'll get a basic reverb effect. Basic method to create an impulseResponse buffer:

function impulseResponse( duration, decay, reverse ) {
    var sampleRate = audioContext.sampleRate;
    var length = sampleRate * duration;
    var impulse = audioContext.createBuffer(2, length, sampleRate);
    var impulseL = impulse.getChannelData(0);
    var impulseR = impulse.getChannelData(1);

    if (!decay)
        decay = 2.0;
    for (var i = 0; i < length; i++){
      var n = reverse ? length - i : i;
      impulseL[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay);
      impulseR[i] = (Math.random() * 2 - 1) * Math.pow(1 - n / length, decay);
    }
    return impulse;
}

Your code has both a BufferSourceNode and the convolver pointing to the same buffer, which is almost certainly wrong; you don't usually play back an impulse response file using a buffersource, and you don't usually use a normal sound file as an impulse response. (Look up convolution on Wikipedia if the role of an impulse response isn't clear.) You need to do something like:

function setupWebAudio() {
    var audio = document.getElementById('music');
    var context = new AudioContext();
    var source = context.createMediaElementSource(audio);
    var convolver = context.createConvolver();
    var irRRequest = new XMLHttpRequest();
    irRRequest.open("GET", "hall.mp3", true);
    irRRequest.responseType = "arraybuffer";
    irRRequest.onload = function() {
        context.decodeAudioData( irRRequest.response, 
            function(buffer) { convolver.buffer = buffer; } );
    }
    irRRequest.send();
// note the above is async; when the buffer is loaded, it will take effect, but in the meantime, the sound will be unaffected.

    source.connect( convolver );
    convolver.connect( context.destination );
}
like image 55
cwilso Avatar answered Nov 11 '22 06:11

cwilso


Connect the output of the convolver to something. What you have now is the source connected to the convolver, but the convolver isn't connected to anything. As a first cut, convolver.connect(context.destination).

like image 35
Raymond Toy Avatar answered Nov 11 '22 05:11

Raymond Toy