goldfire / howler.js

Javascript audio library for the modern web.
https://howlerjs.com
MIT License
23.91k stars 2.23k forks source link

Perfect synchronization with multiple audios #672

Open JoanIzquierdo opened 7 years ago

JoanIzquierdo commented 7 years ago

Is it possible to synchronize several sounds mp3/ogg? .. for example, if I have a song and each instrument in a different file. So, I want to make a player for this song but selecting which instrument should sound.

Thanks

nunoh commented 7 years ago

Also run into howler.js precisely because of the same use case. When I saw in the README:

Control sounds individually, in groups or globally Playback of multiple sounds at once

I thought my problem was solved. I am at the moment though still trying to figure out the Howl (group) api, that I suppose (and hope) will allow me to do that. Doesn't seem to be any documentation on that anywhere on the website... But maybe I'm missing something rather obvious.

@JoanIzquierdo, have you had any luck figuring that out by now by any chance? Cheers.

goldfire commented 7 years ago

You would create a different Howl for each audio file. You can then independently change volume, mute, etc each "instrument" with each Howl. You could also do this with a single sound sprite and keep track of the sound ID that is returned from play(). Am I misunderstanding the question?

nunoh commented 7 years ago

Hey @goldfire, thanks for offering some help here. Really appreciate it.

I have tried exactly that, something like:

function playAll() {
  var sound1 = new Howl({
    src: ['mp3/guitar.mp3'],
    preload: true
  });
  var sound2 = new Howl({
    src: ['mp3/vocals.mp3'],
    preload: true
  });
  var sound3 = new Howl({
    src: ['mp3/drums.mp3'],
    preload: true
  });
  sound1.play()
  sound2.play()
  sound3.play()
}

which then I trigger on the simple onclick event of a button. Just like when using the plain audio element (without Howler.js) I get correctly syncronized audio between all three tracks in both Chrome and Firefox, but in Safari it gets out of sync. In Safari, I can see that .usingWebAudio is set to true.

So I guess the more clear question is: Is there any way with Howler.js to get correctly synced audio between all three tracks at the same time in all major browsers including Safari?

goldfire commented 7 years ago

The loading won't start until you have created the new Howl, so based on your example I would guess it is because they didn't all load and start playing at the exact same instant.

nunoh commented 7 years ago

Geez, that was rather a silly mistake on my end. Pulling the new Howl calls to when the DOM loads made it work in Safari with no problem.

Thanks for the time and help @goldfire, and the lib too of course!

@JoanIzquierdo You might want to look into the snippet I have in my previous comment, which I think will help you solve what you were trying to accomplish. Just remember to pull the new Howl out and not couple it with UI interaction.

goldfire commented 7 years ago

No problem! Always seems like the smallest things cause the biggest headaches when debugging :)

JoanIzquierdo commented 7 years ago

Thanks @nunoh and @goldfire for your comments. I will check

jeffamcavoy commented 1 year ago

Assuming I have loaded all of my Howls first, would adding 8 .play() commands in a row start all 8 audio files at the same exact time? Or, is there a way to combine them all to make sure they're in perfect sync?

I'm noticing some slight delays in a file or two on occasion and would love to eliminate them.

Achuttarsing commented 1 year ago

I have the same issue. Does anyone know how to proceed ?

bananu7 commented 1 year ago

This doesn't seem to be possible in principle with the HTML5 audio elements. There's just no way to consistently

I've been looking for a solution utilizing WebAudio but even there if you add the audio element as a node, playback is still controlled on the element side. There are ways, supposedly, to fill up a processing node's buffer with the samples obtained from playback, but I'm not sure how that'd work with seeking.

Seems that the only way to get streamed (i.e. not loading the entire, potentially large file at once) playback of multiple sources in sync is to, unfortunately, manually download them in chunks and decode on a worker thread, construct WebAudio buffers and feed them to playback. This means that the decoder must be implemented in the user code, as there seem to be no way currently to use browser's builtin codecs that way.

The promising upcoming solution to this is https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API, which would effectively replace that hand-written worker with a browser-provided implementation with parametrizable fetching behavior.

For an example of a hand-written implementation working with Opus, see https://github.com/AnthumChris/fetch-stream-audio