Wavesurfer.js: Cut & Paste Audio

Created on 26 Mar 2015  Â·  15Comments  Â·  Source: katspaugh/wavesurfer.js

I saw this post by katspaugh on stack and was curious if there are any examples of this floating around. There is a piece of potential example code I've tried to abstract but haven't had any luck.

http://stackoverflow.com/questions/24551854/cut-and-paste-audio-using-web-audio-api-and-wavesurfer-js

question

Most helpful comment

here is some script i found on the web that can replace thr buffer2wav function
note that it return a blob so the last line return "(new Blob([arraybuffer], { type : 'audio/wav'}));"

should be chance to the return value of this function

// Convert a audio-buffer segment to a Blob using WAVE representation
// The returned Object URL can be set directly as a source for an Auido element.
// (C) Ken Fyrstenberg / MIT license
function bufferToWave(abuffer, offset, len) {

  var numOfChan = abuffer.numberOfChannels,
      length = len * numOfChan * 2 + 44,
      buffer = new ArrayBuffer(length),
      view = new DataView(buffer),
      channels = [], i, sample,
      pos = 0;

  // write WAVE header
  setUint32(0x46464952);                         // "RIFF"
  setUint32(length - 8);                         // file length - 8
  setUint32(0x45564157);                         // "WAVE"

  setUint32(0x20746d66);                         // "fmt " chunk
  setUint32(16);                                 // length = 16
  setUint16(1);                                  // PCM (uncompressed)
  setUint16(numOfChan);
  setUint32(abuffer.sampleRate);
  setUint32(abuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
  setUint16(numOfChan * 2);                      // block-align
  setUint16(16);                                 // 16-bit (hardcoded in this demo)

  setUint32(0x61746164);                         // "data" - chunk
  setUint32(length - pos - 4);                   // chunk length

  // write interleaved data
  for(i = 0; i < abuffer.numberOfChannels; i++)
    channels.push(abuffer.getChannelData(i));

  while(pos < length) {
    for(i = 0; i < numOfChan; i++) {             // interleave channels
      sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
      sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0; // scale to 16-bit signed int
      view.setInt16(pos, sample, true);          // update data chunk
      pos += 2;
    }
    offset++                                     // next source sample
  }

  // create Blob
  return (URL || webkitURL).createObjectURL(new Blob([buffer], {type: "audio/wav"}));

  function setUint16(data) {
    view.setUint16(pos, data, true);
    pos += 2;
  }

  function setUint32(data) {
    view.setUint32(pos, data, true);
    pos += 4;
  }
}

took me a whole day to get this to work, hope this will save other some time :)

All 15 comments

Without reading the whole stackoverflow post, can you state in one sentence what you'd like to see supported in wavesurfer.js?

Sure.

"A function that creates/fills an empty buffer source by creating a copy of the current buffer source that has a specific start and end point."

Some of the code is in the stack post.

This will take a wavesurfer buffer and will create a smaller version with
the selected area, the function will return a new blob, from which you can
redraw the wavesurfer.

Allan

EXTRACTED FROM A PRIVATE PROJECT IF YOU NEED MORE INFO LET ME KNOW:

var app = {
 trimBlob : function(params){

/*
 EXTRACTED FROM A PRIVATE PROJECT
IF YOU NEED MORE INFO LET ME KNOW:

[email protected]
---------------------------------------------
This method works with wavesurfer.
Make a selection, using wavesurfer api take the start and end.
---------------------------------------------
The function will take the buffer used to create the waveform and will
create
a new blob with the selected area from the original blob using the
offlineAudioContext

*/

var self = this;
var start = params.start;
var end = params.end;

var originalAudioBuffer;


originalAudioBuffer = params.wavesurfer.backend.buffer;

var lengthInSamples = Math.floor( (end - start) *
originalAudioBuffer.sampleRate );

var offlineAudioContext = new webkitOfflineAudioContext(1, 2,
originalAudioBuffer.sampleRate );
 var
new_channel_data,empty_segment_data,original_channel_data,before_data,after_data;

var emptySegment = offlineAudioContext.createBuffer(
originalAudioBuffer.numberOfChannels,lengthInSamples,
originalAudioBuffer.sampleRate );

var newAudioBuffer = offlineAudioContext.createBuffer(
originalAudioBuffer.numberOfChannels,
(start === 0 ? (originalAudioBuffer.length - emptySegment.length) :
originalAudioBuffer.length)
, originalAudioBuffer.sampleRate);

for (var channel = 0; channel < originalAudioBuffer.numberOfChannels;
channel++) {

new_channel_data = newAudioBuffer.getChannelData(channel);
empty_segment_data = emptySegment.getChannelData(channel);
original_channel_data = originalAudioBuffer.getChannelData(channel);

before_data = original_channel_data.subarray(0, start *
originalAudioBuffer.sampleRate);
after_data = original_channel_data.subarray(Math.floor(end *
originalAudioBuffer.sampleRate), (originalAudioBuffer.length *
originalAudioBuffer.sampleRate));

if(start > 0){
new_channel_data.set(before_data);
new_channel_data.set(empty_segment_data,(start *
newAudioBuffer.sampleRate));
new_channel_data.set(after_data,(end * newAudioBuffer.sampleRate));
} else {
new_channel_data.set(after_data);
}

}

var arraybuffer = buffer2wav(newAudioBuffer);//Will create a new Blob with
the IntArray...


return (new Blob([arraybuffer], { type : 'audio/wav'}));

 }
}

On Thu, Mar 26, 2015 at 5:48 PM, Christopher Konopka <
[email protected]> wrote:

Sure.

"A function that creates/fills an empty buffer source by creating a copy
of the current buffer source that has a specific start and end point."

Some of the code is in the stack post.

—
Reply to this email directly or view it on GitHub
https://github.com/katspaugh/wavesurfer.js/issues/419#issuecomment-86755938
.

Thanks! I will try it out in a little bit. Really appreciate the help. :)

@cskonopka closing it now. Feel free to reopen if you have more questions.

@allannaranjo Sorry about the delay, a bunch of stuff came up and haven't been able to focus on this idea. Is it possible to provide more information? I understand the logic but I can't quite implement it properly.

@allannaranjo I'm trying to do the same thing as in the original issue and I'm trying to implement your code example however you haven't provided the code for the buffer2wav function. Any chance you could add that code to the example?

Many thanks in advance.

here is some script i found on the web that can replace thr buffer2wav function
note that it return a blob so the last line return "(new Blob([arraybuffer], { type : 'audio/wav'}));"

should be chance to the return value of this function

// Convert a audio-buffer segment to a Blob using WAVE representation
// The returned Object URL can be set directly as a source for an Auido element.
// (C) Ken Fyrstenberg / MIT license
function bufferToWave(abuffer, offset, len) {

  var numOfChan = abuffer.numberOfChannels,
      length = len * numOfChan * 2 + 44,
      buffer = new ArrayBuffer(length),
      view = new DataView(buffer),
      channels = [], i, sample,
      pos = 0;

  // write WAVE header
  setUint32(0x46464952);                         // "RIFF"
  setUint32(length - 8);                         // file length - 8
  setUint32(0x45564157);                         // "WAVE"

  setUint32(0x20746d66);                         // "fmt " chunk
  setUint32(16);                                 // length = 16
  setUint16(1);                                  // PCM (uncompressed)
  setUint16(numOfChan);
  setUint32(abuffer.sampleRate);
  setUint32(abuffer.sampleRate * 2 * numOfChan); // avg. bytes/sec
  setUint16(numOfChan * 2);                      // block-align
  setUint16(16);                                 // 16-bit (hardcoded in this demo)

  setUint32(0x61746164);                         // "data" - chunk
  setUint32(length - pos - 4);                   // chunk length

  // write interleaved data
  for(i = 0; i < abuffer.numberOfChannels; i++)
    channels.push(abuffer.getChannelData(i));

  while(pos < length) {
    for(i = 0; i < numOfChan; i++) {             // interleave channels
      sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp
      sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0; // scale to 16-bit signed int
      view.setInt16(pos, sample, true);          // update data chunk
      pos += 2;
    }
    offset++                                     // next source sample
  }

  // create Blob
  return (URL || webkitURL).createObjectURL(new Blob([buffer], {type: "audio/wav"}));

  function setUint16(data) {
    view.setUint16(pos, data, true);
    pos += 2;
  }

  function setUint32(data) {
    view.setUint32(pos, data, true);
    pos += 4;
  }
}

took me a whole day to get this to work, hope this will save other some time :)

@moshedri thanks for this function. I'm assuming len is the length of the new buffer? Can you tell me where offset comes from in the context of the previous function?

you're welcome ,

it was a long time ago and as i mentioned above the code , i found it online
but i do remember that offset allow you to cut from the start of the sound file so if you want to convert the whole file you should pass in 0 as the offset , i even change this function in my own code to have offset =0 as default value

I would like to read my .file extension file with wavesurfer.js as .wav, but I could not find a solution. Can you help me please @katspaugh

I would like to read my .file extension file with wavesurfer.js as .wav, but I could not find a solution. Can you help me please @katspaugh

Hi, I have implemented cut, copy, paste in wavesurfer. Please refer to this repo
https://github.com/vikasmagar512/wavesurfer-audio-editor

Hi, I have implemented cut, copy, paste in wavesurfer. Please refer to this repo
https://github.com/vikasmagar512/wavesurfer-audio-editor

How would i implement this in my project?

@johnlandish Here are the functions
Cut, Copy, Paste, bufferToWave. You can call these functions kind of pure functions.
Please refer this file

https://github.com/vikasmagar512/wavesurfer-audio-editor/blob/master/src/utils/waveSurferOperation.js

Happy to help...!!!

Was this page helpful?
0 / 5 - 0 ratings