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:
- tuneit: A simple command-line instrument tuner for Linux (http://delysid.org/tuneit.html, Mario Lang). Puede funcionar como client de JACK
- sndfile-spectrogram: Generate a spectrogram as a PNG file from a given sound file (http://www.mega-nerd.com/libsndfile/tools/, Erik de Castro Lopo)
y también me ha sido últil para mi propio código en este proyecto capture_client:
- capture_client: (https://github.com/jackaudio/example-clients/blob/master/capture_client.c, Paul Davis, Jack O’Quin)
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!