【问题标题】:How can I overwrite part of web audio with new recorded audio?如何用新录制的音频覆盖部分网络音频?
【发布时间】:2023-03-28 15:26:01
【问题描述】:

我正在成功录制音频、存储音频并将其重新加载到Audio 对象中以便在浏览器中播放。

但是,我希望能够录制新音频并在某个时间偏移处将其“拼接”到原始录音中,从该偏移处完全替换原始录音的那部分。例如,假设我从麦克风录制了 10 秒的音频,然后,我希望用 8 秒的全新音频“录制”该音频的最后 5 秒,最终得到一个我可以保留的新 bufferArray。我已经花了几个小时研究这个,但仍然很模糊如何做到这一点。如果有人有任何建议,我将不胜感激。

我能找到的最接近的例子涉及获取两个缓冲区并尝试将它们连接起来,如this fiddle。但是,我在将这个小提琴与我的代码以及我需要做的事情联系起来时遇到了一些困难。某些帖子提到我需要知道采样率,创建具有相同采样率的新缓冲区,并将数据从两个缓冲区复制到新缓冲区中。但是关于这种技术的工作示例很少,我正在努力从 MDN 文档中弄清楚这一点。

这是我现在正在使用的代码。

const saveRecordedAudio = (e) => {
  console.log("Audio data available", e.data);
  const reader = new FileReader();
  reader.addEventListener("loadend", function() {
    // reader.result contains the contents of blob as a typed array
    let bufferArray = reader.result;
    // From: https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
    let base64String = btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c){return p+String.fromCharCode(c)},''));
    // persist base64-encoded audio data on filesystem here.
    storeRecordedAudio(base64String); // defined elsewhere and not shown here for brevity's sake
  });
  reader.readAsArrayBuffer(e.data);

  const audioUrl = window.URL.createObjectURL(e.data);
  // Put the recorded audio data into the browser for playback.
  // From: http://stackoverflow.com/questions/33755524/how-to-load-audio-completely-before-playing (first answer)
  const audioObj = new Audio (audioUrl);
  audioObj.load();

};

const recordAudio = () => {
  navigator.getUserMedia = ( navigator.getUserMedia ||
                             navigator.webkitGetUserMedia ||
                             navigator.mozGetUserMedia ||
                             navigator.msGetUserMedia);
  if (navigator.getUserMedia) {
    navigator.getUserMedia (
      { // constraints - only audio needed for this app
        audio: true
      },
      // Success callback
      function(stream) {
        const mediaRecorder = new MediaRecorder(stream);
        mediaRecorder.ondataavailable = audio.saveRecordedAudio;
      }),
      // fail callback
      function(err) {
        console.log('Could not record.');
      }
   );
  }
};


// I've already fetched a previously recorded audio buffer encoded as
// a base64 string, so place it into an Audio object for playback
const setRecordedAudio => (b64string) => {
  const labeledAudio = 'data:video/webm;base64,' + b64String;
  const audioObj = new Audio(labeledAudio);
  audioObj.load();
};

【问题讨论】:

  • 只保存传递给许多 Blob 构造函数的 bufferArrays 可能会有所帮助。如果你有原件。相应的数组,您可以从聚合的 bufferArray 中添加、减去它们,并将最后一个 BA 传递给新的 blob 构造函数,从而实现音频剪辑的混合和匹配请求。
  • github.com/higuma/mp3-lame-encoder-js/blob/master/src/… - mp3 示例,您可以在其中调整 raw 、 arrayBuffer 以混合、聚合各个剪辑及其原点。数组缓冲区。
  • npmjs.com/package/blob-to-buffer 从 blob 返回到 arrayBuff。
  • 感谢您的提示。这确实对我有帮助。但是,我仍然不确定是否可以将第一个 bufferArray 的任意部分复制到一个新数组中,然后与另一个 bufferArray 聚合(使用 Blob),因为我不知道如何关联要复制的字节数,到毫秒的录音。即,假设我需要 5.27 秒的第一个剪辑与整个第二个剪辑相结合。我将如何计算从第一个 bufferArray 中复制多少字节?
  • 我还会查看节点后端的 ffmpeg 来为您管理时间戳。你只会做 CLI 或 API 调用,而 ffmpeg 会做所有时间戳的东西 4 u。缺点是所有剪辑都必须位于云/后端,CLI 或 API 才能正常工作。

标签: javascript web audio html5-audio web-audio-api


【解决方案1】:

如果我得到你想要做的正确的事情,这是我处理这个问题的方法:

1-我们应该声明一个blob数组并在其中存储数据:

var chuncks = [];

2-我们需要知道记录的秒数:

我们应该使用带有时间片参数的start(1000)方法来限制每个blob中的毫秒数, 在这种情况下,我们知道每个数据块大约为 1 秒长( chunks.length = 记录的秒数)。并且要使用数据填充块数组,ondataavailable 事件处理程序 是我们的朋友:

mediaRecorder.ondataavailable = function( event ) {
    chunks.push( event.data );
}

现在,我们必须处理简单的Arrays 而不是缓冲区数组 :-D(在您的示例中,我们应该删除或覆盖最后 5 个项目并继续向其中添加 blob)

3- 最后,当我们的录音准备就绪时(块数组):

我们应该使用Blob 构造函数将它们连接在一起:

new Blob(chunks, {'type' : 'audio/webm;codecs=opus'});

我希望这会有所帮助:-D

【讨论】:

  • 谢谢,这是一个有用的提示。我将研究 start() 方法。但正如我上面评论的那样,我真正需要的是能够保留第一个剪辑的任意毫秒数,并将其与整个第二个剪辑结合起来。有了你的建议,我不会被限制在1s的分辨率吗?我的意思是,我想这些块可能是 100 毫秒长,这可能足够小而不会导致丢失......但是为了以防万一用户想要添加另一个剪辑,永久保留所有块可能会变得笨拙。
  • 上面的 start(1000) 只是一个例子,如果适合你,你可以使用 100 而不是 1000。
  • 据我所知,这是唯一简单的方法,请记住,裁剪音频文件的确切特定部分并不容易( 5.27s 为您在上面的评论中提到),因为它包含多个声音信号。
  • 请告诉我是否有其他简单的方法可以做到这一点。谢谢。
  • 这完全是错误的,有几个原因。首先,提供给start 的时间片只是对浏览器的建议,它应该多久获取一次数据块。无法保证它们会精确计时,如果您运行它足够长的时间或使用低于 1000 毫秒的值,它很快就会与经过的时间不同步。第二个是Blob数据不是均匀分布的,所以你不能随意剪切和粘贴,因为你很容易最终删除标题信息并导致文件损坏。
猜你喜欢
  • 2014-02-09
  • 1970-01-01
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多