web-audio-apiaudiocontextaudiobuffer

How to skip ahead n seconds while playing track using web audio API?


Using Web Audio API, I'm trying to build an mp3 player with a "Skip ahead 15 seconds" feature.

I'm able to load an mp3 using a source buffer, and can get it to start playing. I want to do something like this, though I know currentTime is not a settable property:

context.currentTime += 15

How do you skip forward n seconds once the song is already playing?


Solution

  • Unfortunately there is no single API call to achieve the desired effect but it's doable. Every AudioBufferSourceNode can only be used once which is why we have to create a new one in order to change something.

    Let's imagine we have two variables coming from somewhere called audioContext and audioBuffer. In addition we define two more variables to store the initial startTime and the currently running AudioBufferSourceNode.

    let audioBufferSourceNode;
    let startTime;
    

    The first time we play the audioBuffer we play it directly from the start. The only special thing here is that we keep a reference to the audioBufferSourceNode and that we remember the startTime.

    audioBufferSourceNode = audioContext.createBufferSource();
    audioBufferSourceNode.buffer = audioBuffer;
    audioBufferSourceNode.connect(audioContext.destination);
    startTime = context.currentTime;
    audioBufferSourceNode.start(startTime);
    

    If you want to skip ahead some time later the previously started audioBufferSourceNode needs to be stopped first.

    const currentTime = context.currentTime;
    
    audioBufferSourceNode.stop(currentTime);
    audioBufferSourceNode.disconnect();
    

    In addition a new one needs to be created by reusing the same audioBuffer as before. The only difference here is that we apply an offset to make sure it skips 15 seconds ahead.

    audioBufferSourceNode = audioContext.createBufferSource();
    audioBufferSourceNode.buffer = audioBuffer;
    audioBufferSourceNode.connect(audioContext.destination);
    audioBufferSourceNode.start(currentTime, currentTime - startTime + 15);
    

    To be prepared to skip another time it's necessary to update the startTime.

    startTime -= 15;
    

    This is of course an oversimplified example. In reality there should be a check to make sure that there is enough audio data left to skip ahead. You could also apply a little fade-in/out when skipping to avoid click sounds. ... This is only meant to illustrate the general idea.