Хитрость заключается в том, чтобы увеличить счетчик в течение последних 0,25 с c продолжительности файла MP3 во время воспроизведения. Вам необходимо:
Зарегистрировать событие "timeupdate"
в теге <audio>
.
Получить время продолжительности файла MP3 с помощью свойство .duration
.
Отслеживание хода выполнения с помощью свойства .currentTime
.
Демонстрация
Примечание: Подробности прокомментированы в демоверсии
// Reference the <audio> tag
const mp3 = document.querySelector('audio');
// Reference the <form> tag
const ctrl = document.forms.controls;
// Collect all <output> and <button> into a HTML Collection
const ui = ctrl.elements;
// Define an external variable for a counter reference
let loops = 0;
/*
- Utility function to reset counter at a slight delay
*/
const counterReset = () => setTimeout(function() {
ui.counter.value = '0';
loops = 0;
}, 100);
/*
- Utility function to stop <audio> when playing
- There were multiple occurances of these 4 statements so
this was made for the sake of DRY
*/
const stopPlay = () => {
ui.playback.classList.add('play');
ui.playback.classList.remove('pause');
mp3.pause();
mp3.currentTime = 0;
};
/*
- <audio> registered to the "timeupdate" event which is
fired when playing at the frequenncy of 4 times a second
- So every 250ms event handler function countLoop is
called during playback
*/
mp3.ontimeupdate = countLoop;
// <form> is registered to "click" and "reset" events
ctrl.onclick = playLoop;
ctrl.onreset = resetLoop;
// Click handler for <form>
function playLoop(event) {
const clicked = event.target;
let cmd = clicked.className;
switch (cmd) {
case 'play':
clicked.classList.remove('play');
clicked.classList.add('pause');
mp3.play();
break;
case 'pause':
clicked.classList.add('play');
clicked.classList.remove('pause');
mp3.pause();
break;
case 'loop':
clicked.classList.add('once');
clicked.classList.remove('loop');
mp3.loop = true;
stopPlay();
counterReset();
break;
case 'once':
clicked.classList.add('loop');
clicked.classList.remove('once');
mp3.loop = false;
stopPlay();
counterReset();
break;
default:
break;
}
}
// Timeupdate handler for <audio>
function countLoop(event) {
// Get the time of MP3 file
let time = this.duration;
/*
- if [loop] is enabled AND the current time is more or
equal to the difference of the duration of the MP3
file and 0.3sec
- Increment the counter in 0.15sec.
- This odd delay pattern is to ensure that within the
last 0.25sec of the MP3 file the counter will
increment
*/
if (this.loop && this.currentTime >= time - .3) {
setTimeout(function() {
loops++;
ui.counter.value = loops
}, 150);
// Otherwise if the MP3 file ends, increment counter
} else if (this.ended) {
this.currentTime = 0;
loops++;
ui.playback.classList.add('play');
ui.playback.classList.remove('pause');
}
ui.counter.value = loops;
}
// Reset Handler for <form>
function resetLoop(event) {
stopPlay();
counterReset();
}
:root,
body {
font: 400 4vh/1.5 Consolas;
}
output,
button {
display: inline-block;
font: inherit;
font-size: 1rem
}
button {
padding: 0;
border: 0;
font-size: 4rem;
background: none;
cursor: pointer;
}
#counter {
width: 8rem;
height: 4rem;
font-size: 4rem;
text-align: center;
color: #0078D7;
}
#playback.play::before {
content: '▶️'
}
#playback.pause::before {
content: '⏸️'
}
#loopback.once::before {
content: '?'
}
#loopback.loop::before {
content: '?'
}
<audio src='http://www.orangefreesounds.com/wp-content/uploads/2019/09/Horse-trotting-sound.mp3?_=1'></audio>
<form id='controls'>
<button id='playback' class='play' type='button'></button>
<button type='reset'>⏹️</button>
<button id='loopback' class='loop' type='button'></button>
<output id='counter'>0</output>
</form>