gapless.js

A gapless playback javascript library

gapless.js is a javascript library for playing back a queue of audio files without gaps between tracks. It was specifically designed to suit our needs in listening to recorded concerts over at https://relisten.net. It is driven by a state machine and is completely headless (you design and bring your own UI) as well as framework agnostic.

It is not intended to be a universal solution to all use-cases, but specifically to solve playing back concerts and similar “song”/“album”/“playlist” style playback.

This library is over a decade old at this point, though it was completely re-written from scratch in the past year. It takes inspiration from Gapless 5 by Rego Sen, who pioneered these techniques on the web. We wrote our own after we had slightly different use-cases and functionality requirements.

Here's a demo:

Plain <audio /> tags (non-library)Not gapless

Plain <audio>

play() the next file on ended

gap

Scarlet Begonias

Fire on the Mountain

0:00

gapless.jsGapless

gapless.js

Starts instantly over HTML5 Audio, then hands off to a decoded Web Audio buffer.

gapless

Scarlet Begonias

Not loaded

Fire on the Mountain

Not loaded

The next file is scheduled on the AudioContext clock to start on the exact sample the first one ends.

0:00 / 0:10

A complete gapless.js concert

A full set

Grateful Dead, Cornell University, May 8, 1977 — set one, eleven tracks.

New Minglewood Blues

1 / 11

0:00

–:––

Press play. Audio starts right away over HTML5 while tracks decode in the background.

Debug

queue=idle track=— output=— buffer=—

    Quick start

    import Queue from 'gapless';
    
    const player = new Queue({
      tracks: [
        'https://example.com/set1-01.mp3',
        'https://example.com/set1-02.mp3',
        'https://example.com/set1-03.mp3',
      ],
      onProgress: (track) => console.log(track.index, track.currentTime, track.duration),
      onEnded: () => console.log('Show over'),
    });
    
    // Call from a click handler. Browsers only allow audio after a user gesture.
    playButton.addEventListener('click', () => player.togglePlayPause());

    gapless.js preloads and decodes upcoming tracks in the background and starts each one on the exact sample the previous one ends. Bring your own UI. Read the full docs →