Errare Humanum Est

Errar es humano. O mejor aún, es errar lo que nos hace humanos. Toda una amalgama de errores que se concatenan, y que inundan cada rincón de nuestra vida: desde olvidar donde pone uno las llaves hasta fallos de ejecución en una obra musical, pasando por sesgos cognitivos e incoherencias internas que son las que nos dan poco a poco la vidilla, y la razón para pensar.

Pero es de los fallos en la música de lo que hablaré. Porque si hay algo que me fascinó cuando era mucho más pequeñajo era la perfección de un disco, con una filosofía que bebía directamente del mundo de las ideas de Platón, haciendo de una pista grabada el ideal de la canción que luego cambiaría en cada una de las ejecuciones.

La música grabada, en ese momento, me parecía la obra culmen de la música, el pico de perfección que jamás se podría alcanzar, tal vez solo llegar infinitesimalmente cerca. Una suerte de mundo de ideas de platón que, al pasar por nuestras manos, se convertirían al mundo de lo físico añadiendo imperfecciones.

Con la llegada de la música electrónica llegó una autoimposición bestial de la perfección. Todo se podía racionalizar, cuantizar… La era del MIDI y la informática que transformó a la música en algo inmutable, reproducible. En definitiva, tan inerte como una piedra. Esto está tan dentro de nuestro ADN que nos hace parir chistes tan geniales como:

– ¿Te vienes a echar unas cervezas?

– No, estoy grabando a un grupo…

– ¿Grabar? ¿Y eso qué es?

– Es como el MIDI, pero con personas..

No es tan alocado como puede parecer, en todo caso. Poco a poco, y estando ya en Anima Adversa, vi como todos nos dejábamos llevar por la obsesión con esa perfección. Una perfección que es falsa.

Recuerdo habiendo sacado El Grito en el Cielo, como Juanpy dijera: a mi me gusta más El Otro Yo, tiene un alma, un algo. En ese momento, mi respuesta fue: claro, tiene que está mal grabado. Y es increíble como, estando tan acertado, estaba tan equivocado. Por supuesto, el disco es en sí una sucesión de ejemplos de como no hay que grabar. Sin embargo, esa sucesión de imperfecciones hacían que la música cobrase vida.

Hoy en día creo firmemente en que la música sólo está viva en directo, y que por tanto, la música grabada no debe ser reflejo de la perfección inerte del mundo de las ideas. Este mundo de las ideas no existe mas que en nuestras cabezas. La música grabada debe ser una de las reflexiones físicas de nuestro mundo de las ideas interior, y que fluye a través de nuestras propias capacidades de ejecución, entrenadas al máximo.

Y es que errar no es más que el acto creador que nos convierte en dioses capaces de conferir alma a la música. El resto, son piedras.

Errare Humanum Est

¿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

Entre APIs y Ces…

Sí, la interfaz pyFluidSynth que estoy forkeando tiene una función principal: interactuar con la API de fluidsynth, que está escrita en C. Eso lleva a algunos problemas, por ejemplo, en el tipo de datos y estructuras que maneja.

Más o menos podemos decir que la cosa va viento en popa, y he ampliado el número de funciones que la clase Synth posee con muchas de las funciones que provee la API, pero hay cosas con las que he tenido que recurrir a magia negra. Para obtener una lista de todos los instrumentos que posee una función he tenido que crear una interfaz para capturar durante unos momentos la salida del shell. En fluidsynth, hay dos opciones de obtener la lista: construir una serie de estructuras horrendas (con las que interactuar en python se puede convertir en un infierno), o capturar la salida del shell con los comandos inst SF_ID. Así que opté por esta última.

Tras darle muchísimas vueltas, por fin conseguí hacer una clase, que llamé StdoutHandler, y que llamando objeto.freopen() abres un archivo y escribe la salida de la shell en el mismo, y con objeto.freclose() se devuelve la salida al stdout del sistema.

Así que esto es lo que he hecho, por si a alguien le hace falta (basado en este post de StackOverflow):

class StdoutHandler(object):
    def __init__(self, f):
        """Create new stdouthandler, for management of stdin and
        stdout (some methods of Synth DO need to capture stdout stream).
        """
        self.prevOutFd = os.dup(1)
        self.prevInFd = os.dup(0)
        self.prevErrFd = os.dup(2)
        self.newf = open(f, 'w')
        self.newfd = self.newf.fileno()  # The new file output


    def freopen(self):
        """
        Redirects the standard input, output and error stream
        to the established newfd.
        :return:
        """
        os.dup2(self.newfd, 0)
        os.dup2(self.newfd, 1)
        os.dup2(self.newfd, 2)

    def freclose(self):
        """
        Closes the modified input, output and error stream
        :return:
        """
        self.newf.close()
        os.dup2(self.prevOutFd, 1)
        os.close(self.prevOutFd)
        os.dup2(self.prevInFd, 0)
        os.close(self.prevInFd)
        os.dup2(self.prevErrFd,2)
        os.close(self.prevErrFd)
Entre APIs y Ces…