martes, 20 de marzo de 2012

SIGUIENTE PASO


Objetivos:
- Importar un código en lenguaje C a nuestra aplicación android, mediante Cygwin y la herramienta NDK-build.
-Realizar la FTT de la señal grabada, calcular la energía de cada frecuencia de ésta y obtener la banda de frecuencia que contiene la mayor energía.

Lo primero que hicimos fue descargarnos una herramienta que fuese capaz de construir una librería android “.so” a partir de un código en lenguaje C, que fue el NDK-build. Para poder generarla necesitamos también instalar un terminal, en este caso, el Cygwin.

Todo esto era necesario ya que el código en C tenía un método que realizaba la FFT de una señal a partir de sus muestras y era justo lo que necesitábamos. La otra opción era realizarlo mediante el filtrado de la práctica normal pero la FFT nos abría un abanico de funcionalidades.

Lo primero que tuvimos que hacer fue crear un directorio “jni” dentro de nuestro proyecto “AudioSense”. En este directorio incluimos tanto el archivo “.mk”, donde definimos el nombre de la librería “.so” a crear y la ruta del fichero C, como el fichero C, a partir del cual creamos la librería y el cual contiene el método de la FFT.

Desde Cygwin, situados dentro de la carpeta “jni” arriba nombrada, ejecutamos el NDK-build, el cual nos genera en ese proyecto la librería deseada.

Para un correcto funcionamiento, en el código, tuvimos que declarar el método como “native” además de cargar la librería.

El primer problema que nos encontramos es que al “llamar” a la método realfft()  compilaba pero no era reconocido en la ejecución.

Para solucionar esto tuvimos que añadir algunos prefijos al nombre del método  para fijar mejor su ubicación y que fuese “reconocido” (y también a los métodos llamados dentro de éste) y añadir varios argumentos  al propio método (JNIEnv y jobject).

Volvimos a realizar el proceso arriba explicado desde el Cygwin y el método ya era reconocido tanto en la compilación como en la ejecución.

Una vez hecho todo esto, obtuvimos la FFT de la señal  mediante el método realfft(), al cual le pasábamos como argumento 257 muestras de la señal grabada. Este método nos devuelve 128 valores de la FFT de la señal repartidos entre 0 y 4KHz (tanto su parte real como su parte imaginaria).

A partir de estos valores, calculamos la energía en cada frecuencia y luego obtuvimos, mediante una media ponderada, la “frecuencia central” de la banda que acumula mayor energía. Mediante el valor de esta “frecuencia central”  y la energía total calcularemos los parámetros de vibración.

Nuestro siguiente objetivo es un ecualizador gráfico para comprobar la funcionalidad de todo lo arriba explicado.

martes, 13 de marzo de 2012

Primer Paso



Nombre de la aplicación: “Audio Sense”.

Primer objetivo: Comprender como se graba, a través del micrófono del móvil, en la RAM del terminal android, comprobando como se lleva a cabo ese proceso para luego saber tratar la señal adecuadamente, llegando finalmente a las vibraciones.

La finalidad de este primer “paso”  era llegar a tener un programa que grabase nuestra voz al darle a un botón (botón de comenzar), y después al volverle a dar al mismo botón (botón de terminar) dejase de grabar y reprodujese  lo grabado justo a continuación.

El primer paso fue crear la interfaz gráfica del programa con un botón que tuviese dos “posiciones”, una para empezar a grabar (comenzar) y otra para terminar de grabar y que reprodujese al instante (terminar). También añadimos otro botón para salir de la aplicación.


Configuramos los buffers, tanto el de grabación como el de reproducción, que son almacenados en la RAM del terminal. El buffer de grabación tiene una frecuencia de muestreo de 8 kHz, es decir, para tomar 8000 muestras por segundo. Cada muestra la configuramos para que esté codificada en 16 bits-PCM.

Después de toda la configuración de buffers y creación de botones, nos metimos ya en el proceso de grabación y reproducción.

La primera opción que propusimos fue que grabase como máximo durante 20 segundos. El  inicio de esta grabación era la pulsación del botón COMENZAR, y la finalización de la grabación era la pulsación del botón TERMINAR y a continuación de ésta reproducir lo grabado. La idea era que si el intervalo entre ambas pulsaciones superaba los 20 segundos, no influyese ya que el terminal dejaría solo de grabar al cubrir esos 20 segundos y la pulsación del botón terminar solo indicaría el inicio de la reproducción.

Esto lo implementamos mediante el método “read” de la clase AudioRecord. El problema que tenía esta implementación era que el programa se quedaba los 20 segundos esperando hasta que grabase todo y después lo reproducía. Por lo tanto solo teníamos la posibilidad de grabar 20 segundos sin poder nosotros decidir el fin de la grabación. Por tanto decidimos enfocarlo desde otro punto de vista.

 Lo siguiente que intentamos fue recoger los datos de la señal de audio (grabación) con menos bits . Por ejemplo, en vez de coger los 20 segundos como bloque de bits, los cogíamos por bloques de bits de contenido las muestras  de un segundo. Una vez implementado nos dimos cuenta que esta tampoco era la solución, ya que lo que necesitábamos era crear un segundo hilo para que la grabación se hiciese en segundo plano, mientras que en el primer plano se controlaba las pulsaciones de botones.

Para implementar esto, hicimos uso de una subclase llamada AsyncTask, capaz de crear un segundo hilo y que la grabación se hiciese en ese segundo plano.

Conseguimos que se grabase la voz el tiempo que queríamos nosotros pero reproducía durante los 20 segundo en vez de reproducir solo lo que habíamos grabado, sonando vacío en los huecos sin grabar.

Al final la solución definitiva fue crear un array bidimensional para que en cada “fila” del array se vaya guardando lo grabado por el micrófono de forma que cogemos pequeñas muestras de tantos bits como “columnas” del array. Además esta solución en vez de reproducir al terminar  de grabar, lo que hicimos fue reproducir cada “fila” del array una vez guardado la muestra en ella consiguiendo  el efecto de reproducción en tiempo real, dado el pequeño de éstas.

Por tanto la implementación final de éste módulo es todo lo explicado en el párrafo anterior en un segundo hilo gracias a la subclase Asynctask junto a la creación de botones y buffers y “tratamiento” de botones en un primer hilo (actividad principal).  

 Al pulsar el botón de COMENZAR,  la aplicación nos asiente la pulsación mediante el mensaje “grabando” y  al igual cuando pulsamos el botón de TERMINAR  mediante el mensaje “terminando”.

El aspecto final de la aplicación hasta ahora es el siguiente: