c#中的实时麦克风幅度测量

我正在寻找简单的解决方案,它将在c#中返回麦克风输入的整数值。 我已经在网上检查可用的样本,但它们都没有在x64环境中工作。 (VS2008 + W7 x64)。

是否有任何简单的解决方案可以返回c#中麦克风输入的幅度(或频率)值?

我试过没有结果的NAudio,这个: http : //www.codeproject.com/KB/audio-video/cswavrec.aspx? msg=2155497没有运气。

我认为最简单的方法是使用旧的Windows多媒体API,因为它非常简单。

这是MSDN的链接: http : //msdn.microsoft.com/en-us/library/dd743586( v = VS.85).aspx

你所做的就是使用waveInOpen函数来获取输入设备。 要确定要使用的设备,请不要枚举所有设备,但可以查询每个设备。 通过调用waveInGetNumDevs返回已安装设备的数量。 然后,您可以为每个设备调用waveInGetDevCaps并检查这些属性。

当您有设备处理时,然后重复调用waveInAddBuffer以获取小块数据。 根据您在waveInOpen期间指定的格式,字节表示原始音频数据。 在某个频率下以8位或16位有符号或无方向采样的幅度。

然后,您可以应用滚动平均值来平滑信号并打印出来。

C#没有我所知道的声音API,所以你要做的是使用P / Invoke来获取Win32 API函数。 这是相当简单的,您只需要移植Win32标头的小版本就可以直接从C#调用它们。

如果你是更硬核,你可以用C ++ / CLI编写一个包装器库。 这并不是一个想法,因为它让你使用现有的Windows C / C ++头文件,并以有趣的方式混合C ++和托管代码。 只需要小心非托管资源,您就可以立即拥有一个非常强大的intropability库。

但是还有更先进的音频API,从Windows Vista开始,Windows Core Audio组件可能会更加有趣。 但是对于基本的I / O操作,Windows多媒体function可以让您更快地到达目的地。

在构建简单的软件合成器时,我已经在很多场合使用过这些函数。 可悲的是,代码早已不复存在。

我推荐SlimDX,因为它应该适用于几乎任何版本的Windows(x86或x64),并提供最多的function和灵活性。 但是,由于没有完整的代码示例,因此启动和运行是一件痛苦的事。 我写了一个包装类来简化它的用法,所以它可以这样调用(我在Win7 x64上测试了这段代码):

  public void CaptureAudio() { using (var source = new SoundCardSource()) { source.SampleRateKHz = 44.1; source.SampleDataReady += this.OnSampleDataReady; source.Start(); // Capture 5 seconds of audio... Thread.Sleep(5000); source.Stop(); } } private void OnSampleDataReady(object sender, SampleDataEventArgs e) { // Do something with e.Data short array on separate thread... } 

以下是SlimDX包装类的源代码:

 using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using SlimDX.DirectSound; using SlimDX.Multimedia; public class SampleDataEventArgs : EventArgs { public SampleDataEventArgs(short[] data) { this.Data = data; } public short[] Data { get; private set; } } public class SoundCardSource : IDisposable { private volatile bool running; private int bufferSize; private CaptureBuffer buffer; private CaptureBufferDescription bufferDescription; private DirectSoundCapture captureDevice; private WaveFormat waveFormat; private Thread captureThread; private List notifications; private int bufferPortionCount; private int bufferPortionSize; private WaitHandle[] waitHandles; private double sampleRate; public SoundCardSource() { this.waveFormat = new WaveFormat(); this.SampleRateKHz = 44.1; this.bufferSize = 2048; } public event EventHandler SampleDataReady = delegate { }; public double SampleRateKHz { get { return this.sampleRate; } set { this.sampleRate = value; if (this.running) { this.Restart(); } } } public void Start() { if (this.running) { throw new InvalidOperationException(); } if (this.captureDevice == null) { this.captureDevice = new DirectSoundCapture(); } this.waveFormat.FormatTag = WaveFormatTag.Pcm; // Change to WaveFormatTag.IeeeFloat for float this.waveFormat.BitsPerSample = 16; // Set this to 32 for float this.waveFormat.BlockAlignment = (short)(waveFormat.BitsPerSample / 8); this.waveFormat.Channels = 1; this.waveFormat.SamplesPerSecond = (int)(this.SampleRateKHz * 1000D); this.waveFormat.AverageBytesPerSecond = this.waveFormat.SamplesPerSecond * this.waveFormat.BlockAlignment * this.waveFormat.Channels; this.bufferPortionCount = 2; this.bufferDescription.BufferBytes = this.bufferSize * sizeof(short) * bufferPortionCount; this.bufferDescription.Format = this.waveFormat; this.bufferDescription.WaveMapped = false; this.buffer = new CaptureBuffer(this.captureDevice, this.bufferDescription); this.bufferPortionSize = this.buffer.SizeInBytes / this.bufferPortionCount; this.notifications = new List(); for (int i = 0; i < this.bufferPortionCount; i++) { NotificationPosition notification = new NotificationPosition(); notification.Offset = this.bufferPortionCount - 1 + (bufferPortionSize * i); notification.Event = new AutoResetEvent(false); this.notifications.Add(notification); } this.buffer.SetNotificationPositions(this.notifications.ToArray()); this.waitHandles = new WaitHandle[this.notifications.Count]; for (int i = 0; i < this.notifications.Count; i++) { this.waitHandles[i] = this.notifications[i].Event; } this.captureThread = new Thread(new ThreadStart(this.CaptureThread)); this.captureThread.IsBackground = true; this.running = true; this.captureThread.Start(); } public void Stop() { this.running = false; if (this.captureThread != null) { this.captureThread.Join(); this.captureThread = null; } if (this.buffer != null) { this.buffer.Dispose(); this.buffer = null; } if (this.notifications != null) { for (int i = 0; i < this.notifications.Count; i++) { this.notifications[i].Event.Close(); } this.notifications.Clear(); this.notifications = null; } } public void Restart() { this.Stop(); this.Start(); } private void CaptureThread() { int bufferPortionSamples = this.bufferPortionSize / sizeof(float); // Buffer type must match this.waveFormat.FormatTag and this.waveFormat.BitsPerSample short[] bufferPortion = new short[bufferPortionSamples]; int bufferPortionIndex; this.buffer.Start(true); while (this.running) { bufferPortionIndex = WaitHandle.WaitAny(this.waitHandles); this.buffer.Read( bufferPortion, 0, bufferPortionSamples, bufferPortionSize * Math.Abs((bufferPortionIndex - 1) % bufferPortionCount)); this.SampleDataReady(this, new SampleDataEventArgs(bufferPortion)); } this.buffer.Stop(); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { this.Stop(); if (this.captureDevice != null) { this.captureDevice.Dispose(); this.captureDevice = null; } } } } 

它是完全multithreading的,可以最大限度地减少延迟。 我最初是为实时信号处理分析工具编写的,并使用浮点输出而不是简短但我修改了代码示例以匹配您请求的用法。 如果您需要频率数据,我会使用http://www.mathdotnet.com/Neodym.aspx或http://www.exocortex.org/dsp/获得一个好的C#FFT库。