martpie / museeks

🎵 A simple, clean and cross-platform music player
https://museeks.io
MIT License
1.7k stars 200 forks source link

Gapless playback #31

Open martpie opened 9 years ago

martpie commented 9 years ago

What

Currently, when a song is over, the src of the audio tag is changed, but the tag has to preload the file a bit. So there is a micro interruption of a few miliseconds.

How

~Instead of having a single Audio object, need to have an array of 3: [previous, current, next]. Then when playing next or previous, it should be faster, cause tracks will already be loaded + Pop/Shift audio when needed.~ not working :[

martpie commented 8 years ago

This could be done by using an array of Audio objects, less dirty than only two audio tags

martpie commented 8 years ago

I might consider a switch to Web Audio API instead of the current Audio element implementation. Might be a first step to #114

YurySolovyov commented 8 years ago

I wonder if it is enough to have 2 elements - current + next. We can start playing audio on next element, and when current track is over, we just swap pointers, to next becomes new current and we allocate a new next.

martpie commented 8 years ago

The problem is the next sont can be the previous one. I've done some test, and there's still a microcut between the ended event and the next track play start. As mentioned, I think I'll switch to the Web Audio API with an AudioContext, but it's a huge work, and I don't know well this API.

YurySolovyov commented 8 years ago

The problem is the next song can be the previous one.

I still don't quite get why this is a problem.

there's still a microcut between the ended event and the next track play start

As I understand, if we have say 1000ms overlap/crossfading duration, we should not worry about these conks of microcuts, because transition period is still much longer.

martpie commented 8 years ago

I still don't quite get why this is a problem

You need to preload three songs: the current one, the next one, and the previous one. If they are preloaded, then the microcute should be smaller.

As I understand, if we have say 1000ms overlap/crossfading duration, we should not worry about these conks of microcuts, because transition period is still much longer.

Yes sure, but what if there is a 0ms crossfade (the user will be able to choose a value), there would still be one ;)

martpie commented 5 years ago

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/audioTracks

Trough an experimental flag though :/

DrEVILish commented 5 years ago

Could you not have an array var nowPlaying = ['previous','current','next'] of which you can nowPlaying.shift() the first element out, once the current song has finished playing. nowPlaying.push(nextTrack)the next song to play onto the end of the array.

This should always leave the previous track as nowPlaying[0], Current playing as nowPlaying[1] and next track nowPlaying[2].

probably won't work knowing me :D

martpie commented 5 years ago

I tried it, the result is unfortunately the same, there's still a mini-gap :(

DrEVILish commented 5 years ago

I tried it, the result is unfortunately the same, there's still a mini-gap :(

I'd not realised the mini-gap before :( just played War of the Worlds and there it was...

DrEVILish commented 5 years ago

A gapless JavaScript/CSS audio player for HTML5

PROBLEM: There are 2 modern APIs for playing audio through the web, and both of them have problems:

SOLUTION: Use both!

http://github.com/regosen/Gapless-5 Might be able to replace the whole player engine with a single JS app. Designed for browser-based usage.

DrEVILish commented 5 years ago

Just tested this in chrome and the gap is still there but it's a lot lot smaller. It still does this weird click.

DrEVILish commented 5 years ago

This project looks interesting: https://github.com/astoeckel/opus_gapless/ which is bundled into https://github.com/astoeckel/http_audio_server

It currently triggers an FFmpeg process upon a single audio file and streams it into OPUS blocks.

https://somweyr.de/opus/demo.html -> Demo of actual different tracks being played back gaplessly.

Using the Electron client purely as an Open stream connected to an application that pulls each file and blockifys each file into a folder, this means the process can become multithreaded transcoding the previous. Each block can be continually streamed out to the client one after the other. As each block would have a crossfade between it and the previous one, we can have that as a client setting that would set the size of the overlap of each block.

If each block contains only 2seconds worth of data could a crossfade be longer than the length of a block?

martpie commented 5 years ago

https://lists.w3.org/Archives/Public/www-archive/2014Oct/0007.html http://www.htmlfivewow.com/slide58

s0 commented 4 years ago

I've been playing around with the WebAudio API in Musseks for a slightly different reason (accurate timestamps for synchronizing audio with lighting with my synesthesia project), which it turned out the HTML <audio> tag was insufficient for (see https://github.com/synesthesia-project/synesthesia/tree/master/precise-audio). I'd be willing to attempt implementing gapless playback in Museeks using web audio, though I cannot provide a timescale.

s0 commented 4 years ago

This is also a useful article: http://dalecurtis.github.io/llama-demo/index.html

martpie commented 4 years ago

@s0 great to hear! #128 is a blocker for that though. I really want to solve this so I will try to find myself some time to work on AudioContext.

I would also like to try https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/audioTracks as maybe Gapless playback comes baked in.

s0 commented 4 years ago

Made progress with updating my precise-audio library for gapless playback with a small POC in the browser. Seems to work relatively well in chrome when playing LAME encoded MP3 files:

After I've tightened up the library a bit more, I'll work on pulling the functionality into museeks, and hopefully open a PR soon.