如何从作品音频中获取振幅?

时间:2018-07-06 21:57:01

标签: javascript opus web-mediarecorder

我使用webapi MediaRecorder捕获语音。

var options = {mimeType: "audio/webm;codecs=opus", audioBitsPerSecond:16000};
mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.addEventListener("dataavailable", function(event) {
    var reader = new FileReader();
    reader.addEventListener("loadend", function() {
        var int8View = new Int8Array(reader.result);
    });
    reader.readAsArrayBuffer(event.data);
});
mediaRecorder.start(200);

所以每隔200毫秒,我会得到一个包含音频剪辑的Blob。该数据的int8View看起来像:

-5,-127,36,84,-128,123,-125,37,35,-109,-94,120,111,-110,40,-93,-7,77,35,-62,83,- 36,-12,47,127,47,-75,-35,89,55,65,-75,-106,96,-86,30,118,37,51,-28,-2,-38,124,-95,102, -91,-109,.....

我的问题是如何获得每个采样点的幅度或该剪辑的平均幅度?我的意图是用它来检测语音与静音。

剪辑是在作品中编码的,所以我想将每个数字的绝对值相加是行不通的,对吧?

谢谢!

1 个答案:

答案 0 :(得分:0)

正如您所说,您不能只对数组取绝对值来获取振幅,因为这些值仍将采用压缩的opus格式。所以在我看来有两个步骤:

1。解码您的作品音频

当然可以使用许多库来完成此操作,但这只是我发现的一个库:opus-to-pcm。这建议您使用他们的库或Web-Audio API来解码作品。他们的lib的例子:

var decoder = new Decoder.OpusToPCM({
  channels: 1,
  fallback: true 
});
decoder.on('decode', function(pcmData) {
     //do whatever you want to do with PCM data
});

// single opus packet and it is a typedArray
decoder.decode(opus_packet); 

似乎简单易用!尽管我还没有机会自己使用它。

2。得到你的振幅

您提到了如何获得整个片段/单个样本的幅度,但是要获得整个片段,您确实需要单独的样本(至少用于计算)。

解码音频后,要查找单个样本的线性幅度,只需在缓冲区所需索引中获取值的绝对值即可

var sampleAmplitude = Math.abs(buffer[index]);

更常用的方法是使用RMS(均方根)值获取整个块的平均值。

var rms = 0;

for (var i = 0; i < buffer.length; i++) {
  rms += buffer[i] * buffer[i];
}

rms /= buffer.length;
rms = Math.sqrt(rms);

这会遍历整个缓冲区,并对缓冲区的所有平方值求和。然后通过将平均值除以样本长度来得出平均值,最后得出平方根。

我提到的两种计算都以线性形式(即0到1之间)将值返回给您,但是在音频中,我们倾向于使用dB(分贝)。要转换您计算出的线性项,只需使用:

var dBAmplitude = 20*Math.log10(linAmplitude);

通常在该方程式中使用RMS值代替linAmplitude

3。示例程序

这是您要查找带有注释的代码的示例(使用opus-to-pcm。请注意,这不是理想的处理方式,因为无需在首先(请参阅此link for a clear tutorial一起跳过opus格式)!此示例还将在每次解码音频时创建阅读器,但是我认为这可以更清楚地说明您的特定问题的解决方案。此外,根据{{3 }}音频为int16格式(我更改了您的数组类型)。

// Calculate RMS of block (Linear)
function calcrms_lin(buffer){

    var rms = 0;

    for(var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++){
        rms+= buffer[bufferIndex]*buffer[bufferIndex];
    }

    rms /= buffer.length;
    rms = Math.sqrt(rms);

    return rms;

}

// Calculate RMS of block db
function calcrms_db(buffer){
    return 20*Math.log10(calcrms_lin(buffer));
}

// Create opus-to-pcm decoder
var decoder = new Decoder.OpusToPCM({
    channels: 1,
    fallback: true 
  });

// Assign function to decode callback
decoder.on('decode', function(pcmData) {

    // Get amplitude of entire block rms (in dB) everytime its decoded
    var dBAmplitude = calcrms_db(pcmData);

    // Do what you want with the dBAmplitude variable e.g. display it to the screen or whatever

});

// Create options for media recorder
var options = {mimeType: "audio/webm;codecs=opus", audioBitsPerSecond:16000};

// Construct media recorder
mediaRecorder = new MediaRecorder(stream, options);

// Add callback for when data available from recorder
mediaRecorder.addEventListener("dataavailable", function(event) {

    // New file 
    var reader = new FileReader();

    // Assign callback
    reader.onload = function(){
        var audioBuffer = new Int16Array(reader.result);
        decoder.decode(audioBuffer);
    }

    // Read data into file reader (will start the onload function above)
    reader.readAsArrayBuffer(event.data);

});

// Start media recorder process
mediaRecorder.start(200);

注意:此代码未经测试,仅应作为示例

额外

如果您不确定这方面的知识,也许值得进一步研究JS opus docs的一般理论,因为音频特别倾向于基于回调,因为客户端JS是“单线程”。

我不确定这是否是您要遵循的过程,但是如果您需要Opus格式的音频,那么就足够了。但是,如果您只是想录制音频以显示数据,那我肯定会看看callbacks-这是一个Web-Audio API入门(它内置了音频FX,实际上是易于可视化音频数据!)。