2013-12-21 31 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不保证它会在确切的指定时间跨度后继续执行。您可能会获得比所需时间稍长的记录。