计算分贝

我正在使用XNA库录制麦克风输入(我认为这不是特定技术,但它永远不会受到伤害)。 每次我得到一个样本,我想计算分贝。 我在互联网上做了很多搜索,没有发现坚如磐石的例子……

这是我尝试从样本计算分贝:

double peak = 0; for (var i = 0; i  peak) peak = sample; else if (sample < -peak) peak = -sample; } var decibel = (20 * Math.Log10(peak/32768)); 

如果我将分贝值输出到屏幕上,我可以看到值越高越响,因为我说话更柔和。 然而,当我绝对安静时,它总是在-40左右徘徊……我认为它会是-90。 我必须在上面的块中计算错误? 从我在某些网站上看到的内容-40相当于“软谈话”…但是,它完全安静。

另外,如果我将麦克风静音,它会直接转到-90。

我做错了吗?

测量声音信号的电平时,应根据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相关,您需要校准信号以找到从数字值到压力值的正确转换。

我很欣赏Han的post,并编写了一个例程,可以计算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; } } 

我认为Yann意味着Decibels是一个相对的尺度。 如果您正在尝试测量实际的声压级或SPL,则需要进行校准。 您测量的是dBFS(我认为是全尺寸分贝)。 您正在测量信号比信号系统可以表示的最大信号(“满量程”信号,或者这些16位采样的32768)更安静的分贝数。 这就是为什么所有的价值都是负面的。