使用网络音频 api 和 wavesurfer.js 剪切和粘贴音频

Posted

技术标签:

【中文标题】使用网络音频 api 和 wavesurfer.js 剪切和粘贴音频【英文标题】:Cut and Paste audio using web audio api and wavesurfer.js 【发布时间】:2014-07-03 10:57:40 【问题描述】:

我目前正在尝试制作一个网络编辑器,允许用户轻松调整其音频文件的基本设置,作为一个插件,我集成了 wavesurfer.js,因为它有一个非常简洁和跨浏览器的波形解决方案。

在为功能的必备列表编制索引后,我决定剪切和粘贴对于使该产品正常工作至关重要,但是在花费数小时试图弄清楚如何在现有库中实现这一点甚至开始从头开始重建 wavesurfer.js 功能以了解我尚未成功的逻辑。

我的问题是,是否有人可以给我一些关于如何开始构建剪切和粘贴功能的指示,或者甚至是一个非常感谢的示例。

提前致谢!

wavesurfer 插件: http://wavesurfer-js.org

网络编辑器 http://plucked.de

编辑解决方案(实例是 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')
  

【问题讨论】:

【参考方案1】:

阅读此answer 建议您可以创建一个与要复制的音频片段大小相同的空 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!

【讨论】:

非常感谢 katspaugh!这很棒!当我将新段粘贴到原始缓冲区时,是否还有一种方法可以重绘波形。 @dennis,是的,有 wavesurfer.loadDecodedBuffer 方法,它需要一个 AudioBuffer。见github.com/katspaugh/wavesurfer.js/blob/…【参考方案2】:

有趣的问题。想到的第一个词是ffmpeg。我不能从经验中谈起,但如果我想实现这一点,我会这样处理:

假设您选择了音轨的一个区域,并且您想要复制它并从中制作一个新音轨(稍后可能只是将其附加到现有音轨)。

    使用 nice wavesurfer.js 库提供的getSelection() 方法。这将为您提供startPosition()endPosition()[以秒为单位]。 鉴于这些要点,您现在可以在后端使用 ffmpeg 来选择区域并将其保存为新文件(最终将其上传到 S3 等)。请参阅此thread,了解如何从您的 ruby​​ 应用调用 ffmpeg(此处显示的命令行参数也很有帮助)。

请注意,如果您打算复制和粘贴许多区域来拼凑新轨道,那么一直在后端进行此操作可能没有意义,我想我会尝试寻找客户端 JS接近。

我希望这至少对一个简单的用例有所帮助,并帮助您开始其余的工作;)

更新 这可能值得一读。

Web Audio API,教程here。 html5 音频 - 播放状态。 here(不要错过 TimeRanges 部分,看起来是个不错的选择)。 这个one(已过时,但值得一看,有趣的链接)。

【讨论】:

您好 vint-i-vuit,非常感谢您的意见。我现在有了如何设置的方向,我将采用客户端方法,因为后端方法可能太重了。如果成功,我将确保回报并发布我的解决方案。 @dennis:我很高兴听到您现在对挑战有了更多的了解 :) 另外,再看看我更新的答案,我添加了一些可以帮助您的链接开始使用基于 JS 的方法。 非常感谢!事实上,TimeRanges 的文章看起来很有希望,我目前正在开发一个 javascript 库来涵盖这些功能,并结合 wavesurferjs 的波形,一旦它处于测试阶段,它将托管在 github 上。

以上是关于使用网络音频 api 和 wavesurfer.js 剪切和粘贴音频的主要内容,如果未能解决你的问题,请参考以下文章

如何使用来自网络套接字的网络音频 API 流式传输音频块?

如何在隐藏其容器 div 后使用网络音频 api 停止 iframe 中的音频?

预计算的 Web 音频 API 时域和频谱图可视化

使用网络音频 api 播放简单的声音

在连接到网络音频 api 的音频元素上设置播放速率

使用网络音频 API Ionic 2