How to get current gain from microphone?

I have the following code to check the pcm data from my microphone:

private const int NUM_SAMPLES_TO_AVERAGE = 8;
private const int PCM_SAMPLE_RATE = 16000;
private float[] _pcm = new float[NUM_PCM_SAMPLES];
private float _gain = 0;
private AudioClip _audio;
public GameObject gainBar;

void Start()
{
    if (Microphone.devices.Length == 0) {
        Debug.LogError("No Microphone");
        return;
    }
    _deviceName = Microphone.devices[0];
    _audio = Microphone.Start(_deviceName, true, 1, PCM_SAMPLE_RATE);
}

void Update()
{
    var audioPosition = Microphone.GetPosition(_deviceName);
    _audio.GetData(_pcm, audioPosition);
    _gain = 0;
    for(int i = 0; i < NUM_SAMPLES_TO_AVERAGE; i++) {
        _gain += Mathf.Abs(_pcm[NUM_PCM_SAMPLES - i - 1]);
    }
    _gain /= NUM_SAMPLES_TO_AVERAGE;
    gainBar.transform.localScale = new Vector3(4, _gain, 1);
}

So I have my _pcm array every frame. But it’s not like what I expected. I want to visualize the gain of current time using _gainBar.transform.localScale, but its scale seems irrelevant to my loudness. Did I make a mistake?

First of all the average over 8 samples is really not enough. You have to average over way more samples. At a sample rate of 16k and a framerate of 60 fps you get about 266 samples in between two frames.

So you should probably average over the last 1000 samples. Also note that you probably have a lot of noise with rather low amplitude. You can try to shift the sensitivity up by simply squaring each sample before adding. The highest value of 1 will stay 1. However a sample of 0.5 will become 0.25 and a sample of .0.25 would become 0.0625. Of course the overall value would get smaller, but you should get more sensitivity the higher the amplitude. After the division you can take the square root of the value to get back the previous range which should be “more” linear.

Just for example a 440 Hz tone has 440 cycles in a second. At a sample rate of 16kHz it would take 36 samples to cover the whole cycle. Deeper frequencies require even more samples (half the frequency, double the samples). If you only take 8 samples they could be right between the relatively low up and down half cycle you get almost no output even though there are much louder parts . With about 1000 samples you would capture frequencies down to about 16Hz. Just a few PCM samples always just look like random noise since there’s no real structure in it.

ps: Note that you have an early exit in your Start method (which is fine). However if there’s no microphone and you return, your “_audio” and “_deviceName” variables aren’t initialized and would cause a null reference exception inside Update. You probably want to disable the script in Start when there’s no mic and maybe print a Debug.LogWarning to the console / log