JavaScript web端录音测试噪声

流程:

  1. 使用scriptprocessor记录前端音频流,转换成Float32Array
  2. 将Float32Array转换成16bit PCM
  3. 计算公式:引用:如何计算音频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数据编码

原文地址:https://www.cnblogs.com/xym4869/p/13638008.html