Tapita un contador de BPM

  • 1
#1 por monon el 18/06/2013
Rompo el silencio de muchos dias para comentaros sobre una nueva aplicacion de cosecha propia , "Tapita" , que mediante "tapping" en el teclado alfanumerico (tecla espacio) calcula las BPMs, los tiempos en milisegundos.
Hace un par de años que hice la primera version, la cual estaba desarrollada en python y GTK, y habia quedado un poco abandonada.

He decidido retomar su desarrollo partiendo de cero y desarrollando en C con una GUI basada enGTK+ (vaya locura, las lineas de codigo se multiplican por 1000, aparte del pesimo estilo de mi programacion ).
La razon de volver a las andadas es por haberme topado con un homologo llamado "Qrest" (hace uso de las bibliotecas QT) y del cual he fusilado una caracteristica que encuentro insteresante. El calculo de desviacion de cada golpe con respecto a la media.

Para aquellos que querais probar "Tapita", podeis descargarlo desde sourceforge
Y esta es la pagina del proyecto http://sourceforge.net/projects/tapita

Una caracteristica que me gustaria añadirle (poco a poco) es poder calcular los "beats" usando una entrada de audio a través de jack.
Osea a los que os gusta programar ya sabeis, las puertas están abiertas a la colaboracion.
Subir
2
#2 por igny el 19/06/2013
Saludos maestro¡ :)

Ya probaré el "artefacto" en casa.

Seguro que es una maravilla.

Salut monon.
Subir
#3 por igny el 19/06/2013
Saludos amigo monon. Disculpa que te moleste pero no consigo que funcione tapita.

Mira descargado del enlace, descomprimido cuando intento compilar muestra esto el terminal:
gny@igny-System-Product-Name:~/Descargas/v1.1$ cd ./src
igny@igny-System-Product-Name:~/Descargas/v1.1/src$ make
make: «tapita» está actualizado.

después esto:

igny@igny-System-Product-Name:~/Descargas/v1.1/src$ sudo make install
[sudo] password for igny:
cp tapita /usr/bin/
cp ../share/tapita.desktop /usr/share/applications/
cp ../share/tapita.svg /usr/share/pixmaps/

Se crea el icono en el menú y cuando intento ponerlo en marcha:

igny@igny-System-Product-Name:~/Descargas/v1.1/src$ tapita
bash: /usr/bin/tapita: no se puede ejecutar el fichero binario

Supongo que serà por algún error mío pero no se arranca claro. Parece que me falta algo?

Salut i disculpa las molèstias. :oops:
Subir
#4 por monon el 19/06/2013
No Xavi, el error es mio.
Subí las fuentes sin haber limpiado la ultima compilacion hecha por mi, la cual era para 64 bits.
Para corregirlo solo tines que ir al directorio tapita/src :

make clean
sudo make uninstall

eliminando así la compilacion anterior y desinstalarlo de tu sistema.
Luego solo tienes que volver a hacer:

make
sudo make install


Lo siento, voy ahora mismo a corregirlo y a subir el nuevo paquete
Subir
#5 por monon el 19/06/2013
Corregido!

Deberas tener instaladas las bibliotecas de desarrollo de GTK+
libgtk2.0-devel o libgtk2.0-dev, dependiendo de la ditro
Subir
#6 por Pablo_F el 19/06/2013
Ayer lo probé un poco. Es una aplicación sencilla y útil. Cuando quería saber el tempo de una canción normalmente usaba gtklik pero tapita está mucho mejor para esto. El gráfico ayuda a saber cómo llevas la pulsación. Gracias Monon!

Y el icono es muy divertido!
Lo que no entiendo bien es para qué está la indicación de 4th. Son los milisegundos entre dos cuartos de beat, no? Pero no le veo la utilidad, si ya calculas el tiempo entre dos beats.
Subir
#7 por monon el 20/06/2013
Gracias Pablo por el "review".
Lo de marcar los cuartos de "pulso" es por no usar una calcualdora, y creo que para los delays y reverbs es mas efectivo usar las semicorcheas, pero puedo estar equivocado,. Así que es precisamente a esa "vision" la que espero como colaboracion.
De hecho en la primera version (en python) solo indicaba las negras.
¿Es realmente útil? ¿Puedo eliminar esa informacion?

Otra cosa que he pensado a partir de tu comentario, es que en inglés los 1/4 son precisamente las negras y no las semicorcheas y puede dar lugar a confusion. Pensad que aunque lo he escrito en inglés sigo pensndo en castellano ¿¡!?
¿Alguna opnion al respecto? Booo?
Subir
#8 por Pablo_F el 20/06/2013
Alguien escribió:
Otra cosa que he pensado a partir de tu comentario, es que en inglés los 1/4 son precisamente las negras y no las semicorcheas y puede dar lugar a confusion. Pensad que aunque lo he escrito en inglés sigo pensndo en castellano ¿¡!?
¿Alguna opnion al respecto? Booo?


Y qué tal "beat/4".

Alguien escribió:
Lo de marcar los cuartos de "pulso" es por no usar una calcualdora, y creo que para los delays y reverbs es mas efectivo usar las semicorcheas, pero puedo estar equivocado


No se me había ocurrido. Si piensas que es útil, no me hagas caso. :)
Subir
#9 por vagar el 21/06/2013
¡Mola! Pulgarazo verde al canto.

Aunque nunca viene mal tener una cuenta aproximada, los eventos de teclado o de ratón no son los más precisos en cuanto a temporización, normalmente van con bastante baja prioridad y si tienes alguna otra aplicación pesada corriendo (típicamente algún editor de audio con visualización y seguimiento de onda como audacity) te puede meter desviaciones que te fastidien la medida.

Como sugerencia a lo mejor para la versión 0.2, y antes de jack audio, que te requiere un poquito más de trabajo porque tienes que implementar detección de picos, puedes pensar en incluir jackmidi o alsa midi raw.

¡Gracias por compartir!

Ars longa, vita brevis.
Mi colección de enlaces web en diigo.

Subir
#10 por monon el 21/06/2013
Hola Luis, en ti andaba pensando...
... para consultarte:
¿Debo usar "threads" para usar jack junto con una GUI?
¿O no es necesario?

Lo de "tapear" con MIDI en vez de hacerlo con el teclado alfanumérico también se me pasó por la cabeza. Pero me parecía mas fácil empezar con el audio de jack.

Posiblemente tengas razón y sean esos lo pasos a seguir:
1- Implementar jack ( o alsa ) MIDI.
2- Incorporar detección de audio.
Subir
#11 por vagar el 21/06/2013
monon escribió:
¿Debo usar "threads" para usar jack junto con una GUI?


En este caso no explícitamente. Tu aplicación y jack corren en distintos procesos, ergo distintos hilos. Lo que haces es que cuando te registras como cliente de jack le das la dirección de una función de tu aplicación como callback, así que esa parte de tu código se ejecuta en el thread de jack. Pero tú no tienes que crear ningún thread adicional.

La dificultad del modelo callback estriba en la comunicación y la sincronización de esa parte de tu programa con el resto, dado que en el callback de jack no debes usar ninguna función que no sea realtime safe, lo que excluye, entre otras cosas, primitivas de sincronización como los bloqueos.

En tu caso es bastante sencillo, porque el esquema productor-consumidor está perfectamente delimitado. En el callback usas una variable primitiva para escribir el valor de BPM una vez calculado y en tu aplicación principal la vas leyendo, me imagino que con un temporizador que se ejecuta en el bucle de eventos.

Si hicieras otra cosa que interfiriera con la interfaz de usuario, tal como volcar a disco el buffer de audio, entonces sí que sería conveniente añadir un thread específico para esta función.

monon escribió:
Posiblemente tengas razón y sean esos lo pasos a seguir:
1- Implementar jack ( o alsa ) MIDI.
2- Incorporar detección de audio.


Yo lo haría así si no tienes experiencia. Añadir detección de beats no es complicado una vez que controles cómo trabajar con callbacks.

Ars longa, vita brevis.
Mi colección de enlaces web en diigo.

Subir
#12 por monon el 22/06/2013
Alguien escribió:
...no escomplicado una vez que controles cómo trabajar con callbacks.

:? en eso radica la dificultad precisamente, en controlar los callbacks, y los punteros, y ... bueno, un monton de cosas mas.

Te agradezco muchisimo la informacion, aunque me parece que haré una digestion de boa constrictor :-D
La iré desmenuzando poquito a poco.

Buscaré algun ejemplo sencillo del cual nutrir mi codigo.
Subir
#13 por vagar el 22/06/2013
La mejor manera de empezar es precisamente a partir de ejemplos.

El problema principal de C es la memoria dinámica (crear y destruir objetos), ahí me temo que la curva de aprendizaje es elevada.

No obstante, como esta aplicación es sencilla y usas GTK es probable que no tengas que usar directamente ningún puntero para adquirir o liberar memoria, ya se encargan las funciones de GTK de gestionarlo todo.

http://www.cs.hunter.cuny.edu/~sweiss/course_materials/csci493.70/lecture_notes/GTK_memory_mngmt.pdf

Como guía general en la función que le pases a jack como callback sólo debes hacer dos cosas: leer/escribir en memoria datos simples (enteros, flotantes, etc.) y operaciones matemáticas. Nada de crear/destruir objetos o entrada/salida. Como el callback y el resto de la aplicación se ejecutan en hilos distintos ten cuidado de que no haya una variable que se modifique en los dos sitios. Es decir, si en el callback tienes una línea que dice:

bpm = beatcount / minutes;

asegúrate de que en ninguna parte del resto de la aplicación que no sea callback haya líneas que empiecen por:

bpm = ....

Pero sí puedes poner, por ejemplo:

sprintf(label, "BPM = %d", bpm);

Porque ahí bpm sólo se accede para lectura.

Ars longa, vita brevis.
Mi colección de enlaces web en diigo.

Subir
#14 por monon el 22/06/2013
De momento he intentado incluir codigo de alsa con snd_seq_event_input en una aplicacion con qtk, pero...
Los eventos midi se leen en un bucle infinito "while" en main() y por tanto nunca llegaría a gtk_main().

La otra posibilidad sería crear una funcion "callback" al estilo "g_signal_connect" para que reaccionase a eventos externos al propio gtk (en este caso midi) ... pero no tengo ni puñetera idea de como crearla.
Aquí encontre algo, pero no acaba de funcionar http://osdir.com/ml/linux.alsa.devel/2002-05/msg00106.html
Seguire con mis pesquisas....
Subir
#15 por vagar el 22/06/2013
Pues a ver, lo más eficiente y elegante en este caso sería añadir un thread con lectura con bloqueo que se encargara de ir procesando los eventos. Pero si no tienes experiencia en programación multithread lo mejor es usar polling, es decir, mirar la cola de entrada cada cierto tiempo.

Abres el puerto pasándole el flag sin bloqueo

snd_seq_open(seq, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK);

Después creas un temporizador (g_timeout_add) de unos 20-50 ms para tener un refresco de 50-20 Hz. En la rutina de atención al temporizador haces un bucle de lectura de eventos hasta que se terminen:

while (snd_seq_event_input(seq, &ev) >= 0) {
... procesar los eventos que haya en la cola
}

El temporizador se ejecuta en el mismo thread del bucle de eventos de la GUI, así que procura ser eficiente en el procesado o la interfaz perderá velocidad de respuesta. La ventaja es que no tienes que preocuparte de la concurrencia, porque sólo hay un hilo.

Ars longa, vita brevis.
Mi colección de enlaces web en diigo.

Subir
Respuesta rápida

Regístrate o para poder postear en este hilo