FluidSynth superado. Ahora empieza lo bueno.

Por fin puedo decir que he echado un pulso a fluidsynth, sus python bindings (pyFluidSynth, see original project and my personal fork) y a todas las dificultades que un proyecto de estas características te pone delante. Pero lo primero es lo primero, así que aquí tenéis una Demo de como funciona fluidsynth en una Raspberry Pi 2 B+ (Raspbian), haciendo llamadas mediante los python bindings de fluidsynth:

Y ahora vamos con los detalles. El video muestra simplemente una llamada a liveDemo.py, un script que he preparado para probar 20 segundos del programa 0 y 20 segundos del programa 50 de cualquier soundfont que tengamos (por defecto carga /usr/share/sounds/sf2/FluidR3_GM). Así que los pasos para probarlo, desde una Raspberry Pi conectada a internet con Raspbian son los siguientes.

En primer lugar, nos aseguramos de tener instalado FluidR3_GM y las librerías de python de ALSA:

sudo apt-get install fluid-soundfont-gm python-pyalsa

Posteriormente, hacemos un clone de pyFluidSynth, con el código:

git clone https://github.com/pakitochus/pyfluidsynth.git

Navegamos hasta el lugar donde está la instalación y ejecutamos:

cd pyfluidsynth
sudo python setup.py install

Y en principio, ya podríamos ejecutar el test con:

cd test
python liveDemo.py

Por supuesto, hace falta tener un teclado midi conectado a la raspberry, yo sugiero MIDI USB. En el script, se presupone que el puerto en el que está conectado es el 20,0, pero esto no tiene por qué ser así. La forma correcta de saber cual es el dispositivo que tenemos completado es mediante el comando:

aconnect -i

que listará algo así como:

cliente 0: 'System' [tipo=kernel]
    0 'Timer           '
    1 'Announce        '
cliente 14: 'Midi Through' [tipo=kernel]
    0 'Midi Through Port-0'
cliente 23: 'MIDI KEYBOARD' [tipo=kernel]
    0 'MIDI KEYBOARD MIDI 1'

Suponiendo esos datos, para cambiar el que está por defecto, editamos el archivo liveDemo.py, y en la línea 29, donde aparece

sender = (20, 0)  # Modify according to the current port of the USB MIDI input

cambiamos por

sender = (29, 0)

De igual modo, para cambiar la soundfont a utilizar o modificar la ruta, vamos a la línea 22 del archivo, y sustituimos la línea

sfid = fs.sfload("/usr/share/sounds/sf2/FluidR3_GM.sf2")

por la ruta hasta el archivo de soundfont que queramos. En el video, he utilizado una colección que he recopilado y creado -a partes iguales- llamada ChusoCol, que podéis encontrar en Sourceforge (pronto subiré la ChusoCol 2, la del video).

Y eso es todo. No deja de ser una demostración de como funciona el fork de pyFluidSynth. Ahora es cuando viene lo bueno: convertir la RPi2 en un single-purpose computer y añadir todos los controles para usar el PiFace Control and Display module.

Esto no ha hecho más que empezar. Pero ya hay un paso menos que dar.

FluidSynth superado. Ahora empieza lo bueno.

ChusoCol

Conforme pasa el tiempo, parece que he abandonado por completo el proyecto ChuSynth. Nada más lejos de la realidad. Simplemente, con diferentes tareas que surgen de la investigación (y ahora también obligaciones docentes) pues no tengo tanto tiempo para dedicar a ello. Sin embargo, en estos días atrás estoy continuando otro proyecto que va de la mano de ChuSynth, y que es su principal fuente de sonido: ChusoCol, una soundfont ligera (alrededor de 300 MB), enfocada en el realismo de instrumentos acústicos y que pueda ser ejecutada de forma eficiente en una Raspberry Pi.

ChusoCol

La página web la diseñé hace tiempo y la mayor parte del trabajo de actualización lo hice durante mi estancia en Cambridge, pero ahora estoy dando los últimos retoques y espero poder lanzar ChusoCol 2 en poco tiempo. Mientras tanto, en la página web se puede descargar la primera ChusoCol, que me acompañó a muchísimos sitios cuando iba de conciertos con Anima Adversa.

ChusoCol

¿Qué IDE puedo usar para trabajar con Python como si fuera Matlab?

Esta es la primera pregunta que me hice a la hora de pasarme a Python. Y no es una respuesta fácil. Si dejamos de lado diferencias tan sustanciales como que Python es orientado a objetos y Matlab no, y las diferencias a la hora de trabajar con uno y otro, habría que atender a varias circunstancias. Para mi, un IDE que funcione bien tiene que tener al menos:

  • Editor integrado (si puede ser con sugerencias)
  • Ventana de comandos (IPython a ser posible)
  • Visor de variables
  • Posibilidad de salvar un workspace

Prácticamente todos los IDEs cumplen estas características. Después de mucho navegar por la web me encontré los más parecidos a Matlab que me podía tirar a la cabeza: Spyder y IEP. Ambos cumplen exactamente lo que prometen: un IDE para trabajar con SciPy (con todo lo que ello conlleva: numpy, matplotlib, scipy, sklearn).

Spyder UI

El primero que probé era Spyder, bastante consolidado ya en el mundillo, y que cumple todo lo anteriormente dicho. Es bueno, fiable y permite guardar el workspace en un único fichero (pero esto también puede ser un problema, porque es un fichero propio de spyder). Tiene un autodetector de las funciones que se están usando, que muestra la ayuda de dicha función en una pestaña (si la tenemos visible). En su contra diré que es más bien feo (tanto la UI como el icono) y que no tiene sugerencias instantáneas.

EIP UI

Por otra parte, conocí EIP, que por el momento me gusta más. Está en un desarrollo un poco más activo, aunque menos maduro que Spyder, con todo lo que ello conlleva. La principal diferencia es que no tiene un asistente para guardar workspace (se puede hacer desde código), pero en contrapartida posee sugerencias live de funciones, objetos y demás que estén en el workspace, lo que es muy conveniente cuando uno está empezando. También en el apartado estético gana por su limpieza e integración con el sistema operativo. Todavía es pronto para hacer un diagnóstico y me quedan muchas horas que trabajar con alguno de ellos, pero por lo pronto, yo me quedo con EIP, por las sugerencias y por su interfaz más pulida. Quizá en algún momento necesite guardar variables del workspace, en ese momento me plantearé que opción es más buena.

Editado: Una tercera opción que se me olvidó citar al ser de pago (aunque tienen una versión gratuita) es Canopy. Quizá es la que más se parezca a Matlab y viene perfecamente equipado con todo lo necesario para trabajar. Lo que es más, está disponible tanto para Windows como para Mac y Linux, lo que lo hace una opción muy buena a tener en cuenta si no importa el hecho de que no sea open source.

¿Qué IDE puedo usar para trabajar con Python como si fuera Matlab?

Tocando mis primeras notas

Por primera vez, he logrado lanzar fluidsynth desde una terminal python, crear su correspondiente driver MIDI y tocar algunas notas con el teclado en directo. A partir de aquí, es todo mejorar.

El problema que estaba teniendo era con la función new_fluid_midi_driver(settings, handler, event_handler_data), en el que en la documentación aparece como que hay que llamarlo (en C) de esta forma:

fluid_settings_t* settings;
fluid_midi_driver_t* mdriver;
settings = new_fluid_settings();
mdriver = new_fluid_midi_driver(settings, handle_midi_event, NULL);

sugiriendo el uso de fluid_midi_router_handle_midi_event() como handler callback. Finalmente, la mejor opción para mi fue:

mdriver = new_fluid_midi_driver(settings, fluid_synth_handle_midi_event, synth)

O sea, que había que la función fluid_synth_handle_midi_event es la pancea y en ningún sitio de la documentación de API te la especifican. Bien por fluidsynth. Y usar el propio objeto sintetizador synth como event_handler_data.

Tocando mis primeras notas

Mañana me pongo

Pero de verdad. Mañana empiezo el curso de Edx llamado 6.00.2x Introduction to Computational Thinking and Data Science. Otro MOOC más que espero que me de buenas bases para migrar decididamente desde el malvado y pesado, pero cómodo, Matlab a Python, que es Open Source (vaya, de lo mío).

Es un paso importante, porque además de seguir a la peña científica que generalmente están migrando a Python desde plataformas como R o Matlab con proyectos como SciPy, apoyo a proyectos que me resultan extremadamente atractivos, como Jupyter, una especie de IPython evolucionado para ser language-agnostic y poder trabajar a la vez con Python, R, y Julia.

El mundo del software evoluciona muy rápidamente, y si hasta ahora Matlab tenía el beneficio de la comodidad, multitud de extensiones y paquetes para trabajar en casi cualquier cosa, parece que cada vez Python se yergue como un potente rival. Una listilla con mis razones para hacer el cambio podría ser esta:

Matlab Python
Librerías third-party
Diseño de Aplicaciones Horrendo1 Fácil
Multi-purpose No
Gráficos Propia2 MatPlotLib
Open Source No
Eficiencia Computacional Baja Baja
Integración con otros lenguajes Difícil3 Buena
Shell interactivo IPython
Multitud de IDEs No

  1. Matlab contiene utilidades para crear interfaces gráficas y programas empaquetados, pero su uso es muy difícil, ineficiente y depende de una instalación de Matlab en el ordenador en el que se ejecute. 
  2. La librería de plots de Matlab es muy variada y los resultados son bastante visuales, pero ha sido superada por ggplot2 y matplotlib hace tiempo. 
  3. Existen formas de interactuar con C, C++ y Java desde Matlab, pero de forma un poco limitada. La capacidad de extensión de Python con otros lenguajes lo supera con diferencia. 
Mañana me pongo

A estas alturas

Y cuando ya pensaba que tenía el fork de pyFluidSynth casi terminado, me doy cuenta de que todavía me falta lo más importante: añadir el driver midi. Sin embargo, conforme uno va implementando cosas se da cuenta de que cada vez es más complicado añadir funcionalidad desde python a una API en C.

En esta ocasión, utilizando las funciones de la API, logro crear un driver MIDI al que conectar luego un teclado. Pero en cuando mando la primera nota, me manda un bonito SYSSEG: reading NULL VMA que hará las delicias de todos. ¿Por qué tengo un puntero nulo? Creía que ctypes se encargaría de todo.

Este es el código que manejo ahora mismo:

    def start_midi(self, mididriver='alsa_seq'):
        """
        Starts the MIDI driver to allow the MIDI keyboard interaction.
        :param mididriver: name of the midi driver, that can be one of these:
            'alsa_raw', 'alsa_seq', 'coremidi', 'jack',
            'midishare', 'oss', 'winmidi'
        :return:
        """
        if mididriver is not None:
            assert (mididriver in ['alsa_raw', 'alsa_seq', 'coremidi', 'jack',
                                   'midishare', 'oss', 'winmidi'])
            fluid_settings_setstr(self.settings, 'midi.driver', mididriver)
            # Optionally: sets the real time priority to 99.
            fluid_settings_setnum(self.settings, 'midi.realtimeprio', 99)
        self.midi_driver = new_fluid_midi_driver(self.settings, fluid_midi_router_handle_midi_event, new_fluid_midi_event)
        return self.midi_driver

No tengo ni idea de como voy a salir del paso, porque en principio parece que la función fluid_midi_router_handle_midi_event debería pasar todos los comandos de entrada al sintetizador, pero en lugar de ello, da fallo de segmentación. No sé si es por el midi.realtimeprio (que siempre da un warning), o por la función en sí, o por el recientemente añadido new_fluid_midi_event, pero la verdad es que estoy bastante estancado. A ver si esta tarde salimos del paso.

A estas alturas

Los proyectos personales

Esto es una reflexión un tanto manida, pero de la que uno se da cuenta de vez en cuando. Cuando inicias un proyecto personal, por el mero hecho de hacer algo nuevo por ti mismo, con tus manos, ya sea un armario de Ikea o un theremin casero, no estás perdiendo el tiempo. La gente hablará, dirán que “cuánto tiempo libre tiene ese tío”, aunque seas el más ocupado del mundo. Tú mismo llegarás a creerte que estás perdiendo el tiempo.

Pero no. Un proyecto personal es mucho más que un Hobby. Hobby es ir a comprar los viernes por la tarde a recogidas. Un proyecto personal es la búsqueda de algo que no has podido encontrar, es ese vaivén sentimental que sólo provocan los altibajos de uno de estos proyectos: las horas -y días- de frustración y la increíble realización personal que supone cuando se consigue una de las pequeñas metas que se ponen.

Al final de un proyecto personal aprendes mucho. Aprendes las tecnologías que utilizas (ya sea que existen diferentes tipos de tornillos o un nuevo lenguaje de programación). Aprendes a enfrentarte a retos, y a no abandonar. Aprendes a superar los obstáculos que pone la vida, algo que, en la sociedad de la obsolescencia programada, no solemos hacer. Nos gusta más el usar y tirar.

Por último, aprendes a conocerte a tí mismo, cuales son tus capacidades, cuales son tus puntos débiles. Y los potencias y solucionas respectivamente. Al final de un proyecto eres otra persona. Quizá has ganado un armario de Ikea (eso lo puedes comprar), pero lo más importante es que te has ayudado a conocerte, un poquito más, a tí mismo.

Los proyectos personales