Robert Moog creó uno de los primeros sintetizadores modulares comerciales. El invento consistía en un banco de cables y mandos, que permitía a los músicos poder crear sonidos que nunca antes habían escuchado. Estos instrumentos tampoco son baratos, cuestan miles de dólares, incluso el modelo más básico.
Ahora, gracias a la API de Web Audio, podemos crear nuestro propio sintetizador de sonidos por el módico precio de cero euros. No sólo eso, podemos distribuir nuestro sintetizador instantáneamente a cualquier persona en el mundo gracias a la web.
Empezamos
Vamos a empezar creando una página HTML básica:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Add sound to your web app</title>
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<div class="container">
<h1>Synthesizer!</h1>
</div>
</body>
</html>
Añadimos unos cuantos estilos en nuestra hoja de estilos de styles/main.css
body { font-family: sans-serif; } .container { margin: auto; width: 800px; }
Teclado
Quizá lo más importante de un sintetizador es el teclado. Por suerte, he creado un pequeño snippet de JavaScript que agregará un teclado virtual en tu página. Descárgate una copia de Qwerty Hancock y referéncialo en la parte inferior de la página tal que así.
<script src="scripts/qwerty-hancock.min.js"></script>
A continuación, añade un div vacío en tu página con el id “keyboard”
<div id="keyboard"></div>
En esta capa es donde se insertará el teclado. También vamos a necesitar un archivo Javascript exclusivo, al cual llamaremos synth.js, para gestionar nuestro sintetizador, por lo que, vamos a crearlo también y a referenciarlo al igual que hemos hecho con Qwerty Hancock
<script src="scripts/qwerty-hancock.min.js"></script>
<script src="scripts/synth.js"></script>
Dentro de synth.js inicializamos el teclado mediante el siguiente procedimiento:
var keyboard = new QwertyHancock({ id: 'keyboard', width: 600, height: 150, octaves: 2 });
Esto indica a nuestra página que debe insertar una instancia a nuestro teclado en el elemento con id “keyboard”, cambiar su tamaño a 600x150px y hacer que el número de teclas del teclado cubra dos octavas. Guarda y actualiza el navegador para que puedas ver el teclado en pantalla. Utiliza las teclas o el ratón para comprobar el efecto de iluminación de las teclas cuando son presionadas.
Qwerty Hancock nos proporciona dos detectores de eventos, keyUp y keyDown. Esto nos permite agregar funciones de Javascript cuando se presiona el teclado, lógicamente. También nos indica que tecla ha sido presionada y su correspondiente frecuencia en herzios.
keyboard.keyDown = function (note, frequency) { console.log('Note', note, 'has been pressed'); console.log('Its frequency is', frequency); }; keyboard.keyUp = function (note, frequency) { console.log('Note', note, 'has been released'); console.log('Its frequency was', frequency); };
Oscilar salvajemente
Vamos a crear un oscilador cuando se presione una tecla. Lo detendremos pasado un segundo para que no se reproduzca eternamente.
var context = new AudioContext(); keyboard.keyDown = function (note, frequency) { var osc = context.createOscillator(); osc.connect(context.destination); osc.start(context.currentTime); osc.stop(context.currentTime + 1); };
¿Por qué creamos el oscilador dentro de la función keyDown? ¿No es ineficiente? Los osciladores están diseñados para ser ligeros y deben desecharse después de su uso. En realidad solo se pueden utilizar una vez. Piensa en ellos como una especie de fuegos artificiales de audio extraños.
Ahora al pulsar una tecla, oímos un sonido. Es un poco ruidoso, así que vamos a crear un gainNode para que actúe como control de volumen principal.
var context = new AudioContext(), masterVolume = context.createGain(); masterVolume.gain.value = 0.3; masterVolume.connect(context.destination); keyboard.keyDown = function (note, frequency) { var osc = context.createOscillator(); osc.connect(masterVolume); masterVolume.connect(context.destination); osc.start(context.currentTime); osc.stop(context.currentTime + 1); };
Un teclado que reproduce una sola nota una no es muy divertido, así que vamos a conectar la frecuencia del oscilador antes de empezar a tocarlo.
osc.frequency.value = frequency;
Muy bien. Ahora tenemos que detener la reproducción del oscilador cuando soltamos la tecla en vez de después de un segundo. Debido a que estamos creando el oscilador dentro de la función keyDown, tenemos que hacer un seguimiento de la frecuencia que está reproduciendo el oscilador con el fin de detenerlo cuando se suelte la tecla. Una forma sencilla de hacer esto es crear un objeto vacío y añadir las frecuencias como keys.
var oscillators = {}; keyboard.keyDown = function (note, frequency) { // Previous code here oscillators[frequency] = osc; osc.start(context.currentTime); };
Esto significa que podremos fácilmente usar la frecuencia que hemos obtenido de nuestra función noteUp para parar el oscilador en cuestión.
keyboard.keyUp = function (note, frequency) { oscillators[frequency].stop(context.currentTime); };
Ahora tenemos un sintetizador completamente funcional (muy básico) en el navegador. Parece que no suena del todo bien, ¿verdad? Intentaremos arreglarlo.
Lo primero que hay que hacer es cambiar el tipo de onda de las salidas del oscilador. Tenemos cuatro tipos donde elegir: sine, square, triangle y sawtooth. Cada forma de onda cuenta con sonidos diferentes. Juega con ellos y elige el que más te guste. Para este ejemplo, voy a elegir "sawtooth".
osc.type = 'sawtooth';
Ahora suena mucho mejor.
Es muy raro que encuentres un sintetizador que utilice un único oscilador. La mayoría de los sintetizadores refuerzan su sonido mediante la combinación de diferentes osciladores de distintos tipos. Vamos a ver cómo suena si añadimos otro más. Recuerda, tendremos que duplicar todas nuestras conexiones, y tendremos que añadir los osciladores de la misma frecuencia en una matriz. Esto significa que podemos iterar sobre ellos con el fin de detener todos los osciladores que están reproduciendo la misma nota.
keyboard.keyDown = function (note, frequency) { var osc = context.createOscillator(), osc2 = context.createOscillator(); osc.frequency.value = frequency; osc.type = 'sawtooth'; osc2.frequency.value = frequency; osc2.type = 'triangle'; osc.connect(masterVolume); osc2.connect(masterVolume); masterVolume.connect(context.destination); oscillators[frequency] = [osc, osc2]; osc.start(context.currentTime); osc2.start(context.currentTime); }; keyboard.keyUp = function (note, frequency) { oscillators[frequency].forEach(function (oscillator) { oscillator.stop(context.currentTime); }); };
Fuente: code.tutsplus.com