javascript 如何使用网络音频 api 获取麦克风输入音量值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21247571/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get microphone input volume value with web audio api?
提问by kikkpunk
I am using the microphone input with web audio api and need to get the volume value.
我正在使用带有网络音频 api 的麦克风输入,需要获取音量值。
Right now I have already got the microphone to work: http://updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled
现在我已经让麦克风工作了:http: //updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled
Also, i know there's a method manipulating the volume of audio file: http://www.html5rocks.com/en/tutorials/webaudio/intro/
另外,我知道有一种操作音频文件音量的方法: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;
But how to combine these two and get the input volume value? I just need to the value, no need to manipulate it.
但是如何将这两者结合起来得到输入音量值呢?我只需要值,不需要操纵它。
Does anybody know?
有人知道吗?
采纳答案by cwilso
There are two main reasons to want to get the "volume":
想要获得“音量”有两个主要原因:
- detect when the source "clips"- i.e. the absolute value of the signal goes over a preset level, usually very near 1.0, where it will start clipping.
- give the user a feel for how loud their signal is.
- 检测源何时“削波”- 即信号的绝对值超过预设电平,通常非常接近 1.0,它将开始削波。
- 让用户感觉到他们的信号有多大。
The reason I list these separately is because the first requires that you process everysample - because you might miss a short transient otherwise. For this, you'll need to use a ScriptProcessor
node, and you'll have to iterate through every sample in the buffer inside onaudioprocess
to look for absolute values above your clip level. You couldjust determine the RMS level then, too - just sum the squares of each sample, divide by N and take the square root. DO NOTrender from within onaudioprocess
, though - set values that you access on requestAnimationFrame
.
我单独列出这些的原因是因为第一个要求您处理每个样本 - 因为否则您可能会错过一个短暂的瞬态。为此,您需要使用一个ScriptProcessor
节点,并且必须遍历内部缓冲区中的每个样本,onaudioprocess
以查找高于剪辑级别的绝对值。然后您也可以确定 RMS 电平 - 只需将每个样本的平方相加,除以 N 并取平方根。 不要从内部渲染onaudioprocess
,尽管设置了您访问的值requestAnimationFrame
。
You can also use an AnalyserNode
to do the level detection, and just average out the data, kind of like what the other answer doeswith getAverageVolume
. However, the other answer is NOTa good use of ScriptProcessor
- in fact, it's doing no processing of the script node at all, not even passing the data through, it's just using it like a timer callback. You would be FARbetter served by using requestAnimationFrame
as the visual callback; don't ever set layout or visual parameters from inside onaudioprocess
like this, or you're begging to thrash your audio system. If you don't need clip detection, just do the getByteFrequencyCount
/getAverageVolume
from above on an AnalyserNode
(but you should minimize the number of bands in the Analyser - 64 is the minimum, I think), and you should pre-allocate and reuse a Uint8Array
rather than allocating it each time (that will amp up the garbage collection).
你也可以使用一个AnalyserNode
做电平检测,只是平均出的数据,有点像在什么其他的回答也有getAverageVolume
。但是,另一个答案不是很好的用途ScriptProcessor
- 事实上,它根本不处理脚本节点,甚至不传递数据,它只是像计时器回调一样使用它。你会被FAR更好地利用担任requestAnimationFrame
作为视觉回调; 永远不要onaudioprocess
像这样从内部设置布局或视觉参数,否则你会乞求你的音频系统。如果您不需要剪辑检测,只需在上面执行getByteFrequencyCount
/getAverageVolume
AnalyserNode
(但您应该尽量减少分析器中的频段数量 - 我认为 64 是最少的),并且您应该预先分配和重用 aUint8Array
而不是每次都分配它(这会放大垃圾收集)。
回答by Netorica
I did a volume display for a playing audio when I was studying HTML 5.
我在学习 HTML 5 时为播放的音频做了一个音量显示。
I followed this great tutorial
我跟着这个很棒的教程
http://www.smartjava.org/content/exploring-html5-web-audio-visualizing-sound
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;
}
NOTE: I just don't know if it will work on an audio input came from a microphone
注意:我只是不知道它是否适用于来自麦克风的音频输入
回答by Huooo
Although it is a bit late, I still hope to help you.
虽然有点晚了,但还是希望能帮到你。
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
}