Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web audio "Click" sound even when using exponentialRampToValueAtTime

I am trying to avoid having the ugly "click" sound when stopping an oscillator, so I decided to try some fade-outs with exponentialRampToValueAtTime. Like this:

var playButton = document.getElementById('play');
var stopButton = document.getElementById('stop');

var context = new AudioContext();
var gainNode = context.createGain();
var oscillator =  context.createOscillator();

gainNode.connect(context.destination);
oscillator.connect(gainNode);
gainNode.gain.setValueAtTime(1, context.currentTime);
oscillator.start();
gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 1);

This works well, there's no "click" sound and the ramp down is smooth. However, as soon as I do this using buttons and event listeners, the ugly click comes back and somehow the ramp down is more brute

btw, please wait 1 second after pressing "stop" and before re-pressing "play" or ugly things happen :)

var playButton = document.getElementById('play');
var stopButton = document.getElementById('stop');

var context = new AudioContext();
var gainNode = context.createGain();
var oscillator;

gainNode.connect(context.destination);


playButton.addEventListener('click', function() {
  oscillator = context.createOscillator();
  oscillator.connect(gainNode);
  gainNode.gain.setValueAtTime(1, context.currentTime);
  oscillator.start();
}, false);

stopButton.addEventListener('click', function() {
  gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 1);
  setTimeout(function(){
  	oscillator.stop();
  }, 1000)
}, false);
<button id="play">play</button>
<button id="stop">stop</button>

I'm clearly missing some theory here. The code is very similar except for the listeners and the outcome of both snippets is very different in quality. Can you please explain where that difference comes from?

Is there a way to achieve the first snippet quality while using buttons/listeners?

Thanks!

like image 675
alemangui Avatar asked Dec 26 '15 23:12

alemangui


1 Answers

The problem is that the ramp is done from the previously scheduled value, which in this case is when you pressed the play button. If you set the value once more before scheduling the ramp you'll get a smooth transition again!

var playButton = document.getElementById('play');
var stopButton = document.getElementById('stop');

var context = new AudioContext();
var gainNode = context.createGain();
var oscillator;

gainNode.connect(context.destination);


playButton.addEventListener('click', function() {
  oscillator = context.createOscillator();
  oscillator.connect(gainNode);
  gainNode.gain.setValueAtTime(1, context.currentTime);
  oscillator.start();
}, false);

stopButton.addEventListener('click', function() {
  gainNode.gain.setValueAtTime(gainNode.gain.value, context.currentTime);
  gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 1);
  setTimeout(function(){
  	oscillator.stop();
  }, 1000)
}, false);
<button id="play">play</button>
<button id="stop">stop</button>
like image 143
Oskar Eriksson Avatar answered Oct 17 '22 01:10

Oskar Eriksson