2010-12-27 16 views
10

私はC#でマイク入力の整数値を返す簡単な解決策を探しています。私はすでにネット上で利用可能なサンプルをチェックしていましたが、x64環境では動作しませんでした。 (VS2008 + W7 x64)。ライブマイクの振幅測定C#

C#でマイク入力の振幅(または周波数)の値を返す簡単な解決法はありますか?

私はNAudioを結果なしで試しましたが、これは:http://www.codeproject.com/KB/audio-video/cswavrec.aspx?msg=2155497運がありません。

+0

DirectX DirectSoundを試しましたか? – JYelton

+0

プログラムを「Any CPU」から「32 bit only」に設定しようとしましたか?ほとんどのプログラムは、64ビットモードで実行されることによる利益はあまりありません。 – CodesInChaos

+0

私はそれをもう一度試みましたが、これまで運がありませんでした。単純なdirectSoundの例も見つかりませんでした。私はSlimDXも試しましたが、そのような例すべてには常に問題があるように見えます。私の場合のほかに、動的更新(1秒間に何回かサンプリングされる)で整数値が必要です。誰もがそれにいくつかの経験がありますか?助けてくれてありがとう。 – Marian

答えて

2

私が考えている最も簡単なルートは、これまでの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++とマネージコードをintrestingの方法で混用するので、これはあまり意味がありません。管理されていないリソースには注意が必要です。すぐに非常に強力なイントロニーズライブラリが用意されています。

しかし、Windows Vistaで始まるより高度なオーディオAPIもあります.Windows Core Audioのコンポーネントは、さらに面白いかもしれません。しかし、基本的なI/O操作のために、Windowsのマルチメディア機能はあなたをより速くそこに連れて行きます。

私はシンプルなソフトウェアシンセサイザーを構築するときに、これらの機能をさまざまな機会に使用しました。悲しいことに、そのコードは長くなくなっています。

1

私はSlimDXをWindows(x86またはx64)のほぼすべてのバージョンで動作させる必要があり、多くの機能と柔軟性を提供するので、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<NotificationPosition> 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<SampleDataEventArgs> 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<NotificationPosition>(); 

     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; 
      } 
     } 
    } 
} 
:ここ
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ラッパークラスのソースです:私はそれは次のように呼び出すことができるようにかかわらず、その使用方法を簡素化するラッパークラスを書いた(私はWin7のx64の上でこのコードをテストしました)

待ち時間を最小限に抑えるため、完全にマルチスレッドです。私はもともとリアルタイム信号処理解析ツール用に書いたもので、短いものではなくfloat出力を使用しましたが、要求された用途に合わせてコードサンプルを修正しました。周波数データが​​必要な場合は、良いC#FFTライブラリにhttp://www.mathdotnet.com/Neodym.aspxまたはhttp://www.exocortex.org/dsp/を使用します。

関連する問題