これにもう少し取り組みました。キャリブレーション済みの 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 値を評価します。現時点では 90 dB(SPL)/0.6325 Pa であり、これは妥当な推測にすぎません。おそらくそれよりわずかに高いでしょう。
また情報が入り次第、更新します。