2010-12-27 68 views
10

Tôi đang tìm giải pháp đơn giản sẽ trả về giá trị nguyên của đầu vào micrô trong C#. Tôi đã kiểm tra các mẫu có sẵn trên mạng, nhưng không có mẫu nào trong số đó hoạt động trong môi trường x64. (VS2008 + W7 x64).Micrô đo biên độ trực tiếp trong C#

Có giải pháp đơn giản nào sẽ trả về giá trị của biên độ (hoặc tần số) đầu vào micrô trong C# không?

Tôi đã thử NAudio không có kết quả và điều này: http://www.codeproject.com/KB/audio-video/cswavrec.aspx?msg=2155497 mà không có may mắn.

+0

Bạn đã thử DirectX DirectSound chưa? – JYelton

+0

Bạn đã thử cài đặt chương trình của mình từ "CPU bất kỳ" thành "chỉ 32 bit" chưa? Hầu hết các chương trình không lợi nhuận nhiều từ việc chạy ở chế độ 64 bit. – CodesInChaos

+0

Tôi đã thử điều đó rồi, nhưng không có may mắn cho đến nay. Đã không tìm thấy bất kỳ ví dụ directSound đơn giản nào. Tôi cũng đã thử SlimDX, nhưng có vẻ như, luôn có một số rắc rối với tất cả các ví dụ đó. Bên cạnh đó trong trường hợp của tôi, tôi cần giá trị số nguyên với cập nhật động (lấy mẫu vài lần mỗi giây). Bất cứ ai cũng có một số kinh nghiệm với điều đó? Cảm ơn vì bất kì sự giúp đỡ. – Marian

Trả lời

2

Tôi cho rằng tuyến đường dễ nhất để đi là sử dụng API đa phương tiện Windows cũ vì nó thực sự thẳng về phía trước.

Đây là liên kết để MSDN: http://msdn.microsoft.com/en-us/library/dd743586(v=VS.85).aspx

Những gì bạn làm là bạn nên sử dụng waveInOpen chức năng để có được một thiết bị đầu vào. Để tìm ra thiết bị nào để sử dụng, bạn không liệt kê tất cả các thiết bị nhưng bạn có thể truy vấn từng thiết bị. Số lượng thiết bị đã cài đặt được trả về bằng cách gọi waveInGetNumDevs. Sau đó, bạn có thể gọi waveInGetDevCaps cho từng thiết bị và kiểm tra các thuộc tính đó.

Khi bạn để thiết bị của mình xử lý, bạn hãy liên tục gọi waveInAddBuffer để nhận các khối dữ liệu nhỏ. Tùy thuộc vào định dạng bạn đã chỉ định trong waveInOpen các byte đại diện cho dữ liệu âm thanh thô. Biên độ trong 8 hoặc 16 bit được ký hoặc không được lấy mẫu ở một số tần số.

Sau đó, bạn có thể áp dụng giá trị trung bình lăn để làm mịn tín hiệu và chỉ in ra.

C# không có API âm thanh mà tôi biết, vì vậy những gì bạn làm là bạn sử dụng P/Gọi để nhận các chức năng API Win32. Điều này là khá thẳng về phía trước, bạn chỉ cần cổng các phiên bản nhỏ của các tiêu đề Win32 để có thể gọi chúng từ C# trực tiếp.

Nếu bạn mạnh hơn, bạn có thể viết thư viện trình bao bọc trong C++/CLI. Đó không phải là một ý tưởng tồi vì nó cho phép bạn sử dụng các tệp tiêu đề Windows C/C++ hiện có và kết hợp C++ và mã được quản lý theo các cách intresting. Chỉ cần cẩn thận với các tài nguyên không được quản lý và bạn sẽ có một thư viện intropability rất mạnh mẽ trong thời gian không.

Nhưng cũng có nhiều API âm thanh nâng cao hơn bắt đầu bằng Windows Vista, các thành phần Windows Core Audio có thể thú vị hơn nữa dọc theo dòng. Nhưng đối với hoạt động I/O cơ bản, các chức năng đa phương tiện của Windows sẽ giúp bạn nhanh hơn.

Tôi đã sử dụng các chức năng này trong một số trường hợp khi xây dựng các bộ tổng hợp phần mềm đơn giản. Đáng buồn là mã đã biến mất lâu rồi.

1

Tôi khuyên bạn nên sử dụng SlimDX vì nó chỉ hoạt động trên mọi phiên bản của windows (x86 hoặc x64) và cung cấp nhiều tính năng và tính linh hoạt nhất. Tuy nhiên, nó là một nỗi đau để có được và chạy vì không có mẫu mã hoàn chỉnh tốt. Tôi đã viết một lớp wrapper để đơn giản hóa việc sử dụng của nó mặc dù vậy nó có thể được gọi như thế này (tôi đã kiểm tra mã này trên 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... 
    } 

Đây là nguồn gốc cho lớp wrapper 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; 
      } 
     } 
    } 
} 

Nó hoàn toàn đa luồng để giảm thiểu độ trễ. Ban đầu tôi đã viết nó cho một công cụ phân tích xử lý tín hiệu thời gian thực và sử dụng đầu ra float thay vì ngắn nhưng tôi đã sửa đổi mẫu mã để phù hợp với việc sử dụng yêu cầu của bạn.Nếu bạn cần dữ liệu tần suất, tôi sẽ sử dụng http://www.mathdotnet.com/Neodym.aspx hoặc http://www.exocortex.org/dsp/ để có thư viện C# FFT tốt.

Các vấn đề liên quan