依次播放多个音轨,而非同时播放。

3

我尝试使用<audio>标签,并且我想添加多个音轨,但现在它们会同时播放,我是否可以让它们以某种方式按顺序播放?

<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>

我找到了一个解决方案,它可以运行,但不是我想要的方式。
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();
}

这里一切都可以立即播放,但我希望能通过按钮自己播放曲目并随时暂停。这在第一个版本中已完成,但那里所有曲目都同时播放。


1
你不能只用 Promises 或 async/await 来完成吗? - F. Müller
@F.Müller 我不是很擅长JavaScript,所以我在寻求帮助。 - user17541419
会想出一些东西。 - F. Müller
4个回答

0

音频文件

为了测试,我使用了一些来自https://www.freesoundeffects.com的免费音效音频文件。

为了使它在所有浏览器中正常工作,W3C建议使用带有标签的

解决方案

我添加了一些任意的声音文件和按钮。这些按钮将重置当前正在播放的所有音频,然后播放data-track属性中的声音。

data-track语法:

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

你可以像这样做:

<!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>


0

我不知道为什么没有人提到onended事件

<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>

非常简单 :)


但是在ended上进行链接并不那么简单。它可以在非常简单的情况下工作。如果您动态初始化音频内容,它会变得棘手。想象一下,如果您只想播放audio1而不总是与audio2一起播放(提供两个选项),这将强制进行紧密耦合。 - F. Müller
@F.Müller 您说得对。但是,ch11确实说了他不太擅长这个。所以我想也许选择一些更简单的东西比较好,这样就不会让他/她感到困惑。显然,他/她可以在方便的时候添加其他内容。但就基本水平而言,我认为这样已经足够了。 PS.如果您认为这个方案基本可行,请随意点赞! - Sive

0

尽可能多地使用 音频事件。我们可以使用 freesound.org 进行测试。

let sounds = new Array(new Audio("https://freesound.org/data/previews/46/46992_514283-lq.mp3"),
  new Audio("https://freesound.org/data/previews/610/610823_13156161-lq.mp3"),
  new Audio("https://freesound.org/data/previews/92/92005_1499847-lq.mp3"), new Audio("https://freesound.org/data/previews/46/46992_514283-lq.mp3"),
  new Audio("https://freesound.org/data/previews/610/610823_13156161-lq.mp3"),
  new Audio("https://freesound.org/data/previews/92/92005_1499847-lq.mp3"));

let current = random(0);
let paused = true;

// set event handlers on all audio objects
for (let s of sounds) {
  s.addEventListener('ended', ended);
  s.addEventListener('play', play);
  s.addEventListener('pause', pause);
}

updateVolume()

// handle button click
function playPause() {
  if (paused) {
    sounds[current].play();
    btn.innerText = 'pause';
    paused = false;

  } else {
    sounds[current].pause();
    btn.innerText = 'play';
    paused = true;
  }
}

function ended(e) {
  document.getElementById(current + '').classList.remove('playing');
  document.getElementById(current + '').classList.remove('paused');
  /*i++;
  if (i >= sounds.length) //loop
    i = 0;
  */
  current = random(current); // shuffle

  paused = true;
  playPause();
}

function play() {
  document.getElementById(current + '').classList.add('playing');
  document.getElementById(current + '').classList.remove('paused');
}

function pause() {
  document.getElementById(current + '').classList.add('paused');
  document.getElementById(current + '').classList.remove('playing');
}

function random(i) {
  let next = i;
  while (next == i)
    next = Math.floor(Math.random() * sounds.length);
  return next;
}

function updateVolume() {
  for (let s of sounds) {
    s.volume = volume.value;
  }
}
#list {
  margin-top: 1rem;
  border: 1px solid gray;
  width: 100px;
}

#controls {
  position: fixed;
  right: 2rem;
  top: 1rem;
  width: 50px;
}

#volume {
  width: 150px;
  height: 20px;
  transform-origin: 75px 75px;
  transform: rotate(-90deg) translateY(50%);
}

.playing {
  background-color: lightblue;
}

.paused {
  background-color: wheat;
}
<Button id=btn onClick='playPause()'>play</Button>
<div id=list>
  <div id='0'>Guitar</div>
  <div id='1'>Drum</div>
  <div id='2'>Violin</div>
  <div id='3'>Guitar</div>
  <div id='4'>Drum</div>
  <div id='5'>Violin</div>
</div>
<div id=controls>
  <label for="volume">Volume</label><br>
  <input id=volume type="range" id="volume" name="volume" min="0" max="1" step='.1' value='.5' onInput='updateVolume()'>

</div>


谢谢,这正是我需要的)) 那么制作一个可以随机切换曲目的迷你播放器难吗? - user17541419
很简单。在 ended() 函数中,不要将索引递增,而是将随机数分配给它。请查看更新的答案。 - the Hutt
很酷,非常感谢,你是最棒的)) 最后一个问题,有没有可能调整一下声音?它播放得太响了。 - user17541419
我已经更新了答案。请参考HTMLMediaElement获取更多详细信息。 - the Hutt

-2

是的,您可以通过一个简单的真值/假值检查来检查是否有元素:

if (!slider) return;


2
什么是 slider - WOUNDEDStevenJones
@WOUNDEDStevenJones 未定义 ;) - F. Müller
“slider” 是标题中所提到的对象名称,但有人将其编辑删除了。 - K Scandrett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接