Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Seamless audio loop to an arbitrary position

One of the things I most love about the MOD format is the ability to loop back to any given point in the song, making it perfect for songs that have an "intro" followed by a "main loop".

Of course, MP3 can't do this.

Up until now, I've done things like this:

<audio src="/path/to/song.mp3" onEnded="this.currentTime = 12.345;"></audio>

Where the float value is the time at which the main loop starts.

While this works there is a noticeable fraction-of-a-second pause as the audio restarts. I can lessen the effect of this pause by setting the target time a little ahead of where it should be, so the beats are at least kept closer in time, however it's not really ideal.

The main alternative I can think of is to manually loop the audio file (eg. in Audacity by copy-pasting) to produce a song that is longer than it would most likely be needed for, but the problem with that is that it would result in a lot of wasted hard drive space and bandwidth, and it wouldn't solve the problem of people liking a song and stopping to listen to it for a long time.

So I was wondering if there's any way to loop an MP3 stream. If I understand the format correctly, I should be able to determine at what position in the file (in bytes) the main loop starts (in seconds), so in theory I could construct a stream that loops indefinitely. However, would such a stream be supported by HTM5 audio?

like image 739
Niet the Dark Absol Avatar asked Jun 17 '13 16:06

Niet the Dark Absol


1 Answers

Try measuring the delay each time:

function playSeamless(clip, next) {
    if(!next) {
        next = clip.cloneNode(true);
        next.controls = false;
    }

    var start = Date.now();
    clip.play();

    setTimeout(function() {
        var time = (Date.now() - start) / 1000;
        var position = clip.currentTime;
        var delay = time - position;

        setTimeout(function() {
            // Set desired currentTime on next here and adjust delay above
            playSeamless(next, clip);
        }, (clip.duration - clip.currentTime - delay * 2.35) * 1000 | 0);
    }, 200);
}

playSeamless(yourAudioClip);

It was better, but not entirely accurate, so I need to adjust * 2.35 or make it a subtraction or something.

like image 120
Ry- Avatar answered Oct 21 '22 05:10

Ry-