bbc / peaks.js

JavaScript UI component for interacting with audio waveforms
https://waveform.prototyping.bbc.co.uk
GNU Lesser General Public License v3.0
3.16k stars 277 forks source link

Howler <> External Player #465

Closed jakiestfu closed 1 year ago

jakiestfu commented 1 year ago

Hello! For the life of me I am having difficulty fully understanding the external player API. The Tone.js example is a little confusing. Do you think it'd be possible to provide a rudimentary demo or example/pseudocode of a player using the Howler API?

https://github.com/goldfire/howler.js#documentation

chrisn commented 1 year ago

A Howler example would be welcome. I can answer specific questions about the player API if you have them (documentation is here).

jakiestfu commented 1 year ago

Well I’m controlling howler via react-howler, and subsequently redux. I dispatch actions that should in turn reflect the status of howler, and I update redux with the players current seek state.

if I were to create a custom player, is my external player my set of redux actions?

If I were to “play audio” through redux, do I need to invoke customPlayer.play()? Or does peaks observe the state of customPlayer.isPlaying()?

I’m unsure of what my responsibilities are as a developer when implementing a custom player.

jakiestfu commented 1 year ago

I guess another concern I have is surrounding memorization. I have the current seek state stored in redux, but that value needs to be passed via the custom player function, which is only created during instantiation. If I were to use useCallbacks and stuff to get correct reference to a current value, do I need to destroy and recreate my player? Do I need to setSource everytime my player options (custom player) change? It doesn’t make sense to have to destroy and reinit everytime seek time changes.

I also tried just setting the seek on the player when redux changes but it wasn’t through the custom player API and felt like the incorrect approach @chrisn

jakiestfu commented 1 year ago

Following up with some findings.

Refs. Refs everywhere.

const currentTimeRef = useRef<number>(null)
currentTimeRef.current = seek // seek comes from redux, represents the current audio playback time

// Access the current time mutably.
const getCurrentTime = () => currentTimeRef.current

Before, getCurrentTime was a memoized function and that limited my access to recent values, but by using refs, I've avoided that.

chrisn commented 1 year ago

It seems that you have two separate but related questions: How to integrate Peaks.js with howler.js, then how to integrate those with React+Redux. I can probably help with the first question, but probably less so with the second.

chrisn commented 1 year ago

Here's an example of using Peaks.js with howler.js.

jakiestfu commented 1 year ago

@chrisn Thank for very much. I think after spending some more time dissecting my problem, I came to a solution. Thanks! Your addition of the Howler Demo is very much appreciated 🙏