我使用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,.....
我的问题是如何获得每个采样点的幅度或该剪辑的平均幅度?我的意图是用它来检测语音与静音。
剪辑是在作品中编码的,所以我想将每个数字的绝对值相加是行不通的,对吧?
谢谢!
答案 0 :(得分:0)
正如您所说,您不能只对数组取绝对值来获取振幅,因为这些值仍将采用压缩的opus
格式。所以在我看来有两个步骤:
当然可以使用许多库来完成此操作,但这只是我发现的一个库: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);
似乎简单易用!尽管我还没有机会自己使用它。
您提到了如何获得整个片段/单个样本的幅度,但是要获得整个片段,您确实需要单独的样本(至少用于计算)。
解码音频后,要查找单个样本的线性幅度,只需在缓冲区所需索引中获取值的绝对值即可
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
。
这是您要查找带有注释的代码的示例(使用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,实际上是易于可视化音频数据!)。