scieee AI-readable full text Open interactive document viewer

Desarrollo de un paquete de software acústico para dispositivos móviles basados en Adroid

Moreno Ibarra, Gabriel

Abstract

En la actualidad, el uso de dispositivos móviles es un hábito muy cotidiano y en pleno auge. Existen varias plataformas: iOS, Symbian, Windows Phone, Blackberry¿ pero la que más se está extendiendo es, sin lugar a dudas, Android. En este trabajo se aplican los conocimientos acústicos aprendidos durante el Máster, para el desarrollo de una aplicación para este sistema operativo. En concreto, el software será una herramienta capaz de calcular el tiempo de reverberación en cualquier lugar y de forma gratuita.

Full text

UNIVERSIDAD POLITÉCNICA DE VALENCIA ESCUELA POLITÉCNICA SUPERIOR DE GANDÍA Máster en Ingeniería Acústica DESARROLLO DE UN PAQUETE DE SOFTWARE ACÚSTICO PARA DISPOSITIVOS MÓVILES BASADOS EN ANDROID TRABAJO FINAL DE MÁSTER Autor: Gabriel Moreno Ibarra Director/es: D. Francisco Javier Redondo Pastor D. Jordi Bataller Mascarell GANDIA, 2012 Desarrollo de un paquete de software para dispositivos móviles basados en Android 2 Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 3  Resumen En la actualidad, el uso de dispositivos móviles es un hábito muy cotidiano y en pleno auge. Existen varias plataformas: iOS, Symbian, Windows Phone, Blackberry… pero la que más se está extendiendo es, sin lugar a dudas, Android. En este trabajo se aplican los conocimientos acústicos aprendidos durante el Máster, para el desarrollo de una aplicación para este sistema operativo. En concreto, el software será una herramienta capaz de calcular el tiempo de reverberación en cualquier lugar y de forma gratuita. Abstract Nowadays, use of mobile devices is a daily habit and booming. There are several platforms: iOS, Symbian, Windows Phone, Blackberry... but the one that is spreading more is undoubtedly, Android. In this work the knowledge about acoustics learned during the Master is applied to develop an app for this operating system. Specifically, the software will be a tool to calculate the reverberation time anywhere for free. Autor: Gabriel Moreno Ibarra, e-mail: [email protected]s Fecha de entrega: 03-09-2012 DESARROLLO DE UN PAQUETE DE SOFTWARE ACÚSTICO PARA DISPOSITIVOS MÓVILES BASADOS EN ANDROID Autor: Gabriel Moreno Ibarra Director 1: D. Francisco Javier Redondo Pastor Director 2: D. Jordi Bataller Mascarell Desarrollo de un paquete de software para dispositivos móviles basados en Android 4 Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 5 ÍNDICE I. OBJETO Y ANTECEDENTES ............................................................................................................. 7 II. INTRODUCCIÓN TEÓRICA ............................................................................................................... 8 II.1. Tiempo de reverberación ................................................................................................................................ 8 II.1.1 Valores típicos ......................................................................................................................... 9 III. METODOLOGÍA Y HERRAMIENTAS ........................................................................................... 10 III.1. Android ........................................................................................................................................................ 10 III.1.1 Java ........................................................................................................................................ 11 III.1.2 XML ...................................................................................................................................... 11 III.2. Eclipse .......................................................................................................................................................... 11 III.3. MATLAB ..................................................................................................................................................... 11 III.3.1 MATLAB Coder.................................................................................................................... 11 III.4. JNI ................................................................................................................................................................ 11 III.4.1 C/C++ .................................................................................................................................... 11 IV. ANÁLISIS DE REQUISITOS ............................................................................................................. 12 V. DISEÑO DEL PROGRAMA ............................................................................................................... 12 V.1. Diseño de la clase RTActivity ...................................................................................................................... 12 V.2. Diseño de las clases Butterworth.................................................................................................................. 13 V.3. Relaciones entre clases ................................................................................................................................. 13 V.4. Algoritmo para calcular el tiempo de reverberación .................................................................................... 14 VI. IMPLEMENTACIÓN .......................................................................................................................... 15 VI.1. Butterworth_x .............................................................................................................................................. 15 VI.2. RTActivity ................................................................................................................................................... 16 VI.3. AndroidManifest .......................................................................................................................................... 18 VI.4. main .............................................................................................................................................................. 18 VII. MANUAL DEL USUARIO .................................................................................................................. 19 VII.1. Instalación ................................................................................................................................................ 19 VII.2. Funcionamiento ....................................................................................................................................... 19 VII.2.1 Arrancar la aplicación. ........................................................................................................... 19 VII.2.2 Apretar START. .................................................................................................................... 19 VII.2.3 Dar una palmada. ................................................................................................................... 19 VII.2.4 Apretar STOP. ....................................................................................................................... 20 VII.2.5 Darle a “Sí” si la medida ha sido correcta. ............................................................................ 20 VIII. CONCLUSIONES Y LÍNEAS FUTURAS ......................................................................................... 21 IX. AGRADECIMIENTOS ........................................................................................................................ 21 X. REFERENCIAS .................................................................................................................................... 22 XI. ANEXOS ................................................................................................................................................ 23 XI.1. Butterworth_2 .............................................................................................................................................. 23 XI.2. Campos RTActivity ..................................................................................................................................... 26 XI.3. Métodos RTActivity ..................................................................................................................................... 28 XI.3.1 onCreate() .............................................................................................................................. 28 Desarrollo de un paquete de software para dispositivos móviles basados en Android 6 XI.3.2 rt() .......................................................................................................................................... 28 XI.3.3 getNombreFile() .................................................................................................................... 29 XI.3.4 setNombreFile() ..................................................................................................................... 29 XI.3.5 setNombreFileSinTiempo() ................................................................................................... 29 XI.3.6 getTempNombreFile() ........................................................................................................... 30 XI.3.7 startRecording() ..................................................................................................................... 30 XI.3.8 escribirWavTempFile() ......................................................................................................... 31 XI.3.9 stopRecording() ..................................................................................................................... 31 XI.3.10 borrarTempFile() ............................................................................................................... 32 XI.3.11 borrarFile() ........................................................................................................................ 32 XI.3.12 escribirWavFile() ............................................................................................................... 32 XI.3.13 escribirWavDesdeArrayDeBytes() .................................................................................... 33 XI.3.14 escribirWavDesdeArrayDeDoubles() ................................................................................ 34 XI.3.15 escribirHeadDeWavFile() .................................................................................................. 35 XI.3.16 construirArrayDeBytesDesdeWav() .................................................................................. 36 XI.3.17 mostrarResultados() ........................................................................................................... 36 XI.3.18 calcularRT() ....................................................................................................................... 37 XI.3.19 redimensionarArrayfromBytesToDoubles() ...................................................................... 38 XI.3.20 normalizarArrayDeDoubles() ............................................................................................ 38 XI.3.21 enventanarArrayDeDoubles() ............................................................................................ 39 XI.3.22 getSetCoeficientes() ........................................................................................................... 40 XI.3.23 exportarArrayDeDoublesAFicheroCSV() ......................................................................... 41 XI.3.24 exportarArrayDeBytesAFicheroCSV() ............................................................................. 42 XI.3.25 exportarArrayDeDoublesAFicheroCSVSinTiempo() ....................................................... 43 XI.3.26 exportarArrayDeBytesAFicheroCSVSinTiempo() ............................................................ 44 XI.3.27 fxReverb() .......................................................................................................................... 44 XI.3.28 filtroIIR() ........................................................................................................................... 45 XI.3.29 schroeder() ......................................................................................................................... 47 XI.3.30 normaLogaritmizar() ......................................................................................................... 48 XI.3.31 posiciones() ........................................................................................................................ 48 XI.3.32 limpiarPrincipioYFinal() ................................................................................................... 48 XI.3.33 redondear() ........................................................................................................................ 49 XI.3.34 nDecimales() ...................................................................................................................... 49 XI.3.35 interpolar() ......................................................................................................................... 49 XI.3.36 hacerArrayDivisiblePor32() .............................................................................................. 49 XI.3.37 onCreateOptionsMenu() .................................................................................................... 50 XI.3.38 onOptionsItemSelected() ................................................................................................... 50 Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 7 I. OBJETO Y ANTECEDENTES El objeto de este proyecto es la realización de una aplicación para smartphones con sistema operativo Android. Tiene que ser capaz de calcular el tiempo de reverberación en bandas de octava por medio de una medición sencilla y amigable para el usuario. El rango de medición estará comprendido entre 125 Hz y 4 kHz. Por lo que se obtendrán resultados en las siguientes 6 bandas: [125, 250, 500, 1000, 2000, 4000] (Hz) Habrá que empezar por aprender el lenguaje/s que utiliza este SO 1 y familiarizarse con él, haciendo aplicaciones más sencillas hasta obtener un grado de entendimiento global suficiente como para poder abordar el problema en conjunto. El hecho de que exista un mercado tan amplio, la creciente demanda de profesionales del sector, así como la posibilidad de emprender con ideas propias, son sin lugar a dudas, las tónicas desencadenantes para decidirse a la realización de este Trabajo Final de Máster. Palabras clave: android, reverb, tiempo, app, cálculo. 1 SO: Sistema Operativo. Desarrollo de un paquete de software para dispositivos móviles basados en Android 8 II. INTRODUCCIÓN TEÓRICA II.1. Tiempo de reverberación La acústica de salas es la rama de la acústica que estudia la interacción del sonido con los elementos estructurales. Desde hace miles de años existen pruebas acerca del conocimiento en el que la arquitectónica afecta a los fenómenos sonoros y cómo estos son percibidos por el ser humano. Pero no fue hasta casi finalizar el siglo XIX, cuando el físico Wallace Sabine (considerado el padre de la acústica moderna), dedujo que la calidad acústica de un recinto estaba íntimamente relacionada con la reverberación de éste. De hecho, incluso fue capaz de construir una ecuación para poder calcular el tiempo de reverberación teniendo en cuenta las dimensiones y la absorción de una sala. Con el paso de los años, se ha ido añadiendo mayor precisión en la obtención de este parámetro. Actualmente, uno de los métodos que se emplean para conseguir evaluar el RT es mediante la medición del tiempo de caída de una señal impulsiva. Básicamente, consiste en hacer una integración invertida en el tiempo de dicha señal elevada al cuadrado y extraer el tiempo que pasa desde que tenemos un determinado nivel de amplitud hasta otro (en esto se basa el algoritmo de la app de este trabajo). El tiempo de reverberación es un parámetro que permite evaluar la calidad acústica de una sala. Dependiendo de su valor se puede caracterizar un recinto. Fig. 1: Tiempo de reverberación. Se define como el tiempo que tarda en decaer la energía de una fuente sonora desde que deja de emitir hasta que se ha reducido en 60 dB. Existen otras maneras de medirlo, realizando una extrapolación: Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 9  EDT 2 : (Caída entre 0 y -10 dB) x 6 [s]  T20: (Caída entre -5 y -25 dB) x 3 [s]  T30: (Caída entre -5 y -35 dB) x 2 [s] Otro detalle a tener en cuenta es que conforme mayor sea la frecuencia, el RT 3 normalmente se ve reducido. II.1.1 Valores típicos Cada tipo de sala suele tener asociados un rango de valores característico. A continuación se citan algunos de ellos: Campo libre4 (exterior sin superficies reflectantes) 0.0 s Habitación con muebles 0.3 – 0.5 s Habitación vacía 0.6 – 0.8 s Recinto para palabra 0.5 – 0.9 s Ópera 1.3 – 1.7 s Sala de conciertos 2.1 – 2.4 s Catedral > 2 s Tabla 1: Valores típicos del tiempo de reverberación. 2 En la app se trabaja con un parámetro muy similar al EDT, ya que es entre -5 y -15 dB. 3 RT: Tiempo de Reverberación. 4 Caso ideal. Desarrollo de un paquete de software para dispositivos móviles basados en Android 16 VI.2. RTActivity Es la actividad principal. Desde esta clase se realizan todas las gestiones con el resto de componentes del programa. Esta clase está basada en la siguiente función implementada en MATLAB: function tiempo = reverbTotal(x) %---------------------------------------------------------------------- % "Calcula el tiempo de reverberación de una señal mono" % % tiempo = reverbTotal(x) % % x: Señal (array de doubles) % tiempo: Tiempo de reverberación %---------------------------------------------------------------------- %% INICIALIZACIONES PARA EL CODER: tiempo = 0; y = zeros(176384, 6); % Lo inicilizamos al múltiplo de 32 más cercano a 176400 hacia abajo %% fs, dBstart y dBend: fs = 44100; dBstart = -5; % ejemplo: -5 -15 -> EDT dBend = -15; aux = 0; % Inicializamos la variable auxiliar %% REDIMENSIONAMOS LA SEÑAL "x" PARA QUE QUEDE con un número de muestras múltiplo de 32: x = x(1:floor(length(x)/32)*32); % Simplemente se le quitan unas casillas del final %% HACEMOS LA INTEGRAL DE SCHROEDER: x = cumsum(x.^2); % Hacemos la suma acumulada (integral discreta) de la señal filtrada al cuadrado %% NORMALIZAMOS Y PASAMOS A LOGARÍTMICO: x = 10*log10(1-x/max(x)); %% POSICIONES FINAL E INICIAL (dB) PARA HACER EL CÁLCULO DEL RT: [~,posi_dBend] = min(abs(x-dBend)); % ~ es para que vaya mejor [~,posi_dBstart] = min(abs(x-dBstart)); tiempo = 60/(-dBend+dBstart)*(posi_dBend-posi_dBstart)/fs; % RT (Resultado final) return % para que vaya el ejecutable (si es que se hace uno) Esta función es una versión simplificada de lo que finalmente hace el programa, ya que no considera el cálculo de cada tiempo en función de la frecuencia, pero ha sido de mucha utilidad para extraer los algoritmos e implementarlos finalmente en Java. Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 17 La clase RTActivity está compuesta por multitud de campos y métodos. Los nombres de cada uno de ellos son descriptivos según su función. No obstante, en los anexos vienen adjuntos y explicados con detalle en el mismo programa. Se enumeran a continuación:  Campos. (Ver anexo XI.22)  Métodos: onCreate() (Ver anexo XI.3.1) rt() (Ver anexo XI.3.2) getNombreFile() (Ver anexo XI.3.3) setNombreFile() (Ver anexo XI.3.4) setNombreFileSinTiempo() (Ver anexo XI.3.5) getTempNombreFile() (Ver anexo XI.3.6) startRecording() (Ver anexo XI.3.7) escribirWavTempFile() (Ver anexo XI.3.8) stopRecording() (Ver anexo XI.3.9) borrarTempFile() (Ver anexo XI.3.10) borrarFile() (Ver anexo XI.3.11) escribirWavFile() (Ver anexo XI.3.12) escribirWavDesdeArrayDeBytes() (Ver anexo XI.3.13) escribirWavDesdeArrayDeDoubles() (Ver anexo XI.3.14) escribirHeadDeWavFile() (Ver anexo XI.3.15) construirArrayDeBytesDesdeWav() (Ver anexo XI.3.16) mostrarResultados() (Ver anexo XI.3.17) calcularRT() (Ver anexo XI.3.18) redimensionarArrayfromBytesToDoubles() (Ver anexo XI.3.19) normalizarArrayDeDoubles() (Ver anexo XI.3.20) enventanarArrayDeDoubles() (Ver anexo XI.3.21) getSetCoeficientes() (Ver anexo XI.3.22) exportarArrayDeDoublesAFicheroCSV() (Ver anexo XI.3.23) exportarArrayDeBytesAFicheroCSV() (Ver anexo XI.3.24) exportarArrayDeDoublesAFicheroCSVSinTiempo() (Ver anexo XI.3.25) exportarArrayDeBytesAFicheroCSVSinTiempo() (Ver anexo XI.3.26) fxReverb() (Ver anexo XI.3.27) filtroIIR() (Ver anexo XI.3.28) schroeder() (Ver anexo XI.3.29) normaLogaritmizar() (Ver anexo XI.3.30) posiciones() (Ver anexo XI.3.31) limpiarPrincipioYFinal() (Ver anexo XI.3.32) redondear() (Ver anexo XI.3.33) nDecimales() (Ver anexo XI.3.34) interpolar() (Ver anexo XI.3.35) hacerArrayDivisiblePor32() (Ver anexo XI.3.36) onCreateOptionsMenu() (Ver anexo XI.3.37) onOptionsItemSelected() (Ver anexo XI.3.38) Tabla 2: Métodos implementados en RTActivity. Desarrollo de un paquete de software para dispositivos móviles basados en Android 18 VI.3. AndroidManifest Es la parte donde indicamos la versión del programa, permisos que se necesitan, actividades existentes, etc. <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.appacoustic.rt" android:versionCode="1" android:versionName="1.0.0" > <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name=".RTActivity" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission> </manifest> En este caso se dan las siguientes características: 1. Es la primera versión. 2. La versión mínima de Android es la 2.2 (Froyo). 3. Existe una actividad (RTActivity). 4. No hay barra de título. 5. La pantalla no gira y está en vertical. 6. Se necesitan permisos de escritura en el almacenamiento externo (normalmente SD) y grabación de audio. VI.4. main Se trata de la pantalla principal del software. En esta primera versión, es la única existente, y desde ella se realiza toda la interactuación con el usuario. Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 19 VII. MANUAL DEL USUARIO AppAcoustiC RT 1.0 Aplicación para calcular el tiempo de reverberación en bandas de octava. VII.1. Instalación Copiar el archivo RT.apk a la memoria SD del terminal e instalar. VII.2. Funcionamiento VII.2.1 Arrancar la aplicación. Fig. 6: Botón de inicio de la aplicación. VII.2.2 Apretar START. Fig. 7: Pantalla de inicio. VII.2.3 Dar una palmada. Fig. 8: Palmada. Desarrollo de un paquete de software para dispositivos móviles basados en Android 20 VII.2.4 Apretar STOP. Fig. 9: Pantalla para acabar de realizar la medición. VII.2.5 Darle a “Sí” si la medida ha sido correcta. Fig. 10: Validación de la medida. Para conseguir unos resultados óptimos, es más que recomendable tratar de situar el dispositivo lejos de superficies reflectantes y pegar la palmada a mayor distancia del radio crítico, para que el sonido reverberado sea mayor que el directo. Si el tiempo de medida ha sido demasiado corto, aparecerá un mensaje en la pantalla indicándolo. La app está disponible en español e inglés. Se dispondrá automáticamente en un idioma u otro según la configuración que tengamos en el sistema operativo. Para salir de la aplicación pulsar la tecla de menú y apretar Salir. Fig. 11: Pantalla de salida. Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 21 VIII. CONCLUSIONES Y LÍNEAS FUTURAS El hecho de realizar una aplicación para este sistema operativo, era con el afán de conocimiento y poder aplicarlo a un entorno laboral. Es un campo en el que actualmente hay una demanda de profesionales creciente ya que se necesitan programadores que dominen los lenguajes y las herramientas para llevar a cabo este tipo de aplicaciones. Dependiendo de la calidad del micrófono y/o infraestructura de audio en recepción del dispositivo, se tendrán unos resultados más o menos fidedignos. En el caso del modelo Sony Ericsson Xperia Neo, con el cual se han realizado las primeras pruebas, únicamente se obtienen resultados fiables a partir de 1 kHz. Sería interesante probar micrófonos de precisión periféricos. En breve, esta aplicación estará disponible en el Google Play. Como línea futura, se destaca que éste es el primer proyecto de una familia de aplicaciones para móviles en el ámbito acústico. IX. AGRADECIMIENTOS A mi buen amigo, gran persona y excelentísimo profesor, Javier Redondo. A Jordi Bataller, por sus inestimables consejos sobre programación. A Miguel Ferrer, por la confianza depositada hacia mi persona. A mis grandes compañeros de piso, Juanri y Andrés. A mis queridos compañeros del Máster. A todo el equipo M&M Publicidad. Y especialmente, a tod@s y cada un@ de los buen@s amig@s que he hecho a lo largo de todos estos años en Gandía. Desarrollo de un paquete de software para dispositivos móviles basados en Android 22 X. REFERENCIAS [1] Ableson, F., Collins, C., & Sen, R. (2011). Android: guía para desarrolladores. Madrid: Anaya Multimedia. [2] AENOR. (Abril de 2001). Medición del tiempo de reverberación de recintos con referencia a otros parámetros acústicos. Madrid. [3] AENOR. (Diciembre de 2008). Medición de parámetros acústicos en recintos. Tiempo de reverberación en recintos ordinarios. Madrid. [4] AENOR. (Septiembre de 2009). Medición de parámetros acústicos en recintos. Tiempo de reverberación en recintos ordinarios. Madrid. [5] AENOR. (Febrero de 2010). Medición de parámetros acústicos en recintos. Salas de espectáculos. Madrid. [6] Brinkmann, P. (2012). Making musical apps. Sebastopol: O'reilly. [7] Garrido, A. (1997). Principios de acústica. Madrid: Sanz y Torres. [8] Hughes, J. (2011 ). Marketing de aplicaciones Android. Madrid: Anaya Multimedia. [9] Kinsler, L. E. (1995). Fundamentos de Acústica. México: Limusa. [10] Lee, W. (2012). Android 4. Desarrollo de aplicaciones. Madrid: Anaya Multimedia. [11] Llinares Galiana, J., Llopis Reina, A., & Sancho, J. (1996). Acústica arquitectónica y urbanística. Valencia: SPUPV. [12] Mednicks, Z., Dornin, L., Blake Meike, G., & Nakamura, M. (2011). Programming Android. Beijing: O'Reilly. [13] Pueo Ortega, B., & Romá Romero, M. (2003). Electroacústica: Altavoces y micrófonos. Madrid: Pearson Prentice Hall. [14] Recuero López, M. (1994). Ingeniería Acústica. Madrid: Paraninfo. [15] Recuero López, M., & Gil, C. (1992). Acústica Arquitectónica. Madrid: Ártica. [16] Stackoverflow. (s.f.). Recuperado el 2012, de http://stackoverflow.com/ [17] Stark, J. (2010). Building android apps with HTML, CSS, and JavaScript. Farnham: O'Reilly. [18] Tomás Gironés, J. (2011 ). El gran libro de Android. Barcelona: Marcombo. [19] Zechner, M. (2011 ). Desarrollo de juegos para Android. Madrid: Anaya Multimedia. Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 23 XI. ANEXOS XI.1. Butterworth_2 Sólo se ha incluido la clase Butterworth_2, ya que las otras dos son muy similares. package com.appacoustic.butterworth; public class Butterworth_2 { /* * N=2. Vectores de coeficientes de 2*2+1 = 5 elementos * * Se usan tantos decimales en los coeficientes de Buttherworth porque podríamos enfrentarnos con NaN (Not a Number) * si pusieramos pocos, ya que la falta de resolución puede ocasionar problemas tipo división por cero * * En versiones posteriores del paquete hay que: * - Aprovechar la simetría de los coeficientes del numerador (B) para ahorrar memoria * - Implementar la obtención de coeficientes */ public int orden = 2; public Double B_125[]; public Double A_125[]; public Double B_250[]; public Double A_250[]; public Double B_500[]; public Double A_500[]; public Double B_1000[]; public Double A_1000[]; public Double B_2000[]; public Double A_2000[]; public Double B_4000[]; public Double A_4000[]; // getters public Double[] getB_125() { return B_125; } public Double[] getA_125() { return A_125; } public Double[] getB_250() { return B_250; } public Double[] getA_250() { return A_250; } public Double[] getB_500() { return B_500; } public Double[] getA_500() { return A_500; } public Double[] getB_1000() { return B_1000; } public Double[] getA_1000() { return A_1000; } public Double[] getB_2000() { return B_2000; } public Double[] getA_2000() { return A_2000; } public Double[] getB_4000() { return B_4000; } public Double[] getA_4000() { Desarrollo de un paquete de software para dispositivos móviles basados en Android 24 return A_4000; } // setters public void setB_125() { B_125 = new Double[orden*2+1]; B_125[0]=3.929676515700289e-05; B_125[1]=(double) 0; B_125[2]=-7.859353031400579e-05; B_125[3]=(double) 0; B_125[4]=3.929676515700289e-05; } public void setA_125() { A_125 = new Double[orden*2+1]; A_125[0]=(double) 1; A_125[1]=-3.981559459679419e+00; A_125[2]=5.945472787148730e+00; A_125[3]=-3.946261397152608e+00; A_125[4]=9.823481693904715e-01; } public void setB_250() { B_250 = new Double[orden*2+1]; B_250[0]=1.558059149882655e-04; B_250[1]=(double) 0; B_250[2]=-3.116118299765310e-04; B_250[3]=(double) 0; B_250[4]=1.558059149882655e-04; } public void setA_250() { A_250 = new Double[orden*2+1]; A_250[0]=(double) 1; A_250[1]=-3.961870007021670e+00; A_250[2]=5.888793913787786e+00; A_250[3]=-3.891930251948569e+00; A_250[4]=9.650079262290459e-01; } public void setB_500() { B_500 = new Double[orden*2+1]; B_500[0]=6.124167588371880e-04; B_500[1]=(double) 0; B_500[2]=-1.224833517674376e-03; B_500[3]=(double) 0; B_500[4]=6.124167588371880e-04; } public void setA_500() { A_500 = new Double[orden*2+1]; A_500[0]=(double) 1; A_500[1]=-3.918823751633717e+00; A_500[2]=5.769261524124245e+00; A_500[3]=-3.781653237866402e+00; A_500[4]=9.312403077020502e-01; } public void setB_1000() { B_1000 = new Double[orden*2+1]; B_1000[0]=2.366944651196807e-03; B_1000[1]=(double) 0; B_1000[2]=-4.733889302393613e-03; B_1000[3]=(double) 0; B_1000[4]=2.366944651196807e-03; } Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 25 public void setA_1000() { A_1000 = new Double[orden*2+1]; A_1000[0]=(double) 1; A_1000[1]=-3.818619281298950e+00; A_1000[2]=5.507523751882116e+00; A_1000[3]=-3.555730199154567e+00; A_1000[4]=8.672088097654537e-01; } public void setB_2000() { B_2000 = new Double[orden*2+1]; B_2000[0]=8.861384842871868e-03; B_2000[1]=(double) 0; B_2000[2]=-1.772276968574374e-02; B_2000[3]=(double) 0; B_2000[4]=8.861384842871868e-03; } public void setA_2000() { A_2000 = new Double[orden*2+1]; A_2000[0]=(double) 1; A_2000[1]=-3.566233905008885e+00; A_2000[2]=4.910270117609992e+00; A_2000[3]=-3.090416995530277e+00; A_2000[4]=7.520594824636435e-01; } public void setB_4000() { B_4000 = new Double[orden*2+1]; B_4000[0]=3.135695184246452e-02; B_4000[1]=(double) 0; B_4000[2]=-6.271390368492903e-02; B_4000[3]=(double) 0; B_4000[4]=3.135695184246452e-02; } public void setA_4000() { A_4000 = new Double[orden*2+1]; A_4000[0]=(double) 1; A_4000[1]=-2.889193822757614e+00; A_4000[2]=3.560473220464110e+00; A_4000[3]=-2.159920874581686e+00; A_4000[4]=5.658008519099556e-01; } } // () Butterworth_2 (Volver al apartado VI.1) Desarrollo de un paquete de software para dispositivos móviles basados en Android 32 XI.3.10 borrarTempFile() public void borrarTempFile(){ // Método para borrar el fichero temporal File file = new File(getTempNombreFile()); file.delete(); } // borrarTempFile() (Volver a la Tabla 2) XI.3.11 borrarFile() public void borrarFile(){ // Método para borrar el fichero de audio guardado en la SD File file = new File(nombreFileGlobal); file.delete(); } // borrarFile() (Volver a la Tabla 2) XI.3.12 escribirWavFile() public void escribirWavFile(String inFileNombre,String outFileNombre){ // Método para copiar el fichero de audio // Le damos la entrada (archivo temporal) y la salida (archivo en el directorio bueno) FileInputStream in = null; // Inicializamos el flujo de datos de entrada FileOutputStream out = null; // Inicializamos el flujo de datos de salida long longSampleRate = RECORDER_SAMPLERATE; // frecuencia de muestreo int channels = 1; // El número de canales es 1 al ser una señal mono long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8; // Tasa de bits byte[] data = new byte[bufferSize]; // Buffer para poder copiar el audio en formato byte try { in = new FileInputStream(inFileNombre); // entrada out = new FileOutputStream(outFileNombre); // salida totalAudioLen = in.getChannel().size(); // Longitud del archivo de audio (duración). Cargamos el tamaño del archivo para poder usarlo después en construirArrayDeBytesDesdeWav() long totalDataLen = totalAudioLen + 36; // El archivo de datos tiene 36 "casillas" más //Toast.makeText(getApplicationContext(), "Tamaño del archivo capturado: " + totalDataLen/1024 + " KB", Toast.LENGTH_SHORT).show(); // Mostramos el tamaño // Escribimos el encabezamiento del fichero escribirHeadDeWavFile(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate); while(in.read(data) != -1){ out.write(data); in.close(); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // escribirWavFile() (Volver a la Tabla 2) Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 33 XI.3.13 escribirWavDesdeArrayDeBytes() public void escribirWavDesdeArrayDeBytes(byte[] array, String outFileNombre){ // Método para copiar el audio desde el array de bytes FileOutputStream out = null; // Inicializamos el flujo de datos de salida (wav) long longSampleRate = RECORDER_SAMPLERATE; // frecuencia de muestreo int channels = 1; // El número de canales es 1 al ser una señal mono long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8; // Tasa de bits try { out = new FileOutputStream(outFileNombre); // salida long totalDataLen = totalAudioLen + 36; // Lo saco de antes, ya que es global //Toast.makeText(getApplicationContext(), "Tamaño del archivo escrito a partir del array de bytes: " + totalDataLen/1024 + " KB", Toast.LENGTH_SHORT).show(); // Mostramos el tamaño // Escribimos el encabezamiento del fichero escribirHeadDeWavFile(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate); out.write(array); // Escribimos el fichero de audio con el array de bytes out.close(); // cerramos el flujo } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // escribirWavDesdeArrayDeBytes() (Volver a la Tabla 2) Desarrollo de un paquete de software para dispositivos móviles basados en Android 34 XI.3.14 escribirWavDesdeArrayDeDoubles() public void escribirWavDesdeArrayDeDoubles(double[] array, String outFileNombre){ // Método para copiar el audio desde el array de doubles FileOutputStream out = null; // Inicializamos el flujo de datos de salida (wav) long totalAudioLen = 0; // Longitud del archivo de audio (duración) long totalDataLen = totalAudioLen + 36; // El archivo de datos tiene 36 "casillas" más long longSampleRate = RECORDER_SAMPLERATE; // frecuencia de muestreo int channels = 1; // El número de canales es 1 al ser una señal mono long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8; // Tasa de bits try { out = new FileOutputStream(outFileNombre); // salida totalAudioLen = array.length; // Lo calculamos de un modo alternativo (sigue siendo el tamaño a fin de cuentas) totalDataLen = array.length+36; //Toast.makeText(getApplicationContext(), "Tamaño del archivo escrito a partir del array de doubles: " + totalDataLen/1024 + " KB", Toast.LENGTH_SHORT).show(); // Mostramos el tamaño // Escribimos el encabezamiento del fichero escribirHeadDeWavFile(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate); // Convertimos a bytes, ya que el flujo de salida no admite doubles int n; byte array_convertido_en_bytes[] = new byte[array.length]; for (n=0;n<array.length;n=n+1){ array_convertido_en_bytes[n] = (byte) array[n]; } out.write(array_convertido_en_bytes); // Escribimos el fichero de audio con el array de doubles(sin buffer ni nada) out.close(); // cerramos el flujo } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // escribirWavDesdeArrayDeDoubles() (Volver a la Tabla 2) Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 35 XI.3.15 escribirHeadDeWavFile() public void escribirHeadDeWavFile(FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate, int channels, long byteRate) throws IOException{ // Método para escribir el encabezamiento del fichero byte[] header = new byte[44]; header[0] = 'R'; // Encabezamiento RIFF/WAVE header[1] = 'I'; header[2] = 'F'; header[3] = 'F'; header[4] = (byte) (totalDataLen & 0xff); header[5] = (byte) ((totalDataLen >> 8) & 0xff); header[6] = (byte) ((totalDataLen >> 16) & 0xff); header[7] = (byte) ((totalDataLen >> 24) & 0xff); header[8] = 'W'; header[9] = 'A'; header[10] = 'V'; header[11] = 'E'; header[12] = 'f'; // 'fmt ' Trozo header[13] = 'm'; header[14] = 't'; header[15] = ' '; header[16] = 16; // 4 bytes: tamaño del trozo 'fmt ' header[17] = 0; header[18] = 0; header[19] = 0; header[20] = 1; // formato = 1 header[21] = 0; header[22] = (byte) channels; header[23] = 0; header[24] = (byte) (longSampleRate & 0xff); header[25] = (byte) ((longSampleRate >> 8) & 0xff); header[26] = (byte) ((longSampleRate >> 16) & 0xff); header[27] = (byte) ((longSampleRate >> 24) & 0xff); header[28] = (byte) (byteRate & 0xff); header[29] = (byte) ((byteRate >> 8) & 0xff); header[30] = (byte) ((byteRate >> 16) & 0xff); header[31] = (byte) ((byteRate >> 24) & 0xff); header[32] = (byte) (2 * 16 / 8); // Bloqueamos la alineación header[33] = 0; header[34] = RECORDER_BPP; // bits por muestra header[35] = 0; header[36] = 'd'; header[37] = 'a'; header[38] = 't'; header[39] = 'a'; header[40] = (byte) (totalAudioLen & 0xff); header[41] = (byte) ((totalAudioLen >> 8) & 0xff); header[42] = (byte) ((totalAudioLen >> 16) & 0xff); header[43] = (byte) ((totalAudioLen >> 24) & 0xff); out.write(header, 0, 44); } // escribirHeadDeWavFile (Volver a la Tabla 2) Desarrollo de un paquete de software para dispositivos móviles basados en Android 36 XI.3.16 construirArrayDeBytesDesdeWav() public void construirArrayDeBytesDesdeWav(String inFileNombre){ // Método para copiar el array desde el audio FileInputStream in = null; // Flujo de datos de entrada (el archivo de audio) ByteArrayOutputStream out = null; // Flujo de datos de salida (para guardar el array) byte[] data = new byte[bufferSize]; // Buffer para el array try{ in = new FileInputStream(inFileNombre); // Instanciamos el flujo de salida del array out = new ByteArrayOutputStream(); // Instanciamos el flujo de salida del array while(in.read(data) != -1){ out.write(data); // Escribimos en el ByteArrayOutputStream } // Una vez hecho todo el flujo... x_byte = new byte[out.size()]; x_byte = out.toByteArray(); in.close(); out.close(); }catch (Exception e) { } } // construirArrayDeBytesDesdeWav() (Volver a la Tabla 2) XI.3.17 mostrarResultados() public void mostrarResultados(){ // Nos hace la interfaz más amena AlertDialog.Builder dialogo = new AlertDialog.Builder(this); dialogo.setTitle(R.string.tiempo_de_reverberacion); dialogo.setMessage(R.string.quieres_calcular); dialogo.setPositiveButton(R.string.si, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { //Toast.makeText(getApplicationContext(), R.string.calculando, Toast.LENGTH_LONG).show(); dialog.cancel(); calcularRT(); // Lo hacemos después de que haya grabado la señal de audio al pulsar el diálogo de alerta. } }); dialogo.setNegativeButton(R.string.no, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); dialogo.create(); dialogo.show(); } // mostrarResultados() (Volver a la Tabla 2) Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 37 XI.3.18 calcularRT() public void calcularRT(){ // Calculamos el tiempo de reverberación (es una especie de "main") borrarFile(); // Lo primero que hacemos es borrar el fichero, ya que ya lo hemos cargado en un array y no queremos llenar la memoria de la SD con archivos improductivos x_byte=limpiarPrincipioYFinal(x_byte, 0.25); // Limpiamos el principio y la cola de la señal double[] x = new double[x_byte.length/2]; // El tamaño es la mitad, ya que se ocupará la mitad de casillas al redimensionarlo x=redimensionarArrayfromBytesToDoubles(x_byte); x=interpolar(x); // Ahora queda con el formato de MATLAB (sin normalizar) //exportarArrayDeDoublesAFicheroCSVSinTiempo(x, "x"); x=enventanarArrayDeDoubles(x, 300, 100); // Para cargarnos la parte no útil de la grabación //exportarArrayDeDoublesAFicheroCSVSinTiempo(x, "x_enventanado"); x=hacerArrayDivisiblePor32(x); // Para agilizar cálculos //exportarArrayDeDoublesAFicheroCSVSinTiempo(x, "x_divisible"); x=normalizarArrayDeDoubles(x); // Para gastar menos memoria //exportarArrayDeDoublesAFicheroCSVSinTiempo(x, "x_normalizado"); getSetCoeficientes(); // Sacamos los coeficientes de las clases Butterworth y los metemos en esta double[] y_125 = new double[x.length]; // La salida tendrá 6 arrays de doubles (uno por cada octava) double[] y_250 = new double[x.length]; double[] y_500 = new double[x.length]; double[] y_1000 = new double[x.length]; double[] y_2000 = new double[x.length]; double[] y_4000 = new double[x.length]; y_125=filtroIIR(x, 125); // Filtramos la señal en bandas de octava y_250=filtroIIR(x, 250); y_500=filtroIIR(x, 500); y_1000=filtroIIR(x, 1000); y_2000=filtroIIR(x, 2000); y_4000=filtroIIR(x, 4000); //exportarArrayDeDoublesAFicheroCSVSinTiempo(y_1000, "y_1000"); //exportarArrayDeDoublesAFicheroCSVSinTiempo(y_2000, "y_2000"); y_125=schroeder(y_125); // Hacemos la integral de Schroeder y_250=schroeder(y_250); y_500=schroeder(y_500); y_1000=schroeder(y_1000); y_2000=schroeder(y_2000); y_4000=schroeder(y_4000); y_125=normaLogaritmizar(y_125); // Normalizamos y pasamos a dB y_250=normaLogaritmizar(y_250); y_500=normaLogaritmizar(y_500); y_1000=normaLogaritmizar(y_1000); y_2000=normaLogaritmizar(y_2000); y_4000=normaLogaritmizar(y_4000); posicion_dBStart_125 = posiciones(y_125, dBStart); posicion_dBEnd_125 = posiciones(y_125, dBEnd); posicion_dBStart_250 = posiciones(y_250, dBStart); posicion_dBEnd_250 = posiciones(y_250, dBEnd); posicion_dBStart_500 = posiciones(y_500, dBStart); posicion_dBEnd_500 = posiciones(y_500, dBEnd); posicion_dBStart_1000 = posiciones(y_1000, dBStart); posicion_dBEnd_1000 = posiciones(y_1000, dBEnd); posicion_dBStart_2000 = posiciones(y_2000, dBStart); posicion_dBEnd_2000 = posiciones(y_2000, dBEnd); posicion_dBStart_4000 = posiciones(y_4000, dBStart); posicion_dBEnd_4000 = posiciones(y_4000, dBEnd); reverbTime_125 = (60/(-(double) dBEnd+(double) dBStart)*((double) posicion_dBEnd_125-(double) posicion_dBStart_125)/(double) RECORDER_SAMPLERATE); // Cálculo del RT reverbTime_250 = (60/(-(double) dBEnd+(double) dBStart)*((double) posicion_dBEnd_250-(double) posicion_dBStart_250)/(double) RECORDER_SAMPLERATE); Desarrollo de un paquete de software para dispositivos móviles basados en Android 38 reverbTime_500 = (60/(-(double) dBEnd+(double) dBStart)*((double) posicion_dBEnd_500-(double) posicion_dBStart_500)/(double) RECORDER_SAMPLERATE); reverbTime_1000 = (60/(-(double) dBEnd+(double) dBStart)*((double) posicion_dBEnd_1000-(double) posicion_dBStart_1000)/(double) RECORDER_SAMPLERATE); reverbTime_2000 = (60/(-(double) dBEnd+(double) dBStart)*((double) posicion_dBEnd_2000-(double) posicion_dBStart_2000)/(double) RECORDER_SAMPLERATE); reverbTime_4000 = (60/(-(double) dBEnd+(double) dBStart)*((double) posicion_dBEnd_4000-(double) posicion_dBStart_4000)/(double) RECORDER_SAMPLERATE); // Metemos el valor de los tiempos de reverberación en los TextView textView_t_125.setText(Double.toString(nDecimales(reverbTime_125, 2))); textView_t_250.setText(Double.toString(nDecimales(reverbTime_250, 2))); textView_t_500.setText(Double.toString(nDecimales(reverbTime_500, 2))); textView_t_1000.setText(Double.toString(nDecimales(reverbTime_1000, 2))); textView_t_2000.setText(Double.toString(nDecimales(reverbTime_2000, 2))); textView_t_4000.setText(Double.toString(nDecimales(reverbTime_4000, 2))); } // calcularRT() (Volver a la Tabla 2) XI.3.19 redimensionarArrayfromBytesToDoubles() public double[] redimensionarArrayfromBytesToDoubles(byte[] entrada){ // Al tener 16 bits (2 bytes) y el formato "byte" sólo cojer 8 casillas, hay que ir de 2 en 2 // Conseguimos el doble de información que la que obtendríamos haciendo un "wavread" en MATLAB // De hecho, si comparamos los ficheros "csv", el wavread de MATLAB es una interpolación de lo obtenido aquí con un factor de 2:1 double[] salida = new double[entrada.length/2]; int i=0; for(int n=0;n<entrada.length;n=n+2){ salida[i] = (entrada[n]&0xFF) | (entrada[n+1]<<8); i=i+1; } return salida; } // redimensionarArrayfromBytesToDoubles() (Volver a la Tabla 2) XI.3.20 normalizarArrayDeDoubles() public double[] normalizarArrayDeDoubles(double[] entrada){ // Deja en el rango [-1,1] el array de doubles double[] salida = new double[entrada.length]; for(int n=0;n<entrada.length;n=n+1){ salida[n]=entrada[n]/Math.pow(2, 15); } return salida; } // normalizarArrayDeDoubles() (Volver a la Tabla 2) Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 39 XI.3.21 enventanarArrayDeDoubles() public static double[] enventanarArrayDeDoubles(double[] entrada, int ruido_fondo_principio, int ruido_fondo_final){ // Quita todos lo que sobra por delante y por detrás enventando la información útil de la señal int inicio=0, fin=0; // Tengo que inicializarlos por el bucle for(int n=0;n<entrada.length;n=n+1){ // Ceros por la izquierda if(entrada[n]>ruido_fondo_principio){ inicio=n; break; // salimos del bucle } } for(int n=entrada.length-1;n>0;n=n-1){ // Ceros por la derecha if(entrada[n]>ruido_fondo_final){ fin=n; break; // salimos del bucle } } int duracion=fin-inicio+1; int i=0; double[] salida = new double[duracion]; for (int n=inicio;n<=fin;n=n+1){ salida[i] = entrada[n]; i++; } return salida; } //enventanarArrayDeDoubles() (Volver a la Tabla 2) Desarrollo de un paquete de software para dispositivos móviles basados en Android 40 XI.3.22 getSetCoeficientes() public void getSetCoeficientes(){ // Carga los coeficientes de los filtros // Los coeficientes del filtro de Butterworth los calculamos con MATLAB // Nos valemos de las clases Butterworth, donde están almacenados todos los coeficientes que nos interesan // De este modo el código, aparte de ser más sencillo, será mucho más rápido Butterworth_2 miButterworth_125 = new Butterworth_2(); Butterworth_4 miButterworth_250 = new Butterworth_4(); Butterworth_4 miButterworth_500 = new Butterworth_4(); Butterworth_4 miButterworth_1000 = new Butterworth_4(); // De 1 kHz hacia abajo, de orden 8 se hace inestable (polos fuera de la circunferencia unidad) Butterworth_8 miButterworth_2000 = new Butterworth_8(); Butterworth_8 miButterworth_4000 = new Butterworth_8(); // Rellenamos los campos de miButterworth miButterworth_125.setB_125(); miButterworth_125.setA_125(); miButterworth_250.setB_250(); miButterworth_250.setA_250(); miButterworth_500.setB_500(); miButterworth_500.setA_500(); miButterworth_1000.setB_1000(); miButterworth_1000.setA_1000(); miButterworth_2000.setB_2000(); miButterworth_2000.setA_2000(); miButterworth_4000.setB_4000(); miButterworth_4000.setA_4000(); // Extraemos el contenido de los campos y lo copiamos a los arrays de esta clase B_125 = miButterworth_125.getB_125(); A_125 = miButterworth_125.getA_125(); B_250 = miButterworth_250.getB_250(); A_250 = miButterworth_250.getA_250(); B_500 = miButterworth_500.getB_500(); A_500 = miButterworth_500.getA_500(); B_1000 = miButterworth_1000.getB_1000(); A_1000 = miButterworth_1000.getA_1000(); B_2000 = miButterworth_2000.getB_2000(); A_2000 = miButterworth_2000.getA_2000(); B_4000 = miButterworth_4000.getB_4000(); A_4000 = miButterworth_4000.getA_4000(); // Establecemos el el tamaño de los arays de coeficientes tam_125 = miButterworth_125.orden*2+1; tam_250 = miButterworth_250.orden*2+1; tam_500 = miButterworth_500.orden*2+1; tam_1000 = miButterworth_1000.orden*2+1; tam_2000 = miButterworth_2000.orden*2+1; tam_4000 = miButterworth_4000.orden*2+1; } // getSetCoeficientes() (Volver a la Tabla 2) Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 41 XI.3.23 exportarArrayDeDoublesAFicheroCSV() public static void exportarArrayDeDoublesAFicheroCSV(double[] entrada, String nombreFile){ // Escribimos un array de doubles en un fichero CSV (añade milisegundos desde 1970) // De este modo podemos ver fácilmente lo que vale cada casilla en MATLAB o EXCEL String filepath = Environment.getExternalStorageDirectory().getPath(); // Obtenemos la ruta donde se alojará el fichero de audio File file = new File(filepath, CSV_FOLDER); if(!file.exists()){ file.mkdirs(); // Si no existe el directorio, lo creamos } File outFile = new File(file.getAbsolutePath()+"/"+System.currentTimeMillis()+nombreFile+".csv"); BufferedWriter buffer = null; try { buffer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile))); } catch (FileNotFoundException e) { e.printStackTrace(); } for (int n=0;n<entrada.length;n++){ try { buffer.write(""+entrada[n]+"\n"); } catch (IOException e) { e.printStackTrace(); } try { buffer.flush(); } catch (IOException e) { e.printStackTrace(); } } try { buffer.close(); } catch (IOException e) { e.printStackTrace(); } } // exportarArrayDeDoublesAFicheroCSV() (Volver a la Tabla 2) Desarrollo de un paquete de software para dispositivos móviles basados en Android 48 XI.3.30 normaLogaritmizar() public double[] normaLogaritmizar(double[] entrada){ // Normalizamos y pasamos a dB double[] salida = new double[entrada.length]; double max; int i; max=entrada[0]; for(i=0;i<entrada.length-1;i=i+1){ if(entrada[i+1]>max){ max=entrada[i+1]; } } for(i=0;i<entrada.length;i=i+1){ salida[i]=10*Math.log10(1-entrada[i]/max); } return salida; } // normaLogaritmizar() (Volver a la Tabla 2) XI.3.31 posiciones() public int posiciones(double[] entrada, int dB_Start_End){ // Averiguamos las posiciones inicial y final para hacer el cálculo del RT double aux[] = new double[entrada.length]; int i,j,pos; double lugar; for(i=0;i<entrada.length;i=i+1){ aux[i]=Math.abs(entrada[i]-dB_Start_End); } lugar=aux[0]; i=-1; for(j=0;j<aux.length-1;j=j+1){ if(aux[j+1]<lugar){ lugar=aux[j+1]; i=j; } } pos = i+2; return pos; } // posiciones() (Volver a la Tabla 2) XI.3.32 limpiarPrincipioYFinal() public byte[] limpiarPrincipioYFinal(byte[] entrada, double segundos){ // Anulamos lo que nos molesta por delante y por detrás int n; double casillas = segundos*RECORDER_SAMPLERATE*2; int casillas_int=redondear(casillas); for(n=0;n<casillas_int;n=n+1){ entrada[n]=0; } for(n=(int) (entrada.length-casillas_int);n<entrada.length;n=n+1){ entrada[n]=0; } return entrada; } // limpiarPrincipioYFinal() (Volver a la Tabla 2) Desarrollo de un paquete de software acústico para dispositivos móviles basados en Android 49 XI.3.33 redondear() public static int redondear(double sinRedondear){ // Redondeo de double a entero int entero; entero = (int) Math.round(sinRedondear); return entero; } // redondear() (Volver a la Tabla 2) XI.3.34 nDecimales() public static double nDecimales(double sinRedondear, int cuantosDecimales){ // Para mostrar un determinado número de decimales BigDecimal bd = new BigDecimal(sinRedondear); BigDecimal redondeado = bd.setScale(cuantosDecimales, BigDecimal.ROUND_HALF_UP); return redondeado.doubleValue(); } // nDecimales() (Volver a la Tabla 2) XI.3.35 interpolar() public static double[] interpolar(double[] entrada){ // Interpolación 2:1 // Este método es para dejar el array igual que hace MATLAB y poder depurar el programa double[] salida = new double[entrada.length/2]; int i=0; for(int n=0;n<entrada.length;n=n+2){ salida[i]=entrada[n]; i=i+1; } return salida; } // interpolar() (Volver a la Tabla 2) XI.3.36 hacerArrayDivisiblePor32() public static double[] hacerArrayDivisiblePor32(double[] entrada){ // Redimensionamos la señal de entrada para que quede con un número de muestras múltiplo de 32 // Hay que hacer un "floor" para redondear hacia abajo. int nuevoTamArray = (int) (Math.floor((double)(entrada.length/32))*32); double[] salida = new double[nuevoTamArray]; for(int n=0;n<salida.length;n++){ salida[n] = entrada[n]; } return salida; } // hacerArrayDivisiblePor32() (Volver a la Tabla 2) Desarrollo de un paquete de software para dispositivos móviles basados en Android 50 XI.3.37 onCreateOptionsMenu() @Override public boolean onCreateOptionsMenu(android.view.Menu menu){ // Mostramos el menu al apretar el botón físico del dispositivo MenuInflater miMenuInflater=getMenuInflater(); miMenuInflater.inflate(R.menu.menu, menu); return true; } // onCreateOptionsMenu() (Volver a la Tabla 2) XI.3.38 onOptionsItemSelected() @Override public boolean onOptionsItemSelected(MenuItem item){ // Las 2 opciones del menú switch (item.getItemId()) { case R.id.item1: Toast miToast=Toast.makeText(getApplicationContext(),"AppAcoustiC RT 1.0.0\n\nGabriel Moreno Ibarra\n\n2012-09-04",Toast.LENGTH_LONG); miToast.setGravity(Gravity.CENTER, 0, 0); miToast.show(); break; case R.id.item2: finish(); } return true; } // onOptionsItemSelected() (Volver a la Tabla 2)