O metrônomo um dispositivo que deixa uma batida constante e ajuda os músicos a manterem um ritmo quando estão treinando. Esse ritmo pode aumentar ou diminuir de acordo com a escolha do músico.
Teremos um HTML simples, e primeiro vamos criar um input type range para gerar uma barra que será onde vamos controlar a velocidade do nosso metrônomo. Nele conseguimos colocar qual o valor mínimo e qual o valor máximo. Vamos pegar o do google como exemplo, o mínimo será 40 e o máximo 218. Um value inicial e um ID para conseguirmos recuperar este valor.
Em seguida, vamos colocar o áudio que será tocado (no meu caso tenho um clap.wav e um botão play para controlar o metrônomo).
<html>
    <head>
        <tittle>Metronomo</tittle>
    </head>
    <body>
        <input type="range"  min="40" max="218" value="40" id="bpm"/>
        <audio src="clap.wav"></audio>
        <button id="play">Play</button>
    </body>
<html>
Ele ficará assim:
Também é interessante colocarmos antes do input um H1 com o número inicial de batida que está configurado.
<h1>40bpm</h1>
Feito isso, podemos começar a adicionar um pouco de comportamento. Vamos colocar o script no corpo do HTML mesmo, pois a intenção no exemplo é só demonstrar como poderíamos reconstruir o metrônomo.
Toda vez que trocar o valor do range tem que ser trocado o que está escrito em H1. Então vamos pegar o BPM e o H1. Toda vez que o BPM mudar, ou seja, dar um change, o h1 tem que mudar também. Lembrando que essa técnica de colocar todos os seletores em cima é chamada de cash.
Primeiro faremos um teste com um valor fixo criando uma função que faz o play. Vamos chamá-la de tick e um intervalo fixo, que em sequência vamos resolver.
Nessa função tick, temos que pegar o áudio
<script>
    const bpm = document.getElementById('bpm')
    const h1 = document.querySelector('h1')
    const play = document.getElementByld('play')
    const.audio = document.querySelector('audio')
    let currentBpm = 40
    function tick(){
        audio.currentTime= 0
        audio.play()
    }
    bpm.addEventListener('change', function(){
        h1.innerHTML = this.value + ' bpm'
        currentBpm = parseInt(this.value)
    })
    play.addEventListener('click', function(){
        const timer = setInterval(tick, 100)
    })
    </script>
Agora vamos pensar um pouco: Se precisamos ter 40 batimentos por minuto e o minuto tem 60 segundos, 60 segundos tem 60 mil milissegundos, temos que distribuir 40 batidas dentro de 60 mil, então vamos dividir isso no valor do Bpm, ficando assim:
play.addEventListener('click', function () {
  const timer = setInterval(tick, (60 * 1000) / currentBpm)
})
Precisamos agora de uma forma para desligar essa batida, para isso vamos usar declarar o let isPlaying, o timer, e um if para, caso ele estiver tocando, darmos um clearInterval nesse timer.
<script>
    const bpm = document.getElementById('bpm')
    const h1 = document.querySelector('h1')
    const play = document.getElementByld('play')
    const.audio = document.querySelector('audio')
    let currentBpm = 40
    let isPlaying = false
    let timer = null
    function tick(){
        audio.currentTime= 0
        audio.play()
    }
    bpm.addEventListener('change', function(){
        h1.innerHTML = this.value + ' bpm'
        currentBpm = parseInt(this.value)
    })
    play.addEventListener('click', function(){
        if(isPlaying){
            clearInterval(timer)
        } else {
            const timer = setInterval(tick, (60*1000)/currentBpm)
        }
        isPlaying = !isPlaying
    })
</script>
Uma vez que estartamos o timer, ele começa a tocar. Ao clicar novamente, ele para, pois carrega na página com valor null. Ao clicarmos, damos um valor para ele e clicando de novo ele cai no isPlaying = !isPlaying que faz ele voltar a Null. Chamamos isso de toggle.
Também podemos trocar o texto do botão para play caso esteja tocando e Stop para quando estiver parado. Perceba que, ao apertar o play, ele começa a tocar apenas no próximo tick, pois o setInterval demora esse tick. Podemos fazer ele começar já com esse tick.
play.addEventListener('click', function () {
  if (isPlaying) {
    play.innerHTML = 'Play'
    clearInterval(timer)
  } else {
    tick()
    play.innerHTML = 'Stop'
    const timer = setInterval(tick, (60 * 1000) / currentBpm)
  }
  isPlaying = !isPlaying
})
Para esse valor atualizar sempre que mudamos o range, temos que fazer um if, que vai limpar o intervalo e começar um novo valor baseado no cálculo.
bpm.addEventListener('change', function () {
  h1.innerHTML = this.value + ' bpm'
  currentBpm = parseInt(this.value)
  if (isPlaying) {
    clearInterval(timer)
    timer = setInterval(tick, (60 * 1000) / currentBpm)
  }
})
Com isso, acabamos de construir um metrônomo.
Essa é uma ideia do que se pode construir com javaScript e HTML. Algumas outras ideias faremos posteriormente.
Confira o passo a passo em vídeo:
Curta o 
DevPleno no Facebook, 
inscreva-se no canal e não se esqueça de cadastrar seu e-mail para não perder as novidades. Abraço!