【问题标题】:Extracting audio data every t seconds每 t 秒提取一次音频数据
【发布时间】:2014-05-05 18:34:44
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

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

    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 秒的这些任意块的幅度。

    【讨论】:

    • 这是一个很好的方法。使用 OfflineAudioContext 不太可能更快 - 它并不是真正为完成这项任务而设计的。
    • +1,顺便说一下,把这个处理放到一个网络工作者中的想法。但是,这将有点挑战,因为您需要跨线程边界移动 AudioBuffer 的通道数据内容。使用可转让物品有效地做到这一点需要一些工作。
    猜你喜欢
    • 2011-04-23
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2023-03-11
    • 2016-02-08
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    相关资源
    最近更新 更多