Search code examples
javascriptweb-audio-api

Web Audio API: Why can you only start sources once?


Suppose you use the Web Audio API to play a pure tone:

ctx = new AudioContext();
src = ctx.createOscillator();
src.frequency = 261.63; //Play middle C
src.connect(ctx.destination);
src.start();

But, later on you decide you want to stop the sound:

src.stop();

From this point on, src is now completely useless; if you try to start it again, you get:

src.start()
VM564:1 Uncaught DOMException: Failed to execute 'start' on 'AudioScheduledSourceNode': cannot call start more than once.
    at <anonymous>:1:5

If you were making, say, a little online keyboard, you're constantly turning notes on and off. It seems really clunky to remove the old object from the audio nodes graph, create a brand new object, and connect() it into the graph, (and then discard the object later) when it would be simpler to just turn it on and off when needed.

Is there some important reason the Web Audio API does things like this? Or is there some cleaner way of restarting an audio source?


Solution

  • Use connect() and disconnect(). You can then change the values of any AudioNode to change the sound, for example here, repeated mouseover events increase the frequency.

    (The button is because AudioContext requires a user action to run in Snippet.)

    play = () => {
    d.addEventListener('mouseover',()=>{src.connect(ctx.destination);src.frequency.value+=10;});
    d.addEventListener('mouseout',()=>src.disconnect(ctx.destination));
    ctx = new AudioContext();
    src = ctx.createOscillator();
    src.frequency.value = 261.63; //Play middle C
    src.start();
    }
    div {
    height:32px;
    width:32px;
    background-color:red
    }
    div:hover {
    background-color:green
    }
    <button onclick='play();this.disabled=true;'>play</button>
    <div id='d'></div>