Multiple Wavesurfer instances and bottom player in React / Next.js (Soundcloud like implementation) #3190
-
Hello I hope someone could help with the following: I am doing a project using next.js 12 and wavesurfer.js I need to have multiple tracks with waveforms and Play/pause showing on the same page. When pressing play, I need to have a bottom player also showing wave form of the track being played + controls. Very much like it is implemented on Soundcloud. The important point is to have the bottom audio player still playing whilst browsing other pages throughout the website so obviously via context. Could someone give me some pointers about how to go to implement this or even some resources ? It is quite a common implementation and yet I don't seem to see much code examples out there and I did try multiple searches on here. So far I managed to generate multiple instances of wave surfer and manage the instances via react context to ensure only one is playing at a time but implementing the bottom player proves much more difficult. Below is my WaveSurferPlayer component any help would be greatly appreciated 🙏🏻
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 12 replies
-
You can sync the bottom player with the currently playing track by making them share the same E.g. const topPlayers = topTracks.map((url) => WaveSurfer.create({ container, url }))
const currentPlayer = topPlayers[0]
const bottomPlayer = WaveSurfer.create({ container, media: currentPlayer.getMediaElement() }) The bottom player will then play, pause and seek whenever the current player is played/paused/seeking. |
Beta Was this translation helpful? Give feedback.
-
If we need the bottom player to persist across screen navigations we run into a problem because the Unfortunately, there is no setter method to update Since JavaScript doesn't truly have protected/constant implementation one hack would be to manually mutate the protected media element. // This creates the <audio> element we want to share between players
const bottomPlayer = WaveSurfer.create({ container })
// Only render waverform with pre-generated waveform peaks data
const topPlayers = topTracks.map((peaks) => WaveSurfer.create({ container, peaks }))
// On a top track play we attach to bottom player's media element
let currentPlayer = topPlayers[0]
let origMediaEl = currentPlayer.getMediaElement()
// This mutates a protected property of wavesurfer object
currentPlayer.media = bottomPlayer.getMediaElement()
bottomPlayer.load(url)
bottomPlayer.play()
// On a track change
// 1. detach previous top player from bottom player's media
// 2. attach new top player to bottom player's media element
currentPlayer.media = origMediaEl
currentPlayer = topPlayers[1]
origMediaEl = currentPlayer.getMediaElement()
currentPlayer.media = bottomPlayer.getMediaElement()
bottomPlayer.load(url)
bottomPlayer.play() Note: The above example is not intended for real use but just to demonstrate a workaround. Would be nice if we had a public setter method to update |
Beta Was this translation helpful? Give feedback.
-
Hey guys, I'm trying to implement something similar as well. There's one weird that I've noticed with this: if you go to the example and start playing the 2nd track, you'll see that global waveform is lagging, but the row one is not. Upon pausing and resuming the track, global waveform performance is improved and there are no signs of lag. Any ideas on what is going on? EDIT: I've had a quick look at what could be wrong and I've noticed that on the first click, progress is rendered on line 192 in |
Beta Was this translation helpful? Give feedback.
You can sync the bottom player with the currently playing track by making them share the same
media
element.E.g.
The bottom player will then play, pause and seek whenever the current player is played/paused/seeking.