计算分贝

时间:2010-11-11 07:29:27

标签: c# audio audio-recording

我正在使用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。

我做错了吗?

3 个答案:

答案 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)更安静的分贝数。这就是为什么所有的价值都是负面的。