30

Android MediaRecorder 有一个功能

.getMaxAmplitude();
正如API告诉我的那样,“返回自上次调用此方法以来采样的最大绝对幅度。” 但我找不到这是什么幅度?是帕斯卡还是瓦特?

我在网上的几个页面上发现,您可以使用(如此处建议的)计算与分贝密切相关的值。

double db = (20 * Math.log10(amplitude / REFERENCE)); 

这会让我假设返回的值是某种线性比例(可能类似于 milipascal ......)

REFERENCE=0.1(我知道这应该类似于 2*10^(-5) Pascal ((20 uPascal)),但它返回奇怪的值...... 0.1 奇怪地工作得更好。)

现在我测量 MaxAmplitude() 使用

获取最大振幅()
并将其放入可变幅值中。

这是方法:

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;
    }
}

这是在半秒内完成 5 次,这是平均的

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);

我得到的东西看起来有点像分贝,但我根本不确定它的实际分贝......

那么,有人可以帮我解决这个问题吗?API根本没有指定返回的内容似乎很奇怪......

4

2 回答 2

24

我可以找到这个问题的答案,我会在这里分享给关心的人:该MediaRecorder.getMaxAmplitude()函数返回无符号的 16 位整数值 (0-32767)。这可能只是范围从 -32768 到 32767 的 CD 质量样本值的 abs()。这意味着它们可能代表麦克风构建的 0-100% 最大电压范围的电输出的 16 位数字化进那部手机。由于即使在一个品牌的手机中,这些麦克风的精确范围有时也会有所不同,即使是类似的手机,在与相同声源的距离相同的情况下也不一定会返回相同的值。

然而,这个值与帕斯卡中的声压相关,因为它也是声压的线性量化,在可以用给定麦克风测量声音的区域(由于手机的限制,它不会覆盖整个频谱)。

于 2012-10-17T10:28:41.260 回答
23

在这方面又做了一些工作。使用经过校准的 SPL 计和具有不同纯频率、白噪声和粉红噪声的智能手机进行的一些测试,我现在知道手机麦克风不适用于任何应在 90 到 100 dB(SPL)以上的地方注册的任何东西,具体取决于手机.

假设 90 dB(SPL) 是最大值,可以计算出这将对应于麦克风处 0.6325 Pa 的压力。现在假设 p0=0.0002 Pa 是参考最小值,并假设这将在 getMaxAmplitude() 中注册为 0(实际上永远不会发生),我们可以将 getMaxAmplitude() 函数的值与麦克风的最大压力相关联。这意味着来自 getMaxAmplitude() 的 16375 的结果将对应于 0.3165 Pa 的最大压力。这当然不是很科学,因为最大值和最小值纯属猜想,但它为我们提供了一个起点。我们现在可以计算 p

p=getMaxAmplitude()/51805.5336

知道麦克风的压力后,我们可以使用众所周知的公式计算 dB(SPL) 值

X = 20 log_10 (p/p0)

这仍然会给出一个很高的值,因为在计算中只使用了最大幅度。要解决这个问题,一定不要使用 getMaxAmplitude() ,虽然这稍微超出了这个问题的重点,但无论如何我都会把代码放进去,希望它会有所帮助

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;
}
}

这些值现在来自 4 秒样本中所有幅度的平均值,因此更准确。之后完成上述计算。这将给出更现实的分贝值。请注意,手机麦克风仍然很糟糕,并且该算法不会产生实际的 dB(SPL),而只会产生比之前更好的近似值。

要获得某些应用程序的性能,还需要做更多工作。这些应用程序中的大多数都使用滑动窗口,这意味着持续录制并滑动 x 秒的窗口以持续评估声音级别。此外,我将进行一些评估,什么 db Value 最适合用作最大值,现在它是 90 dB(SPL)/0.6325 Pa,这只是一个合理的猜测,它可能会略高于该值。

一旦我有更多我会更新信息。

于 2013-02-14T08:16:28.793 回答