【问题标题】:How to get amplitude from opus audio?如何从作品音频中获取振幅?
【发布时间】:2018-07-10 16:56:06
【问题描述】:

我使用 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 编码的,所以我假设将每个数字的绝对值相加是行不通的,对吧?

谢谢!

【问题讨论】:

    标签: javascript opus web-mediarecorder


    【解决方案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。示例程序

    这是您使用 cmets 查找的代码示例(使用 opus-to-pcm。请注意,这不是理想的方法,因为首先不需要将音频编码为 opus (请参阅link for a clear tutorial 一起跳过 opus 格式)!此外,此示例将在您每次解码音频时创建阅读器,但我认为这更清楚地解释了您的特定问题的解决方案。另外,根据opus docs,音频位于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 callbacks 的一般理论,因为音频尤其倾向于非常基于回调,因为客户端 JS 是“单线程”的。

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

    【讨论】:

    • 谢谢!如何获得作品包?在我的代码中,每 200 毫秒我会得到一些字节数组,代表我假设的 200 毫秒内 opus 压缩音频的价值。抱歉,我对音频编码一无所知。我现在所做的就是使用 MediaRecorder webapi,每 200 毫秒(正如我在启动函数中设置的那样)我会得到一个字节数组。
    • 嗨@zhao,请查看我的更新答案以获得更深入的回复。如果正确,请标记为正确!非常感谢,希望对您有所帮助:)
    • 谢谢。 MediaRecorder 教程没有为音频指定 mime 类型或编解码器。它可能正在使用默认值。在 chrome 中,它是“video/webm”。我做了一些实验。如果我错了,请纠正我,但似乎捕获的数据仍在作品编解码器中。如果不是,它默认使用什么编解码器?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    相关资源
    最近更新 更多