使用Web Audio API和WaveSurfer.js剪切和粘贴音频

10
我正在尝试制作一个Web编辑器,允许用户轻松调整其音频文件的基本设置。我已经集成了wavesurfer.js插件,因为它具有非常整洁和跨浏览器的波形解决方案。
在编制必须功能列表后,我决定剪切和粘贴对于使此产品工作至关重要,然而,在花费数小时尝试如何在现有库中实现此功能甚至开始从头重建wavesurfer.js功能以理解逻辑后,我仍未成功。
我的问题是,是否有人可以给我一些指针,告诉我如何开始构建剪切和粘贴功能,或者甚至提供一个示例,这将非常感激。
先行致谢!
wavesurfer插件: http://wavesurfer-js.org plucked web编辑器: http://plucked.de 编辑解决方案(instance是wavesurfer对象):
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')
  }
}
2个回答

12
阅读这个 答案,建议您可以创建一个大小为要复制的音频片段的空AudioBuffer(大小=秒数×采样率),然后使用片段数据填充其通道数据。
因此,代码可能是这样的:
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!

3
非常感谢,katspaugh!太好了!当我将新的片段粘贴到原始缓冲区时,是否还有一种重新绘制波形的方法? - dennis
4
是的,@dennis,有一个名为 wavesurfer.loadDecodedBuffer 的方法,它需要传入一个 AudioBuffer。请参见 https://github.com/katspaugh/wavesurfer.js/blob/a8772b8b5148c58c231d4ad7c1d8b62f37409efb/src/wavesurfer.js#L514。 - katspaugh

5
有趣的问题。我首先想到的是ffmpeg。虽然我没有亲身经历,但如果我想实现这个目标,我会采用以下方法:
假设您选择了音频轨道的一个区域,并且您想将其复制并制作成一个新的轨道(稍后可能只是将其附加到现有轨道)。
1.使用wavesurfer.js库提供的getSelection()方法。这将为您提供startPosition()endPosition()(以秒为单位)。
2.给定这些点,您现在可以在后端使用ffmpeg选择该区域并将其保存为新文件(最终上传到S3等)。请参见此thread以了解如何从ruby应用程序调用ffmpeg(其中显示的命令行参数也可能有帮助)。
请注意,如果您计划复制和粘贴许多区域来拼接新的轨道,那么在后端进行所有操作可能没有意义,我猜我会尝试寻找客户端JS方法。
我希望这对于简单的用例至少是有帮助的,并为您开始其余部分做好了准备 ;)
更新 这可能值得一读。
- Web Audio API,教程在这里。 - HTML5音频 - 现状。 在这里(不要错过关于TimeRanges的部分,看起来是一个合理的选项)。 - 这个one(已过时,但值得一看,有趣的链接)。

1
嗨vint-i-vuit,非常感谢您的输入。现在我有了一个设置方式的方向,我将采用客户端方法,因为后端方法可能太过繁重。成功后,我一定会回报并公布我的解决方案。 - dennis
1
@dennis:很高兴听到你现在对挑战有了更清晰的概述 :) 此外,请再看一下我的更新答案,我添加了一些链接,可以帮助你开始JS方面的工作。 - lllllll
非常感谢!确实,TimeRanges文章看起来非常有前途。我目前正在开发一个Javascript库,以涵盖这些功能,并结合wavesurferjs的波形图。一旦进入beta版,它将托管在github上。 - dennis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接