image.png最近公司想做一个小程序, 有个功能就是声控, 判断用户声音的大小, 去让机器执行多大的频率.
怎么做?
官网网站并没有明确的api给你提供, 正当我疑惑的时候, 我查看官方文档看到frameBuffer
, 查了很多资料,渐渐找到了解决方式
onFrameRecorded 传过来的是MP3帧,但是,这个帧有的时候是不完整的帧,好像是小程序的性能问题或者之类的其他问题。
使用js-mp3,把MP3帧解码成PCM数据,然后再按照pcm数据,来计算分贝数。
npm i js-mp3
-
踩坑的地方:
1.famebuffer设置的太小,造成传过来的arrayBuffer里面没有一个完整的mp3帧,结果就是Decode失败。以为是小程序的黑箱问题。
2.js-mp3声称自己不支持mpeg2,感觉心里凉了半截,后来“高坚果”给了一个表格:
image.png
原来是采样率设置问题,修改为44.1khz采样率,搞定。
- 效率很差。因为中间经过了mp3压缩,然后再解码,再判断分贝大小,所以,效率真的很差。不过能解决问题的办法都是好办法
代码如下:
先让uni.getRecorderManager()
变成全局
var _this = this;
_this.rec = uni.getRecorderManager();
再通过Mp3压缩进行计算
_this.rec.onFrameRecorded(function(res) {
// console.log(res);
if (res.isLastFrame) return; // 为true当前帧是否正常录音结束前的最后一帧
const { frameBuffer } = res
var decoder = Mp3.newDecoder(frameBuffer); // 压缩
if (decoder != null) {
var pcmArrayBuffer = decoder.decode()
var pcmArr = new Int16Array(pcmArrayBuffer)
var size = pcmArr.length
var sum = 0;
for (var i = 0; i < size; i++) {
sum += Math.abs(pcmArr[i]);
}
var powerLevel = sum * 500.0 / (size * 16383);
if (powerLevel >= 100) {
powerLevel = 100
}
if (powerLevel <= 5) {
powerLevel = 2
}
powerLevel = parseInt(powerLevel);
var db = Math.floor(120 * (powerLevel / 100));
powerLevel = Math.floor(-108 + 108 * 2 * (powerLevel / 100));
if(db >= 40){ // 大于等于40为交流声, 显示
console.log(db);
}
}
})
}
完整代码可访问github, 如果对你有帮助, 点个赞呗
https://github.com/xxj435/smi_demo
网友评论