我正在使用带有网络音频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;
但如何将这两者结合起来并获得输入音量值? 我只需要价值,不需要操纵它。
有人知道吗?
答案 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)
虽然已经有点晚了,但我仍然希望能为您提供帮助。
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
}