0

The code below (also live here) seems to demonstrate inconsistent performance from setTargetAtTime... it "should" swell to maximum at 2 seconds, then fade to silence at 7 seconds, then terminate the oscillator at 12 seconds (safely quiet enough to avoid "the ugly click".)

Instead, it swells to maximum at 2 seconds, then begins a fade which is not finished yet at 12 seconds, at which point we do hear the ugly click.

Can anyone explain why this is happening? Note that a short value (the commented //0.3) drops it quickly enough to avoid the click. I've tried this in a variety of contexts, and it seems as if, (when fading to 0 anyway) that third parameter stretches out proportionally further beyond the proper stop time as the value rises.

<button id = "button" >
Start then stop oscillators
</button>

<script>
var audioContext = new AudioContext();
var fadeIn = 2;
var fadeOut = 5; //0.3
var gainNode = audioContext.createGain();
var osc = audioContext.createOscillator();
osc.type = "sine";
osc.frequency.value = 300;
osc.connect(gainNode);
gainNode.gain.value = 0;
gainNode.connect(audioContext.destination);

function startAndStop() {
    osc.start(audioContext.currentTime);
    gainNode.gain.setTargetAtTime(1, audioContext.currentTime, fadeIn);    
    gainNode.gain.setTargetAtTime(0, audioContext.currentTime + fadeIn, fadeOut);
    osc.stop(audioContext.currentTime + fadeIn + fadeOut + 5);
};

var button = document.getElementById("button");
button.addEventListener("click", startAndStop);

</script>
drenl
  • 1,321
  • 4
  • 18
  • 32
  • See [Web audio api, stop sound gracefully](https://stackoverflow.com/questions/41511541/web-audio-api-stop-sound-gracefully) – guest271314 Oct 25 '17 at 02:54

1 Answers1

1

Third parameter of setTargetAtTime is not a time parameter, so no, it should not swell to maximum at 2 seconds, then fade to silence at 7 seconds, then terminate the oscillator at 12 seconds.

This parameter sets the exponential decay rate for which the value will change.

So a value of 5 will create a very slow decay, so slow that it won't have finished when your reach t'.

The timing should be done in the second parameter.

Fixing your code by using fixed decay rate of 0.5 removes the click:

var audioContext = new AudioContext();

var fadeIn = 2;
var fadeOut = 5;

var gainNode = audioContext.createGain();
var osc = audioContext.createOscillator();
osc.type = "sine";
osc.frequency.value = 300;
osc.connect(gainNode);
gainNode.gain.value = 0;
gainNode.connect(audioContext.destination);

function startAndStop() {
  osc.start(audioContext.currentTime);
  gainNode.gain.setTargetAtTime(1, audioContext.currentTime + fadeIn, 0.5);
  gainNode.gain.setTargetAtTime(0, audioContext.currentTime + fadeOut, 0.5);
  osc.stop(audioContext.currentTime + fadeIn + fadeOut + 5);
};

var button = document.getElementById("button");
button.addEventListener("click", startAndStop);
<button id="button">
Start then stop oscillators
</button>

But indeed, you seem to want to use linearRampValueAtTime instead of setTargetAtTime.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • 1
    Yes! Ok, great this makes much more sense. The third parameter seems to "stretch out proportionally" because that is exactly what it is doing. Next time I will remember to check the Moz documentation rather my my references/tutorials for the behavior of functions. Thank you! – drenl Oct 25 '17 at 15:21