Archivo de la categoría: Audio programming

diatonicbaixos v1.0: ayuda para los bajos del acordeón diatónico

Maria está estudiando el acordeón diatónico (y de paso yo también me he enganchado). Una de las cosas que siempre he encontrado difíciles es la coordinación de la mano derecha (con la que tocamos la melodía) y la mano izquierda (los bajos). Igual que pasa con el piano, que siempre me ha parecido difícil tocar con las dos mans al mismo tiempo.

Aquí va un pequeño programa para ayudar a poner la mano izquierda en el acordeón diatónico. Mientras suena la melodía (se necesita el fichero midi de la melodía), por pantalla se muestran las posiciones de los bajos que se han de tocar (en el acordeón diatónico hay 8 botones para los bajos/acordes, que suenan diferente si abres o cierras el fuelle). Cuando se muestra un botón en color verde significa que hay que cerrar el fuelle; en color rojo hay que abrirlo.

Para la interficie gráfica se ha utilizado la librería ncurses, que es la primera vez que programaba en esta llibrería (y estoy muy contento del resultat obtenido). El programa es un cliente de JACK (el servidor de audio para Linux, www.jackaudio.org), y de hecho es el time master, es decir, controla el transporte. Para utilizar la aplicación lo mejor es lanzar el script bash que se proporciona, diatonicbaixos.sh, donde se pone de manifiesto toda la cadena de programas que se utilizan.

Primero de todo se cambia el tempo deseado al fichero midi mediante el script change_tempo_smf (se proporciona el código fuente). Luego se arranca el servidor JACK, y el sintetizador fluidsynth, que es el que hará sonar la melodía. Después arrancamos la utilitat jack-smf-player, que se encargará de hacer sonar la melodía. También arranco el klick, que es un metrónomo cliente de JACK. Finalmente ya puedo lanzar mi aplicación, diatonicbaixos. El resultado, com se ve en el video, es que suena la melodía mientras se van mostrando las posiciones de los bajos. Se puede cambiar el tempo, se puede habilitar o no el metrónomo, y hay otro parámetro que permite mostrar el siguiente bajo que se tendrá que pulsar.

Para hacerse una idea del funcionamiento del programa lo mejor es ver el video:

Descargar diatonicbaixos v1.0

Jugando con la FFT

Hace ya mucho tiempo (realment mucho tiempo) que estudiaba la Transformada de Fourier (http://en.wikipedia.org/wiki/Fourier_transform) en la facultad, e incluso utilicé el algoritmo de la FFT (Fast Fourier Transform, http://en.wikipedia.org/wiki/Fast_Fourier_transform) en un aplicativo escrito en C para procesamiento digital de imágenes. Desde entonces no me había preocupado de la FFT y realmente lo tenía muy olvidado.

Estos días he vuelto a la carga con la FFT pues, con la idea de aprender las técnicas de programación de aplicaciones de audio, quería programar un afinador o un analizador de la potencia espectral de una señal, que fuese compatible con JACK.

Antes que nada hay que mirar qué algoritmo de FFT se podría utilizar, con licencia GPL, y rápidamente he visto que la elección sería FFTW (http://www.fftw.org/):

FFTW is a C subroutine library for computing the discrete Fourier transform (DFT) in one or more dimensions, of arbitrary input size, and of both real and complex data (as well as of even/odd data, i.e. the discrete cosine/sine transforms or DCT/DST). We believe that FFTW, which is free software, should become the FFT library of choice for most applications.

Me he puesto a compilar unos cuantos ejemplos y a familiarizarme con los cálculos. En definitiva yo lo que quiero es calcular la potencia espectral de una señal de audio, por tanto el señal de entrada serán unas muestras reales (una sola dimensión). La salida de la FFT serán unos valores complejos, y he de tener en cuenta tanto la parte real como la parte imaginaria para hacer los cálculos de la potencia espectral.

fftPlan = fftwf_plan_dft_r2c_1d(fftSize, fftIn, fftOut, FFTW_MEASURE); //r2c_1d: real to complex, one dimension

Mirando si hay algún afinador de código libre, que trabaje en modo consola, y compatible con JACK, me he encontrado estos dos proyectos, que precisamente utilizan la librería FFTW:

y también me ha sido últil para mi propio código en este proyecto capture_client:

He dividido el problema en dos partes:

  • Primero de todo capturo la señal que proviene del micrófono, y como resultado obtengo dos ficheros: el fichero de sonido wav y un fichero de texto donde pongo un número suficiente de muestas.
  • Segundo: abro el fichero de muestras, aplico una ventana de Hanning a les muestras como es habitual, calculo la FFT, calculo la potencia espectral de la señal, y obtengo un fichero de salida para ser procesado con la utilidad de creación de gráficos gnuplot (http://www.gnuplot.info/).

No había trabajado nunca con gnuplot, que sería el equivalente a Matlab para el mundo Linux. Viendo la demo de gnuplot que se distribuye con el código fuente, y que muestra de forma rápida todas las posibilidades de gnuplot, me he quedado realmente sorprendido. En mi caso dibujar el gráfico es muy fácil:

$ gnuplot
gnuplot> plot «data_440_trumpet_output.txt»

La prueba que presento se ha grabado con un mini teclado Casio SK-8, un mini-teclado de los años 80, escogiendo el sonido de trompeta, y obtengo el siguiente resultado.

Casio SK-8 440Hz (A) trumpet, 44100 fps by joanillo

Ahora quiero comparar el resultado de mis cálculos con los obtenidos con Audacity y Ardour, para comprobar que los cálculos son correctos:

Mis cálculos y Gnuplot Audacity Ardour

Perfecto! Lo he clavado!

jcapture: grabar la señal del micro a un fichero wav

jcapture es un pequeño programa desarrollado en C++ que capta la señal del micrófono y escribe un fichero de audio en format wav. Básicament es un cliente de JACK que se conecta automáticamente a system:capture_1, que es el puerto físico que representa la entrada del micro de la tarjeta de sonido, y mediante la librería libsndfile va escribiendo los datos del micro en el buffer del fichero de audio.

Además, muestra el nivel del señal de entrada de forma gráfica en la consola (pues es un programa que funciona por la consola, no tiene interficie gráfica). Si te interesa la programación de la API de JACK puedes descargar jcapture:

jplay-sndfile: una aplicación educativa para Procesamiento Digital del Señal

jplay-sndfile es una aplicación que he estado programando la última semana y que tiene un carácter didáctico. Básicamente es un reproductor de ficheros de audio que además puede aplicar un cambio de frecuencia, y también puede hacer un barrido continuo de frecuencias sobre la muestra de audio. Es un cliente de JACK (el servidor de audio de Linux), y está basado, como punto de partida, en sndfile-jackplay que se encuentra dentro de las utilidades de la librería libsndfile (http://www.mega-nerd.com/libsndfile/tools/#jackplay).

Todo el mundo saber que cuando se reproduce un fichero de audio al doble de la frecuencia original dura la mitad de tiempo. Sería equivalente a coger una muestra de cada dos, y reproducirlas a la misma frecuencia de muestreo original.

Ahora vamos a hacer el caso contrario, queremos dividir la frecuencia por dos, y el tiempo que durará la reproducción tendría que ser el doble. Para hacerlo, lo más fácil es doblar cada muestra en dos, y reproducirlo a la frecuencia de muestreo original.

Estos dos casos especiales, multiplicar por dos y dividir por dos, son los casos fáciles y más evidentes. Un análisis de estos casos y estudiar el código fuente proporcionado puede aclarar muchos conceptos a losestudiantes de Procesamiento Digital del Señal. Ahora bien, más difícil es hacer frecuencias intermedias entre 0.5 y 2; y más difícil todavía es hacer un barrido continuo de frecuencias en un rango determinado. Todo esto es lo que se puede ver y se puede estudiar en esta aplicación que tiene un carácter didáctico.

La salida de la ayuda del programa proporciona la siguiente información:

$ jplay-sndfile -h

jplay-sndfile 1.00
Created by Joan Quintana Compte (joanillo)
joanqc arroba gmail.com – www.joanillo.org
Licensed under GPL v.3

jplay-sndfile is a JACK client intended for playing audio files (wav) and pitch shifting, written basically for learning, testing and educational purposes, and the first stage for future developments. A part of playing an audio file, you can change the pitch (between *0.5 and *2) of your audio file, you can play the audio file combing the pitch between two ranges. For testing is useful a sine wave, but remember that you can use any mono (one channel) audio files.
This Jack Audio client connects automatically to system:playback_1 and system:playback_2

usage: jplay-sndfile [-h] [[pitch-shift] | [pitch-shift-start pitch-shift-end]] wav-file

\t-h –help: this usage information
\t[pitch-shift] (0.5,2): shifting pitch
\t[pitch-shift-start] (0.5,2): shifting pitch start range
\t[pitch-shift-end] (0.5,2): shifting pitch end range
\twav file: mono channel audio file
\t

\tExamples:
\t./jplay_sndfile samples/hellosine.wav
\t./jplay_sndfile 0.65 samples/hellosine.wav
\t./jplay_sndfile 0.5 2 samples/hellosine.wav

La muestra de audio que se presenta quiere ser un compendio de qué puede hacer jplay-sndfile, y contempla los siguientes casos:

  • ./jplay_sndfile samples/test_44100.wav
  • ./jplay_sndfile .5 samples/test_44100.wav
  • ./jplay_sndfile .8 samples/test_44100.wav
  • ./jplay_sndfile 1.4 samples/test_44100.wav
  • ./jplay_sndfile 2 samples/test_44100.wav
  • ./jplay_sndfile .5 2 samples/test_44100x3.wav
  • ./jplay_sndfile samples/sine_440_44100.wav
  • ./jplay_sndfile .5 1 samples/square_440_44100.wav
  • ./jplay_sndfile 1 2 samples/saw_440_44100.wav
  • ./jplay_sndfile .5 samples/waves.wav
  • ./jplay_sndfile 2 samples/waves.wav

jplay-sndfile-examples by joanillo

Una de les cosas más interesants es estudiar la función callback de la API de JACK, que ha quedado bastante escueta, y donde está el meollo del asunto. Básicamente la función callback() es llamada por el servidor de audio cada vez que la interfície de audio (la tarjeta de sonido hardware) necesita llenar su buffer con más datos.

static int process (jack_nframes_t nframes, void * arg)
{

\tjack_default_audio_sample_t buf ;
\tunsigned int i;
\touts = (jack_default_audio_sample_t *)jack_port_get_buffer (output_port, nframes) ;

\tinfo_t *info = (info_t *) arg;
\t
\tmemcpy (outs_original, buffer2 + frames_counter_original, sizeof (jack_default_audio_sample_t) * nframes * DOUBLE_SAMPLES * 2);

\tint k=0;
\tfloat k2;
\tk2 = nframes/info->shift_pitch;
\tfloat var, var2 = 0;
\tint part_entera = 0;
\tvar = 1/info->shift_pitch – 1;

\tfor (i = 0 ; i < nframes ; i++)
\t{\t

\t\tif (info->shift_pitch < 1) {
\t\t\tif (frames_counter + i >= info->numFrames / shift_pitch_equivalent) { // shift_pitch_equivalent = info.shift_pitch quan no faig un escombrat
\t\t\tinfo->play_done=1;
\t\t\treturn 0;
\t\t\t}
\t\t} else { // >= 1
\t\t\tif (frames_counter_original + i >= info->numFrames * DOUBLE_SAMPLES) {
\t\t\tinfo->play_done=1;
\t\t\treturn 0;
\t\t\t}
\t\t}
\t\t
\t\tif (info->shift_pitch > 1) {
\t\t\tk=(int)(i*DOUBLE_SAMPLES*info->shift_pitch + .5);
\t\t\touts[i] = outs_original[k];\t
\t\t} else if (info->shift_pitch <= 1) {
\t\t\touts[k] = outs_original[i*DOUBLE_SAMPLES];
\t\t\tif ((int)var2 != part_entera) {
\t\t\t\touts[k+1] = outs_original[i*DOUBLE_SAMPLES+1];
\t\tpart_entera = int(var2);
\t\tk++;
\t\t\t}
\t\t\tvar2 = var2 + var;
\t\t\tk++;\t\t\t
\t\t}

\t}
\tframes_counter += nframes;
\tframes_counter_original += nframes * DOUBLE_SAMPLES * info->shift_pitch ;
\t
\treturn 0 ;
} /* process */

¿Y para qué sirve todo esto? Como hemos dicho es una aplicación didáctica, sirve sobre todo para aprender:

  • para aprender: teoría del Procesamiento Digital del Señal
  • para aprender: API de libsndfile
  • para aprender API de JACK, ejemplo de cómo funciona la función de callback

pero a parte de aprender, se ha desarrollado con una idea en mente, que ha de ser el siguiente proyecto a realizar: utilizar una tableta gráfica Wacom, de las que utilizan los diseñadores gráficos, para producir sonidos realísticos, sensibles al movimiento y a la presión del lápiz, pero esto es otro proyecto: Reconocimiento real de gestos con la wacom y Síntesis de audio

Wacom Theremin

El Theremin es un instrumento inventado por Léon Theremin en 1918 que tiene la particularidad de que se toca con los gestos de las manos. Está considerado uno de los primeros instrumentos electrónicos, y su sonido sintético y característico se ha utilizado muchas veces para películas de ciencia ficción y efectos especiales.

En este proyecto se implementa la manera de tocar y el sonido de un theremin con un controlador poco convencional: una tableta gráfica Wacom de las que utilizan los diseñadores gráficos. Si sabes cómo se toca un theremin la implementación es evidente:  con el eje x cambias el tono (Pitch Bend en terminología MIDI; con el eje y cambias el volumen; y claro: apretar el lápiz produce el sonido de la nota (mensaje MIDI NoteOn) y levantar el lápiz apaga la nota (NoteOff). Además de la posición XY, la tecnología wacom proporciona otros sensores que dan información como es la presión y la inclinación. Aunque no se ha hecho en este proyecto, se podría haber asociado la presión y la inclinación a otros mensajes MIDI CC (Continuous Controller) com pueden ser la modulación (efecto de vibrato).

Se ha utilizado un sintetizador Roland JV-2080 para producir un sonido de Theremin, aunque no estoy muy contento con el resultado obtenido. Lo bueno del JV-2080 es que tiene un espacio de memoria para guardar los patch de usuari y muchos parámetros, osciladores y efectos para poder ir jugando si tienes suficiente tiempo. Y lo que es mejor del JV-2080 es que puedes configurar el pitch bend (variación del tono) con una amplitud muy grande, también configurable, cosa que normalmente no pasa en otros sintes (sobretodo los sintes software).

Una de las cosas que me ha gustado más del proyecto es la integración de la aplicación desarrollada en lenguaje C (hay un enlace para descargar el código más abajo) con Gimp (el editor de imágenes y fotos de referencia en el mundo Linux). Esto da pie a múltiples posibilidades y ideas para hacer proyectos que combinen Gimp con efectos sonoros y interactivos.

Evidentmente, la idea no es nueva, hay otra gente que ha hecho Theremins con wacom’s y otros controladores como la Wii, pero en el proyecto 50 Ways to Play Una Plata d’Enciam no podía faltar un Wacom Theremin hecho exclusivamente con herramientas de Código Libre.

smf_parser v1.01: SMF (Standard Midi File) Parser


jplayfine (http://wiki.joanillo.org/index.php/Jplayfine) es un proyecto musical que estoy desarrollando, que consiste en poder hacer un play-along sobre un fichero midi (fichero SMF), y que puedas obtener una nota relacionada con la similitud entre lo que has tocado y lo que se supone que has de tocar. Para hacerlo, el programa ha de saber en qué canal está la melodía en el fichero midi, y por qué canal
toca el controlador midi. jplayfine es un cliente JACK que convive bien dentro del ecosistema de las aplicaciones de audio y midi para Linux. Bien, hablaré de jplayfine en otra ocasión.

Aunque jplayfine utiliza un secuenciador externo per hacer sonar el fichero midi (las pruebas las estoy haciendo con jack-smf-player), el tema es que desarrollando el proyecto jplayfine me he encontrado con la necesidad de parsear el fichero midi que contiene la melodía y el acompañamiento. Podia utilizar la librería smf.h que utiliza jack-smf-player. La verdad es que, con los objetivos de buscar la simplicidad, tener el máximo control del código, y entender con
profundidad el formato MIDI, me he embarcado en hacer un parseador de SMF con C++. Aquí va la versión 1.01, por si alguien se lo quiere mirar. Por una parte hay una aplicación standalone; y por otra hay la librería y una aplicación de test que muestra como utilizar la librería. También hay una carpeta midi/ con los midifiles que se han utilizado para testear. Para utilizar la librería necesitas un ompilador C++ para Linux (g++).

Enlace del proyecto: http://wiki.joanillo.org/index.php/Fitxers_MIDI_(SMF)._Format#smf_parser
Información sobre el protocolo MIDI: http://www.sonicspot.com/guide/midifiles.html
Descargar smf_parser1.01