Region playback documentation
danijel3 opened this issue · 6 comments
The auto playback/loop feature described in the documentation sucks. It's an important feature if you want to set up the region boundaries precisely and need to playback the regions multiple times while doing fine adjustments.
The problem with the example in the demos is that it always overshoots the ending by a random amount and using region events simply doesn't work.
Looking through the source code, I found that WebAudio backend supports a slightly more accurate method of pausing the audio at region end. Granted this method doesn't work for HTML audio element backend, but I think it would be worth documenting this feature somewhere, so people don't have to look for it in the sourcecode.
My solution requires the appropriate backend in the Wavesrufer constructor:
wavesurfer = WaveSurfer.create({
container: '#segmentation-container',
url: audio_url,
backend: "WebAudio",
...
})
Next I create a playBetween
method like this:
function playBetween(start, end) {
wavesurfer.media.currentTime = start
wavesurfer.media.play()
wavesurfer.media.stopAt(end)
}
Which I can use in various contexts, for example:
regions.on('region-clicked', (r, e) => {
e.stopPropagation() // prevent triggering a click on the waveform
playBetween(r.start, r.end)
})
Thanks that was useful I was experiencing the same issue with looping regions. I'll let you know once I try it.
Yea, this isn't really perfect for looping, but you could implement something yourself. To see how, you need to look at the implementation of the stopAt
function:
Lines 135 to 148 in 2682460
It works similarly to the example case, but instead of looking for wavesurfer events, it is using a slightly more accurate buffer node events. It's worth noting this is still far from perfect. The safest, most perfect approach would simply copy the portion of the buffer to a separate location (say another audio node) and simply play/loop that.
EDIT: Upon reviewing the documentation, it's actually quite accurate:
https://developer.mozilla.org/en-US/docs/Web/API/AudioScheduledSourceNode/stop
You could go with copying the buffer if you were extremely paranoid, but for most use cases, this is quite sufficient. The only small bug I notice is the playhead is sometimes a bit off graphically, but the audio is actually pretty accurate.
Has loop?
Again, this functionality (unlike stopAt
) isn't implemented anywhere in the project. I got something to work, using this function:
function loopBetween(start, end) {
if (!wavesurfer.media.paused) return
wavesurfer.media.paused = false
wavesurfer.media.bufferNode?.disconnect()
wavesurfer.media.bufferNode = wavesurfer.media.audioContext.createBufferSource()
if (wavesurfer.media.buffer) {
wavesurfer.media.bufferNode.buffer = wavesurfer.media.buffer
}
wavesurfer.media.bufferNode.playbackRate.value = wavesurfer.media._playbackRate
wavesurfer.media.bufferNode.connect(wavesurfer.media.gainNode)
wavesurfer.media.bufferNode.loop = true
wavesurfer.media.bufferNode.loopStart = start
wavesurfer.media.bufferNode.loopEnd = end
wavesurfer.media.bufferNode.start(wavesurfer.media.audioContext.currentTime, start)
}
However, this won't advance the playhead, even if the audio does loop. You can check out the documentation here:
https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/loop
Hello, can you try to load large files through range slicing in wavesuier?
Again, this functionality (unlike
stopAt
) isn't implemented anywhere in the project. I got something to work, using this function:function loopBetween(start, end) { if (!wavesurfer.media.paused) return wavesurfer.media.paused = false wavesurfer.media.bufferNode?.disconnect() wavesurfer.media.bufferNode = wavesurfer.media.audioContext.createBufferSource() if (wavesurfer.media.buffer) { wavesurfer.media.bufferNode.buffer = wavesurfer.media.buffer } wavesurfer.media.bufferNode.playbackRate.value = wavesurfer.media._playbackRate wavesurfer.media.bufferNode.connect(wavesurfer.media.gainNode) wavesurfer.media.bufferNode.loop = true wavesurfer.media.bufferNode.loopStart = start wavesurfer.media.bufferNode.loopEnd = end wavesurfer.media.bufferNode.start(wavesurfer.media.audioContext.currentTime, start) }
However, this won't advance the playhead, even if the audio does loop. You can check out the documentation here: https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/loop
However, the pointer of the wavesufer waveform does not run synchronously and is not linked to the waveform. Although audio playback is implemented