如何使用web audio api获取麦克风输入音量值?

时间:2014-01-21 01:39:56

标签: javascript html5 google-chrome html5-audio web-audio

我正在使用带有网络音频API的麦克风输入,需要获取音量值。

现在我已经让麦克风工作了: http://updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled

另外,我知道有一种操作音频文件音量的方法: http://www.html5rocks.com/en/tutorials/webaudio/intro/

    // Create a gain node.
    var gainNode = context.createGain();
    // Connect the source to the gain node.
    source.connect(gainNode);
    // Connect the gain node to the destination.
    gainNode.connect(context.destination);
   // Reduce the volume.
   gainNode.gain.value = 0.5;

但如何将这两者结合起来并获得输入音量值? 我只需要价值,不需要操纵它。

有人知道吗?

3 个答案:

答案 0 :(得分:20)

想要获得“音量”有两个主要原因: 1)检测源“剪辑”的时间 - 即信号的绝对值超过预设水平,通常非常接近1.0,它将开始削波。 2)让用户感觉信号的响亮程度。

我单独列出这些内容的原因是因为第一个要求您处理每个样本 - 因为否则您可能会错过短暂的瞬态。为此,您需要使用ScriptProcessor节点,并且您必须遍历onaudioprocess内缓冲区中的每个样本,以查找高于剪辑级别的绝对值。然后你可以确定RMS水平 - 只需将每个样本的平方和除以N并取平方根。但是,不要在onaudioprocess中渲染 - 设置您在requestAnimationFrame上访问的值。

您还可以使用AnalyserNode进行电平检测,并将数据平均化,就像上面的答案在getAverageVolume中所做的那样。但是,上面的答案并不能很好地利用ScriptProcessor - 事实上,它根本不对脚本节点进行处理,甚至不传递数据,它只是像计时器回调一样使用它。使用requestAnimationFrame作为可视回调,您将获得更好的服务;不要像这样在onaudioprocess里面设置布局或视觉参数,或者你要求捶打你的音频系统。如果您不需要剪辑检测,只需在AnalyserNode上从上面执行getByteFrequencyCount / getAverageVolume(但您应该最小化Analyzer中的波段数 - 我认为64是最小的),您应该预先分配和重用Uint8Array而不是每次都分配它(这会增加垃圾收集)。

答案 1 :(得分:6)

我在学习HTML 5时播放音频时进行了音量显示。

我遵循了这个伟大的教程

http://www.smartjava.org/content/exploring-html5-web-audio-visualizing-sound

 // setup a analyzer
 analyser = context.createAnalyser();
 analyser.smoothingTimeConstant = 0.3;
 analyser.fftSize = 1024;

 javascriptNode = context.createScriptProcessor(2048, 1, 1);


 javascriptNode.onaudioprocess = function() {

        // get the average, bincount is fftsize / 2
        var array =  new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(array);
        var average = getAverageVolume(array)

         console.log('VOLUME:' + average); //here's the volume
 }

 function getAverageVolume(array) {
        var values = 0;
        var average;

        var length = array.length;

        // get all the frequency amplitudes
        for (var i = 0; i < length; i++) {
            values += array[i];
        }

        average = values / length;
        return average;
  }

注意:我只是不知道它是否适用于来自麦克风的音频输入

答案 2 :(得分:1)

虽然已经有点晚了,但我仍然希望能为您提供帮助。

h5_get_microphone_volume

var audioContext = new (window.AudioContext || window.webkitAudioContext)()
var mediaStreamSource = null
var meter = null

if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  navigator.mediaDevices.getUserMedia({audio: true}).then((stream) => {
    mediaStreamSource = audioContext.createMediaStreamSource(stream)
    meter = createAudioMeter(audioContext)
    mediaStreamSource.connect(meter)
  })
}

function createAudioMeter(audioContext, clipLevel, averaging, clipLag) {
  const processor = audioContext.createScriptProcessor(512)
  processor.onaudioprocess = volumeAudioProcess
  processor.clipping = false
  processor.lastClip = 0
  processor.volume = 0
  processor.clipLevel = clipLevel || 0.98
  processor.averaging = averaging || 0.95
  processor.clipLag = clipLag || 750

  // this will have no effect, since we don't copy the input to the output,
  // but works around a current Chrome bug.
  processor.connect(audioContext.destination)

  processor.checkClipping = function () {
    if (!this.clipping) {
      return false
    }
    if ((this.lastClip + this.clipLag) < window.performance.now()) {
      this.clipping = false
    }
    return this.clipping
  }

  processor.shutdown = function () {
    this.disconnect()
    this.onaudioprocess = null
  }

  return processor
}

function volumeAudioProcess(event) {
  const buf = event.inputBuffer.getChannelData(0)
  const bufLength = buf.length
  let sum = 0
  let x

  // Do a root-mean-square on the samples: sum up the squares...
  for (var i = 0; i < bufLength; i++) {
    x = buf[i]
    if (Math.abs(x) >= this.clipLevel) {
      this.clipping = true
      this.lastClip = window.performance.now()
    }
    sum += x * x
  }

  // ... then take the square root of the sum.
  const rms = Math.sqrt(sum / bufLength)

  // Now smooth this out with the averaging factor applied
  // to the previous sample - take the max here because we
  // want "fast attack, slow release."
  this.volume = Math.max(rms, this.volume * this.averaging)
  document.getElementById('audio-value').innerHTML = this.volume
}