Audio panner

facebook-svg gplus-svg twitter-svg

Si el sonido se reproduce en dos canales audio decimos que se trata de sonido estereofónico. El sonido cuadrafónico se reproduce en cuatro canales audio, y hay también sonido hexafónico que se reproduce en seis canales auditivos distintos.
El panning es una técnica que permite redistribuir la señal de sonido entre los varios canales audio.

Para crear un nodo panner estereo utilizamos el método StereoPannerNode.

var pan = audioCtx.createStereoPanner(audioCtx);

Un ejemplo básico

En el siguiente ejemplo, en el HTML creamos un slider ( <input type="range" ) cuyo valor puede variar entre -1 ( min = "-1" ) y 1 ( max = "1" ), ya que la propiedad pan del panner puede tomar valores entre -1 ( el sonido se oye solo en el auricular izquierdo ) y 1 ( el sonido se oye solo en el auricular derecho ).
El paso del slider es de 0.01 ( step="0.01" ).


<div class="inputDiv">
  <!--El valor del panControl es un número decimal entre -1 y 1 -->
  <p><input id="panControl" type="range" min="-1" max="1" value="0.5" step="0.01"  /></p>
</div>

También creamos un panner estéreo y un oscilador.
Conectamos el oscilador ( la fuente de sonido ) con el panner, y el panner con los dispositivos de salida.
El slider ( panControl ) es utilizado para cambiar el balance del sonido hacia la derecha o la izquierda.
Para que el oscilador no sea molesto utilizamos el evento "mousedown" para iniciar la oscilación y "mouseup" para pararla.


  var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  // crea un nuevo nodo audio panner
  var pan = audioCtx.createStereoPanner(audioCtx);
  // crea un nuevo oscildor, 
  // lo conecta con el panner y 
  // conecta el panner con los dispositivos de salida
  crearOscilador();

  // al arrastrar el boton del slider
  panControl.addEventListener("input", function() {
  // el balance cambia hacia la derecha o hacia la izquierda
    pan.pan.value = this.value;
  });
  
  // inicia el oscilador al presionar el botón del ratón 
  panControl.addEventListener("mousedown", function() {
      crearOscilador();
      oscilador.start();
  });
  // para el oscilador al soltar el botón del ratón
  panControl.addEventListener("mouseup", function() {
      oscilador.stop();
  });

  function crearOscilador() {
    // crea un nuevo oscilador
    oscilador = audioCtx.createOscillator();
    // establece la frequencia del oscilador
    oscilador.frequency.value = 100;
    // conecta el oscilador con el panner
    oscilador.connect(pan);
    // y el panner con los dispositivos de destino
    pan.connect(audioCtx.destination);
  }

Vea este ejemplo en codepen. Para una mejor experiencia por favor utilice auriculares.

See the Pen createStereoPanner* by Gabi (@enxaneta) on CodePen.

Crear un separador de canales

Si queremos manipular por separado los canales audio necesitamos un separador de canales ( channel splitter ).

Para crear un nuevo separador utilizamos el método createChannelSplitter, que toma como argumento el número de canales que queremos generar. El valor por defecto es 6.

var splitter = audioCtx.createChannelSplitter(2);

El siguiente ejemplo utiliza como punto de partida un ejemplo anterior: Reproducir archivos de sonido.

Primero tenemos que declarar algunas variables globales:


  // un separador de canales
  var splitter = audioContext.createChannelSplitter(2);
  // la ganancia para el auricular / altavoz izquierdo
  var gainIzq = audioContext.createGain();
  // la ganancia para el auricular / altavoz derecho
  var gainDcha = audioContext.createGain();
  // el panner para el auricular / altavoz izquierdo
  var pannerIzq = audioContext.createStereoPanner();
  // el panner para el auricular / altavoz derecho
  var pannerDcha = audioContext.createStereoPanner();

También hay que modificar la función reproducirAudio(). Ahora la fuente de reproducción se conecta con el splitter

fuenteDeReproduccion.connect(splitter);

Que a su turno se conecta con dos nodos de ganancia, uno para la izquierda y otro para la derecha. Observe por favor el segundo argumento del método connect() que especifica el canal audio con cual conectarse.

splitter.connect(gainIzq, 0);
splitter.connect(gainDcha, 1);

A continuación conectamos los nodos de ganancia, cada uno con el panner correspondiente.

gainIzq.connect(pannerIzq);
gainDcha.connect(pannerDcha);

Finalmente los panner se conectan con los dispositivos de destino. Es importante observar que el valor del panner izquierdo es -1 ( el sonido se oye solo en el auricular izquierdo )

pannerIzq.pan.value = -1;

mientras que el valor del panner derecho es 1 ( el sonido se oye solo en el auricular derecho )

pannerDcha.pan.value = 1;

   function reproducirAudio() {
   // fuenteDeReproduccion --> splitter --> gainIzq  --> pannerIzq  --> destination
   //                                   ↳ gainDcha --> pannerDcha --> destination
    fuenteDeReproduccion = audioContext.createBufferSource();
    fuenteDeReproduccion.loop = true;
    fuenteDeReproduccion.buffer = audioBuffer;
    
    fuenteDeReproduccion.connect(splitter);
    
    splitter.connect(gainIzq, 0);
    splitter.connect(gainDcha, 1);
    
    gainIzq.connect(pannerIzq);
    
    gainDcha.connect(pannerDcha); 
 
    pannerIzq.connect(audioContext.destination);
    pannerIzq.pan.value = -1;
    
    pannerDcha.connect(audioContext.destination);
    pannerDcha.pan.value = 1;
    fuenteDeReproduccion.connect(audioContext.destination);
    fuenteDeReproduccion.start(audioContext.currentTime);
  }

Vea este ejemplo en codepen. Para una mejor experiencia por favor utilice auriculares.

See the Pen createChannelSplitter by Gabi (@enxaneta) on CodePen.