下午写了一篇关于NAudio的录音、播放和波形图的博客,不太满意,感觉写的太乱,又总结了下

     
NAudio是个相对成熟、开源的C#音频开发工具,它包含录音、播放录音、格式转换、混音调整等功能。本次介绍主要功能有音频、录音文件播放、实时音频流波形图显示等。具体如下:

1. 录音

      NAudio录音主要使用WaveIn和WaveFileWriter两个类

   1.1   WaveIn

     
WaveIn的功能是对录音的音频参数进行设置以及对数据的采集,参数如通道数、采样率、平均数据传输速率(WaveFormat)、数据回调事件、录音停止回调函数等参数 

      其中,DataAvailable为数据回调参数,是在录音时实时将录音数据传递出来,有需要使用录音数据的可以订阅该事件进行接收业务和相关处理。

   1.2   WaveFileWriter

     该类是创建相对应格式的音频文件,并提供想对应的写入数据方法、保存方法等,具体如下:
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回调函数,读取其数据并写入流文件,最后保存到本地。

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的格式设置,上述代码都是基于通道数为2、PCM为16bit的情况下,如这两项修改会发生转换和调用失败等问题

    可调试Demo:示例Demo <https://download.csdn.net/download/qq_17005083/11644031>