El reloj interno de Web Audio Api

facebook-svg gplus-svg twitter-svg

Al crear una nueva instancia del objeto AudioContext, el reloj interno de Web Audio Api se pone en marcha. Para leer el valor del reloj interno utilizamos la propiedad currentTime del AudioContext:

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
. . . . . . . . 
console.log(audioCtx.currentTime);

Podemos utilizar la propiedad currentTime del AudioContext para programar eventos, como por ejemplo parar un oscilador después de un segundo:

oscilador.stop(audioCtx.currentTime +  1); 

oscilador.stop(audioCtx.currentTime +  1);
function crearOscilador(){
  oscilador = audioCtx.createOscillator();
  oscilador.type = "triangle";
  oscilador.frequency.value = 73;  
  oscilador.connect(audioCtx.destination);
  // inicia el oscilador
  oscilador.start(audioCtx.currentTime);
  // para el oscilador después de un segundo
  oscilador.stop(audioCtx.currentTime +  1); 
}

Vea este ejemplo en codepen.io

El reloj interno y los parámetros audio

Hay un grupo de métodos de Web Audio Api que permiten manipular el valor de las propiedades del audio en tiempo: setValueAtTime, linearRampToValueAtTime, exponentialRampToValueAtTime, setTargetAtTime, y setValueCurveAtTime.

Recordatorio: los nodos de ganancia

Los nodos de ganancia ( gain nodes ) son nodos audio que permiten ajustar el volumen del sonido. Veamos como:


// crea un nuevo contexto audio
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function crearOscilador(){
  // crea un nuevo oscilador
  oscilador = audioCtx.createOscillator();
  // crea un nodo de ganancia
  gain = audioCtx.createGain();
  // establece el valor inicial del volumen del sonido
  gain.gain.value = .5;
  // establece el tipo de oscilador  
  oscilador.type = "triangle";
  // y el valor de la frecuencia 
  oscilador.frequency.value = 73;
  // conecta el oscilador con el nodo de ganancia 
  oscilador.connect(gain);
  // y la ganancia con el dispositivo de destino
  gain.connect(audioCtx.destination);
  // inicia el oscilador 
  oscilador.start(audioCtx.currentTime);
  // para el oscilador después de un segundo
  oscilador.stop(audioCtx.currentTime +  1); 
}
document.body.addEventListener("click", crearOscilador, false);

Vea este ejemplo en codepen

En lugar de establecer el valor de la ganancia como en el ejemplo anterior, podemos utilizar uno de los métodos de Web Audio Api que permiten manipular el valor de las propiedades del audio en tiempo:

El método setValueAtTime

El método setValueAtTime permite programar el cambio repentino del valor un parámetro audio en un momento dado. El método setValueAtTime toma dos argumentos: el nuevo valor del parámetro audio, y el momento cuando el cambio ocurre.

parametroAudio.setValueAtTime(valor, momento)

En el siguiente ejemplo  el valor inicial del volumen es 3, pero baja después de 0.5 segundos a 0.25.

gain.gain.value = 3;  
gain.gain.setValueAtTime(0.25, audioCtx.currentTime + 0.5);

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

function crearOscilador(){
oscilador = audioCtx.createOscillator();
// crea un nodo de ganancia
gain = audioCtx.createGain();
// el valor inicial del volumen es 3  
gain.gain.value = 3;  
// pero baja después de 0.5 segundos a .25
gain.gain.setValueAtTime(0.25, audioCtx.currentTime + .5) 
// establece el tipo de oscilador  
oscilador.type = "triangle";
// y el valor de la frecuencia 
oscilador.frequency.value = 73;
// conecta el oscilador con el nodo de ganancia
oscilador.connect(gain);
// y la ganancia con el dispositivo de destino
gain.connect(audioCtx.destination);
// inicia el oscilador  
oscilador.start(audioCtx.currentTime);
// para el oscilador después de dos segundos
oscilador.stop(audioCtx.currentTime +  2); 
}
document.body.addEventListener("click", crearOscilador, false);

Vea este ejemplo comentado en codepen

El método linearRampToValueAtTime

El método linearRampToValueAtTime permite programar el cambio gradual del valor un parámetro audio hacia un valor dado. La transformación es lineal. El método linearRampToValueAtTime toma dos argumentos: el nuevo valor del parámetro audio y el momento final de la transformación:

parametroAudio.linearRampToValueAtTime (valor, momentoFinal)

En el siguiente ejemplo el volumen baja gradualmente a 0. La transformación dura 1 segundo.

gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 1);

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

function crearOscilador(){
oscilador = audioCtx.createOscillator();
// crea un nodo de ganancia
gain = audioCtx.createGain();
// establece el valor inicial del volumen
gain.gain.value = 2; 
// el volumen baja gradualmente a 0. La transformación dura 1 segundo.
gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 1);
// establece el tipo de oscilador  
oscilador.type = "triangle";
// y el valor de la frecuencia 
oscilador.frequency.value = 73;
// conecta el oscilador con el nodo de ganancia
oscilador.connect(gain);
// y la ganancia con el dispositivo de destino
gain.connect(audioCtx.destination);
// inicia el oscilador  
oscilador.start(audioCtx.currentTime);
// para el oscilador después de un segundo
oscilador.stop(audioCtx.currentTime +  1); 
}
document.body.addEventListener("click", crearOscilador, false);

Vea este ejemplo comentado en codepen

El método exponentialRampToValueAtTime

El método exponentialRampToValueAtTime permite programar el cambio exponencial del valor un parámetro audio hacia un valor dado. La transformación es exponencial.
El método exponentialRampToValueAtTime toma dos argumentos: el nuevo valor del parámetro audio y el momento final de la transformación:

parametroAudio.exponentialRampToValueAtTime (valor, momentoFinal);

En el siguiente ejemplo el volumen baja exponencialmente a 0.01. La transformación dura 1 segundo.

gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 1);

¡OJO! El valor final del parámetro audio tiene que ser un número positivo ( en este caso 0.01 ). Un valor final igual a 0 da error ( invalid o illegal ).


const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

function crearOscilador(){
oscilador = audioCtx.createOscillator();
// crea un nodo de ganancia
gain = audioCtx.createGain();
// establece el valor inicial del volumen
gain.gain.value = 2; 
// el volumen baja exponencialmente a 0.01. La transformación dura 1 segundo.
// ¡OJO! El valor final del parámetro audio tiene que ser un número positivo ( en este caso 0.01 ). Un valor final igual a 0 da error!
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 1);
// establece el tipo de oscilador  
oscilador.type = "triangle";
// y el valor de la frecuencia 
oscilador.frequency.value = 73;
// conecta el oscilador con el nodo de ganancia
oscilador.connect(gain);
// y la ganancia con el dispositivo de destino
gain.connect(audioCtx.destination);
// inicia el oscilador  
oscilador.start(audioCtx.currentTime);
// para el oscilador después de un segundo
oscilador.stop(audioCtx.currentTime +  1); 
}
document.body.addEventListener("click", crearOscilador, false);

Vea este ejemplo comentado en codepen

El método setTargetAtTime

El método setTargetAtTime permite programar el cambio exponencial del valor un parámetro audio y toma 3 argumentos:

parametroAudio.setTargetAtTime( valorFinal, cuandoEmpieza, constanteDeTiempo );

Donde:
valorFinal:  representa el valor final del parámetro audio.
cuandoEmpieza: representa el momento en el cual empieza la transición.
constanteDeTiempo: determina la duración de la transición exponencial. Como más grande, más tiempo dura la transición. Si este último parámetro es 0 el cambio es repentino.

En el siguiente ejemplo el volumen del sonido baja exponencialmente a 0. La transición empieza después de 0.5 segundos.

gain.gain.setTargetAtTime(0, audioCtx.currentTime + 0.5, 0.3);

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

function crearOscilador(){
oscilador = audioCtx.createOscillator();
// crea un nodo de ganancia
gain = audioCtx.createGain();
// establece el valor inicial del volumen
gain.gain.value = 2; 
// el volumen del sonido baja gradualmente a 0. 
// la transición empieza después de 0.5 segundos
// el último parámetro determina la duración de la transición exponencial. Como más grande, más tiempo dura la transición. Si este último parámetro es 0 el cambio es repentino.
gain.gain.setTargetAtTime(0, audioCtx.currentTime + 0.5, .3); 
// establece el tipo de oscilador  
oscilador.type = "triangle";
// y el valor de la frecuencia 
oscilador.frequency.value = 73;
// conecta el oscilador con el nodo de ganancia
oscilador.connect(gain);
// y la ganancia con el dispositivo de destino
gain.connect(audioCtx.destination);
// inicia el oscilador  
oscilador.start(audioCtx.currentTime);
// para el oscilador después de dos segundos
oscilador.stop(audioCtx.currentTime +  2); 
}
document.body.addEventListener("click", crearOscilador, false);

Vea este ejemplo comentado en codepen

El método setValueCurveAtTime

El método setValueCurveAtTime permite programar la transición entre varios valores utilizando Float32Array, un iterable muy parecido a un array de números decimales ( float number ) de 32 bits, y toma tres argumentos:

parametroAudio.setValueCurveAtTime(valores, cuandoEmpieza, duración)

En el siguiente ejemplo el volumen del sonido varía entre los valores definidos utilizando un Float32Array. El "array" de los valores tiene 7 elementos.

let valores = new Float32Array(7);
  valores[0] = 1;
  valores[1] = 1.5;
  valores[2] = 2;
  valores[3] = 1.5;
  valores[4] = 1;
  valores[5] = 0.5;
  valores[6] = 0;

La transición empieza en el primer momento ( audioCtx.currentTime ) y dura un segundo (1)

gain.gain.setValueCurveAtTime(valores, audioCtx.currentTime, 1);

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// crea el "array" de los valores
let valores = new Float32Array(7);
valores[0] = 1;
valores[1] = 1.5;
valores[2] = 2;
valores[3] = 1.5;
valores[4] = 1;
valores[5] = 0.5;
valores[6] = 0;

function crearOscilador(){
oscilador = audioCtx.createOscillator();
// crea un nodo de ganancia
gain = audioCtx.createGain();
// el volumen del sonido varía entre los valores definidos utilizando un Float32Array
gain.gain.setValueCurveAtTime(valores, audioCtx.currentTime, 1);  
// establece el tipo de oscilador  
oscilador.type = "triangle";
// y el valor de la frecuencia 
oscilador.frequency.value = 73;
// conecta el oscilador con el nodo de ganancia
oscilador.connect(gain);
// y la ganancia con el dispositivo de destino
gain.connect(audioCtx.destination);
// inicia el oscilador  
oscilador.start(audioCtx.currentTime);
// para el oscilador después de dos segundos
oscilador.stop(audioCtx.currentTime +  1); 
}
document.body.addEventListener("click", crearOscilador, false);        

Vea este ejemplo en codepen

Lea más acerca de Uint8Array y otros arrays parecidos: JavaScript typed arrays

Vea también este ejemplo comentado que crea una especie de xilófono, que toca al pasar con el ratón por encima de los botones.