如何使用Web音频API获取麦克风输入音量值?

27

我正在使用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个回答

26

希望得到“音量”的两个主要原因:

  1. 检测声源何时“削波”——即信号的绝对值超过预设水平,通常非常接近1.0,此时将开始削波。
  2. 让用户感受他们的信号有多响。

我将这两个原因分开列出是因为第一个需要处理每个采样——因为否则你可能会错过短暂的瞬变。为此,您需要使用ScriptProcessor节点,并且在onaudioprocess中迭代缓冲区中的每个样本以查找超过您的削波级别的绝对值。您也可以只确定RMS级别——只需将每个样本的平方和相加,除以N并取平方根。但是,请不要onaudioprocess内渲染——请设置可以在requestAnimationFrame中访问的值。

您还可以使用 AnalyserNode 进行级别检测,并且只需对数据进行平均处理,有点像其他答案中getAverageVolume。 但是,另一个答案不是良好地使用了ScriptProcessor - 实际上,它根本没有处理脚本节点的任何数据,甚至没有通过它传递数据,只是像一个计时器回调一样使用它。 最好使用 requestAnimationFrame 作为视觉回调;请勿在 onaudioprocess 中设置布局或可视化参数,否则您将使音频系统陷入混乱。 如果您不需要剪辑检测,只需在 AnalyserNode 上执行以上的 getByteFrequencyCount/getAverageVolume(但应将 Analyser 中的带数最小化 - 我想最小值为 64),并且您应该预分配和重用 Uint8Array 而不是每次都分配它(这将增加垃圾收集)。

2
有没有快速获取峰值的方法?我本来以为这是AnalyserNode的基本功能之一(除了RMS)。它已经为我们完成了FFT的所有工作,但却没有提供简单峰值或RMS计量所需的基本功能。ScriptProcessorNode仍然是最快的方法吗?如果是,恐怕它只能在同时处理几个通道时才能使用。请您发挥专业知识,希望能得到奇迹。 :-) - Brad
1
不,ScriptProcessor目前是唯一用于检测峰值剪辑的工具。当然,AudioWorkers会使这个过程更快,但它还没有发布。 - cwilso
3
为什么要使用 getByteFrequencyData 而不是 getByteTimeDomainData - bennlich

8

虽然有点晚了,但我仍然希望能帮到你。

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
}

6
这.volume的单位是什么?是dbs吗?还是某个百分比? - Falieson
2
我给他点了赞,但上面的代码是由Chris Wilson @cwilso编写的。请参阅:https://github.com/cwilso/volume-meter - Giorgio Robino

8

当我学习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;
  }

注意:我不确定它是否适用于来自麦克风的音频输入。


教程链接已失效,但我找到了这个(也许是同一篇文章):https://dzone.com/articles/exploring-html5-web-audio这个教程是学习Web Audio API的好地方,但它使用了过时的特性(比如javascriptNode)。建议阅读一次后,学习新的AudioWorklet特性:https://dev59.com/OFIG5IYBdhLWcg3w2VMZ - ssnake

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接