JavaScript web端錄音測試噪聲
阿新 • • 發佈:2020-09-09
流程:
- 使用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資料編碼