最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Cut and Paste audio using web audio api and wavesurfer.js - Stack Overflow

programmeradmin1浏览0评论

I am currently trying to make a web editor allowing users to easily adjust basic settings to their audio files, as a plugin I've integrated wavesurfer.js as it has a very neat and cross-browser solution for it's waveform.

After indexing a must-have list for the functionalities I've decided that the cut and paste are essential for making this product work, however after spending hours of trying to figure out how to implement this in the existing library and even starting to rebuild the wavesurfer.js functionalities from scratch to understand the logic I have yet to succeed.

My question would be if anyone can give me some pointers on how to start building a cut and paste functionality or maybe even an example that would be greatly appreciated.

Thanks in advance!

wavesurfer plugin:

plucked web editor

EDIT Solution (instance is the wavesurfer object.):

function cut(instance){
  var selection = instance.getSelection();
  if(selection){
    var original_buffer = instance.backend.buffer;
    var new_buffer      = instance.backend.ac.createBuffer(original_buffer.numberOfChannels, original_buffer.length, original_buffer.sampleRate);

    var first_list_index        = (selection.startPosition * original_buffer.sampleRate);
    var second_list_index       = (selection.endPosition * original_buffer.sampleRate);
    var second_list_mem_alloc   = (original_buffer.length - (selection.endPosition * original_buffer.sampleRate));

    var new_list        = new Float32Array( parseInt( first_list_index ));
    var second_list     = new Float32Array( parseInt( second_list_mem_alloc ));
    var combined        = new Float32Array( original_buffer.length );

    original_buffer.copyFromChannel(new_list, 0);
    original_buffer.copyFromChannel(second_list, 0, second_list_index)

    combined.set(new_list)
    combined.set(second_list, first_list_index)

    new_buffer.copyToChannel(combined, 0);

    instance.loadDecodedBuffer(new_buffer);
  }else{
    console.log('did not find selection')
  }
}

I am currently trying to make a web editor allowing users to easily adjust basic settings to their audio files, as a plugin I've integrated wavesurfer.js as it has a very neat and cross-browser solution for it's waveform.

After indexing a must-have list for the functionalities I've decided that the cut and paste are essential for making this product work, however after spending hours of trying to figure out how to implement this in the existing library and even starting to rebuild the wavesurfer.js functionalities from scratch to understand the logic I have yet to succeed.

My question would be if anyone can give me some pointers on how to start building a cut and paste functionality or maybe even an example that would be greatly appreciated.

Thanks in advance!

wavesurfer plugin: http://wavesurfer-js.org

plucked web editor http://plucked.de

EDIT Solution (instance is the wavesurfer object.):

function cut(instance){
  var selection = instance.getSelection();
  if(selection){
    var original_buffer = instance.backend.buffer;
    var new_buffer      = instance.backend.ac.createBuffer(original_buffer.numberOfChannels, original_buffer.length, original_buffer.sampleRate);

    var first_list_index        = (selection.startPosition * original_buffer.sampleRate);
    var second_list_index       = (selection.endPosition * original_buffer.sampleRate);
    var second_list_mem_alloc   = (original_buffer.length - (selection.endPosition * original_buffer.sampleRate));

    var new_list        = new Float32Array( parseInt( first_list_index ));
    var second_list     = new Float32Array( parseInt( second_list_mem_alloc ));
    var combined        = new Float32Array( original_buffer.length );

    original_buffer.copyFromChannel(new_list, 0);
    original_buffer.copyFromChannel(second_list, 0, second_list_index)

    combined.set(new_list)
    combined.set(second_list, first_list_index)

    new_buffer.copyToChannel(combined, 0);

    instance.loadDecodedBuffer(new_buffer);
  }else{
    console.log('did not find selection')
  }
}
Share Improve this question edited Jan 25, 2016 at 18:00 katspaugh 17.9k12 gold badges67 silver badges105 bronze badges asked Jul 3, 2014 at 10:57 dennisdennis 2,02019 silver badges28 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 13

Reading this answer suggests you can create an empty AudioBuffer of the size of the audio segment you want to copy (size = length in seconds ⨉ sample rate), then fill its channel data with the data from the segment.

So the code might be like this:

var originalBuffer = wavesurfer.backend.buffer;
var emptySegment = wavesurfer.backend.ac.createBuffer(
    originalBuffer.numberOfChannels,
    segmentDuration * originalBuffer.sampleRate,
    originalBuffer.sampleRate
);
for (var i = 0; i < originalBuffer.numberOfChannels; i++) {
    var chanData = originalBuffer.getChannelData(i);
    var segmentChanData = emptySegment.getChannelData(i);
    for (var j = 0, len = chanData.length; j < len; j++) {
        segmentChanData[j] = chanData[j];
    }
}

emptySegment; // Here you go!
              // Not empty anymore, contains a copy of the segment!

Interesting question. First word that comes to mind is ffmpeg. I can't talk from experience but if I was trying to achieve this I would approach it like:

Let's assume you select a region of your audio track and you want to copy it and make a new track out of it (later maybe just appending it to an existing track).

  1. Use the getSelection() method provided by the nice wavesurfer.js library. This will give you startPosition() and endPosition()[in seconds].
  2. Given those points you now can use ffmpeg on the backend to select the region and save it as a new file (eventually upload it to S3,etc.). See this thread to get an idea of how to call ffmpeg from your ruby app (the commandline parameters shown there can be helpful too).

Note that if you plan to copy and paste many regions to piece up a new track, making this in the backend all the time will probably make no sense, and I guess I'd try to look for a client-side JS approach.

I hope this is helpful at least for an easy use case, and gets you started for the rest ;)

Update This might be worth reading.

  • Web Audio API, tutorial here.
  • HTML5 audio - State of play. here(don't miss the section on TimeRanges, looks like a reasonable option to try).
  • This one(Outdated, but worth a look, interesting links).
发布评论

评论列表(0)

  1. 暂无评论