本文讲述了C# NAudio 库的各种常见使用方式之播放 录制 转码 音频可视化!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:
在 NAudio 中, 常用类型有 WaveIn, WaveOut, WaveStream, WaveFileWriter, WaveFileReader, AudioFileReader 以及接口: IWaveProvider, ISampleProvider, IWaveIn, IWavePlayer
播放音频
常用的播放音频方式有两种, 播放波形音乐, 以及播放 MP3 音乐
播放波形音乐:
1 2 3 4 5 6 7 8 | // NAudio 中, 通过 WaveFileReader 来读取波形数据, 在实例化时, 你可以指定文件名或者是输入流, 这意味着你可以读取内存流中的音频数据 // 但是需要注意的是, 不可以读取来自网络流的音频, 因为网络流不可以进行 Seek 操作. // 此处, 假设 ms 为一个 MemoryStream, 内存有音频数据. WaveFileReader reader = new WaveFileReader(ms); WaveOut wout = new WaveOut(); wout.Init(reader); // 通过 IWaveProvider 为音频输出初始化 wout.Play(); // 至此, wout 将从指定的 reader 中提供的数据进行播放 |
播放 MP3 音乐:
1 2 3 4 5 6 7 8 | // 播放 MP3 音乐其实与播放波形音乐没有太大区别, 只不过将 WaveFileReader 换成了 Mp3FileReader 罢了 // 另外, 也可以使用通用的 Reader, MediaFoundationReader, 它既可以读取波形音乐, 也可以读取 MP3 // 此处, 假设 ms 为一个 MemoryStream, 内存有音频数据. Mp3FileReader reader = new Mp3FileReader(ms); WaveOut wout = new WaveOut(); wout.Init(reader); wout.Play(); |
音频录制
录制麦克风输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // 借助 WaveIn 类, 我们可以轻易的捕获麦克风输入, 在每一次录制到数据时, 将数据写入到文件或其他流, 这就实现了保存录音 // 在保存波形文件时需要借助 WaveFileWriter, 当然, 如果你想保存为其他格式, 也可以使用其它的 Writer, 例如 CurWaveFileWriter 以及 // AiffFileWriter, 美中不足的是没有直接写入到 MP3 的 FileWriter // 需要注意的是, 如果你是用的桌面程序, 那么你可以直接使用 WaveIn, 其回调基于 Windows 消息, 所以无法在控制台应用中使用 WaveIn // 如果要在控制台应用中实现录音, 只需要使用 WaveInEvent, 它的回调基于事件而不是 Windows 消息, 所以可以通用 WaveIn cap = new WaveIn(); // cap, capture WaveFileWriter writer = new WaveFileWriter(); cap.DataAvailable += (s, args) => writer.Write(args.Buffer, 0, args.BytesRecorded); // 订阅事件 cap.StartRecording(); // 开始录制 // 结束录制时: cap.StopRecording(); // 停止录制 writer.Close(); // 关闭 FileWriter, 保存数据 // 另外, 除了使用 WaveIn, 你还可以使用 WasapiCapture, 它与 WaveIn 的使用方式是一致的, 可以用来录制麦克风 // Wasapi 全称 Windows Audio Session Application Programming Interface (Windows音频会话应用编程接口) // 具体 WaveIn, WaveInEvent, WasapiCapture 的性能, 笔者还没有测试过, 但估计不会有太大差异. // 提示: WasapiCapture 和 WasapiLoopbackCapture 位于 NAudio.Wave 命名空间下 |
录制声卡输出
1 2 3 4 5 6 | // 录制声卡输出, 也就是录制计算机正在播放的声音, 借助 WasapiLoopbackCapture 即可简单实现, 使用方式与 WasapiCapture 无异 WasapiLoopbackCapture cap = new WasapiLoopbackCapture(); WaveFileWriter writer = new WaveFileWriter(); cap.DataAvailable += (s, args) => writer.Write(args.Buffer, 0, args.BytesRecorded); cap.StartRecording(); |
高级应用
获取计算机实时播放音量大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 既然我们已经知道了, 那些数据都是一个个的采样, 自然也可以通过它们来绘制频谱, 只需要进行快速傅里叶变换即可 // 而且有意思的是, NAudio 也为我们准备好了快速傅里叶变换的方法, 位于 NAudio.Dsp 命名空间下 // 提示: 进行傅里叶变换所需要的复数(Complex)类也位于 NAudio.Dsp 命名空间, 它有两个字段, X(实部) 与 Y(虚部) // 下面给出在 IeeeFloat 格式下的音乐可视化的简单示例: WasapiLoopbackCapture cap = new WasapiLoopbackCapture(); cap.DataAvailable += (s, args) => { float[] samples = Enumerable .Range(0, args.BytesRecorded / 4) .Select(i => BitConverter.ToSingle(args.Buffer, i * 4)) .ToArray(); // 获取采样 int log = (int)Math.Ceiling(Math.Log(samples.Length, 2)); float[] filledSamples = new float[(int)Math.Pow(2, log)]; Array.Copy(samples, filledSamples, samples.Length); // 填充数据 int sampleRate = (s as WasapiLoopbackCapture).WaveFormat.SampleRate; // 获取采样率 Complex[] complexSrc = filledSamples.Select(v => new Complex(){ X = v }).ToArray(); // 转换为复数 FastFourierTransform.FFT(false, log, complexSrc); // 进行傅里叶变换 double[] result = complexSrc.Select(v => Math.Sqrt(v.X * v.X + v.Y * v.Y)).ToArray(); // 取得结果 }; |
音频格式转换
1 2 3 4 5 6 7 8 9 | // 对于 Wave, CueWave, Aiff, 这些格式都有其对应的 FileWriter, 我们可以直接调用其 Writer 的 Create***File 来 // 从 IWaveProvider 创建对应格式的文件. 对于 MP3 这类没有 FileWriter 的格式, 可以调用 MediaFoundationEncoder // 例如一个文件, "./Disconnected.mp3", 我们要将它转换为 wav 格式, 只需要使用下面的代码, CurWave 与 Aiff 同理 using (Mp3FileReader reader = new Mp3FileReader("./Disconnected.mp3")) WaveFileWriter.CreateWaveFile("./Disconnected.wav", reader); // 从 IWaveProvider 创建 MP3 文件, 假如一个 WaveFileReader 为 src MediaFoundationEncoder.EncodeToMp3(src, "./NewMp3.mp3"); |
提示
对于刚刚所说的音频录制, 采样的格式有一点需要注意, 将数据转换为一个 float 数组后, 其中还需要区分音频通道, 例如一般音乐是双通道, WaveFormat 的 Channel 为 2, 那么在 float 数组中, 每两个采样为一组, 一组采样中每一个采样都是一个通道在当前时间内的采样.
以双通道距离, 下图中, 采样数据中每一个圆圈都表示一个 float 值, 那么每两个采样时间点相同, 而各个通道的采样就是每一组中每一个采样
所以对于我们刚刚进行的音乐可视化, 严格意义上来讲, 还需要区分通道
对于采样的大小, BitsPerSample, 可以是 8, 16, 32, 其中 8 和 16 都是整数存储采样, 32 是浮点数存储采样.
另外, 对于音乐可视化部分的傅里叶变换结果, 我们只需要其中一部分, 取前 256 个足矣. (我也不知道它这个运算结果是如何分布的)。
更多相关技术内容咨询欢迎前往并持续关注六星社区了解详情。
想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!