PortAudio + libsndfile. Reproducir Ogg Vorbis, FLAC y WAV en C++

Escribo este post ya que cuando quise buscar información sobre el tema no encontré nada en castellano y en inglés poca información. Así pues escribo el que yo considero el mejor método para reproducir audio Ogg Vorbis, FLAC y WAV en C++.
Lo primero es descargar e instalar las librerías, ambas son multiplataforma. En Windows irás a la página oficial y seguirás las instrucciones:

A su vez si tenemos que compilar libsndfile también necesitaremos libogg y libvorbis para activar la reproducción de Ogg Vorbis o las librerías de FLAC para activar FLAC en la librería. El soporte para WAV es nativo y no hace falta nada.
En Linux podemos ahorrarnos tiempo instalando los paquetes binarios. En Debian/Ubuntu:

sudo apt-get install portaudio19-dev libsndfile1-dev

Ahora creamos un fichero de C. Atención, aunque C++ sea compatible con el código de C, este código de C tiene problemas en compiladores de C++. Así pues el código de aquí abajo da error con g++ pero funciona correctamente y sin advertencias en gcc. Si quieres insertarlo en un programa de C++, sigue creando este fichero como fichero de C y en el header encapsula la función definida en un “extern C”:

extern "C" {   
	miFuncionAudio();
}

Ahora en el ejemplo voy a usar una función main para no liarnos y usar solo C, pero eso serán los pasos a seguir si tienes C++.  Creamos el fichero con extensión .c y escribimos la función main(). Ahora abriremos el archivo de audio con la librería encargada de decodificar el audio, libsndfile. Después inicializamos PortAudio y obtenemos el dispositivo de audio por defecto (en el caso de mi Ubuntu, es ALSA). Configuramos el dispositivo con los datos que tenemos del fichero. Abrimos un stream de PortAudio que leerá el archivo. Esta función necesita dos funciones de callbak que se crean más arriba. La principal tiene como objetivo leer el fichero más y la otra hacer algo cuando termine el fichero (se puede dejar vacía). En la de leer el fichero tenemos que tener en cuenta si el equipo es Mono o Estéreo. Yo no he llegado a saber como detectarlo, así que hago la multiplicación por 2 para el estéreo. Luego en el flujo principal iniciamos el stream, sonará, esperamos 10 segundos, paramos y cerramos el stream. Finalmente cerramos el fichero de audio y deshabilitamos PortAudio. Fácil y sencillo. Ahora el código:

#include "portaudio.h"
#include "sndfile.h"

SF_INFO sfinfo;
PaStreamParameters out_param;
PaStream * stream;
PaError err;
SNDFILE * file;
static int
output_cb(const void * input, void * output, unsigned long frames_per_buffer,
        const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags flags, void * data)
{
	SNDFILE * filex = data;
	/* Here you need to multiply per 2 for stereo and per 1 for mono*/
	sf_read_short(filex, output, frames_per_buffer*2);
	return paContinue;
}
static void
end_cb(void * data)
{
	 Pa_StopStream(stream);
	 Pa_CloseStream(stream);
	 sf_close(file);
	 Pa_Terminate();
}  
#define error_check(err) \     do {\         if (err) { \             fprintf(stderr, "line %d ", __LINE__); \             fprintf(stderr, "error number: %d\n", err); \             fprintf(stderr, "\n\t%s\n\n", Pa_GetErrorText(err)); \             return err; \         } \     } while (0)  
int main(int argc, char ** argv)
{
	 file = sf_open(argv[1], SFM_READ, &sfinfo);
	 printf("%d frames %d samplerate %d channels\n", (int)sfinfo.frames,
	 sfinfo.samplerate, sfinfo.channels);
	 /* init portaudio */
	 err = Pa_Initialize();
	 error_check(err);
	 /* we are using the default device */
	 out_param.device = Pa_GetDefaultOutputDevice();
	 if (out_param.device == paNoDevice)
	 {
		fprintf(stderr, "Haven't found an audio device!\n");
		return -1;
	 }
	 /* stero or mono */
	 out_param.channelCount = sfinfo.channels;
	 out_param.sampleFormat = paInt16;
	 out_param.suggestedLatency = Pa_GetDeviceInfo(out_param.device)->defaultLowOutputLatency;
	 out_param.hostApiSpecificStreamInfo = NULL;
	 err = Pa_OpenStream(&stream, NULL, &out_param, sfinfo.samplerate,
	 paFramesPerBufferUnspecified, paClipOff,output_cb, file);
	 error_check(err);
	 err = Pa_SetStreamFinishedCallback(stream, &end_cb);
	 error_check(err);
	 err = Pa_StartStream(stream);
	 error_check(err);
	 printf("Play for 10 seconds.\n");
	 Pa_Sleep(10000);
	 err = Pa_StopStream(stream);
	 error_check(err);
	 err = Pa_CloseStream(stream);
	 error_check(err);
	 sf_close(file);
	 Pa_Terminate();
	 return 0;
}

Y para terminar un diagrama de salidas de audio nativas soportadas por PortAudio:

loading...

Preparando el nuevo curso

Acaba Agosto, llega Septiembre y algo ocurre; es el inicio del curso. ¿Qué decir? Para mí el año no empieza en Enero sino en Septiembre. Además el día 25 de ese mes será mi cumpleaños… ¿Qué nos deparaá el nuevo curso? Entre mis proyectos está lanzar Azpazeta 2.0 (ya está hecho) y hacerle algunas actualizaciones, DivCity en 3D podría salir bien, Bloco avanza a buen ritmo (el mejor de todos), DivHotel avanza fijo, los complementos de Firefox recibirán alguna que otra actualización, redactaré el guión de una película o una novela, manejaré mis BitCoins y puede que alguna sorpresa más. me gustaría también empezar a escribir más a menudo (1 vez a la semana mínimo) y hablar más sobre muchas más cosas. Y vosotros ¿qué proyectos teneis para el nuevo curso?

PD: Supuestamente este año me toca ser miembro del Consejo Escolar el instituto, veremos como sale todo… y de regalo el trailer de Azpazeta que ya se puede descargar si sabeis mirar:

Calculadora de 4 Bits

Un día que no sabía que hacer con un circuito de una bombilla y su pila de 4,5 V se me ocurrió hacer una calculadora binaria (sabía que decimal sería difícil). Antes de nada necesitaba diseñar los planos del diseño para saber que iba a necesitar y como lo tenía que hacer. No sabía por donde empezar así que busque en Google algo de información. Nada. Busqué entonces tutoriales de Redstone del juego Minecraft con el que se pueden hacer calculadoras. Al final eran diseños muy complejos y largos, pero no debía de ser tan difícil pensaba. Empezé a diseñar en el Crocodile Clips varios prototipos, pero llegaba a liarme mucho con si debía poner 1 o 2 o 3 puertas lógicas, etc. Al final di de casualidad con una página en la que expliacaban como montar una calculadora de 4 bits. Vi los planos y los adapté a un circuito completo. Es una calculadora binaria y con el límite en 15 (16-1) como máximo resultado. No es muy útil, pero es fácilmente extensible en potencias de base 2. Así pues os dejo los diseños de mi calculadora a ver si algún día la construyo:

El funcionamiento es algo retorcido (faltan conversores de decimal a binario y viceversa). Primero ponemos los sumandos activando los interruptores de los sumandos que queremos sumar. Podemos activar 1,1,2,2,4,4,8 y 8. Pero hay que tener cuidado si sumamos más de 15, pues habrá un overflow un el circuito en cuestión será físicamente dañado. Una vez ajustados los interruptores presionamos el botón al lado de la pila de 2V y veremos el resultado en los LEDs. Para obtener el resultado deberemos sumar un valor diferente por cada LED encendido. En el siguiente orden: 1,2,4 y 8. Así podemos obtener hasta 15. Digo que este modelo es fácilmente extensible, pues podemos añadir más módulos como el de los 2 y los 4. Así aumentaremos la capacidad de procesamiento. Por cierto, dentro de poco vereis más novedades sobre mi videojuego.

Planos originales: http://www.instructables.com/id/4-Bit-Binary-Adder-Mini-Calculator/step5/Building-It-On-A-Breadboard/

La Fuente Q y el problema sinóptico

Hoy vamos a hablar sobre el problema sinóptico. Quizá a muchos no os suene pero es un tema importante en la teología (habéis leído bien, la ciencia de las religiones).

¿Qué es el Problema Sinóptico?

Como muchos sabéis en la religión católica hay 4 evangelios oficiales (correctamente llamados canónicos). Además existen los evangelios apócrifos que son aquellos que por su contenido no están en la Biblia. El problema sinóptico ocurre cuando 3 de los 4 evangelios son muy parecidos en algunas partes (usando los mismos párrafos algunas veces). Estos evangelios son los de Marcos, Mateo y Lucas. Esto tiene una explicación lógica pues el de Marcos fue primero y los de Mateo y Lucas se inspiraron en él. Se le llama la Fuente M. Sin embargo hay partes coincidentes entre Mateo y Lucas que no aparecen en Marcos (y son bastante abundantes). Se sabe que ni Mateo conoció a Lucas ni Lucas a Mateo. Este es el problema sinóptico que ocurre además con algunos evangelios apócrifos.

La Teoría de las dos fuentes

Hay una teoría muy aceptada que dice que tanto Marcos, como Lucas tuvieron acceso a una fuente hoy en día desconocida, esta fuente se la llama la Fuente Q (del alemán “queller”, fuente). La Fuente Q explicaría las similitudes entre los diversos evangelios

La Fuente Q

Mientras la Fuente M se la conoce como la una lista de hechos y milagros de Jesús, la Fuente Q sería una recopilación de dichos de Jesús. Las bienaventuranzas y el Padre Nuestro solo aparecen por ejemplo en los evangelios con Fuente Q. Actualmente no se conoce ninguna referencia a la Fuente Q en la antigüedad por lo que ha sido criticada por expertos que simplemente dicen que no existe. Sin embargo, la teoría de las dos fuentes que explica la existencia de la Fuente Q es la más sencilla y como nos dice la navaja de Ocam (ya explicaré), lo más probable es que esta teoría sea cierta.

Intercambio con Francia

Recientemente he tenido un intercambio con Francia entre alumnos que estudian español en Francia y alumnos que estudian francés en España. He de decir que es una muy buena experiencia en la que se aprende mucho del idioma y de las costumbres de un país. Lo primero decir que es una experiencia cansada pero a la vez divertida y os la recomiendo a todos. Mi intercambio se realizaba con el pueblo de St. Brevin Les Pins, un pueblo cerca de Nantes.