Play Sounds Sequentially in Howler.js

Playing audio files in a specific order is a common requirement in game development, interactive storytelling, and web audio applications. This article provides a straightforward guide on how to create a sequence of sounds to play one after another using the howler.js library. You will learn how to use the library’s built-in event listeners—specifically the onend callback—to chain multiple audio tracks together seamlessly.

While howler.js does not have a built-in playlist queue feature, you can easily implement sequential playback using a recursive function and an array of audio sources.

Step 1: Define Your Sound Queue

First, create an array containing the file paths of the audio tracks you want to play in sequence. You also need a variable to keep track of the current active index.

const audioQueue = [
  'audio/sound1.mp3',
  'audio/sound2.mp3',
  'audio/sound3.mp3'
];

let currentIndex = 0;

Step 2: Create the Playback Function

Next, write a function that instantiates a Howl object for the current sound. The key to making the sounds play sequentially is the onend callback. When the current sound finishes playing, the onend event triggers, increments the index, and calls the playback function again.

function playSequence() {
  // Check if we have reached the end of the sequence
  if (currentIndex >= audioQueue.length) {
    console.log("Sequence finished.");
    return;
  }

  // Initialize the Howl instance for the current sound
  const sound = new Howl({
    src: [audioQueue[currentIndex]],
    autoplay: false,
    onend: function() {
      // Move to the next sound and play it
      currentIndex++;
      playSequence();
    },
    onloaderror: function(id, error) {
      console.error("Error loading sound: ", error);
      // Optionally skip to the next sound if one fails to load
      currentIndex++;
      playSequence();
    }
  });

  // Play the sound
  sound.play();
}

Step 3: Start the Sequence

To begin playing your sequence, simply call the function. Because browser autoplay policies usually prevent audio from playing without user interaction, you should trigger this function via a user event like a button click.

const playButton = document.getElementById('start-sequence-btn');

playButton.addEventListener('click', () => {
  // Reset index in case the sequence is being replayed
  currentIndex = 0; 
  playSequence();
});

Optimizing Transition Latency

Creating a new Howl instance on the fly can sometimes introduce a small delay between tracks while the browser loads the next file. If gapless playback is critical for your project, you can preload all Howl instances in an array beforehand, and then chain their playback using the same onend logic:

const playlist = [
  new Howl({ src: ['audio/sound1.mp3'] }),
  new Howl({ src: ['audio/sound2.mp3'] }),
  new Howl({ src: ['audio/sound3.mp3'] })
];

let activeIndex = 0;

function playPreloadedSequence() {
  if (activeIndex >= playlist.length) return;

  const currentSound = playlist[activeIndex];

  currentSound.once('end', () => {
    activeIndex++;
    playPreloadedSequence();
  });

  currentSound.play();
}