Aprende a recuperar y mostrar una representación del nivel de señal del micrófono en su navegador con JavaScript.

Cómo crear un medidor de volumen (medir el nivel de sonido) en el navegador con JavaScript

Como uno de esos proyectos raros que nos gusta compartir aquí en Our Code World, te traemos hoy una de esas funciones que probablemente no usarás en tu escena Laboral sino en proyectos personales o simplemente para ampliar tus conocimientos de Javascript. Estamos hablando de un útil "Volume Meter" que viene muy bien para visualizarlo gráficamente para advertir al que usa el sistema con la famosa barra verde y roja, que debe hablar en voz baja.

Empecemos !

1. Descarga Volume Meter

Volume Meter no es un complemento, sino una colección de 2 funciones útiles que lo ayudarán a recuperar el nivel de entrada del micrófono a través de la API de WebAudio. Si estás trabajando en algún tipo de proyecto científico sobre cómo recuperar el nivel de sonido del micrófono a través del navegador, probablemente esto no sea lo que estás buscando. Pero si el objetivo es tener una idea general de una medida del nivel de sonido para su usuario, entonces podría ser bastante útil.

Descargue el script del medidor de volumen en el repositorio de Github aquí . Este script fue escrito por Chris Wilson en Google, visite el repositorio oficial en Github para obtener más información.

2. Uso del medidor de volumen

Como se mencionó anteriormente, el "complemento" son 2 funciones, puede decidir por su cuenta si desea declararlas en la ventana o simplemente agregarlas como un nuevo script en su documento. El punto es que las 2 funciones del complemento están disponibles:  createAudioMetery  volumeAudioProcess.

Con esas funciones, ahora puede recuperar el nivel de sonido del micrófono y puede realizar cualquiera de las siguientes tareas:

Importante

Vale la pena decir que los scripts ( getUserMedia) deben ejecutarse una vez que se cargue la ventana, de lo contrario fallará por razones obvias.

Nivel de visualización en Canvas

Para mostrar la barra conocida que se vuelve verde y roja según el nivel de entrada del micrófono, puede usar el siguiente código. Intentará acceder al User Media API y a través del flujo recibido como primer argumento en la devolución de llamada onMicrophoneGranted, se podrá recuperar el nivel de entrada del micrófono gracias a las funciones del plugin createAudioMeter y volumeAudioProcess:

<!-- El lienzo que se utilizará para representar el nivel de entrada.  -->
<canvas id="meter" width="500" height="50"></canvas>

<script>
/*
The MIT License (MIT)

Copyright (c) 2014 Chris Wilson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
var audioContext = null;
var meter = null;
var canvasContext = null;
var WIDTH=500;
var HEIGHT=50;
var rafID = null;

window.onload = function() {

    // tomar el canvas
	canvasContext = document.getElementById( "meter" ).getContext("2d");
	
    // monkeypatch Web Audio
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
	
    // tomar un contexto de audio
    audioContext = new AudioContext();

    // Intenta obtener entrada de audio
    try {
        // monkeypatch getUserMedia
        navigator.getUserMedia = 
        	navigator.getUserMedia ||
        	navigator.webkitGetUserMedia ||
        	navigator.mozGetUserMedia;

        // pide una entrada de audio
        navigator.getUserMedia(
        {
            "audio": {
                "mandatory": {
                    "googEchoCancellation": "false",
                    "googAutoGainControl": "false",
                    "googNoiseSuppression": "false",
                    "googHighpassFilter": "false"
                },
                "optional": []
            },
        }, onMicrophoneGranted, onMicrophoneDenied);
    } catch (e) {
        alert('getUserMedia threw exception :' + e);
    }

}

function onMicrophoneDenied() {
    alert('Stream generation failed.');
}

var mediaStreamSource = null;

function onMicrophoneGranted(stream) {
    // Cree un AudioNode a partir de la transmisión.
    mediaStreamSource = audioContext.createMediaStreamSource(stream);

    // Cree un nuevo medidor de volumen y conéctelo.
    meter = createAudioMeter(audioContext);
    mediaStreamSource.connect(meter);

    // iniciar la actualización visual
    onLevelChange();
}

function onLevelChange( time ) {
    // limpiar el fondo
    canvasContext.clearRect(0,0,WIDTH,HEIGHT);

    // compruebe si actualmente estamos recortando
    if (meter.checkClipping())
        canvasContext.fillStyle = "red";
    else
        canvasContext.fillStyle = "green";

    console.log(meter.volume);

    // dibuja una barra basada en el volumen actual
    canvasContext.fillRect(0, 0, meter.volume * WIDTH * 1.4, HEIGHT);

    // configurar la siguiente devolución de llamada visual
    rafID = window.requestAnimationFrame( onLevelChange );
}
</script>

El código anterior debería mostrar un lienzo simple en forma de barra que cambia cuando usa el micrófono:

Microphone Input Level

Puede consultar el script de trabajo que muestra  una implementación básica del Medidor de volumen en su navegador aquí  (y lo muestra en un lienzo).

Standalone

En caso de que desee mostrar un medidor de volumen personalizado con su propio estilo, solo necesitará los valores del medidor de volumen en lugar de mostrarlos en un lienzo. Para recuperar solo los valores, simplemente puede eliminar todo el código relacionado con el elemento canvas del script anterior.

El siguiente fragmento mostrará, una vez iniciado, el valor de volumen del objeto medidor (de 0,00 a 1,00) en la consola (respectivamente con console.logsi el nivel es "normal" o con console.warnsi el volumen está "recortado") con la onLevelChangefunción:

/**
 * Cree variables accesibles globales que se modificarán más adelante
 */
var audioContext = null;
var meter = null;
var rafID = null;
var mediaStreamSource = null;

// Recuperar AudioContext con todos los prefijos de los navegadores
window.AudioContext = window.AudioContext || window.webkitAudioContext;

// Obtenga un contexto de audio
audioContext = new AudioContext();

/**
 * Devolución de llamada activada si se deniega el permiso del micrófono
 */
function onMicrophoneDenied() {
    alert('Stream generation failed.');
}

/**
 * Devolución de llamada activada si se concede el acceso al micrófono
 */
function onMicrophoneGranted(stream) {
    // Cree un AudioNode a partir de la transmisión.
    mediaStreamSource = audioContext.createMediaStreamSource(stream);
    // Cree un nuevo medidor de volumen y conéctelo.
    meter = createAudioMeter(audioContext);
    mediaStreamSource.connect(meter);

    // Activar devolución de llamada que muestra el nivel del "Medidor de volumen"
    onLevelChange();
}

/**
 * Esta función se ejecuta repetidamente
 */
function onLevelChange(time) {
    // compruebe si actualmente estamos recortando

    if (meter.checkClipping()) {
        console.warn(meter.volume);
    } else {
        console.log(meter.volume);
    }

    // configurar la siguiente devolución de llamada
    rafID = window.requestAnimationFrame(onLevelChange);
}


// Intenta acceder al micrófono
try {

    // Recuperar la API getUserMedia con todos los prefijos de los navegadores
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

    // Solicita una entrada de audio
    navigator.getUserMedia(
        {
            "audio": {
                "mandatory": {
                    "googEchoCancellation": "false",
                    "googAutoGainControl": "false",
                    "googNoiseSuppression": "false",
                    "googHighpassFilter": "false"
                },
                "optional": []
            },
        },
        onMicrophoneGranted,
        onMicrophoneDenied
    );
} catch (e) {
    alert('getUserMedia threw exception :' + e);
}

La  función onLevelChange es la función a la que debe prestar atención.

Crea tu wrapper personalizado

Como la implementación del código será un poco complicada, puede crear un script personalizado para facilitar su uso con solo ejecutar una función. Mira el siguiente ejemplo, creará la microphoneLevelfunción en la ventana y espera 2 devoluciones de llamada ( onResultonError):

(function(){
    function wrapperAudioMeter(OPTIONS){
        var audioContext = null;
        var meter = null;
        var rafID = null;
        var mediaStreamSource = null;

        // Recuperar AudioContext con todos los prefijos de los navegadores
        window.AudioContext = window.AudioContext || window.webkitAudioContext;

        // Obtenga un contexto de audio
        audioContext = new AudioContext();

        function onMicrophoneDenied() {
            if(typeof(OPTIONS["onError"]) == "function"){
                OPTIONS.onError('Stream generation failed.');
            }
        }

        function onMicrophoneGranted(stream) {
            // Cree un AudioNode a partir de la transmisión.
            mediaStreamSource = audioContext.createMediaStreamSource(stream);
            // Cree un nuevo medidor de volumen y conéctelo
            meter = createAudioMeter(audioContext);
            mediaStreamSource.connect(meter);

            // Activar devolución de llamada que
            onLevelChange();
        }

        function onLevelChange(time) {
            if(typeof(OPTIONS["onResult"]) == "function"){
                OPTIONS.onResult(meter, time);
            }

            // configurar la siguiente devolución de llamada
            rafID = window.requestAnimationFrame(onLevelChange);
        }

        // Intenta acceder al micrófono
        try {

            // Recuperar la API getUserMedia con todos los prefijos de los navegadores
            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

            // Solicita una entrada de audio
            navigator.getUserMedia(
                {
                    "audio": {
                        "mandatory": {
                            "googEchoCancellation": "false",
                            "googAutoGainControl": "false",
                            "googNoiseSuppression": "false",
                            "googHighpassFilter": "false"
                        },
                        "optional": []
                    },
                },
                onMicrophoneGranted,
                onMicrophoneDenied
            );
        } catch (e) {
            if(typeof(OPTIONS["onError"]) == "function"){
                OPTIONS.onError(e);
            }
        }
    }

    window["microphoneLevel"] = wrapperAudioMeter;
})();

Este script se puede utilizar de la siguiente manera:

/**
 * Ejecute el script una vez que se cargue la ventana
 **/
window.onload = function(){

    // Solicitar micrófono para mostrar el nivel
    window.microphoneLevel({
        onResult: function(meter , time){
            if (meter.checkClipping()) {
                console.warn(meter.volume);
            } else {
                console.log(meter.volume);
            }
        },
        onError: function(err){
            console.error(err);
        }
    });
};

La onResultdevolución de llamada se activa repetidamente y recibe el objeto del medidor con la información y los métodos del AudioContext. Es fácil de leer y trabajar, ¿no?

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores