每t秒提取音频数据

时间:2014-03-27 01:27:44

标签: html5-audio web-audio sampling audio-processing amplitude

我正在尝试使用Web Audio API瞬间(不是实时)从URL加载的声音中提取振幅信息,这可能需要OfflineAudioContext。我希望在声音的持续时间内每隔t秒获得一个包含声音幅度的数组线(大小取决于声音的持续时间除以t) 。不幸的是,此时文档很少,我不确定如何继续。如何加载声音并每隔t秒提取振幅?

1 个答案:

答案 0 :(得分:2)

这很快就完成了,所以数学可能搞砸了。但希望它能让你开始......

var ac = new webkitAudioContext(),
  url = 'path/to/audio.mp3';

function fetchAudio( url, callback ) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer';
  xhr.onload = function() {
    callback(xhr.response);
  };
  xhr.send();
}

function decode( arrayBuffer, callback ) {
  ac.decodeAudioData(arrayBuffer, function( audioBuffer ) {
    callback(audioBuffer);
  });
}

// return an array of amplitudes for the supplied `audioBuffer`
//
// each item in the array will represent the average amplitude (in dB)
// for a chunk of audio `t` seconds long
function slice( audioBuffer, t ) {
  var channels = audioBuffer.numberOfChannels,
    sampleRate = ac.sampleRate,
    len = audioBuffer.length,
    samples = sampleRate * t,
    output = [],
    amplitude,
    values,
    i = 0,
    j, k;
  // loop by chunks of `t` seconds
  for ( ; i < len; i += samples ) {
    values = [];
    // loop through each sample in the chunk
    for ( j = 0; j < samples && j + i < len; ++j ) {
      amplitude = 0;
      // sum the samples across all channels
      for ( k = 0; k < channels; ++k ) {
        amplitude += audioBuffer.getChannelData(k)[i + j];
      }
      values.push(amplitude);
    }
    output.push(dB(values));
  }
  return output;
}

// calculate the average amplitude (in dB) for an array of samples
function dB( buffer ) {
  var len = buffer.length,
    total = 0,
    i = 0,
    rms,
    db;
  while ( i < len ) {
    total += ( buffer[i] * buffer[i++] );
  }
  rms = Math.sqrt( total / len );
  db = 20 * ( Math.log(rms) / Math.LN10 );
  return db;
}


// fetch the audio, decode it, and log an array of average
// amplitudes for each 5-second chunk
fetchAudio(url, function( arrayBuffer ) {
  decode(arrayBuffer, function( audioBuffer ) {
    console.log(slice(audioBuffer, 5));
  });
});

基本上,如果您想要比实时更快地获取整个缓冲区的数据,那么您甚至不需要OfflineAudioContext。你可以阅读样本,做一些数学计算,然后弄明白。

但这很慢。特别适合较大的音频文件。所以你可能想把它放在Web Worker中。

使用OfflineAudioContext可能会更快。我真的不确定。但是,即使你决定沿着这条路走下去,仍然需要做大量的手工工作才能获得t秒这些任意块的振幅。