I’m working on an application where I need to auto-calibrate the recording level volume based on a standard that I establish. To do this, I plan on recording a few seconds of audio on the Line In channel from a known standard, analyze the volume of the recorded sample, and adjust the Record Level based on the results & iterate until I zero in on the expected value.

I’m currently using the following code (modified from the Pitch measuring sample) to measure volume but I keep getting a repeatable, unexpected result of -109dB if I use SPECTRUMSIZE=64 or -67dB if I use SPECTRUMSIZE=8192. I’ve manually adjusted the Line In volume but it doesn’t seem to matter.

Here’s my code:
[quote:arlfh8ie]public class DetectVolume
public int OUTPUTRATE = 48000;
public int SPECTRUMSIZE = 8192; //64 is the minimum # of values you can have in a spectrum
private float SPECTRUMRANGE = 0;
private float BINSIZE = 0;
public float Peak = 0.0f;
public float Average = 0.0f;
public float RMS = 0.0f;

    public DetectVolume(FMOD.Channel channel)
        SPECTRUMRANGE    = ((float)OUTPUTRATE / 2.0f);     /* 0 to nyquist */
        BINSIZE          = (SPECTRUMRANGE / (float)SPECTRUMSIZE);
        // TODO: Add constructor logic here
    public void GetVolume(FMOD.Channel channel)
        if (channel != null)
            FMOD.RESULT result;
            float[] spectrum = new float[SPECTRUMSIZE];
            float   dominantHzMin = 0.0f;
            float   dominantHzMax = 0.0f;
            float   dominantHzAvg = 0.0f;
            float   max = 0.0f;
            int     count = 0;
            int     nonzeroCount = 0;
            int     bin = 0;
            float   sum = 0.0f;
            float   avg = 0.0f;

            result = channel.getSpectrum(spectrum, SPECTRUMSIZE, 0, FMOD.DSP_FFT_WINDOW.TRIANGLE);

            for (count = 0; count < SPECTRUMSIZE; count++)
                if (spectrum[count] > 0.0f)
                    sum += spectrum[count];
                    if (spectrum[count] > max)
                        max = spectrum[count];
                        bin = count;

            avg = sum / nonzeroCount;

            dominantHzMin  = (float)bin * BINSIZE;       /* dominant frequency min */
            dominantHzMax = dominantHzMin + (((float)bin + 0.99f) * BINSIZE);
            dominantHzAvg = (dominantHzMin + dominantHzMax)/2;

            Peak = 10.0f * (float)Math.Log10(max) * 2.0f;
            Average = 10.0f * (float)Math.Log10(avg) * 2.0f;

            throw new ApplicationException("FMOD channel is NULL");   

If there’s an easier way to measure the volume of a recorded sample, I’d love to simplify my life. :)

Thanks for the help!


  • You must to post comments

BTW, the "Volume Adjustment" attribute in the SOX audio utility does exactly what I need:

"The "Volume Adjustment:" field in the statistics gives you the argument to the -v number which will make the sample as loud as possible without clipping."

Volume Adjustment is a scaling factor by which you could boost a given sample without clipping. So if you get a very low VA, like 1.05, it means your sample is 5% away from clipping. A VA of 100 would mean the sample is virtually silent and could be scaled 100x before clipping.

I used this command line utility to great effect in the past and am trying to replicate this functionality with FMOD. So far, I’m getting bogged down with analyzing the full spectrum rather than an overall "hotness" of the signal. I feel like I’m approaching the problem incorrectly.

Thanks again,


  • You must to post comments

I found the problem that was causing the volume measurement to give the same result each time–my loop to call the volume measurement every 10ms for 1 second wasn’t updating the actual measurement so it was averaging the save value 100x. Turns out the first portion of my recordings are the same volume every time. :)

I’d still like to know if there’s a easier way to measure the "hotness" of a recorded signal.


  • You must to post comments
Showing 2 results
Your Answer

Please first to submit.