C# NAudio錄音和播放音頻文件及實時繪製音頻波形圖(從音頻流數據獲取,而非設備獲取)

 

     下午寫了一篇關於NAudio的錄音、播放和波形圖的博客,不太滿意,感受寫的太亂,又總結了下ide

      NAudio是個相對成熟、開源的C#音頻開發工具,它包含錄音、播放錄音、格式轉換、混音調整等功能。本次介紹主要功能有音頻、錄音文件播放、實時音頻流波形圖顯示等。具體以下:函數

1. 錄音工具

      NAudio錄音主要使用WaveIn和WaveFileWriter兩個類開發工具

   1.1   WaveInspa

      WaveIn的功能是對錄音的音頻參數進行設置以及對數據的採集,參數如通道數、採樣率、平均數據傳輸速率(WaveFormat)、數據回調事件、錄音中止回調函數等參數 .net

      其中,DataAvailable爲數據回調參數,是在錄音時實時將錄音數據傳遞出來,有須要使用錄音數據的能夠訂閱該事件進行接收業務和相關處理。調試

   1.2   WaveFileWritercode

     該類是建立相對應格式的音頻文件,並提供想對應的寫入數據方法、保存方法等,具體以下:orm

 public class WaveFileWriter : Stream
    {
        public WaveFileWriter(Stream outStream, WaveFormat format);
        public WaveFileWriter(string filename, WaveFormat format);

        ~WaveFileWriter();

        public override long Position { get; set; }
        public override bool CanWrite { get; }
        public override bool CanRead { get; }
        public WaveFormat WaveFormat { get; }
        public TimeSpan TotalTime { get; }
        public override long Length { get; }
        public string Filename { get; }
        public override bool CanSeek { get; }

        public static void CreateWaveFile(string filename, IWaveProvider sourceProvider);
        public static void CreateWaveFile16(string filename, ISampleProvider sourceProvider);
        public static void WriteWavFileToStream(Stream outStream, IWaveProvider sourceProvider);
        public override void Flush();
        public override int Read(byte[] buffer, int offset, int count);
        public override long Seek(long offset, SeekOrigin origin);
        public override void SetLength(long value);
        public override void Write(byte[] data, int offset, int count);
        [Obsolete("Use Write instead")]
        public void WriteData(byte[] data, int offset, int count);
        [Obsolete("Use WriteSamples instead")]
        public void WriteData(short[] samples, int offset, int count);
        public void WriteSample(float sample);
        public void WriteSamples(short[] samples, int offset, int count);
        public void WriteSamples(float[] samples, int offset, int count);
        protected override void Dispose(bool disposing);
        protected virtual void UpdateHeader(BinaryWriter writer);
    }

     在調用上是先調用WaveIn的DataAvailable回調函數,讀取其數據並寫入流文件,最後保存到本地。blog

2. 播放錄音

播放錄音主要用到AudioFileReader、WaveOut三個類和接口

      2.1   AudioFileReader

          AudioFileReader主要負責讀取音頻文件,驗證音頻文件格式,對外部提供讀取數據接口,具體以下:

 public class AudioFileReader : WaveStream, ISampleProvider
    {
        public AudioFileReader(string fileName);

        public string FileName { get; }
        public override WaveFormat WaveFormat { get; }
        public override long Length { get; }
        public override long Position { get; set; }
        public float Volume { get; set; }

        public override int Read(byte[] buffer, int offset, int count);
        public int Read(float[] buffer, int offset, int count);
        protected override void Dispose(bool disposing);
    }

 

     2.2   WaveOut

        WaveOut的工做是播放音頻,它調用AudioFileReader.Read進行數據讀取,對讀取的數據進行播放,主要工做流程是從獲取數據,並將數據進行播放成音頻

public class WaveOut : IWavePlayer, IDisposable, IWavePosition
    {
        public WaveOut();
        public WaveOut(IntPtr windowHandle);
        public WaveOut(WaveCallbackInfo callbackInfo);

        ~WaveOut();

        public static int DeviceCount { get; }
        public PlaybackState PlaybackState { get; }
        public WaveFormat OutputWaveFormat { get; }
        public int DeviceNumber { get; set; }
        public int NumberOfBuffers { get; set; }
        public int DesiredLatency { get; set; }
        public float Volume { get; set; }

        public event EventHandler<StoppedEventArgs> PlaybackStopped;

        public static WaveOutCapabilities GetCapabilities(int devNumber);
        public void Dispose();
        public long GetPosition();
        public void Init(IWaveProvider waveProvider);
        public void Pause();
        public void Play();
        public void Resume();
        public void Stop();
        protected void Dispose(bool disposing);
    }

 

3. 波形圖繪製

       錄音時繪製波形圖須要在DataAviliable回調函數中獲取音頻數據並將其從byte[]轉換爲float[],而後用float[]數據作爲波形圖的輸入便可,這個過程源碼上寫一個數據包的波形圖數據爲waveSource.WaveFormat.SampleRate / 100,原理上我還沒搞懂,可是的確是這麼操做顯示是對的,具體以下:

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

                float[] sts = new float[e.Buffer.Length / 2];
                int outIndex = 0;
                for (int n = 0; n < e.Buffer.Length; n += 2)
                {
                    sts[outIndex++] = BitConverter.ToInt16(e.Buffer, n) / 32768f;
                }

                for (int n = 0; n < sts.Length; n += channels)
                {
                    Add(sts[n]);
                }
            }
        }

 

    須要注意的是WaveFormat的通道數設置、PCM的格式設置,上述代碼都是基於通道數爲二、PCM爲16bit的狀況下,如這兩項修改會發生轉換和調用失敗等問題

    可調試Demo:示例Demo

相關文章
相關標籤/搜索