Naudio录制麦克风的X秒数

时间:2013-12-11 21:55:25

标签: c# multithreading event-handling naudio

目前,我可以使用Naudio .dll录制麦克风输入:

public void recordInput()
{
    Console.WriteLine("Now recording...");
    waveSource = new WaveIn();
    waveSource.WaveFormat = new WaveFormat(16000, 1);

    waveSource.DataAvailable += new EventHandler<WaveInEventArgs>(waveSource_DataAvailable);
    waveSource.RecordingStopped += new EventHandler<StoppedEventArgs>(waveSource_RecordingStopped);
    //string tempFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".wav");

    string tempFile = Path.Combine(@"C:\Users\Nick\Desktop",  "test.wav");


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

    waveSource.StartRecording();

    myTimer.Interval = 5000;
    myTimer.Tick += new EventHandler(myTimer_Tick);
    myTimer.Start();

}

目前我使用了一个事件处理程序等待5秒然后onTick我停止录制。但是这会导致问题,因为我无法等待录制任务完成我调用的代码的主要部分:

    public string voiceToText()
    {
        recordInput();

        //Somehow wait here until record is done then proceed.

        convertToFlac();
        return "done";


    }

我已经尝试将Naudio放在一个线程中并使用waitOne();但是waveSource.StartRecording();被放入一个事件处理程序中并进行预测。我也尝试使用Thread.Sleep(5000)并在该线程完成后停止录制,但音频仅出于某种原因记录了前500mS的音频。

我对c#很新,并且不完全了解线程,所以欢迎任何帮助或单独的方法。

2 个答案:

答案 0 :(得分:1)

如果您没有在Windows窗体或WPF应用程序中运行,那么您应该使用WaveInEvent,以便设置后台线程来处理回调。 WaveIn的默认构造函数使用Windows消息。

答案 1 :(得分:0)

我知道这是一个老话题,但这是我为我的一个项目制作的一些代码,它记录了x秒的音频(它使用NAudio.Lame将wave文件转换为mp3):

public class Recorder
{

    /// <summary>
    /// Timer used to start/stop recording
    /// </summary>
    private Timer _timer;

    private WaveInEvent _waveSource;
    private WaveFileWriter _waveWriter;
    private string _filename;
    private string _tempFilename;
    public event EventHandler RecordingFinished;

    /// <summary>
    /// Record from the mic
    /// </summary>
    /// <param name="seconds">Duration in seconds</param>
    /// <param name="filename">Output file name</param>
    public void RecordAudio(int seconds, string filename)
    {
        /*if the filename is empty, throw an exception*/
        if (string.IsNullOrEmpty(filename))
            throw new ArgumentNullException("The file name cannot be empty.");

        /*if the recording duration is not > 0, throw an exception*/
        if (seconds <= 0)
            throw new ArgumentNullException("The recording duration must be a positive integer.");

        _filename = filename;
        _tempFilename = $"{Path.GetFileNameWithoutExtension(filename)}.wav";

        _waveSource = new WaveInEvent
        {
            WaveFormat = new WaveFormat(44100, 1)
        };

        _waveSource.DataAvailable += DataAvailable;
        _waveSource.RecordingStopped += RecordingStopped;
        _waveWriter = new WaveFileWriter(_tempFilename, _waveSource.WaveFormat);

        /*Start the timer that will mark the recording end*/
        /*We multiply by 1000 because the Timer object works with milliseconds*/
        _timer = new Timer(seconds * 1000);

        /*if the timer elapses don't reset it, stop it instead*/
        _timer.AutoReset = false;

        /*Callback that will be executed once the recording duration has elapsed*/
        _timer.Elapsed += StopRecording;

        /*Start recording the audio*/
        _waveSource.StartRecording();

        /*Start the timer*/
        _timer.Start();

    }

    /// <summary>
    /// Callback that will be executed once the recording duration has elapsed
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void StopRecording(object sender, ElapsedEventArgs e)
    {
        /*Stop the timer*/
        _timer?.Stop();

        /*Destroy/Dispose of the timer to free memory*/
        _timer?.Dispose();

        /*Stop the audio recording*/
        _waveSource.StopRecording();
    }

    /// <summary>
    /// Callback executed when the recording is stopped
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void RecordingStopped(object sender, StoppedEventArgs e)
    {
        _waveSource.DataAvailable -= DataAvailable;
        _waveSource.RecordingStopped -= RecordingStopped;
        _waveSource?.Dispose();
        _waveWriter?.Dispose();

        /*Convert the recorded file to MP3*/
        ConvertWaveToMp3(_tempFilename, _filename);

        /*Send notification that the recording is complete*/
        RecordingFinished?.Invoke(this, null);
    }

    /// <summary>
    /// Callback executed when new data is available
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void DataAvailable(object sender, WaveInEventArgs e)
    {
        if (_waveWriter != null)
        {
            _waveWriter.Write(e.Buffer, 0, e.BytesRecorded);
            _waveWriter.Flush();
        }
    }

    /// <summary>
    /// Converts the recorded WAV file to MP3
    /// </summary>
    private void ConvertWaveToMp3(string source, string destination)
    {
        using (var waveStream = new WaveFileReader(source))
        using(var fileWriter = new LameMP3FileWriter(destination, waveStream.WaveFormat, 128))
        {
            waveStream.CopyTo(fileWriter);
            waveStream.Flush();
        }

        /*Delete the temporary WAV file*/
        File.Delete(source);
    }

}

这是在代码中使用它的方法:

        var rec = new Recorder();
        /*This line allows us to be notified when the recording is complete and the callback 'OnRecordingFinished' will be executed*/
        rec.RecordingFinished += OnRecordingFinished;
        rec.RecordAudio(seconds, recPath);

    private void OnRecordingFinished(object sender, RecordingContentArgs e)
    {
        //Put your code here to process the audio file


    }