suhdonghwi
suhdonghwi

Reputation: 1035

How can I get current microphone input level with C WinAPI?

Using Windows API, I want to implement something like following:

mic test example

i.e. Getting current microphone input level.

I am not allowed to use external audio libraries, but I can use Windows libraries. So I tried using waveIn functions, but I do not know how to process audio input data in real time.

This is the method I am currently using:

  1. Record for 100 milliseconds
  2. Select highest value from the recorded data buffer
  3. Repeat forever

But I think this is way too hacky, and not a recommended way. How can I do this properly?

Upvotes: 1

Views: 2896

Answers (2)

M'hand BOUGHIAS
M'hand BOUGHIAS

Reputation: 750

Instead of computing the values yourself, you can rely on values from Windows. This is actually the values displayed in your screenshot from the Windows Settings.

See the following sample for the IAudioMeterInformation interface:
https://learn.microsoft.com/en-us/windows/win32/coreaudio/peak-meters.
It is made for the playback but you can use it for capture also.

Some remarks, if you open the IAudioMeterInformation for a microphone but no application opened a stream from this microphone, then the level will be 0.
It means that while you want to display your microphone peak meter, you will need to open a microphone stream, like you already did.
Also read the documentation about IAudioMeterInformation it may not be what you need as it is the peak value. It depends on what you want to do with it.

Upvotes: 0

selbie
selbie

Reputation: 104589

Having built a tuning wizard for a very dated, but well known, A/V conferencing applicaiton, what you describe is nearly identical to what I did.

A few considerations:

Enqueue 5 to 10 of those 100ms buffers into the audio device via waveInAddBuffer. IIRC, when the waveIn queue goes empty, weird things happen. Then as the waveInProc callbacks occurs, search for the sample with the highest absolute value in the completed buffer as you describe. Then plot that onto your visualization. Requeue the completed buffers.

It might seem obvious to map the sample value as follows onto your visualization linearly.

For example, to plot a 16-bit sample

// convert sample magnitude from 0..32768 to 0..N
length = (sample * N) / 32768;
DrawLine(length);

But then when you speak into the microphone, that visualization won't seem as "active" or "vibrant".

But a better approach would be to give more strength to those lower energy samples. Easy way to do this is to replot along the μ-law curve (or use a table lookup).

length =  (sample * N) / 32768;
length = log(1+length)/log(N);
length = max(length,N)
DrawLine(length);

You can tweak the above approach to whatever looks good.

Upvotes: 1

Related Questions