2

我正在学习使用 naudio 进行音频编程(使用教程)。我的程序(C# .net winForms)我有录制和停止按钮。代码如下所示:

    NAudio.Wave.WaveIn sourceStream = null;
    NAudio.Wave.WaveFileWriter waveWriter = null;

    private void RecordButton_Click(object sender, EventArgs e)
    {
        int deviceNumber = 0;
        sourceStream = new NAudio.Wave.WaveIn();
        sourceStream.DeviceNumber = deviceNumber;
        sourceStream.WaveFormat = new NAudio.Wave.WaveFormat(44100, NAudio.Wave.WaveIn.GetCapabilities(deviceNumber).Channels);

        sourceStream.DataAvailable += new EventHandler<NAudio.Wave.WaveInEventArgs>(sourceStream_DataAvailable);
        waveWriter = new NAudio.Wave.WaveFileWriter("d:\\a.wav", sourceStream.WaveFormat);

        sourceStream.StartRecording();
    }

    private void sourceStream_DataAvailable(object sender, NAudio.Wave.WaveInEventArgs e)
    {
        if (waveWriter == null) return;

        waveWriter.WriteData(e.Buffer, 0, e.BytesRecorded);
        waveWriter.Flush();
    }

    private void StopButton_Click(object sender, EventArgs e)
    { 
            waveWriter.Dispose();
            waveWriter = null;       
    }

它可以工作,但波形文件质量不好 - 我录制的声音有小间隙。我想要 44100 Hz 的采样率和 16 位的采样格式。

4

2 回答 2

1

我无法完全复制您发现的内容,但我确实注意到该DataAvailable事件并没有为其他操作留下太多空间来阻止。一个简单Thread.Sleep(100);的停止应用程序。

假设您的连续写入(和刷新)可能会导致问题,我实现了一个Queue保持要写入的字节并使用线程池中的线程进行实际写入的天真的问题。

事件现在DataAvailable看起来像这样:

    Queue<byte[]> writebuffer = new Queue<byte[]>();

    private void sourceStream_DataAvailable(object sender, NAudio.Wave.WaveInEventArgs e)
    {
        if (waveWriter == null) return;

        byte[] realbytes = new byte[e.BytesRecorded];
        Array.Copy(e.Buffer, realbytes, e.BytesRecorded);
        writebuffer.Enqueue(realbytes);
    }

就在StartRecording通话之后,我将任务排入队列以读取队列并将数据写入流。如果我在那里添加延迟,则应用程序不再停止。

ThreadPool.QueueUserWorkItem((s) =>
{
    var keeprunning = true;
    sourceStream.RecordingStopped += (rss, rse) => { keeprunning = false; };
    while(keeprunning)
    {
        if (writebuffer.Count==0)
        {
                Thread.Sleep(0);
        }
        else
        { 
            var buf = writebuffer.Dequeue();
            waveWriter.Write(buf,0,buf.Length);
            // Thread.Sleep(100); // for testing 
        }
    }
    waveWriter.Dispose();
    waveWriter = null;
});
于 2016-05-07T18:16:18.393 回答
0

我也遇到过这个问题。解决方案是从使用 WaveIn 进行录制切换到 WasapiCapture。设置和使用几乎相同,但质量要好得多。尝试这个:

public class Recorder
{
    public string _outputFolder { get; set; }
    public string _outputFilePath { get; set; }
    public WasapiCapture _capture { get; set; }
    public WaveFileWriter _writer { get; set; }

    public Recorder()
    {
        _outputFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "NAudio");
        Directory.CreateDirectory(_outputFolder);
        _outputFilePath = Path.Combine(_outputFolder, "recorded.wav");
    }

    public void StartRecording()
    {
        _capture = new WasapiCapture();
        _capture.ShareMode = AudioClientShareMode.Shared;
        _capture.WaveFormat = new WaveFormat(44100, 32, 1);

        _writer = new WaveFileWriter(_outputFilePath, _capture.WaveFormat);

        _capture.DataAvailable += _capture_DataAvailable;
        _capture.RecordingStopped += _capture_RecordingStopped; ;

        _capture.StartRecording();
    }

    public void StopRecording()
    {
        _capture.StopRecording();
    }

    private void _capture_DataAvailable(object sender, WaveInEventArgs e)
    {
        _writer.Write(e.Buffer, 0, e.BytesRecorded);
    }

    private void _capture_RecordingStopped(object sender, StoppedEventArgs e)
    {
        _writer?.Dispose();
        _writer = null;
        _capture.Dispose();
        _capture = null;
    }

}
于 2020-03-28T21:33:03.323 回答