katspaugh / wavesurfer.js

Audio waveform player
https://wavesurfer.xyz
BSD 3-Clause "New" or "Revised" License
8.8k stars 1.63k forks source link

Seeking doesn't work if no audio is provided #3298

Closed jagthedrummer closed 9 months ago

jagthedrummer commented 1 year ago

Bug description

I'm using wavesurfer.js to render a waveform without audio, which is working great.

When I call setTime to try to move the cursor to a particular point it always stays at 0:0. If I register for the interaction event it's picking up clicks at the right spot, but the cursor never moves.

Environment

Minimal code snippet

wavesurfer = WaveSurfer.create({
  container: '#some-container',
  interact: true,
  dragToSeek: true,
  peaks: [/* valid peak data goes here */],
  duration: 300
});
wavesurfer.setTime(150);

Expected result

I'd expect the cursor to move to the halfway point.

Obtained result

The cursor stays at the beginning.

Screenshots

When passing in a url subsequent calls to setTime will move the cursor:

CleanShot 2023-10-25 at 14 40 43

When a url is not passed in calls to setTime do not move the cursor:

CleanShot 2023-10-25 at 14 40 00

katspaugh commented 1 year ago

That’s not a bug but quite an exotic feature request. It can be done though.

katspaugh commented 11 months ago

This can be done with the Web Audio option like this:

// With pre-decoded audio data

import WaveSurfer from 'https://unpkg.com/wavesurfer.js@7/dist/wavesurfer.esm.js'

const wavesurfer = WaveSurfer.create({
  container: document.body,
  backend: 'WebAudio',
  peaks: [ /* pre-decoded peaks */ ],
  duration: 21
})

wavesurfer.on('ready', () => {
  wavesurfer.setTime(10)
})
mvynhb commented 10 months ago

Hi @katspaugh

I understand that seeking is not possible if the audio is not loaded, however this also happens with this scenario:

media = new Audio(src)
media.preload = 'none'
surfer = WaveSurfer.create({
    container: wave,
    media: media,
    peaks: peaks,
    duration: duration
})

So I do pass a media element, however I set preload to none. In this case I am not able to seek before playing back. I do not want to load metadata because I already have peaks and duration. Is there a way to still move the cursor and seek even when no metadata is loaded?

I understand the workaround, but in my case I do have a valid audio element.

katspaugh commented 10 months ago

I don't think it's possible with an actual audio element.

You should either use the Web Audio option as per the workaround above, or you have to subscribe to one of the events indicating the audio has loaded, like loadedmetadata or canplay.

You might also try passing a timestamp in the audio URL like so:

const media = new Audio('/audio.mp3#t=10')

Not sure how widely supported this is. See https://www.w3.org/TR/media-frags/

mvynhb commented 10 months ago

@katspaugh

Thanks for the quick reply!

Actually what I want to do is simply allow the user to move the cursor through the player/waveform without playing, and when they decide to play they press the play button.

The same as here: https://wavesurfer.xyz/examples/?webaudio.js, just without fetching any metadata, setting the preload to none. The reason is because I have a long list of episodes +30, and I dont want to drain user's bandwidth every time they load the page.

Currently my workaround is to have a click event on the waveform with the following method:

playAndPause () {
    if (this.media.preload === 'none') {
        this.play()
        this.pause()
    }
},

It's not ideal, since it starts downloading the whole audio when the user clicks on the waveform. Do you know if there is a better way to just download metadata when the user clicks on the waveform, so they can move the cursor?

katspaugh commented 10 months ago

I haven’t tested this but you can probably dynamically set preload to metadata on click and call the load method on the audio element. https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/load

katspaugh commented 10 months ago

I’ll reopen this issue to see if we can just visually set the cursor on click and schedule an actual seek action for when metadata is loaded.

katspaugh commented 9 months ago

Hey all, I've released this feature in 7.7.0. Please let me know if it works for you!

jagthedrummer commented 9 months ago

Hey @katspaugh, I just updated to 7.7.0 and this is working great. Thank you!

uholland commented 6 months ago

Hey @katspaugh, can you please update wavesurfer/react to the new dependency please? :-) This would be awesome. Thank you!