Universitat Oberta de Catalunya

Sonido con Lenguaje de Programación Processing. Segundo ejemplo.

En este ejemplo vamos a utilizar la librería Minim para cargar y reproducir un fichero de extensión y formato .MP3 en nuestro equipo. Además vamos a cargar una imagen de fondo y a visualizar “la canción” con dos “altavoces” que generaremos vía código, por lo que respecta a las amplitudes de sus canales izquierdo y derecho (estéreo). La librería Minim se instala por defecto con Processing aunque es recomendable actualizarla. Veamos el resultado visual en la figura 1.

Figura 1. Reproducimos un fichero de música, aportamos una imagen de fondo y generamos dos altavoces para los canales izquierdo y derecho. Imagen cortesía de http://www.freeimageslive.com/.

Si observamos el código 1, veremos que empezamos por importar la librería de sonido. Además creamos dos objetos que necesitaremos posteriormente. Por una parte un gestor de audio (AudioManager) y por otra el contenedor de la canción a reproducir (MySong). También un objeto Pimage de Processing que permite cargar una imagen desde un fichero .JPG de disco duro. En la función de inicialización setup() creamos una ventana de 320 por 240 píxeles, que es la resolución de la imagen que cargaremos para el fondo, y a continuación inicializamos los objetos llamando a sus constructores. En el caso de MySong se observa como llamamos a su método loadFile para cargar un fichero de audio de nombre “sweet.mp3”. Aunque es posible, no pasamos un segundo parámetro que indique el tamaño de nuestro “buffer” de almacenamiento de muestras. Por lo tanto asumimos el valor por defecto que es de 1024. Por tanto cargaremos de 1024 en 1024 y eso es lo que mostraremos por pantalla a cada iteración.

Es importante señalar que tanto  el archivo de sonido como el de imagen deberán almacenarse en el subdirectorio “data”, dentro del directorio correspondiente a nuestro sketch Processing. Es el proceso habitual en este lenguaje de programación.

Una vez cargado el archivo de sonido sobre nuestro objeto, llamaremos al método de éste que lo reproduce (play()) y definiremos un ancho de 5 píxeles para las líneas de los círculos que emplearemos para pintar nuestros “altavoces”. No olvidemos que también cargamos una imagen de fondo (image_to_test_with.jpg) sobre nuestro objeto MyImage, gracias a la función loadImage().

// We will use MINIM as our Audio Library
// Therefore we import it
import ddf.minim.* ;
// We create a Minim Object to manage audio
Minim AudioManager;
// We create an AudioPlayer Object to load a track (song)
AudioPlayer MySong;
// An image for the background
PImage MyImage;

// The Setup function that we'll be called only once
void setup(){
// Our window is 320 x 240 pixels (as the background image is)
size(320, 240);
// We initialize the AudioManager object
AudioManager = new Minim(this);
// We use the "loadFile" method inside the "minim" object
// to load an MP3 file, 1024 samples everytime
MySong = AudioManager.loadFile("sweet.mp3");
// We start playing the track/song/file
MySong.play();
// We load our background file into the MyImage object
MyImage = loadImage("image_to_test_with.jpg");
// Our lines we'll be 5 pixels wide
strokeWeight(5);
}

Código 1. Librería, objetos e inicialización de nuestro reproductor de audio e imagen.

En el código 2 observamos la función draw() que será la encargada de “visualizar” 1024  muestras musicales por iteración.

// The infinite loop
void draw(){
// The offset allows us to work within
// the [0,2] window instead of [-1,1]
float offset;
// An image as the background
image(MyImage,0,0);
// Left Channel. A reddish circular item animated with the samples
stroke(255,0,0);
fill(128,0,0);
// We prefer to work within the [0,2] range instead of [-1,1]
offset = MySong.left.get(512)+1;
// We scale the sample for our circular item to get bigger
// depending on the amplitude of the sample
offset*=50;
// We draw the circle for the left channel
ellipse(120, 120, offset, offset);
// Right Channel. A greenish circular item animated with the samples
stroke(0,255,0);
fill(0,128,0);
// We prefer to work within the [0,2] range instead of [-1,1]
offset = MySong.right.get(512)+1;
// We scale the sample for our circular item to get bigger
// depending on the amplitude of the sample
offset*=50;
// We draw the circle for the right channel
ellipse(200, 120, offset, offset);
}

Código 2. “Dibujando” música.

Inicialmente definimos una variable (offset) que necesitaremos para desplazar nuestras muestras y dibujarlas adecuadamente como se explicará en un momento. Posicionamos la imagen de fondo que cuadra perfectamente con el tamaño de ventana (image(MyImage,0,0)) y pasamos a operar con el altavoz del canal izquierdo primero (de color rojo puro en borde y más ligero en relleno) y el del derecho después (de color verde puro en borde y más ligero en relleno).

Tal y como se explica detalladamente en la guía de iniciación a la librería Minim, las muestras que se obtienen tienen valores entre -1 y 1. Esto no nos conviene a la hora de pintarlas así que les sumaremos un cierto desplazamiento. En concreto sumaremos 1 y por lo tanto pasaremos a tener muestras que oscilan entre los valores de 0 y 2.  El resultado de la muestra “desplazada” lo almacenamos en la variable offset, primero para el canal izquierdo (offset = MySong.left.get(512)+1) y después para el derecho (offset = MySong.right.get(512)+1). Observemos que en todo momento utilizaremos una muestra central (la 512 de las 1024 totales) como referencia a la hora de pintar. En ambos casos utilizamos el valor de offset escalado de manera que cuando pintemos los altavoces tengan un tamaño adecuado. Escalamos concretamente por un factor de 50 y esto puede cambiarse. Veámoslo con atención. El código que pinta para el canal izquierdo es ellipse(120, 120, offset, offset) y para el derecho ellipse(200, 120, offset, offset). Por lo tanto se generan dos círculos que cambian continuamente de diámetro en base a la música, en las coordenadas (120, 120) y (200, 120) de ventana. En los dos casos el diámetro es igual a offset. Los valores de muestras, entre 0 y 2, hacen que los diámetros asuman valores de entre 0 y 100 píxeles.

Recordemos que en Processing la coordenada (0,0) es la superior izquierda mientras que la (256,300) es la inferior derecha. Por tanto, las X’s aumentan hacia la derecha y las Y’s hacia abajo, tal y como se muestra en la figura 2.

Figura 2. Sistema de coordenadas de ventana en Processing.

Por último y como observamos en el código 3, creamos una función que es obligatoria para el buen funcionamiento de la librería Minim (void stop()). Ésta se ejecutará al salir del programa y en ella se detiene la reproducción de la canción (MySong.close()), el gestor de audio (AudioManager.stop()) y el proceso en sí (super.stop()).

// Minim needs a method to stop
void stop(){
MySong.close();
AudioManager.stop();
super.stop();
}

Código 3. Cierre de la librería de audio.

A continuación se muestra el código 4 que contiene todo el programa funcional.

// We will use MINIM as our Audio Library
// Therefore we import it
import ddf.minim.* ;
// We create a Minim Object to manage audio
Minim AudioManager;
// We create an AudioPlayer Object to load a track (song)
AudioPlayer MySong;
// An image for the background
PImage MyImage;

// The Setup function that we'll be called only once
void setup(){
// Our window is 320 x 240 pixels (as the background image is)
size(320, 240);
// We initialize the AudioManager object
AudioManager = new Minim(this);
// We use the "loadFile" method inside the "minim" object
// to load an MP3 file, 1024 samples everytime
MySong = AudioManager.loadFile("sweet.mp3");
// We start playing the track/song/file
MySong.play();
// We load our background file into the MyImage object
MyImage = loadImage("image_to_test_with.jpg");
// Our lines we'll be 5 pixels wide
strokeWeight(5);
}

// The infinite loop
void draw(){
// The offset allows us to work within
// the [0,2] window instead of [-1,1]
float offset;
// An image as the background
image(MyImage,0,0);
// Left Channel. A reddish circular item animated with the samples
stroke(255,0,0);
fill(128,0,0);
// We prefer to work within the [0,2] range instead of [-1,1]
offset = MySong.left.get(512)+1;
// We scale the sample for our circular item to get bigger
// depending on the amplitude of the sample
offset*=50;
// We draw the circle for the left channel
ellipse(120, 120, offset, offset);
// Right Channel. A greenish circular item animated with the samples
stroke(0,255,0);
fill(0,128,0);
// We prefer to work within the [0,2] range instead of [-1,1]
offset = MySong.right.get(512)+1;
// We scale the sample for our circular item to get bigger
// depending on the amplitude of the sample
offset*=50;
// We draw the circle for the right channel
ellipse(200, 120, offset, offset);
}

// Minim needs a method to stop
void stop(){
MySong.close();
AudioManager.stop();
super.stop();
}

Código 4. Programa al completo. Reproducción de audio.

Acerca del autor

Oscar García Pañella es Doctor en Realidad Virtual por La Salle-URL y cursó un Post Doctorado en tecnología del entretenimiento en la Carnegie Mellon University.

Ha dirigido el Grado en Ingeniería Multimedia y el Máster en Creación Multimedia y Serious Games de La Salle-URL durante más de 10 años, además de fundar el Ecosistema Creativo Media Dome del mismo centro en 2009.

Actualmente participa en la dirección y la impartición de los estudios en materia Multimedia en distintas universidades como la UOC, l’ERAM, La Salle Barcelona y Holanda, ESADE y Blanquerna y también opera como Consultor en Gamificación para varias empresas.

Un comentario

Deja un comentario

  1. Esta bien todo esto y muy chevere pero tengo una inquietud que no he podido solucionar si yo quiero que mi animacion o mi reproductor o la que cree en processing se vea en otro equipo que no cuenta con processing, si yo quiero que mi reproductor funcione como tal que debo hacer.

    Responder

Deja un comentario