2013-12-21 45 views
1

這是我用它來錄製音頻文件中的代碼:使用記錄波形文件(n音訊)

internal class AudioRecorder 
{ 
    public WaveIn waveSource = null; 
    public WaveFileWriter waveFile = null; 
    public string RECORDING_PATH; 

    public AudioRecorder(string fileName) 
    { 
     RECORDING_PATH = fileName; 
    } 

    public void Start() 
    { 
     waveSource = new WaveIn(); 
     waveSource.WaveFormat = new WaveFormat(44100, 1); 
     waveSource.DeviceNumber = 0; 
     waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable); 
     waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped); 

     waveFile = new WaveFileWriter(RECORDING_PATH, waveSource.WaveFormat); 

     System.Timers.Timer t = new System.Timers.Timer(30000); 

     t.Elapsed += new ElapsedEventHandler(Stop); 

     waveSource.StartRecording(); 

     t.Start(); 


    } 

    private void Stop(object sender, ElapsedEventArgs args) 
    { 
     waveSource.StopRecording(); 
    } 

    private void waveSource_DataAvailable(object sender, WaveInEventArgs e) 
    { 
     if (waveFile != null) 
     { 
      waveFile.Write(e.Buffer, 0, e.BytesRecorded); 
      waveFile.Flush(); 
     } 
    } 

    private void waveSource_RecordingStopped(object sender, StoppedEventArgs e) 
    { 
     if (waveSource != null) 
     { 
      waveSource.Dispose(); 
      waveSource = null; 
     } 

     if (waveFile != null) 
     { 
      waveFile.Dispose(); 
      waveFile = null; 
     } 

    } 
} 

在main方法我做的:

AudioRecorder r = new AudioRecorder(dialog.FileName); 
r.Start(); 
FileInfo file = new FileInfo(r.RECORDING_PATH); 
// Do somehting with the recorded audio // 

的問題是,當我做r.Start()線程不會阻塞並繼續運行。所以我得到一個損壞的文件錯誤。當我嘗試使用Thread.Sleep等線程等待記錄結束時,此時AudioRecorder代碼無法正常工作(即錄製從未結束)。

關於我應該怎麼做的任何想法等待錄音完成,以便我可以安全地使用錄製的文件?

回答

0

您使用ManualResetEvent來等待Stop事件被調用,從而讓其他線程進行更改。 我只添加了新的位......

internal class AudioRecorder 
{ 
    private ManualResetEvent mre = new ManualResetEvent(false); 

    public void Start() 
    { 

     t.Start(); 
     while (!mre.WaitOne(200)) 
     { 
      // NAudio requires the windows message pump to be operational 
      // this works but you better raise an event 
      Application.DoEvents(); 
     } 
    } 

    private void Stop(object sender, ElapsedEventArgs args) 
    { 
     // better: raise an event from here! 
     waveSource.StopRecording(); 
    } 

    private void waveSource_RecordingStopped(object sender, EventArgs e) 
    { 
     /// ... your code here 

     mre.Set(); // signal thread we're done! 
    } 
+0

音頻錄製現在已成功完成並且沒有損壞。但是,它沒有記錄它應該的長度(即30秒)。我得到的是1秒的白噪聲。 – Cemre

+0

Windows消息泵需要運行才能執行引發的事件。這個黑客工程,但你最好提出一個事件RecordingComplete或類似的東西... – rene

1

如果要錄製30秒準確,只需調用StopRecording在DataAvailable事件處理程序,一旦你有足夠的數據。絕對不需要複雜的線程策略。我在開放源代碼.NET voice recorder application中就是這樣做的。

將WaveFileWriter配置到RecordingStopped事件中。

如果您絕對必須有阻止呼叫,請使用WaveInEvent,然後等待Rene建議的在RecordingStopped處理程序中設置的事件。通過使用WaveInEvent,您不再需要Windows消息泵才能運行。

0

如果不需要,最好避免使用任何多線程代碼,而馬克的答案正在很好地解釋這一點。

但是,如果您正在編寫一個Windows應用程序,並且要求記錄30秒,則必須不要阻止主線程等待(等待30秒)。新的異步C#功能在這裏可以非常方便。它將允許您保持直接的代碼邏輯並以非常有效的方式實現等待。

我稍微修改了您的代碼以顯示在這種情況下如何使用異步功能。

這裏的記錄方法:

public async Task RecordFixedTime(TimeSpan span) 
    { 
     waveSource = new WaveIn {WaveFormat = new WaveFormat(44100, 1), DeviceNumber = 0}; 
     waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable); 
     waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped); 

     waveFile = new WaveFileWriter(RECORDING_PATH, waveSource.WaveFormat); 

     waveSource.StartRecording(); 
     await Task.Delay(span); 
     waveSource.StopRecording(); 
    } 

使用記錄從WPF應用程序的點擊處理程序的實例:

private async void btnRecord_Click(object sender, RoutedEventArgs e) 
    { 
     try 
     { 
      btnRecord.IsEnabled = false; 
      var fileName = Path.GetTempFileName() + ".wav"; 
      var recorder = new AudioRecorder(fileName); 
      await recorder.RecordFixedTime(TimeSpan.FromSeconds(5)); 
      Process.Start(fileName); 
     } 
     finally 
     { 
      btnRecord.IsEnabled = true; 
     } 
    } 

但是,你要在這裏注意時機。 Task.Delay不保證它會在確切的指定時間跨度後繼續執行。您可能會獲得比所需時間稍長的記錄。