javascript - ¿Cómo obtener el valor del volumen de entrada del micrófono con la api de audio web?
html5 google-chrome (3)
Aunque es un poco tarde, espero poder ayudarte.
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
}
Estoy utilizando la entrada de micrófono con la api de audio web y necesito obtener el valor del volumen.
Ahora mismo ya tengo el micrófono para trabajar: http://updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled
Además, sé que hay un método para manipular el volumen del archivo de audio: 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;
Pero, ¿cómo combinar estos dos y obtener el valor del volumen de entrada? Solo necesito el valor, no hay necesidad de manipularlo.
¿Alguien sabe?
Hay dos razones principales para querer obtener el "volumen": 1) detectar cuando la fuente se "graba", es decir, el valor absoluto de la señal supera un nivel preestablecido, generalmente muy cerca de 1.0, donde comenzará el recorte. 2) dé al usuario una idea de qué tan fuerte es su señal.
La razón por la que las enumero por separado es porque la primera requiere que procese cada muestra, porque de lo contrario podría perder un breve transitorio. Para esto, necesitará usar un nodo ScriptProcessor, y tendrá que recorrer cada muestra en el búfer dentro de un proceso de audio para buscar valores absolutos por encima de su nivel de clip. También podría determinar el nivel de RMS entonces, simplemente sumar los cuadrados de cada muestra, dividir por N y tomar la raíz cuadrada. Sin embargo, NO se procesa desde dentro de un proceso de audio: establezca los valores a los que accede en requestAnimationFrame.
También puede usar un AnalyserNode para hacer la detección de nivel, y simplemente promediar los datos, algo parecido a lo que hace la respuesta anterior en getAverageVolume. Sin embargo, la respuesta anterior NO es un buen uso de ScriptProcessor; de hecho, no hace ningún procesamiento del nodo de script, ni siquiera pasa la información, solo lo usa como una devolución de llamada del temporizador. Se le MIRARÍA mejor con el uso de requestAnimationFrame como la devolución de llamada visual; nunca establezca el diseño o los parámetros visuales desde adentro en un audioprocesamiento como este, o está pidiendo que golpee su sistema de audio. Si no necesita la detección de clips, solo haga el getByteFrequencyCount / getAverageVolume desde arriba en un AnalyserNode (pero debería minimizar el número de bandas en el Analizador: 64 es el mínimo, creo), y debe pre-asignar y reutilizar un Uint8Array en lugar de asignarlo cada vez (que aumentará la recolección de basura).
Hice una visualización de volumen para una reproducción de audio cuando estaba estudiando HTML 5.
Seguí este gran tutorial
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;
}
NOTA : Simplemente no sé si funcionará en una entrada de audio proveniente de un micrófono