javascript - 如何操作音频标签的内容并从中创建衍生音频标签?

标签 javascript html html5-audio

在我的网页上,我在标签内有一个音频文件。

<!DOCTYPE html>
<html>

<audio src="myTrack.mp3" controls preload="auto"></audio>

</html>

我想将这个存储在标签中的文件分割成多个 10 秒的音频文件,然后我可以将这些文件作为它们自己的音频文件分别插入到网页中 <audio>标签。
是否可以在 javascript 中执行此操作?

最佳答案

是的,这当然是可能的! :)

  • 确保音频满足 CORS 要求,以便我们可以使用 AJAX 加载它(从与页面相同的来源加载当然会满足此要求)。
  • 将文件加载为 ArrayBuffer 并使用 AudioContext 解码
  • 计算片段的数量和每个片段的长度(我使用独立于下面 channel 的基于时间的长度)
  • 将主缓冲区拆分为较小的缓冲区
  • 为新缓冲区创建一个文件包装器(下面我为演示制作了一个简单的 WAVE 包装器)
  • 通过 Object-URL 将其作为 Blob 提供给 Audio 元素的新实例
  • 跟踪对象 URL,以便您可以在不再需要时释放它们 (revokeObjectURL())。

一个缺点当然是您必须在处理之前将整个文件加载到内存中。

例子

希望我用于演示的文件可以通过当前用于允许使用 CORS 的 CDN 获得(我拥有版权,可以随意将其用于测试,但仅用于测试!!:))。加载和解码可能需要一些时间,具体取决于您的系统和连接,所以请耐心等待...

理想情况下,您应该使用异步方法拆分缓冲区,但该演示仅针对使缓冲区段可用作新文件片段所需的步骤。

另请注意,我没有考虑到最后一段比其他段更短(我使用 floor,您应该使用 ceil 作为段数并缩短最后一个 block 的长度)。我将把它作为练习留给读者......

var actx = new(AudioContext || webkitAudioContext)(),
    url = "//dl.dropboxusercontent.com/s/7ttdz6xsoaqbzdl/war_demo.mp3";

// STEP 1: Load audio file using AJAX ----------------------------------
fetch(url).then(function(resp) {return resp.arrayBuffer()}).then(decode);

// STEP 2: Decode the audio file ---------------------------------------
function decode(buffer) {
  actx.decodeAudioData(buffer, split);
}

// STEP 3: Split the buffer --------------------------------------------
function split(abuffer) {

  // calc number of segments and segment length
  var channels = abuffer.numberOfChannels,
      duration = abuffer.duration,
      rate = abuffer.sampleRate,
      segmentLen = 10,
      count = Math.floor(duration / segmentLen),
      offset = 0,
      block = 10 * rate;

  while(count--) {
    var url = URL.createObjectURL(bufferToWave(abuffer, offset, block));
    var audio = new Audio(url);
    audio.controls = true;
    audio.volume = 0.75;
    document.body.appendChild(audio);
    offset += block;
  }  
}

// Convert a audio-buffer segment to a Blob using WAVE representation
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 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;
  }
}
audio {display:block;margin-bottom:1px}

关于javascript - 如何操作音频标签的内容并从中创建衍生音频标签?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29584420/

相关文章:

html - 在 Edge 浏览器中使用 CSS 变量中的 URL

javascript - 网络音频分析器的 getFloatTimeDomainData 缓冲区偏移量在其他时间的缓冲区和 'complete file' 的缓冲区

javascript - 如何不间断地连续播放声音?

javascript - 如何调用保存在单独文件中的 JavaScript?

javascript - 如何从用户悬停的行中获取第一个单元格?

javascript - 如果使用 document.createElement 创建的视频元素在没有附加到页面的情况下播放,何时会被垃圾收集?

html - Perl,使用 Mechanize-Firefox,如何在保留在较大框架集中的同时扩展框架。

javascript - 如何在 angularjs 中注入(inject) persistencejs(未定义不是对象(评估 'persistence.store.cordovasql.config'))

javascript - Bootstrap 折叠导航栏不展开

javascript - 将 .wav 加载到音频缓冲区中