¿Alguien puede explicar cómo este código convierte el volumen en decibeles usando el Acelerado Framework?

Estoy construyendo una aplicación de iOS usando EZAudio. Su delegado devuelve un buffer float** , que contiene valores flotantes que indican el volumen detectado. Este delegado es llamado constantemente y su trabajo se realiza en un hilo diferente.

Lo que trato de hacer es tomar el valor flotante de EZAudio y convertirlo en decibeles.


EZAudioDelegate

Aquí está mi delegado EZAudio simplificado para get datos de micrófono :

 - (void)microphone:(EZMicrophone *)microphone hasAudioReceived:(float **)buffer withBufferSize:(UInt32)bufferSize withNumberOfChannels:(UInt32)numberOfChannels { /* * Returns a float array called buffer that contains the stereo signal data * buffer[0] is the left audio channel * buffer[1] is the right audio channel */ // Using a separate audio thread to not block the main UI thread dispatch_async(dispatch_get_main_queue(), ^{ float decibels = [self getDecibelsFromVolume:buffer withBufferSize:bufferSize]; NSLog(@"Decibels: %f", decibels); }); } 

El problema

El problema es que después de implementar soluciones de los enlaces a continuación, no entiendo cómo funciona. Si alguien pudiera explicar cómo convierte el volumen a decibelios, estaría muy agradecido.

  • ¿Cómo convertir la input de audio a DB? # 85

  • ¿Cómo cambiar el tamaño del búfer para boost la window FFT? # 50

  • Cambio del tamaño de búfer # 84


El código

La solución utiliza los siguientes methods de Accelerate Framework para convertir el volumen en decibelios:

  • vDSP_vsq
  • vDSP_meanv
  • vDSP_vdbcon

A continuación se muestra el método getDecibelsFromVolume que se llama desde EZAudio Delegate. Se pasa el float** buffer y bufferSize del delegado.

 - (float)getDecibelsFromVolume:(float**)buffer withBufferSize:(UInt32)bufferSize { // Decibel Calculation. float one = 1.0; float meanVal = 0.0; float tiny = 0.1; float lastdbValue = 0.0; vDSP_vsq(buffer[0], 1, buffer[0], 1, bufferSize); vDSP_meanv(buffer[0], 1, &meanVal, bufferSize); vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0); // Exponential moving average to dB level to only get continous sounds. float currentdb = 1.0 - (fabs(meanVal) / 100); if (lastdbValue == INFINITY || lastdbValue == -INFINITY || isnan(lastdbValue)) { lastdbValue = 0.0; } float dbValue = ((1.0 - tiny) * lastdbValue) + tiny * currentdb; lastdbValue = dbValue; return dbValue; } 

Explicaré cómo se calcularía un valor de dB para una señal con código y luego se mostrará cómo se relaciona con el ejemplo de vDSP.

Primero, calcule la sum RMS de una porción de datos

 double sumSquanetworking = 0; for (int i = 0 ; i < numSamples ; i++) { sumSquanetworking += samples[i]*samples[i]; } double rms = sumSquanetworking/numSamples; 

Para más información sobre RMS

Luego convierte el valor RMS a dB

 double dBvalue = 20*log10(rms); 

¿Cómo se relaciona esto con el código de ejemplo?

 vDSP_vsq(buffer[0], 1, buffer[0], 1, bufferSize); 

Esta línea recorre el búfer y calcula los cuadrados de todos los elementos en el búfer. Si el buffer contenía los valores [1,2,3,4] antes de la llamada, luego de la llamada contendría los valores [1,4,9,16]

 vDSP_meanv(buffer[0], 1, &meanVal, bufferSize); 

Esta línea recorre el búfer, sumndo los valores en el búfer y luego devuelve la sum dividida por el número de elementos. Entonces, para el buffer de input [1,4,9,16] en computa la sum 30 , divide por 4 y devuelve el resultado 7.5 .

 vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0); 

Esta línea convierte el meanVal en decibelios. Realmente no tiene sentido llamar a una function vectorizada aquí, ya que solo funciona en un solo elemento. Sin embargo, lo que está haciendo es enchufar los parameters en la siguiente fórmula:

 meanVal = n*log10(meanVal/one) 

donde n es 10 o 20 dependiendo del último parámetro. En este caso, es 10 . 10 se usa para mediciones de potencia y 20 se usa para amplitudes. Creo que 20 tendría más sentido para su uso.

El último pequeño código parece estar haciendo un simple alisado del resultado para hacer que el medidor sea un poco less animoso.