'Play multiple audio tracks sequentially, not simultaneously

I'm trying to use the <audio> tag, and I want to have as many tracks playing as I add. But now they play at the same time, can I somehow make them play sequentially?

<audio id="audio1" preload="" autoplay="" loop="" type="audio/mp3" src="music/mus1.mp3"></audio>
<audio id="audio2" preload="" autoplay="" loop="" type="audio/mp3" src="music/mus.mp3"></audio>

<div id="pp" style="cursor: pointer;" onclick="pVid();"><img src="img/heart.png"></div>

<script type="text/javascript">
function pVid() {
var audio1 = document.getElementById("audio1");
var audio2 = document.getElementById("audio2");

    audio1.paused ? audio1.play() : audio1.pause();
    audio2.paused ? audio2.play() : audio2.pause();
}
</script>

I found one solution, it works but not the way I want

var sounds = new Array(new Audio("music/mus1.mp3"), new Audio("music/mus.mp3"));
var i = -1;
pVid();

function pVid() {
    i++;
    if (i == sounds.length) return;
    sounds[i].addEventListener('ended', pVid);
    sounds[i].play();
}

Here everything just plays right away, but I want to be able to play the tracks myself through the button and pause at any time. This is done in the first version, but there all the tracks play at the same time



Solution 1:[1]

I don't know why no one mentioned the onended event

<audio id="aud1" onended="playaud2()" src="whatever.mp3"> <!--first audio-->
<audio id="aud2" src="whatever.mp3"> <!--second audio-->
<script>
//the onended event calls a function when the audio finishes playing
function playaud2() {
document.getElementById("aud2").play()}
</script>

As simple :)

Solution 2:[2]

Audio files

For testing, I used a few free sound-effects audio files from https://www.freesoundeffects.com.

To make it work in all browsers it is recommended by w3c to use the <audio>-tag with <source> tags.

Solution

I added some arbitrary sound files and buttons. The buttons will reset all the audios that are currently playing then play the sounds in the data-track attributes.

data-track syntax:

track-a                   // will play track a
track-a;track-b           // will play track a followed by track b
track-a+track-b           // will play track a and b simultaniously
track-a+track-b;track-c   // as above but add track c to the end

You could do something like this:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <style type="text/css">
    audio {
      display: block;
    }
  </style>
  <script defer type="application/javascript">
    let activeTimeout;

    function init(player) {
      player.innerHTML = `play ${player.dataset.label}`;
      player.addEventListener('click', clickHandler);
    }

    function reset(audio) {
      clearTimeout(activeTimeout);
      audio.pause();
      audio.currentTime = 0;
    }

    function dequeue(tracks) {
      console.log("Queue:", tracks);
      if (tracks.length >= 1) {
        const track = tracks.pop();
        const multiTrack = track.split('+');
        let maxDuration = 0;
        multiTrack.forEach((it) => {
          const audio = document.querySelector(`[data-audio="${it}"]`);
          maxDuration = Math.max(maxDuration, audio.duration);
          audio.play();
        });
        activeTimeout = setTimeout(() => {
          dequeue(tracks);
        }, maxDuration * 1000);
      }
    }

    function clickHandler(e) {
      const allAudios = document.querySelectorAll('[data-audio]');
      const trackAttr = this.dataset.track;
      const tracks = trackAttr.split(';');
      if (tracks) {
        allAudios.forEach(reset);
        dequeue(tracks.reverse()); // reverse to make the pop-operations faster
      } else {
        console.log('No track defined!');
      }
    }

    window.addEventListener('load', function() {
      const players = document.querySelectorAll('[data-player]');
      players.forEach((it) => init(it));
    });
  </script>
</head>

<body>
  <audio data-audio="applause" controls="controls" preload="preload">
          <source src="https://www.freesoundeffects.com/files/mp3_426807.mp3" type="audio/mp3"></source><!-- replace with your audio file -->
        </audio>
  <audio data-audio="bark" controls="controls" preload="preload">
          <source src="https://www.freesoundeffects.com/files/mp3_89478.mp3" type="audio/mp3"></source><!-- replace with your audio file -->
        </audio>
  <audio data-audio="chirp" controls="controls" preload="preload">
          <source src="https://www.freesoundeffects.com/files/mp3_89489.mp3" type="audio/mp3"></source><!-- replace with your audio file -->
        </audio>

  <button data-player data-label="bark!" data-track="bark" />
  <button data-player data-label="chirp!" data-track="chirp" />
  <button data-player data-label="applause!" data-track="applause" />
  <button data-player data-label="applause then bark!" data-track="applause;bark" />
  <button data-player data-label="bark then chirp then bark again!" data-track="bark;chirp;bark" />
  <button data-player data-label="applause then chirp!" data-track="applause;chirp" />
  <button data-player data-label="applause with chirp then bark!" data-track="applause+chirp;bark" />
</body>

</html>

Solution 3:[3]

Yes, you can check if you have an element with a simple truthy/falsy check:

if (!slider) return;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shiven Dhir
Solution 2
Solution 3 DJones