peteris.rocks

WaveSurfer.js copy audio

How to copy a part of an audio clip with WaveSurfer.js and Web Audio API in HTML5

Last updated on

I'm using WaveSurfer.js for a project to show the waveform of an audio clip:

I wanted the user to be able to select a portion of the audio and get that as a separate audio clip.

Based on this StackOverflow answer by the author of the library, here is a more general version of the code:

function createBuffer(originalBuffer, duration) {
  var sampleRate = originalBuffer.sampleRate
  var frameCount = duration * sampleRate
  var channels = originalBuffer.numberOfChannels 
  return new AudioContext().createBuffer(channels, frameCount, sampleRate)
}

function copyBuffer(fromBuffer, fromStart, fromEnd, toBuffer, toStart) {
  var sampleRate = fromBuffer.sampleRate
  var frameCount = (fromEnd - fromStart) * sampleRate
  for (var i = 0; i < fromBuffer.numberOfChannels; i++) {
      var fromChanData = fromBuffer.getChannelData(i)
      var toChanData = toBuffer.getChannelData(i)
      for (var j = 0, f = Math.round(fromStart*sampleRate), t = Math.round(toStart*sampleRate); j < frameCount; j++, f++, t++) {
          toChanData[t] = fromChanData[f]
      }
  }
}

Here is how to use these functions:

// our WaveSurfer instance
var wavesurfer = WaveSurfer.create({ container: '#waveform' })
wavesurfer.load('track.mp3')

// the clip we want to get
var start = 10 // get it with waversufer.getCurrentTime()
var end = 20
var duration = end - start

// create a new buffer to hold the new clip
var buffer = createBuffer(wavesurfer.backend.buffer, duration)
// copy
copyBuffer(wavesurfer.backend.buffer, start, end, buffer, 0)

// load the new buffer
wavesurfer.empty()
wavesurfer.loadDecodedBuffer(buffer)

The reason I structured the code like this is so that I can create a buffer of the clip repeated several times:

var buffer = createBuffer(wavesurfer.backend.buffer, duration*3)
copyBuffer(wavesurfer.backend.buffer, start, end, buffer, 0)
copyBuffer(wavesurfer.backend.buffer, start, end, buffer, duration)
copyBuffer(wavesurfer.backend.buffer, start, end, buffer, duration*2)