How to Detect the End of an Audio Loop in Howler.js
This article explains how to detect when a long audio loop completes
an iteration using howler.js. While howler.js handles seamless looping
automatically, tracking the exact moment a loop restarts requires
utilizing the library’s event system or monitoring playback positioning.
Below, you will find direct methods to capture this event using the
built-in end listener and a high-precision polling
alternative.
Method 1: Using the
Built-In end Event
The simplest way to detect when a loop finishes is by using the
onend callback or binding to the end event.
Even when the loop property is set to true,
howler.js fires the end event every time the audio track
reaches its conclusion and restarts.
const sound = new Howl({
src: ['long-ambient-loop.mp3'],
loop: true,
onend: function(soundId) {
console.log(`Loop finished playing for sound ID: ${soundId}`);
// Trigger your custom logic here (e.g., updating UI, incrementing a loop counter)
}
});
// Play the sound
sound.play();Alternatively, you can register the event listener after initializing the object:
sound.on('end', (id) => {
console.log('A loop iteration has ended.');
});Method 2:
High-Precision Detection Using Polling (seek)
For extremely long audio tracks, browser backgrounding or system
latency can occasionally cause event-firing delays. If you require
frame-perfect precision or want to trigger an event slightly
before the loop actually ends (to pre-load resources, for
example), you can poll the playback position using the
seek() method inside a request animation frame loop.
const sound = new Howl({
src: ['long-ambient-loop.mp3'],
loop: true
});
sound.play();
let lastPosition = 0;
function monitorPlayback() {
if (sound.playing()) {
const currentPosition = sound.seek();
const duration = sound.duration();
// If the current position is less than the last recorded position,
// the audio has looped back to the beginning.
if (currentPosition < lastPosition && lastPosition > 0) {
console.log('Loop detection triggered via position tracking.');
// Execute loop-end code here
}
lastPosition = currentPosition;
}
requestAnimationFrame(monitorPlayback);
}
// Start monitoring
requestAnimationFrame(monitorPlayback);Using either the built-in end event for standard use
cases or the seek() polling method for precise sync
requirements ensures you can reliably track loop iterations in your
application.