读取 WAV 文件并计算 RMS
Reading in a WAV file and calculating RMS
所以我正在尝试测试一些分析某些 PCM 数据量的代码。我得到一些奇怪的体积测量结果,这些测量结果与我从 Audacity 获得的数据毫无意义。好像我的测量结果到处都是。
我不确定我的错误是在我读取 WAV 数据的方式上还是在我计算音量的方式上。
这里是我以字节形式读取数据并转换为短裤的地方,因为它是 PCM 16 位。
InputStream pcmStream = this.getClass().getClassLoader().getResourceAsStream("Test-16Bit-PCM.wav");
ArrayList<Byte> bytes = new ArrayList<>();
int b = pcmStream.read();
while(b != -1)
{
bytes.add((byte)b);
b = pcmStream.read();
}
// First 44 bytes of WAV file are file info, we already know PCM properties since we recorded test audio
byte [] bytesArray = new byte[bytes.size()-44];
for(int i = 44; i < bytes.size(); i++)
{
bytesArray[i-44] = bytes.get(i);
}
bytes = null;
pcmStream = null;
short [] pcm = new short[bytesArray.length/2];
ByteBuffer bb = ByteBuffer.wrap(bytesArray).asShortBuffer().get(pcm);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.asShortBuffer().get(pcm);
bytesArray = null;
然后 short []
直接传递到我的分析器,然后我将数据分成 0.1 秒的时间步长,并对每个时间步长的音量进行平均。
这是我计算 RMS 和 dB 的地方
double sumOfSamples = 0;
double numOfSamples = settings.shortsPerTimeStep();
for(int i = start; i < start+settings.shortsPerTimeStep(); i++)
{
sumOfSamples = originalPcm[i]*originalPcm[i];
}
double rms = Math.sqrt(sumOfSamples/numOfSamples);
// Convert to decibels
calculatedVolume = 20*Math.log10(rms/20);
我正在阅读的音频是在 44100 MONO 上录制的,并大胆地保存为 WAV 16 Signed PCM。不确定我做错了什么。
任何帮助将不胜感激!谢谢
编辑:发现我读错了 WAV 数据。我通过添加 end little endianess 来修复它。但是我仍然对如何计算体积感到困惑。这些值更好但仍然难以破译,我不确定我的 RMS 是什么单位以及参考值应该是什么单位。
您的计算有误 - sumOfSamples = originalPcm[i]*originalPcm[i];
应该在 sumOfSamples += originalPcm[i]*originalPcm[i];
之前,因此您将累加这些值。
至于参考值——为什么用20?通常您使用可能的最低值(在本例中为 1),或者您可以使用最大值(即 sqrt(32768)),并且您的所有值都将低于该值,因此您将得到负 dB 值.
所以我正在尝试测试一些分析某些 PCM 数据量的代码。我得到一些奇怪的体积测量结果,这些测量结果与我从 Audacity 获得的数据毫无意义。好像我的测量结果到处都是。
我不确定我的错误是在我读取 WAV 数据的方式上还是在我计算音量的方式上。
这里是我以字节形式读取数据并转换为短裤的地方,因为它是 PCM 16 位。
InputStream pcmStream = this.getClass().getClassLoader().getResourceAsStream("Test-16Bit-PCM.wav");
ArrayList<Byte> bytes = new ArrayList<>();
int b = pcmStream.read();
while(b != -1)
{
bytes.add((byte)b);
b = pcmStream.read();
}
// First 44 bytes of WAV file are file info, we already know PCM properties since we recorded test audio
byte [] bytesArray = new byte[bytes.size()-44];
for(int i = 44; i < bytes.size(); i++)
{
bytesArray[i-44] = bytes.get(i);
}
bytes = null;
pcmStream = null;
short [] pcm = new short[bytesArray.length/2];
ByteBuffer bb = ByteBuffer.wrap(bytesArray).asShortBuffer().get(pcm);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.asShortBuffer().get(pcm);
bytesArray = null;
然后 short []
直接传递到我的分析器,然后我将数据分成 0.1 秒的时间步长,并对每个时间步长的音量进行平均。
这是我计算 RMS 和 dB 的地方
double sumOfSamples = 0;
double numOfSamples = settings.shortsPerTimeStep();
for(int i = start; i < start+settings.shortsPerTimeStep(); i++)
{
sumOfSamples = originalPcm[i]*originalPcm[i];
}
double rms = Math.sqrt(sumOfSamples/numOfSamples);
// Convert to decibels
calculatedVolume = 20*Math.log10(rms/20);
我正在阅读的音频是在 44100 MONO 上录制的,并大胆地保存为 WAV 16 Signed PCM。不确定我做错了什么。
任何帮助将不胜感激!谢谢
编辑:发现我读错了 WAV 数据。我通过添加 end little endianess 来修复它。但是我仍然对如何计算体积感到困惑。这些值更好但仍然难以破译,我不确定我的 RMS 是什么单位以及参考值应该是什么单位。
您的计算有误 - sumOfSamples = originalPcm[i]*originalPcm[i];
应该在 sumOfSamples += originalPcm[i]*originalPcm[i];
之前,因此您将累加这些值。
至于参考值——为什么用20?通常您使用可能的最低值(在本例中为 1),或者您可以使用最大值(即 sqrt(32768)),并且您的所有值都将低于该值,因此您将得到负 dB 值.