Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebAudio play sound pops at start and end

Whenever I play a sound using code such as

// binaryData = a wave file from a websocket
let ctx = new AudioContext();
ctx.decodeAudioData(binaryData, function(audioData){
   let source = ctx.createBufferSource();
   source.buffer = audioData;
   source.connect(ctx.destination);
   source.start(0);
});

There is a very audible click or pop between each clip played. Forget the fact that I'm trying to play real-time audio with this system; why is it that there is a glitchy noise at the beginning and end of each sound clip played? I'm not understanding how this is acceptable behaviour in 2017 from an audio playing device... Is there any way to mitigate or eliminate this?


Answer

Following the answer below here is a good set of #s to use to reduce clicking to basically nothing. I'm not saying this works great for a tone, but its flawless for voice.

// start of clip
// clipPlayTime may be 0 or your scheduled play time
gain.setValueAtTime(0.01, clipPlayTime);
gain.exponentialRampToValueAtTime(1, clipPlayTime + 0.001);
// end of clip
gain.setValueAtTime(1, clipPlayTime + clipLength - 0.001);
gain.exponentialRampToValueAtTime(0.01, clipPlayTime + clipLength);

This creates a ramp up and a ramp down.

like image 301
J Doe. Avatar asked Oct 23 '25 21:10

J Doe.


1 Answers

Use a exponentialRampToValueAtTime() to remove (or atleast reduce) the clicking noise.

Here's a great explanation: Web Audio, the ugly click and the human ear


Full Example

Base example taken from: https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/decodeAudioData

<button class="play">Play</button>
<button class="stop">Stop</button>

<script type="text/javascript">
var audioCtx = new(window.AudioContext || window.webkitAudioContext)();
var source;
var play = document.querySelector('.play');
var stop = document.querySelector('.stop');
var gainNode = audioCtx.createGain();


function getData() {
    source = audioCtx.createBufferSource();
    var request = new XMLHttpRequest();
    request.open('GET', './sample.wav', true);
    request.responseType = 'arraybuffer';
    request.onload = function() {
        var audioData = request.response;

        audioCtx.decodeAudioData(audioData, function(buffer) {
                source.buffer = buffer;
                source.connect(gainNode);
                gainNode.connect(audioCtx.destination);
                gainNode.gain.setValueAtTime(1, audioCtx.currentTime);
            },

            function(e) {
                console.log("Error with decoding audio data" + e.err);
            });
    }
    request.send();
}


play.onclick = function() {
    getData();
    source.start(0);
    play.setAttribute('disabled', 'disabled');
}

stop.onclick = function() {
    gainNode.gain.setValueAtTime(gainNode.gain.value, audioCtx.currentTime);
    gainNode.gain.exponentialRampToValueAtTime(0.0001, audioCtx.currentTime + 1);
    setTimeout(function() {
        source.stop();
    }, 1000)
    play.removeAttribute('disabled');
}
</script>
like image 51
Marco Avatar answered Oct 25 '25 12:10

Marco



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!