javascriptweb-audio-apijavascript-oscillator

(Web Audio API) Oscillator node error: cannot call start more than once


When I start my oscillator, stop it, and then start it again; I get the following error:

Uncaught InvalidStateError: Failed to execute 'start' on 'OscillatorNode': cannot call start more than once.

Obviously I could use gain to "stop" the audio but that strikes me as poor practice. What's a more efficient way of stopping the oscillator while being able to start it again?

var ctx = new AudioContext();
var osc = ctx.createOscillator();

osc.frequency.value = 440;
osc.connect(ctx.destination);

function startOsc(bool = true) {
  if (bool) {
    osc.start(ctx.currentTime);
  } else {
    osc.stop(ctx.currentTime);
  }
}

document.getElementById("start").addEventListener(`click`, () => startOsc(true));
document.getElementById("stop").addEventListener(`click`, () => startOsc(false));
Warning: this will play at full volume!
<button id="start">start</button>
<button id="stop">stop</button>

The best I could come up with was to rebuild new oscillators every time I need it to play and removing them on stop:

var ctx = new AudioContext();
var osc = ctx.createOscillator();

osc.frequency.value = 440;
osc.connect(ctx.destination);

function startOsc(bool = true) {
  if (bool) {
    osc = ctx.createOscillator();
    osc.frequency.value = 440;
    osc.start(ctx.currentTime);
    osc.connect(ctx.destination);
  } else {
    osc.stop(ctx.currentTime);
    osc.disconnect(ctx.destination);
    osc = null;
  }
}

document.getElementById("start").addEventListener(`click`, () => startOsc(true));
document.getElementById("stop").addEventListener(`click`, () => startOsc(false));
Warning: this will play at full volume!
<button id="start">start</button>
<button id="stop">stop</button>


Solution

  • A better way would be to start the oscillatorNode once and connect/disconnect the oscillatorNode from the graph when needed, ie :

    var ctx = new AudioContext();
    var osc = ctx.createOscillator();   
    osc.frequency.value = 8000;    
    osc.start();    
    $(document).ready(function() {
        $("#start").click(function() {
             osc.connect(ctx.destination);
        });
        $("#stop").click(function() {
             osc.disconnect(ctx.destination);
        });
    });
    

    This how muting in done in muting the thermin (mozilla web audio api documentation)