outputformat - ¿Qué me da la función getMaxAmplitude() de Android para el MediaRecorder?
rec audio android (2)
El Android MediaRecorder tiene una función
.getMaxAmplitude(); que, como me dice la API , "devuelve la amplitud absoluta máxima que se muestreaba desde la última llamada a este método". ¿Pero no puedo encontrar qué amplitud es esta? ¿Está en pascal o vatios?
He encontrado en varias páginas de la web que puede calcular un valor estrechamente relacionado con decibeles utilizando (como se sugiere here ).
double db = (20 * Math.log10(amplitude / REFERENCE));
lo que me permite suponer que el valor devuelto está en una escala lineal (probablemente algo así como milipascal ...)
REFERENCIA = 0.1 (Soy consciente de que esto debería ser algo así como 2 * 10 ^ (- 5) Pascal ((20 uPascal)), pero que devuelve valores extraños ... 0.1 funciona de manera extraña mejor).
En este momento mido el MaxAmplitude () usando el
getMaxAmplitude() y poner esto en la amplitud variable.
Este es el método:
public double getNoiseLevel()
{
//Log.d("SPLService", "getNoiseLevel() ");
int x = mRecorder.getMaxAmplitude();
double x2 = x;
Log.d("SPLService", "x="+x);
double db = (20 * Math.log10(x2 / REFERENCE));
//Log.d("SPLService", "db="+db);
if(db>0)
{
return db;
}
else
{
return 0;
}
}
Esto se hace 5 veces en medio segundo, lo que obtiene un promedio de
for(int i=0; i<5; i++)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
return 0;
}
level = level+getNoiseLevel();
if(level>0)
{
counter++;
}
}
level=level/counter;
Log.d(LOG_TAG, "level="+level);
Obtengo algo que parece decibelio pero no estoy seguro de que sea realmente decibelio ...
Entonces, ¿podría alguien ayudarme en esto? Parece muy extraño que la API no especifique en absoluto lo que se devuelve ...
Podría encontrar la respuesta a esta pregunta y la compartiré aquí para cualquiera que se preocupe: La función MediaRecorder.getMaxAmplitude () devuelve valores enteros de 16 bits sin signo (0-32767). Lo que probablemente sea solo el abs () de los valores de muestra con calidad de CD que van desde -32768 a 32767. Esto significa que probablemente representan una digitalización de 16 bits de la salida eléctrica de 0-100% del rango de voltaje máximo de la estructura del micrófono en ese teléfono móvil. Dado que incluso en una marca de teléfonos móviles, estos micrófonos a veces varían en su rango preciso, ni siquiera a teléfonos similares necesariamente devolverán el mismo valor dada la misma distancia a la misma fuente de sonido.
Sin embargo, este valor se correlaciona con la presión de sonido en Pascal, ya que también es una cuantificación lineal de la presión de solund, en el área donde se puede medir el sonido con el micrófono dado (que no cubrirá todo el espectro debido a las limitaciones del teléfono).
Trabajé en esto un poco más. Utilizando algunas pruebas realizadas con medidores SPL calibrados y teléfonos inteligentes con diferentes frecuencias puras, ruido blanco y ruido rosa, ahora sé que los micrófonos de los teléfonos móviles no se pueden usar para nada que deba registrarse en cualquier lugar por encima de 90 a 100 dB (SPL), dependiendo del teléfono. .
Asumiendo que 90 dB (SPL) es el máximo, uno puede calcular que esto correspondería a una presión de 0.6325 Pa en el micrófono. Ahora, asumiendo que p0 = 0.0002 Pa es el mínimo de referencia y asumiendo que esto se registraría como 0 (lo que nunca sucedería realmente) desde getMaxAmplitude (), podemos alinear los valores de la función getMaxAmplitude () con presión máxima en el micrófono. Esto significa que un resultado de 16375 de getMaxAmplitude () correspondería a una presión máxima de 0.3165 Pa. Por supuesto, esto no es muy científico, ya que los valores máximo y mínimo son pura conjura, pero nos da un punto de partida. Ahora podemos calcular p con
p = getMaxAmplitude () / 51805.5336
Sabiendo la presión en el micrófono podemos calcular el valor de dB (SPL) con la fórmula conocida
X = 20 log_10 (p / p0)
Esto aún dará un valor que es alto ya que solo se utiliza la amplitud máxima en los cálculos. Para resolver esto, uno no debe usar getMaxAmplitude () y si bien esto está ligeramente fuera del foco de esta pregunta, pondré el código de cualquier modo con la esperanza de que ayude.
public class NoiseRecorder
{
private final String TAG = SoundOfTheCityConstants.TAG;
public static double REFERENCE = 0.00002;
public double getNoiseLevel() throws NoValidNoiseLevelException
{
Logging.e(TAG, "start new recording process");
int bufferSize = AudioRecord.getMinBufferSize(44100,AudioFormat.CHANNEL_IN_DEFAULT,AudioFormat.ENCODING_PCM_16BIT);
//making the buffer bigger....
bufferSize=bufferSize*4;
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
44100, AudioFormat.CHANNEL_IN_DEFAULT, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
short data [] = new short[bufferSize];
double average = 0.0;
recorder.startRecording();
//recording data;
recorder.read(data, 0, bufferSize);
recorder.stop();
Logging.e(TAG, "stop");
for (short s : data)
{
if(s>0)
{
average += Math.abs(s);
}
else
{
bufferSize--;
}
}
//x=max;
double x = average/bufferSize;
Logging.e(TAG, ""+x);
recorder.release();
Logging.d(TAG, "getNoiseLevel() ");
double db=0;
if (x==0){
NoValidNoiseLevelException e = new NoValidNoiseLevelException(x);
throw e;
}
// calculating the pascal pressure based on the idea that the max amplitude (between 0 and 32767) is
// relative to the pressure
double pressure = x/51805.5336; //the value 51805.5336 can be derived from asuming that x=32767=0.6325 Pa and x=1 = 0.00002 Pa (the reference value)
Logging.d(TAG, "x="+pressure +" Pa");
db = (20 * Math.log10(pressure/REFERENCE));
Logging.d(TAG, "db="+db);
if(db>0)
{
return db;
}
NoValidNoiseLevelException e = new NoValidNoiseLevelException(x);
throw e;
}
}
Estos valores ahora se derivan del promedio de todas las amplitudes en una muestra de 4 segundos y, por lo tanto, son más precisos. Después se realizan los cálculos descritos anteriormente. Esto le dará un valor de decibelios más realista. Tenga en cuenta que los micrófonos de los teléfonos móviles todavía son malos y que este algoritmo no producirá dB (SPL) real, sino una aproximación ligeramente mejor que la anterior.
Para obtener el rendimiento de algunas aplicaciones, es necesario hacer algo más. La mayoría de estas aplicaciones utilizan ventanas deslizantes, lo que significa mantener la grabación y deslizar una ventana de x segundos para evaluar continuamente el nivel de sonido. También realizaré una evaluación de qué valor de db es el más adecuado para ser utilizado como máximo, en este momento es de 90 dB (SPL) /0.6325 Pa, lo que es solo una estimación razonable, probablemente estará ligeramente por encima de eso.
En cuanto tenga más actualizaré la información.