简体   繁体   中英

recording wave naudio liblary - poor quality of sound

i'm lerning audio programming using naudio (using tutorial). Im my program (C# .net winForms) I have record and stop button. The code looks like that:

    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;       
    }

It works but wave file quality isn't good - there are small gaps in sound i recorded. I want sample rate 44100 Hz and sample format 16-bit.

I couldn't exactly replicate what you found but I did notice that the DataAvailable event doesn't leave much room to be blocked for other operations. A simple Thread.Sleep(100); stalls the application.

Assuming your continuous writing (and flushing) might contribute to the issue I implemented a naive Queue that keeps the bytes to be written and use a thread from the threadpool to do the actual writing.

The DataAvailable event now looks like this:

    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);
    }

Just after the StartRecording call I queue the task for reading the queue and writing the data to the stream. If I add a delay there the application no longer stalls.

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;
});

I experienced this issue as well. The solution was to switch from using WaveIn for the recording to WasapiCapture. The setup and usage is almost the same but the quality if far better. Try this:

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;
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM