views:

1751

answers:

4

I am looking to do three things:

Access data from the microphone. Really all I want to know is the overall volume of the sound sensed by the device.

Set the microphone gain.

Set the system volume.

All of my windows dev experience is C#/WPF, so I'd like to stay managed. I do not need exceptionally high performance or realtime processing or anything.

I've looked around and it seems like SlimDX might be a good wrapper for this, but even there I'm not sure where to start.

Surely it can't be that hard?

+2  A: 

Here's a link that shows how to access the audio mixer in Windows from C#:

http://www.codeguru.com/csharp/csharp/cs_graphics/sound/article.php/c10931

This will let you set the microphone gain and the system volume. The first part is a little more complicated, though. Basically, you need to start recording the input (using DirectSound or the waveInXXXX API [my personal favorite]). As each buffer gets filled with audio, you can calculate the Root Mean Square for the buffer and use this to estimate volume.

Edit: here's a link to a project (that I've used and modified successfully, so I know it works) that shows how to record audio using the waveInXXXX API:

http://www.codeproject.com/KB/audio-video/cswavrec.aspx?df=90&fid=16677&mpp=25&noise=3&sort=Position&view=Quick&select=3005817

Edit 2: and since I'm tired of posting links, here's an actual formula for calculating the Root Mean Square of an audio buffer (the type here is float[], but it can be easily modified to handle short[], which is what you'd normally get from waveInXXXX):

public static float RootMeanSquared(ref float[] audio)
{
    double sumOfSquared = 0;
    for (int i = 0; i < audio.Length; i++)
    {
        sumOfSquared += audio[i] * audio[i];
    }
    return (float)Math.Sqrt(sumOfSquared / (double)audio.Length);
}
MusiGenesis
Thanks for the informative answer. However that sample crashes as soon as I hit the "start" button.
Josh Santangelo
Which one? The first or the second?
MusiGenesis
Why is the float array parameter ref ? shouldn't the value be enough ?
Andreas Grech
btw, +1 for the formula
Andreas Grech
@Dreas: I write a lot of functions that take float[] arrays as parameters. Usually the functions just modify the existing array, but sometimes they either modify the existing or create a new and larger array, depending on what I'm doing (reverb is one example of this). I have to pass the input by ref in order to do this, so it's just become a habit. You're right, this function would work fine without the ref keyword.
MusiGenesis
...C much ? hehe
Andreas Grech
+4  A: 

Unfortunately you can't reliably read (or render) data from managed code unless you're willing to live with serious latency (on the order of .5 second). The problem is that the CLR can interrupt your process for 250 milliseconds at a time without warning. Normally this doesn't matter, but when you're trying to do isochronous processing it can be a significant issue.

Larry Osterman
I wrote a C# app that P/Invoked waveIn* and rendered a spectrograph in (what I thought was) realtime. It didn't appear to have any latency problems of this magnitude. Was I just lucky not to run into this problem?
MusiGenesis
You may not have run out of memory or triggered a GC cycle. It also depends on which OS you're running on. On Vista, the wave APIs have about 100ms latency which makes them more resiliant to glitches. On XP and Win7 they run with about 30ms of latency which is more likely to suffer glitches.
Larry Osterman
I'm running Vista. Thanks, this is good stuff to know. My software synth doesn't do realtime, but I was considering writing a version that does. This kind of latency would make that nearly impossible (I'm assuming the latencies apply to waveOut* as well?), given that my sound-generation process is already relatively expensive.
MusiGenesis
I think because you're using P/Invoke and not managed libraries, it's not as much of an issue... unless I'm mistaken in which case, someone please correct me.
Computer Guru
+1  A: 

You can use NAudio to capture audio from the microphone in managed C#. Have a look at the demo projects for examples of how to do this. As Larry points out above, don't expect great latency though. NAudio also has managed wrappers for the mixer APIs which should let you set the microphone volume, although it can be tricky to get hold of the correct control programmatically.

Mark Heath
+1  A: 

Hi,

I've just wrote a (very basic) sample code on how to capture sound from the microphone using SlimDX. I hope it helps if you're still looking for an answer.