JS:加载时同时播放多个音频源

JS: play multiple audio sources simultaneously when loaded

我有一个包含三个音频源的 Web 项目(仅限香草 HTML/CSS/JS)。想法是让所有三个同时播放,但我注意到在移动设备上文件播放不同步(即一个源开始,然后几毫秒后第二个开始,然后是第三个)。我相信它们正在播放是因为单个文件在加载后立即播放,所以我想请求一旦所有文件都加载完毕,同时对所有三个文件调用 play() 方法,

使用 vanilla JS 实现此目的的最佳方法是什么?

示例:https://jacksorjacksor.xyz/soundblocks/

回购:https://github.com/jacksorjacksor/jacksorjacksor/tree/master/soundblocks

TIA!

富有

MediaElements 用于媒体的正常播放,并没有优化到足以获得低延迟。最好是使用 Web Audio API, and AudioBuffers.

您将首先在内存中获取文件数据,然后从中解码音频数据,一旦所有音频数据都已解码,您就可以安排在同一精确时刻播放所有内容:

(async() => {
  const urls = [ "layer1_big.mp3", "layer2_big.mp3", "layer3_big.mp3" ]
    .map( (url) => "https://cdn.jsdelivr.net/gh/jacksorjacksor/jacksorjacksor/soundblocks/audio/" + url );
  // first, fetch the files's data
  const data_buffers = await Promise.all(
    urls.map( (url) => fetch( url ).then( (res) => res.arrayBuffer() ) )
  );
  // get our AudioContext
  const context = new (window.AudioContext || window.webkitAduioContext)();
  // decode the data
  const audio_buffers = await Promise.all(
    data_buffers.map( (buf) => context.decodeAudioData( buf ) )
  );
  // to enable the AudioContext we need to handle an user-gesture
  const btn = document.querySelector( "button" );
  btn.onclick = (evt) => {
    const current_time = context.currentTime;
    audio_buffers.forEach( (buf) => {
      // a buffer source is a really small object
      // don't be afraid of creating and throwing it
      const source = context.createBufferSource();
      // we only connect the decoded data, it's not copied
      source.buffer = buf;
      // in order to make some noise
      source.connect( context.destination );
      // make it loop?
      //source.loop = true;
      // start them all 0.5s after we began, so we're sure they're in sync
      source.start( current_time + 0.5 );
    } );
  };
  btn.disabled = false;
})();
<button disabled>play</button>