1

我使用 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,……

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

剪辑是用 opus 编码的,所以我假设将每个数字的绝对值相加是行不通的,对吧?

谢谢!

4

1 回答 1

1

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

1.解码你的作品音频

这可以使用许多库来完成,我确定,但这只是我发现的一个:opus-to-pcm。这建议要么使用他们的库,要么使用 Web-Audio API 来解码作品。他们的库的一个例子:

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。请注意,这不是理想的方法,因为首先不需要将音频编码为 opus(请参阅此链接以获取有关一起跳过 opus 格式的清晰教程)!此外,此示例将在您每次解码音频时创建阅读器,但我认为这更清楚地解释了您的特定问题的解决方案。此外,根据opus 文档,音频位于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回调的一般理论,因为音频尤其倾向于非常基于回调,因为客户端 JS 是“单线程”的。

我不完全确定这是否是您想要遵循的过程,但如果您需要 opus 格式的音频,那么就足够公平了。但是,如果您只是想录制音频以显示数据,我肯定会查看Web-Audio API - 这是一个让您入门的示例(它内置了音频 FX,并且非常容易可视化音频数据!)。

于 2018-07-09T07:58:36.383 回答