我正在使用XNA库录制麦克风输入(我认为这不是特定技术,但它永远不会受到伤害)。每次我得到一个样本,我想计算分贝。我在互联网上做了很多搜索,没有发现坚如磐石的例子......
这是我尝试从样本计算分贝:
double peak = 0;
for (var i = 0; i < _buffer.Length; i = i + 2)
{
var sample = BitConverter.ToInt16(_buffer, i);
if (sample > peak)
peak = sample;
else if (sample < -peak)
peak = -sample;
}
var decibel = (20 * Math.Log10(peak/32768));
如果我将分贝值输出到屏幕,我可以看到值越高越响,因为我说话更柔和。然而,当我绝对安静时,它总是在-40左右徘徊......我认为它会是-90。我必须在上面的块中计算错误?从我在某些网站上看到的内容-40相当于“软谈话”...然而,它完全是安静的。
另外,如果我将麦克风静音,它会直接转到-90。
我做错了吗?
答案 0 :(得分:31)
测量声音信号的电平时,应根据RMS值计算dB。在您的样本中,您正在查看绝对峰值水平。即使所有其他样本都恰好为0,单个(峰值)样本值也会确定您的dB值。
试试这个:
double sum = 0;
for (var i = 0; i < _buffer.length; i = i + 2)
{
double sample = BitConverter.ToInt16(_buffer, i) / 32768.0;
sum += (sample * sample);
}
double rms = Math.Sqrt(sum / (_buffer.length / 2));
var decibel = 20 * Math.Log10(rms);
对于“瞬时”dB水平,您通常会计算20-50 ms的RMS。 请注意,计算的dB值是相对于满量程的。对于声音,dB值应与20 uPa相关,您需要校准信号以找到从数字值到压力值的正确转换。
答案 1 :(得分:5)
我很欣赏Han的帖子,并编写了一个例程,可以计算8位和16位音频格式的分贝,其中有多个频道使用他的例子。
public double MeasureDecibels(byte[] samples, int length, int bitsPerSample,
int numChannels, params int[] channelsToMeasure)
{
if (samples == null || length == 0 || samples.Length == 0)
{
throw new ArgumentException("Missing samples to measure.");
}
//check bits are 8 or 16.
if (bitsPerSample != 8 && bitsPerSample != 16)
{
throw new ArgumentException("Only 8 and 16 bit samples allowed.");
}
//check channels are valid
if (channelsToMeasure == null || channelsToMeasure.Length == 0)
{
throw new ArgumentException("Must have target channels.");
}
//check each channel is in proper range.
foreach (int channel in channelsToMeasure)
{
if (channel < 0 || channel >= numChannels)
{
throw new ArgumentException("Invalid channel requested.");
}
}
//ensure we have only full blocks. A half a block isn't considered valid.
int sampleSizeInBytes = bitsPerSample / 8;
int blockSizeInBytes = sampleSizeInBytes * numChannels;
if (length % blockSizeInBytes != 0)
{
throw new ArgumentException("Non-integral number of bytes passed for given audio format.");
}
double sum = 0;
for (var i = 0; i < length; i = i + blockSizeInBytes)
{
double sumOfChannels = 0;
for (int j = 0; j < channelsToMeasure.Length; j++)
{
int channelOffset = channelsToMeasure[j] * sampleSizeInBytes;
int channelIndex = i + channelOffset;
if (bitsPerSample == 8)
{
sumOfChannels = (127 - samples[channelIndex]) / byte.MaxValue;
}
else
{
double sampleValue = BitConverter.ToInt16(samples, channelIndex);
sumOfChannels += (sampleValue / short.MaxValue);
}
}
double averageOfChannels = sumOfChannels / channelsToMeasure.Length;
sum += (averageOfChannels * averageOfChannels);
}
int numberSamples = length / blockSizeInBytes;
double rootMeanSquared = Math.Sqrt(sum / numberSamples);
if (rootMeanSquared == 0)
{
return 0;
}
else
{
double logvalue = Math.Log10(rootMeanSquared);
double decibel = 20 * logvalue;
return decibel;
}
}
答案 2 :(得分:3)
我认为Yann意味着Decibels是相对规模。如果您正在尝试测量实际的声压级或SPL,则需要进行校准。你测量的是dBFS(我认为是全尺寸分贝)。您正在测量信号比信号系统可以表示的最大信号(“满量程”信号,或者这些16位采样的32768)更安静的分贝数。这就是为什么所有的价值都是负面的。