概述

在 NAudio 中, 常用类型有 WaveIn, WaveOut, WaveStream, WaveFileWriter, WaveFileReader, AudioFileReader 以及接口: IWaveProvider, ISampleProvider, IWaveIn, IWavePlayer

  1. WaveIn 表示波形输入, 继承了 IWaveIn, 例如麦克风输入, 或者计算机正在播放的音频流.
  2. WaveOut 表示波形输出, 继承了 IWavePlayer, 用来播放波形音乐, 以 IWaveProvider 作为播放源播放音频, 通过拓展方法也支持以 ISampleProvider 作为播放源播放音频
  3. WaveStream 表示波形流, 它继承了 IWaveProvider, 可以用来作为播放源.
  4. WaveFileReader 继承了 WaveStream, 用来读取波形文件
  5. WaveFileWriter 继承了Stream, 用来写入文件, 常用于保存音频录制的数据.
  6. AudioFileReader 通用的音频文件读取器, 可以读取波形文件, 也可以读取其他类型的音频文件例如 Aiff, MP3
  7. IWaveProvider 波形提供者, 上面已经提到, 是音频播放的提供者, 通过拓展方法可以转换为 ISampleProvider
  8. ISampleProvider 采样提供者, 上面已经提到, 通过拓展方法可以作为 WaveOut 的播放源

播放音频

常用的播放音频方式有两种, 播放波形音乐, 以及播放 MP3 音乐

  1. 播放波形音乐:

    // NAudio 中, 通过 WaveFileReader 来读取波形数据, 在实例化时, 你可以指定文件名或者是输入流, 这意味着你可以读取内存流中的音频数据
    // 但是需要注意的是, 不可以读取来自网络流的音频, 因为网络流不可以进行 Seek 操作.// 此处, 假设 ms 为一个 MemoryStream, 内存有音频数据.
    WaveFileReader reader = new WaveFileReader(ms);
    WaveOut wout = new WaveOut();
    wout.Init(reader);             // 通过 IWaveProvider 为音频输出初始化
    wout.Play();                   // 至此, wout 将从指定的 reader 中提供的数据进行播放
    
  2. 播放 MP3 音乐:

    // 播放 MP3 音乐其实与播放波形音乐没有太大区别, 只不过将 WaveFileReader 换成了 Mp3FileReader 罢了
    // 另外, 也可以使用通用的 Reader, MediaFoundationReader, 它既可以读取波形音乐, 也可以读取 MP3// 此处, 假设 ms 为一个 MemoryStream, 内存有音频数据.
    Mp3FileReader reader = new Mp3FileReader(ms);
    WaveOut wout = new WaveOut();
    wout.Init(reader);
    wout.Play();
    

音频录制

  1. 录制麦克风输入

    // 借助 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 命名空间下
    
  2. 录制声卡输出

    // 录制声卡输出, 也就是录制计算机正在播放的声音, 借助 WasapiLoopbackCapture 即可简单实现, 使用方式与 WasapiCapture 无异WasapiLoopbackCapture cap = new WasapiLoopbackCapture();
    WaveFileWriter writer = new WaveFileWriter();
    cap.DataAvailable += (s, args) => writer.Write(args.Buffer, 0, args.BytesRecorded);
    cap.StartRecording();
    

高级应用

  1. 获取计算机实时播放音量大小

    // 其实这个是基于刚刚的录制声卡输出的, 录制时的回调中, Buffer, BytesRecorded 指定了此次录制的数据 (缓冲区和数据长度)
    // 而这些数据, 其实是计算机对声音的采样(Sample), 具体的采样格式可以查看 WasapiLoopbackCapture 实例的 WaveForamt
    // 波形格式中的 Encoding 与 BitsPerSample 是我们所需要的. 一般默认的 Encoding 是 IeeeFloat, 也就是每一个采样都是
    // 一个浮点数, 而 BitsPerSample 也就是 32 了. 通过 BitConverter.ToSingle() 我们可以从缓冲区中取得浮点数
    // 遍历, 每 32 位一个浮点数, 最终取最大值, 这就是我们所需要的音量了float volume;
    WasapiLoopbackCapture cap = new WasapiLoopbackCapture();
    cap.DataAvailable += (s, args) => volume = Enumerable.Range(0, args.BytesRecorded / 4)                         // 每一个采样的位置.Select(i => BitConverter.ToSingle(args.Buffer, i * 4))   // 获取每一个采样.Aggregate((v1, v2) => v1 > v2 ? v1 : v2);                // 找到值最大的采样
    
  2. 实现音乐可视化
    完整版 NAudio 实现音乐可视化: [C#] 使用 NAudio 实现音频可视化

    // 既然我们已经知道了, 那些数据都是一个个的采样, 自然也可以通过它们来绘制频谱, 只需要进行快速傅里叶变换即可
    // 而且有意思的是, 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, i) =>{double deg = i / (double)sampleRate * Math.PI * 2;                  // 获取当前采样率在圆上对应的角度 (弧度制)return new Complex(){X = (float)(Math.Cos(deg) * v),Y = (float)(Math.Sin(deg) * v)};}).ToArray();                                         // 将采样转换为对应的复数 (缠绕到圆)FastFourierTransform.FFT(false, log, complexSrc);     // 进行傅里叶变换double[] result = complexSrc.Select(v => Math.Sqrt(v.X * v.X + v.Y * v.Y)).ToArray();    // 取得结果
    };
    
  3. 音频格式转换

    // 对于 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 值, 那么每两个采样时间点相同, 而各个通道的采样就是每一组中每一个采样

所以对于我们刚刚进行的音乐可视化, 严格意义上来讲, 还需要区分通道

示例

本文提到的部分内容在 github.com/SlimeNull/AudioTest 仓库中有示例, 例如音频可视化, 音频录制, 以及其他零星的示例


如有错误, 还请指出

[C#] NAudio 各种常见使用方式 播放 录制 转码 音频可视化相关推荐

  1. pyqt5QQ音乐播放器毕设成品音频可视化

    环境介绍 python3.8.1-win32 pycharm 初代版本tkinter https://blog.csdn.net/qq_27383741/article/details/1066949 ...

  2. [C#] 使用 NAudio 实现音频可视化

    预览: 最初版本: 更新: 再次更新 (这次优化了算法): [演示] C# NAudio Direct2D 音频可视化 捕捉声卡输出: 实现音频可视化, 第一步就是获得音频采样, 这里我们选择使用计算 ...

  3. 融云 AMR(Aduio) 播放 AMR 格式 Base64 码音频

    1.必备资料 github AMR 开源库 :https://github.com/jpemartins/amr.js 用心把这个项目看一遍,对于我下面说的话,可以忽略啦,代码是最好的文章,哈哈~~ ...

  4. 配置nginx,使其可以以https的方式播放http-flv的直播流

    一.背景 由于在微信小程序中需要https的接入,所以要想在微信小程序中播放http-flv的直播流可能需要以https的方式.下面讲述如何配置nginx,使其可以以https的方式播放http-fl ...

  5. Python与常见加密方式

    Python与常见加密方式 前言 数据加密与解密通常是为了保证数据在传输过程中的安全性,自古以来就一直存在,古代主要应用在战争领域,战争中会有很多情报信息要传递,这些重要的信息都会经过加密,在发送到对 ...

  6. 单模光纤收发器产品介绍及常见分类方式

    现如今,随着网络技术的进步,许多的场合都会需要光纤收发器进行远距离的传输,以致于现在国外和国内生产光纤收发器厂商非常多,产品线也极为丰富.收发器都是电转光的网络结构.接下来我们就来为大家详细介绍下单模 ...

  7. MySQL 异常:这一篇就够了,MySQL 抛出异常的几种常见解决方式小结

    Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Connectio ...

  8. Mycat-server-1.6.5 常见分片方式

    Mycat-server-1.6.5 常见分片方式 1 安装 [root@hongquan1 soft]# tar zxvf Mycat-server-1.6.5-release-2018012222 ...

  9. 基于JMF录制和播放视频源码

    仅仅播放摄像头拍摄内容(修改版) package org.bruce.myown_product;import java.awt.Component;import java.awt.Dimension ...

  10. 常见充值方式介绍及对比 (转)

    常见充值方式介绍及对比 1:银联充值 1:环境部署 安装NetPay4NTSetup.exe,将MerPrk.key和PgPubk.key两个文件放到C:\WINDOWS目录下,环境部署完成了. 2: ...

最新文章

  1. 【Part2】用JS写一个Blog (node + vue + mongoDB)
  2. 【TYVJ】1359 - 收入计划(二分)
  3. Geoserver在Linux上的安装(图文教程)
  4. Linux学习笔记2_centos7远程登陆前的总结
  5. 项目职责_项目经理的9个职责
  6. c++实现卷积码编码和维特比译码_鑫艾勒维特家用别墅电梯:安全至上,无可替代...
  7. Mongodb 与sql 语句对照
  8. win ollvm环境_Python3 环境搭建
  9. PTA-1015——Reversible Primes
  10. Jquery 根据value值设置下拉列表(select)默认选中项
  11. iOS-layoutSubvies和drawRect何时调用
  12. 使用 CloudFlare CDN 自定义节点加速网站
  13. 电脑桌面的照片文件不见了怎么办
  14. 苹果13可以用无线充电宝吗?苹果专用无线充电宝推荐
  15. 请高手指点,简单的几个数组操作方法不知道是否可以有更好的改进方法或者更简单的方法?
  16. html5测试苹果7plus,苹果7 Plus评测:P3广色域屏幕测试
  17. 历史影像高清晰历史卫星影像
  18. MOSFet cutoff frequency ( From google)
  19. ios接入GameCenter登录
  20. 网站关键词排名:关键词排名提升的5个方法!

热门文章

  1. 二等水准数据平差_二等水准测量方法与步骤
  2. 如何用Java写出热门大鱼吃小鱼游戏
  3. ubuntu16.04 安装微信客户端
  4. 省市区前端json格式 上
  5. 计算机组装主机怎么拆,【电脑组装知识网】电脑主机组装教程之戴尔显示器底座拆卸教程...
  6. 出圈!迅镭激光切割设备亮相热播剧《麓山之歌》
  7. FreeSWITCH对接MRCP Server
  8. 浅淡静态代码分析工具
  9. C++ 实现文件分割、合并
  10. 精练战略云 VS “华丽“战术云