- Home /
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?
Answer by Bunny83 · Apr 26, 2019 at 09:03 AM
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
Hello, Now I have encountered another problem.
Even if I average over 1000 samples, I still find the gain incorrect. I want to visualize the PC$$anonymous$$ wave, and I find the curve is not a nicely continuous one. It looks like the array _pcm is divided into sections, and the newest wave front is not appearing from the end of the array. Could you help me figuring out how PC$$anonymous$$ data stores and updates?
I have my full code attached. Need a Text component for the public infoText field.
Your answer
Follow this Question
Related Questions
Microphone in 3.5 beta 1 Answer
Is it possible to record using Microphone.start and have non-fixed Audio clip length? 1 Answer
Extract pointer from Audioclip's buffer 0 Answers
Microphone recording problems (double sample, audiosource stops working) 0 Answers
Save Mic input and have it load when game starts up again 0 Answers