0
votes

The problem

I'm trying to loop some audio in a React app created with create-react-app using useEffect. I've got it working but there's a short delay between the audio ending and re-starting. I want to use the audio as backing tracks to play guitar to so I need it to loop perfectly smoothly. I'm confident that the track length is correct, I recorded it myself and exported exactly 8 bars, and it loops fine in iTunes.

Current code

Thanks to the accepted answer in this question, my audio player function works fine, and currently looks like this:

import React, { useState, useEffect } from 'react'

const useAudio = audioPath => {
  const [audio] = useState(new Audio(audioPath))
  const [playing, setPlaying] = useState(false)

  const toggle = () => setPlaying(!playing)

  useEffect(() => {
      playing ? audio.play() : audio.pause()
    },
    [playing, audio]
  )

  useEffect(() => {
    audio.addEventListener('ended', () => {
      audio.currentTime = 0
      audio.play()
      setPlaying(true)
    })
  }, [audio])

  return [playing, toggle]
}

const Player = ({ audioPath }) => {
  const [playing, toggle] = useAudio(audioPath)

  return (
    <div>
      <button onClick={toggle}>{playing ? 'Pause' : 'Play'}</button>
    </div>
  )
}

export default Player

The audioPath is passed in and is just a relative path, that loads fine. It plays fine, it pauses fine, it does loop, just with a tiny delay between loops.

What I've tried

As you can see from the code, I've been trying to hijack the audio ended event and setting the audio back to the start of the track but obviously this isn't instant - I'm not really sure how to handle this. I've tried in my first useEffect function checking the time of the audio and if it's within say 500ms of the end of the track setting the time back to 0 but I couldn't get that working, and it seems very hacky and unreliable anyway. Ideally I'm after a proper solution that will work with any tracks as I want to add more.

Demo

Go to the very bottom of the GitHub pages site where this is hosted, expand the very bottom panel and hit play.

1
An <audio> element is not good at that, you should rather use the web audio api. See stackoverflow.com/questions/42968873/… Though I have no idea how that would fit in a react component - Kaiido
@Kaiido I've had a read of that question, makes sense though I'm also not sure how it would fit with React and browser support is a little sketchy. Ultimately I think you're right though, this isn't going to happen with <audio> - NickH

1 Answers

0
votes

Ive been playing around with audio a bit recently as well and found that the react-h5-audio-player npm package was the best option for me.

Its got good storyboard examples which include looping and custom controls etc which you might just be able to hide the display by using CSS if you want to keep the single play/pause button you currently have.