This project has moved and is read-only. For the latest updates, please go here.

Gapless playback

Jul 7, 2014 at 5:54 PM

Is it possible to remove little gaps between different audio tracks?

Currently, when one track ends and PlaybackStopped event fires to load and play new track, there is little (under one second) gap between two tracks. Can I avoid this somehow?

Tracks itself does not contain any silence. If I play them with eg. foobar2000, there is no gaps.

Jul 16, 2014 at 5:42 AM
Edited Jul 16, 2014 at 5:44 AM
I am not sure whether NAudio supports gapless playback or not but achieving gapless playback is very tricky and depends on the two consecutive tracks.

I have struggled with the gapless playback 7 yeas back and it seems true gapless is only possible if the two tracks are compatible are directshhow filter graphlevel. If the same filtergraph is able to play the consecutive tracks then only the true gapless can be achieved else not (which is seldom the case of audio tracks).

The workaround I had to put to overcome this is to start the next track 1 second(could vary for you) prior to the finish of first track. TO do this we need to have two instances of actual player engine and use them for alternate tracks. I was able to achieve the gapless using this trick. It was like cheating the ears. the only problem I had was when I was testing with sine wave. the sine wave can clearly bring this workaround to surface.

P.S. This question reminded me of the good time I had developing that audio product. Those sleepless nights and constant fights with memory leaks.
Jul 16, 2014 at 3:12 PM

If you are waiting for the PlaybackStopped event, you're waiting too long... :)

To do gapless playback, an audio player has to be "ready" with the next file before the current file finishes. That means it will load the next file and pre-decode the first buffer of audio from it some time before the end of the current file (figure out how much time your code needs, then double it; 3 seconds is probably enough for most).

You'll need to put logic in your IWaveProvider.Read(byte[], int, int) implementation to make the switch happen... Mostly it would be just marking that the current file is now the previous file (and needs unloading), marking that the next file is now the current file, and telling the UI that the switch has happened and that it needs to update. If you pre-decode the first buffer-full of audio, you'll have quite a few milliseconds to handle that before running up against the latency limit...

One other item to consider: Even if you don't overlap the tracks, you will probably still want to implement cross-fading so you can do a very quick (< 3ms total) fade-out and fade-in so you don't get a "pop" between tracks... Since it is so quick, most people won't even hear it, and even if they do it shouldn't be unpleasant.

Please note: In this design, PlaybackStopped only gets raised when a track ends and no "Next Track" is available to load & play. You can still handle it, but now it's a true "done playing" event rather than "the track is over".