Web Audio y Sonidos 3D Implementación

En este tutorial envolveremos Web Audio en una API simple que se enfoca en la reproducción de sonidos dentro de un espacio de coordenadas 3D, y puede usarse para aplicaciones interactivas inmersivas que incluyen, entre otros, juegos 3D..

Este tutorial es el segundo de una serie de dos partes. Si no ha leído el primer tutorial de la serie, debe hacerlo antes de leer este tutorial porque le presenta los diversos elementos de audio web que usaremos aquí..

Demostración

Antes de comenzar, aquí hay una pequeña demostración que utiliza la API simplificada que veremos en este tutorial. Los sonidos (representados por los cuadrados blancos) se colocan aleatoriamente y se reproducen en un espacio de coordenadas 3D utilizando la función de transferencia relacionada con la cabeza (HRTF) que Web Audio nos brinda..

Los archivos fuente para la demostración se adjuntan a este tutorial..

Visión general

Debido a que la API simplificada (AudioPlayer) ya se ha creado para este tutorial y está disponible para su descarga, lo que vamos a hacer aquí es echar un vistazo general a la API de AudioPlayer y al código que la potencia..

Antes de continuar este tutorial, por favor lea el tutorial anterior de esta serie si aún no lo ha hecho y es nuevo en el mundo de Web Audio.

Reproductor de música

los Reproductor de música clase contiene nuestra API simplificada y se expone en el ventana objetar junto con las clases estándar de Web Audio si, y solo si, Web Audio es compatible con el navegador web. Esto significa que debemos verificar la existencia de la clase antes de intentar usarla.

if (window.AudioPlayer! == undefined) audioPlayer = new AudioPlayer ()

(Podríamos haber intentado crear una nueva Reproductor de música objeto dentro de un trata de atraparlo declaración, pero un simple control condicional funciona perfectamente bien.)

Detrás de las escenas, el reproductor de música crea un nuevo AudioContext objeto y un nuevo AudioGainNode objeto para nosotros, y conecta el GainNode objetar al destino nodo expuesto por el AudioContext objeto.

var m_context = nuevo AudioContext () var m_gain = m_context.createGain ()… m_gain.connect (m_context.destination)

Cuando se crean y reproducen sonidos, se conectarán a la m_gain nodo, esto nos permite controlar el volumen (amplitud) de todos los sonidos fácilmente.

los reproductor de música También configura el audio. oyente, expuesto por m_context, por lo que coincide con el sistema de coordenadas 3D común utilizado con WebGL. Lo positivo z el eje apunta al espectador (en otras palabras, apunta fuera de la pantalla 2D), el positivo y El eje apunta hacia arriba, y lo positivo. X eje puntos a la derecha.

m_context.listener.setOrientation (0, 0, -1, 0, 1, 0)

La posición de la oyente siempre es cero; se encuentra en el centro del sistema de coordenadas de audio.

Cargando sonidos

Antes de que podamos crear o reproducir cualquier sonido, necesitamos cargar los archivos de sonido; por suerte reproductor de música Se encarga de todo el trabajo duro para nosotros. Expone un carga(… ) función que podemos usar para cargar los sonidos y tres controladores de eventos que nos permiten realizar un seguimiento del progreso de la carga.

audioPlayer.onloadstart = function () … audioPlayer.onloaderror = function () … audioPlayer.onloadcomplete = function () … audioPlayer.load ("sound-01.ogg") audioPlayer.load ("sound-02 .ogg ") audioPlayer.load (" sound-03.ogg ")

El conjunto de formatos de sonido que son compatibles depende del navegador. Por ejemplo, Chrome y Firefox son compatibles con OGG Vorbis, pero Internet Explorer no. Los tres navegadores son compatibles con MP3, lo cual es práctico, pero el problema con MP3 es la falta de un bucle de sonido perfecto, el formato MP3 simplemente no está diseñado para ello. Sin embargo, OGG Vorbis es, y puede hacer un bucle de sonidos perfectamente.

Al llamar al carga(… ) funciona varias veces, reproductor de música empujará las solicitudes en una cola y las cargará secuencialmente. Cuando todos los sonidos en cola han sido cargados (y decodificados) el onloadcomplete el controlador de eventos se llamará.

Entre bastidores, reproductor de música utiliza una sola XMLHttpRequest Objeto para cargar los sonidos. los tipo de respuesta de la solicitud se establece en "arraybuffer", y cuando el archivo se ha cargado el array buffer se envía a m_context para decodificar.

// ejemplo simplificado m_loader = nuevo XMLHttpRequest () m_queue = [] function load () m_loader.open ("GET", m_queue [0]) m_loader.responseType = "arraybuffer" m_loader.onload = onLoad m_loader.end ()) función onLoad (evento) var data = m_loader.response var status = m_loader.status m_loader.abort () // reinicia el cargador si (status < 400)  m_context.decodeAudioData(data, onDecode)  

Si la carga y decodificación de un archivo es exitosa, reproductor de música cargará el siguiente archivo en la cola (si la cola no está vacía) o nos informará que todos los archivos se han cargado.

Creando Sonidos

Ahora que hemos cargado algunos archivos de sonido, podemos crear y reproducir nuestros sonidos. Primero necesitamos decirle reproductor de música para crear los sonidos, y esto se hace usando el crear (…) función expuesta por reproductor de música.

var sound1 = audioPlayer.create ("sound-01.ogg") var sound2 = audioPlayer.create ("sound-02.ogg") var sound3 = audioPlayer.create ("sound-03.ogg")

Somos libres de crear tantos sonidos como sea necesario, incluso si solo hemos cargado un solo archivo de sonido.

var a = audioPlayer.create ("beep.ogg") var b = audioPlayer.create ("beep.ogg") var c = audioPlayer.create ("beep.ogg")

La ruta del archivo de sonido pasa a la crear (…) la función simplemente dice reproductor de música qué archivo debe usar el sonido creado. Si el archivo de sonido especificado no se ha cargado cuando el crear (…) Se llama a la función, se lanzará un error de tiempo de ejecución.

Jugando sonidos

Cuando creamos uno o más sonidos, somos libres de reproducirlos siempre que lo necesitemos. Para reproducir un sonido, utilizamos el nombre adecuado jugar(… ) función expuesta por reproductor de música.

audioPlayer.play (sonido 1)

Para determinar si jugar un serpenteado Sonido, también podemos pasar un booleano a la jugar(… ) función. Si el booleano es cierto, El sonido se repetirá continuamente hasta que se detenga..

audioPlayer.play (sound1, true)

Para detener un sonido, podemos usar el detener(… ) función.

audioPlayer.stop (sonido1)

los está jugando(… ) La función nos permite saber si un sonido se está reproduciendo actualmente..

if (audioPlayer.isPlaying (sound1)) …

Detrás de las escenas, el reproductor de música tiene que hacer una cantidad sorprendente de trabajo para obtener un sonido para reproducir, debido a la naturaleza modular de Web Audio. Cada vez que un sonido necesita ser jugado,reproductor de música tiene que crear nuevos AudioSourceBufferNode y PannerNode objetos, configúrelos y conéctelos, y luego conecte el sonido a la m_gain nodo. Afortunadamente, Web Audio está altamente optimizado, por lo que la creación y configuración de nuevos nodos de audio rara vez causa una sobrecarga notable.

sound.source = m_context.createBufferSource () sound.panner = m_context.createPanner () sound.source.buffer = sound.buffer sound.source.loop = loop sound.source.onended = onSoundEnded // Esto es un poco de un hack pero necesitamos hacer referencia al objeto // de sonido en el controlador de eventos onSoundEnded, y hacer las cosas // de esta manera es más óptimo que vincular el controlador. sound.source.sound = sound sound.panner.panningModel = "HRTF" sound.panner.distanceModel = "linear" sound.panner.setPosition (sound.x, sound.y, sound.z) sound.source.connect (sonido .panner) sound.panner.connect (m_gain) sound.source.start ()

Reproducir sonidos es obviamente útil, pero el propósito de reproductor de música es reproducir sonidos dentro de un sistema de coordenadas 3D, por lo que probablemente deberíamos establecer las posiciones de sonido antes de reproducirlos. reproductor de música Expone algunas funciones que nos permiten hacer precisamente eso..

Sonidos de posicionamiento

  • los setX (…) y getX (…) funciones expuestas por reproductor de música se puede utilizar para establecer y obtener la posición de un sonido a lo largo del sistema de coordenadas X eje.
  • los setY (…) y getY (…) Las funciones se pueden usar para establecer y obtener la posición de un sonido a lo largo del sistema de coordenadas. y eje.
  • los setz (…) y getZ (…) Las funciones se pueden usar para establecer y obtener la posición de un sonido a lo largo del sistema de coordenadas. z eje.
  • Por último, la ayuda. posición de ajuste(… ) La función se puede utilizar para establecer la posición de un sonido a lo largo del sistema de coordenadas X, y, y z ejes respectivamente.
audioPlayer.setX (sonido1, 100) audioPlayer.setZ (sonido1, 200) console.log (audioPlayer.getX (sonido1)) // 100 console.log (audioPlayer.getZ (sonido1)) // 200 audioPlayer.setPosición (sonido1, 300, 0, 400) console.log (audioPlayer.getX (sonido1)) // 300 console.log (audioPlayer.getZ (sonido1)) // 400

Cuanto más lejos esté un sonido del centro del sistema de coordenadas, más silencioso será el sonido. A una distancia de 10000 (el valor predeterminado de Web Audio) un sonido será completamente silencioso.

Volumen

Podemos controlar el volumen global (maestro) de los sonidos usando el setVolume (…) y getVolume (…) funciones expuestas por reproductor de música.

audioPlayer.setVolume (0.5) // 50% console.log (audioPlayer.getVolume ()) // 0.5

los setVolume (…) La función también tiene un segundo parámetro que se puede usar para atenuar el volumen durante un período de tiempo. Por ejemplo, para reducir el volumen a cero durante un período de dos segundos, podríamos hacer lo siguiente:

audioPlayer.setVolume (0.0, 2.0)

La demostración del tutorial aprovecha esto para fundir los sonidos sin problemas..

Detrás de las escenas, el reproductor de música simplemente le dice al m_gain nodo para cambiar linealmente el valor de ganancia cada vez que se necesite cambiar el volumen.

var currentTime = m_context.currentTime var currentVolume = m_gain.gain.value m_gain.gain.cancelScheduledValues ​​(0.0) m_gain.gain.setValueAtTime (currentVolume, currentTime) m_gain.gain.linearRampToValueAtTime tiempo (current / time)

reproductor de música impone un tiempo mínimo de desvanecimiento de 0.01 segundos, para garantizar que los cambios bruscos en el volumen no causen ningún clic o chasquido audible.

Conclusión

En este tutorial, echamos un vistazo a una forma de envolver Web Audio en una API simple que se centra en la reproducción de sonidos dentro de un espacio de coordenadas 3D para usar en (entre otras aplicaciones) juegos 3D.

Debido a la naturaleza modular de Web Audio, los programas que utilizan Web Audio pueden complicarse bastante rápidamente, por lo que espero que este tutorial haya sido de alguna utilidad para usted. Cuando entiendes cómo funciona Web Audio y cuán poderoso es, estoy seguro de que te divertirás mucho con él..

No olvide que AudioPlayer y los archivos fuente de demostración están disponibles en GitHub y están listos para descargar. El código fuente está bien comentado, por lo que vale la pena tomarse el tiempo para echarle un vistazo..

Si tiene comentarios o preguntas, no dude en publicar un comentario a continuación..

Recursos

  • Especificación de audio web W3C
  • Documentación de audio web MDN