Calculate decibels

后端 未结 3 409
轮回少年
轮回少年 2020-12-07 19:34

I\'m recording mic input using the XNA library (I don\'t think this is really technology specific, but it never hurts). Every time I get a sample I would like to calculate

相关标签:
3条回答
  • 2020-12-07 19:54

    I appreciate Han's post, and wrote a routine that can calculate decibels on 8 and 16 bit audio formats, with multiple channels using his example.

    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;
            }
        }
    
    0 讨论(0)
  • 2020-12-07 19:59

    When measuring the level of a sound signal, you should calculate the dB from the RMS value. In your sample you are looking at the absolute peak level. A single (peak) sample value determines your dB value, even when all other samples are exactly 0.

    try this:

    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);
    

    For 'instantaneous' dB levels you would normally calculate the RMS over a segment of 20-50 ms. Note that the calculated dB value is relative to full-scale. For sound the dB value should be related to 20 uPa, and you will need to calibrate your signal to find the proper conversion from digital values to pressure values.

    0 讨论(0)
  • 2020-12-07 20:04

    I think Yann means that Decibels are a relative scale. If you're trying to measure the actual Sound Pressure Level or SPL, you would need to calibrate. What you're measuring is dBFS (decibels full-scale, I think). You're measuring how many decibels quieter the signal is than the loudest possible signal the system can represent (the "full-scale" signal, or 32768 for these 16-bit samples). That's why all the values are negative.

    0 讨论(0)
提交回复
热议问题