2

我有一首歌曲的几首曲目,我想一起播放,并且能够将一些曲目静音并播放其他曲目。所以我需要能够同时启动它们。现在,它们都开始有点不同步:

// Start playing
for ( i = 0; i < 5; i++ ) {
    tracks[i].audio.play();
}

即使这显然还不足以同时启动它们。

javascript中有什么方法可以保证HTML5音频标签将同时开始播放吗?

4

3 回答 3

2

不确定您是否已经这样做了,但这里有一些用于预加载音频的示例代码。

var audios = [];
var loading = 0;
AddNote("2C");
AddNote("2E");
AddNote("2G");
AddNote("3C");

function AddNote(name) {
    loading++;
    var audio = document.createElement("audio");
    audio.loop = true;
    audio.addEventListener("canplaythrough", function () {
        loading--;
        if (loading == 0) // All files are preloaded
            StartPlayingAll();
        }, false);
    audio.src = "piano/" + name + ".mp3";
    audios.push(audio);
}

function StartPlayingAll() {
    for (var i = 0; i < audios.length; i++)
        audios[i].play();
    }
}

您可以尝试的另一件事是audio.currentTime在每个轨道上设置手动同步音频。

于 2012-04-30T02:34:25.483 回答
0

您可以在开始的短暂延迟后使用 setTimeout 同步它们(尽管您可能希望等待所有音频对象加载)。

JSFiddle:http: //jsfiddle.net/bmAYb/35/

var au1 = document.getElementById('au1');
var au2 = document.getElementById('au2');
au1.volume = 1;
au2.volume = 0; //mute
au1.play();
au2.play();
var notfirstRun = false;
//sync for the first time
setTimeout(function() {
    au2.currentTime = au1.currentTime;
    au2.volume = 1;
}, 250);

我最初的想法是使用 setInterval 每 x 毫秒同步一次,但是当你这样做时,如果volume设置为1(可听),音频就会弹出。

我的小提琴并不完全同步,但非常接近。您可以使其 100% 同步,但您需要将其他轨道上的音频静音或处理爆音。

代码(和小提琴中的音乐)来自Hungry Media

于 2012-04-30T03:28:35.160 回答
0

我遇到了同样的问题,并找到了使用Audio API的解决方案。

问题是音频输出有几毫秒的延迟,所以不可能同时启动多个音频。但是,您可以通过使用ChannelMergerNode将音频源合并为一个来解决此问题。通过将GainNode放在两者之间,您可以分别控制每个音频源的音量。

我为此编写了一个简单的 javascript 类。这是您可以使用它的方式:

var audioMerger = new AudioMerger(["file1.ogg", "file2.mp3", "file3.mp3",
                                   "file4.ogg", "file5.mp3"]);
audioMerger.onBuffered(() => audioMerger.play());

// Make sure it's always in sync (delay should be less than 50 ms)
setInterval(() => {
  if (audioMerger.getDelay() >= 0.05) {
    audioMerger.setTime(audioMerger.getTime());
  }
}, 200);

// Set volume of 3rd audio to 50%
audioMerger.setVolume(0.5, 2);

// When you want to turn it off:
audioMerger.pause();

此代码在我的 PC 上的 Firefox 中将音频之间的延迟减少到不到 10 毫秒。这种延迟是如此之小,你不会注意到它。不幸的是,它不适用于 Internet Explorer 等较旧的浏览器。

这是该课程的代码:

class AudioMerger {
  constructor(files) {
    this.files = files;
    this.audios = files.map(file => new Audio(file));

    var AudioContext = window.AudioContext || window.webkitAudioContext;
    var ctx = new AudioContext();
    this.merger = ctx.createChannelMerger(this.audios.length);
    this.merger.connect(ctx.destination);

    this.gains = this.audios.map(audio => {
      var gain = ctx.createGain();
      var source = ctx.createMediaElementSource(audio);
      source.connect(gain);
      gain.connect(this.merger);
      return gain;
    });

    this.buffered = false;

    var load = files.length;
    this.audios.forEach(audio => {
      audio.addEventListener("canplaythrough", () => {
        load--;
        if (load === 0) {
          this.buffered = true;
          if (this.bufferCallback != null) this.bufferCallback();
        }
      });
    });
  }

  onBuffered(callback) {
    if (this.buffered) callback();
    else this.bufferCallback = callback;
  }

  play() {
    this.audios.forEach(audio => audio.play());
  }

  pause() {
    this.audios.forEach(audio => audio.pause());
  }

  getTime() {
    return this.audios[0].currentTime;
  }

  setTime(time) {
    this.audios.forEach(audio => audio.currentTime = time);
  }

  getDelay() {
    var times = [];
    for (var i = 0; i < this.audios.length; i++) {
      times.push(this.audios[i].currentTime);
    }

    var minTime = Math.min.apply(Math, times);
    var maxTime = Math.max.apply(Math, times);
    return maxTime - minTime;
  }

  setVolume(volume, audioID) {
    this.gains[audioID].gain.value = volume;
  }
}
于 2018-11-11T19:44:20.567 回答