流程:
- 使用scriptprocessor记录前端音频流,转换成Float32Array
- 将Float32Array转换成16bit PCM
- 计算公式:引用:如何计算音频dB级别?
代码:
function floatTo16BitPCM(output: DataView, offset: number, input: Float32Array) {
for (let i = 0; i < input.length; i++, offset += 2) {
let s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
}
}
function onMediaSuccess(stream): Promise<Float32Array[]> {
return new Promise(resolve => {
const context = new AudioContext();
const audioInput = context.createMediaStreamSource(stream);
var inputData = [];
const recorder = context.createScriptProcessor(4096, 1, 1);
recorder.onaudioprocess = function(e) {
var data = e.inputBuffer.getChannelData(0);
inputData.push(new Float32Array(data));
};
audioInput.connect(recorder);
recorder.connect(context.destination);
setTimeout(() => {//噪声录音至少需要1s,数据才可用
resolve(inputData);
recorder.disconnect();
audioInput.disconnect();
if (stream) {
stream.getAudioTracks().forEach(function(track) {
track.stop();
});
stream = null;
}
}, 1000);
});
}
//数据合并
function compress(inputData: Float32Array[]) {
let size = 0;
for (let i = 0; i < inputData.length; i++) {
size += inputData[i].length;
}
var data = new Float32Array(size);
var offset = 0;
for (var i = 0; i < inputData.length; i++) {
data.set(inputData[i], offset);
offset += inputData[i].length;
}
return data;
}
//record button click
const onRecord = () => {
navigator.mediaDevices.getUserMedia(mediaConstraints).then(async function computeNoise(stream) {
const inputData = await onMediaSuccess(stream);
const samples = compress(inputData);
const db = getDB(samples);
Recording(db);//正式录音
});
};
//计算DB
const getDB = (samples: Float32Array): number => {
const bitDepth = 16;
const bytesPerSample = bitDepth / 8;
const offset = 0;
let buffer = new ArrayBuffer(samples.length * bytesPerSample);
let view = new DataView(buffer);
floatTo16BitPCM(view, offset, samples);
const int16Audio = new Int16Array(buffer);
let avgEnergy = 0;
int16Audio.forEach(fragment => {
avgEnergy += fragment * fragment;
});
avgEnergy = Math.sqrt(avgEnergy / int16Audio.length);
const db = 20 * Math.log10(avgEnergy / 32767);
return Number(db.toFixed(3));
};
参考:js实现pcm数据编码