Бесшовная звуковая петля в произвольное положение

Одна из вещей, которые мне больше всего нравятся в формате MOD, - это способность возвращаться к любой заданной точке песни, делая ее идеальной для песен, которые имеют "enter", а затем "основной цикл".

Конечно, MP3 не может этого сделать.

До сих пор я делал такие вещи:

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

Где значение float - это время начала основного цикла.

В то время как это работает, есть заметная доля секунды, когда звук перезапускается. Я могу уменьшить эффект этой паузы, установив целевое время немного впереди, где это должно быть, поэтому биты, по крайней мере, со временем приближаются, однако это не идеально.

Главной альтернативой, о которой я могу думать, является ручная запись аудиофайла (например, в Audacity путем копирования) для создания песни, которая больше, чем она, скорее всего, понадобится, но проблема заключается в том, что это привело бы к большому количеству потраченного впустую места на жестком диске и пропускной способности, и это не решило бы проблему людей, любящих песню, и прекратить слушать ее в течение длительного времени.

Так что мне было интересно, есть ли способ спеть поток MP3. Если я правильно понимаю формат, я должен быть в состоянии определить, в какой позиции в файле (в байтах) начинается основной цикл (в секундах), поэтому теоретически я мог бы построить поток, который циклически бесконечно. Однако будет ли такой поток поддерживаться с помощью HTM5 audio?

Ответ 1

Пробуйте измерять задержку каждый раз:

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);

Это было лучше, но не совсем точно, поэтому мне нужно настроить * 2.35 или сделать его вычитанием или чем-то.