¡Saludos visitante! si deseas comentar o hacer una pregunta sobre este post por favor dirígete a la nueva dirección en http://variabletecnica.com.ve. La página que estás leyendo dejará de estar disponible el 15/11/2015. Gracias, y disculpa las molestias 🙂
Estos últimos años los navegadores Web han hecho un notable esfuerzo por implementar el HTML siguiendo las recomendaciones de la W3C… Personalmente no creo que ellos tengan las mejores respuestas a todo (¿alguien dijo modelo de caja anti-intuitivo?) pero el hecho de que los desarrolladores de navegadores estén trabajando bajo un mismo estándar nos ha facilitado a los diseñadores y desarrolladores la tarea de crear páginas y aplicaciones Web coherentes y simples, sustituyendo los viejos hacks por las especificaciones de HTML5.
Pero ya entrando en materia, ¿la etiqueta <BGSOUND>
te suena? ¿no?, pues a mí si, me recuerda aquellas viejas Webs que al abrirlas tocaba la música favorita del dueño de la página, como si a mi realmente me gustara… en fin, eso quedó atrás. Con la nueva API provista por HTML5 contamos con un mayor control sobre el sonido, hasta el punto en que podemos programar complejos juegos con sonido de fondo y efectos especiales usando solo JavaScript.
En este artículo vamos a ver un ejemplo muy simple de lo que se puede hacer con el nuevo elemento Audio
de HTML5.
Woof?
Si estás programando una aplicación Javascript que requiera efectos de sonido (por favor: que realmente lo requiera) o algún juego con disparos o sonidos cortos, tu primera tarea será precargar los sonidos (como cuando hacemos precarga de imágenes) y «sonarlos» cuando corresponda.
Para la precarga, se debe crear un objeto Audio, asignarle la ruta a tu archivo de sonido y detectar el momento en que esté cargado y listo para sonar. Veamos el ejemplo:
//Disponible en: http://es.wikipedia.org/wiki/Archivo:Sound-of-dog.ogg var rutaLadrido = 'http://upload.wikimedia.org/wikipedia/commons/c/ce/Sound-of-dog.ogg'; //Creamos el elemento Audio var sonido = new Audio(); //Para el ejemplo usaremos una console, la veremos en un momento var consola = document.getElementById('consola'); //Primer evento: el audio puede comenzar, pero tal vez se //detenga antes de terminar sonido.addEventListener('canplay', function () { consola.innerHTML += '* <strong>canplay</strong>: ' + 'El audio puede iniciar, pero podría requerir buffering...<br/>'; }, false); //Segundo evento: el audio puede comenzar sin interrumpirse sonido.addEventListener('canplaythrough', function () { consola.innerHTML += '* <strong>canplaythrough</strong>: ' + 'El audio puede iniciar sin interrupciones...<br/>'; }, false); //Tercer evento: El audio ya comenzó sonido.addEventListener('play', function () { consola.innerHTML += '* <strong>play</strong>: ' + '¡El audio acaba de iniciar!<br/>'; }, false); //Cuarto evento: el audio acaba de terminar sonido.addEventListener('ended', function () { consola.innerHTML += '* <strong>ended</strong>: ' + '¡El audio acaba de terminar!<br/>'; }, false); //La ruta la asignamos después de los eventos para //asegurarnos de que se disparen en el momento justo sonido.src = rutaLadrido; //Esperamos a que el usuario presione el botón document.getElementById('iniciar').addEventListener('click', function () { sonido.play(); }, false);
Básicamente lo que hacemos es crear el elemento Audio
, asignarle la ruta al archivo de sonido, y ejecutar el método play()
; bastante simple, ¿no? Si quieres probar el código anterior agrégalo a la siguiente plantilla (o prueba directamente este jsFiddle):
<!DOCTYPE HTML> <html lang="es"> <head> <meta charset="utf-8"> <title>Ejemplo básico de sonido</title> <script type="text/javascript"> window.addEventListener('DOMContentLoaded', function(){ //CODIGO AQUÍ }, false); </script> <style type="text/css"> #consola{ border: 1px solid; width: 90%; height: 100px; overflow-y: scroll; margin: 5px; background-color: #FFD0A0; } </style> </head> <body> <h1>Ejemplo básico de sonido con javascript</h1> <br/> <div id="consola"></div> <input type="button" id="iniciar" value="Iniciar" /> </body> </html>
Bien, ya sabemos como precargar un archivo de audio, y como ejecutar el sonido. Pero, ¿para qué sirven los eventos?
Eventos del elemento Audio
Al abrir la página con el código anterior (o el jsfiddle de ejemplo) verás que los primeros dos eventos se disparan al cargar la página, o para ser exactos, poco después de asignar la ruta el archivo de sonido a nuestro objeto sonido
: el archivo de sonido se ha precargado.
El primero de estos dos eventos, canplay
, indica el momento en que el audio puede iniciar; esto es, el momento a partir del cual puedes usar el método play()
y el sonido comenzará inmediatamente.
Supongo que habrás visto algún videos HD en YouTube, si es así sabrás que ocasionalmente el video puede detenerse y te hará esperar hasta que llene el buffer antes de continuar. Esto mismo puede ocurrir con el audio, especialmente si la conexión a Internet es lenta o el archivo muy pesado. Por esta razón contamos con el evento canplaythrough
, el cual nos indica el momento a partir del cual podemos usar el método play()
con «poco riesgo» de que el sonido requiera buffering. Así es, dije «poco riesgo»: el navegador hará una estimación del tiempo que tomará descargar el archivo, considerando la velocidad de descarga actual (o promedio), y el peso y duración del archivo; y por supuesto, por ser una estimación, es posible que el evetno se dispare un poco antes o después del momento en que debería hacerlo. Este evento te servirá, por ejemplo, para determinar el momento en que todos los sonidos ya han sido precargados y están disponibles para que tu aplicación los utilice.
El evento play
, que no debe confundirse con el método play()
, te indicará el momento en que el sonido comenzó a emitirse. ¿Y para qué sirve eso?, bueno, tiene varios usos. Por ejemplo, cuando tu elemento audio es una etiqueta en el HTML y tiene establecido el atributo autoplay
, tendrás que usar el evento play
para determinar el momento en que empiece el sonido. Otra posibilidad es que uses el mismo elemento Audio
en diferentes partes del código, y necesites un punto centralizado para saber cuando el audio comenzó a sonar.
El evento ended
es un poco problemático, al menos al momento de escribir este artículo. Este evento, como su nombre lo indica, se dispara justo después de que el sonido termina. Sin embargo, en Chrome v28 para linux (probado en Ubuntu 12.4) hay un bug que impide que el evento ended
se dispare al terminar el sonido (más informacioń en este hilo).
El elemento Audio tiene muchos otros eventos disponibles. Para mayor información, aquí tienes una lista completa de los eventos «oficiales»: http://www.w3.org/wiki/HTML/Elements/audio#Media_Events
¿Porqué mi archivo musica.wav no se oye?
Este es un tema interesante y complicado: soporte de codecs. Para simplificar el tema, el formato WebM (que es un contenedor para los codecs de video VP8 y de audio Vorbis) tiene muy buen soporte, aunque en IE9 se debe instalar por separado; ogg (que es un contenedor para los codecs de video Theora y audio Vorbis) es soportado por Chrome, Gekko (Firefox, thunderbird…) y Android; el formato MP4 (con los codecs de video H.264 y de audio AAC o MP3) es soportado por IE, safary y Chrome, y pronto lo estará en Firefox. Más información sobre los formatos de audio en la MDN y Android Developers.
Como puedes ver, a la fecha no hay ningún formato «confiable», ya que diferentes navegadores soportan diferentes formatos y codecs. Una posible estrategia para utilizar el formato apropiado consiste en crear el audio en dos o tres formatos (la W3C propone ogg y mp4) y cargar el formato para el cual el navegador tenga soporte. Esto se hace mediante la función canPlayType
(detalles aquí):
var sonido = new Audio(); var permiteOgg = sonido.canPlayType('audio/ogg'); var permiteMp4 = sonido.canPlayType('audio/mp4'); if ( permiteOgg==="maybe" || permiteOgg === "probably" ) { sonido.src = 'archivo.ogg'; }else if (permiteMp4==="maybe" || permiteMp4 === "probably" ) { sonido.src = 'archivo.mp4'; }else{ //Otro intento (¿o desactivar el sonido?) :( sonido.src = 'archivo.mp3'; }
Sería ideal si el valor devuelto por la función canPlayType fuera de tipo lógico; pero no, el valor devuelto es una cadena con los valores "probably"
(el formato/codec indicado es casi seguro soportado), "maybe"
(el formato/codec indicado podría ser soportado), y uno de los valores "no"
, ""
o null
(estos tres significan no soportado).
Este artículo fue apenas una visión general de lo que se puede hacer con sonido en Javascript. Si tienes un poco de tiempo libre podrías programar un reproductor de música completo, permitir que el usuario seleccione la música desde un listado o que suba propios archivos de música, implementar toda la botonera de un reproductor, son sus botones para pausa, volumen, velocidad, e incluso hacer mezclas y aplicar efectos. Bueno, sería mucho trabajo, tal vez en otro artículo 🙂
Derecho de uso
Los contenidos generados por el autor de este artículo (explicaciones, código fuente, y archivos adjuntos creados por el autor) están disponibles bajo licencia CC BY-SA 3.0, y pueden ser usados, derivados y compartidos bajo los términos indicados en la misma. Los contenidos no generados por el autor de este artículo son propiedad de sus respectivos dueños y están regidos por las licencias que estos hayan dispuesto.
Cita del día
Music can change the world because it can change people.
Bono (Paul David Hewson)
4 respuestas a “Sonido Básico con JavaScript”
gracias, aportes muy útiles y bien explicados.
Gracias, muy buena información. Quisiera saber si me pudieras ayudar al recomendarme algún sitio donde pueda encontrar más documentación acerca del elemento Audio() de javascript, ya que quisiera saber sus métodos, como el volumen, pausa, etcétera, ya que solo encontré lo del «loop». Muchas gracias. Bueno otra duda y comentario… lo estuve probando en ie8 y no funciona sabes de algún otro elemento que sea compatible? Gracias.!
Hola Alejandro. La Información más «entendible» se encuentra en Mozilla Developer Network (MDN):
Bueno, para ser exactos el segundo link casi no tiene información, sino que te indica que la interfaz HTMLAudioElement hereda todas las funciones de HTMLMediaElement (https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement) así que este último es el que debes leer. Los links están en inglés, los tres tienen una versión en español (por ahí está el botón de idioma) pero la versión en Inglés está más actualizada.
La documentación oficial está en estos dos links, aunque toma tiempo aprender a leer la documentación oficial (es muy técnica, no está redactada como para aprender) :
Y con respecto a usar la etiqueta Audio en IE8: Se puede si usas un Polyfill.
La etiqueta Audio se introdujo en IE9, así que en condiciones normales no podrás usarla en IE8, pero existen muchos PollyFills que te permiten usar características nuevas en (algunos) navegadores viejos. Prueba con esta a ver: http://kolber.github.io/audiojs/
En resumen: (1) Descarga y guarda la librería, el gif, y el swf en la misma carpeta (2) agrega la librería a tu página, (3) ejecuta una función que tiene la librería (dos líneas de código JS) antes de usar el audio (en el load de la página, por ejemplo) (4) Usa la etiqueta Audio normalmente, (para dar soporte a navegadores viejos con este pollyfill debes proporcionar audio mp3)
Si no te resulta prueba algún otro polifill de esta lista (busca la sección de Audio): https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
No olvides volver y comentar como te fue! 🙂