前言
在 NAudio 中, 常用类型有 WaveIn, WaveOut, WaveStream, WaveFileWriter, WaveFileReader, AudioFileReader 以及接口: IWaveProvider, ISampleProvider, IWaveIn, IWavePlayer
- WaveIn 表示波形输入, 继承了 IWaveIn, 例如麦克风输入, 或者计算机正在播放的音频流.
- WaveOut 表示波形输出, 继承了 IWavePlayer, 用来播放波形音乐, 以 IWaveProvider 作为播放源播放音频, 通过拓展方法也支持以 ISampleProvider 作为播放源播放音频
- WaveStream 表示波形流, 它继承了 IWaveProvider, 可以用来作为播放源.
- WaveFileReader 继承了 WaveStream, 用来读取波形文件
- WaveFileWriter 继承了Stream, 用来写入文件, 常用于保存音频录制的数据.
- AudioFileReader 通用的音频文件读取器, 可以读取波形文件, 也可以读取其他类型的音频文件例如 Aiff, MP3
- IWaveProvider 波形提供者, 上面已经提到, 是音频播放的提供者, 通过拓展方法可以转换为 ISampleProvider
- ISampleProvider 采样提供者, 上面已经提到, 通过拓展方法可以作为 WaveOut 的播放源
NAudio
使用NAudio
安装
1 | Install-Package NAudio -Version 1.9.0 |
麦克风列表
1 | using NAudio.Wave; |
打印如下
-1: Microsoft Sound Mapper
0: 麦克风 (Realtek(R) Audio)
注意上面是从-1开始遍历的,我们获取麦克风设备的时候可以从0遍历。
默认的设备
1 | MMDevice defaultCaptureDevice = WasapiCapture.GetDefaultCaptureDevice(); |
或者
1 | using NAudio.CoreAudioApi; |
获取支持的采样率
1 | /// <summary> |
采集
WaveIn 和 WasapiCapture都可以采集麦克风。
他两个的区别
WaveIn:
支持Windows 95后的所有系统,也就是支持XP。
由于其底层实现的限制,在音频采集时通常会有相对较高的延迟。
- 资源占用较低。
- 可自定义采样率。
WasapiCapture:
- 支持Windows Vista后的系统。
- 可以实现极低的延迟。
- 资源占用高。
- 只能使用系统设置的采样率。
WaveIn录制
WaveIn可以修改采样率。
1 | WaveIn cap = new WaveIn(); |
WasapiCapture录制
WasapiCapture不能修改采样率,只能使用系统设置的采样率。
1 | WasapiCapture cap = new WasapiCapture(); |
FFT
1 | private static void Capture_DataAvailable(object sender, WaveInEventArgs e) |
匹配代码
特征提取
ZMfcc
1 | namespace ZKeywordSpotting.utils |
ZComplex
1 | namespace ZKeywordSpotting.utils |
相似度
ZDtw
1 | namespace ZKeywordSpotting.utils |
概念
byte/short
byte 是 1 个字节(即 8 位)。
short 是 2 个字节(即 16 位)。
C# 中的 short
实际上就是对 System.Int16
的别名映射。
采样率
采样率(Sample Rate)是指在单位时间内对音频信号进行采样的次数,单位为赫兹(Hz)。
16000Hz 的采样率意味着每秒钟会对音频信号进行 16000 次采样。
音频单位
在音频处理领域,音频数据常常以 16 位(也就是 2 字节)的整数形式进行存储。
1byte(字节) = 8 bit(比特)
运算
音频数据量的计算公式为:
数据量(字节/秒)
=采样率(Hz)
×声道数
×每个样本的字节数
假设是单声道(声道数为 1),每个样本是 16 位(即 2 字节),采样率为 16000 Hz,那么每秒产生的数据量为:
数据量 = 16000×1×2 = 32000 字节/秒
已知缓冲区大小为 bufferSize * 2
字节,这里 bufferSize
为 1024,所以缓冲区大小为 (1024*2 = 2048) 字节。
根据时间的计算公式:
将缓冲区大小 2048 字节和每秒数据量 96000 字节 / 秒代入公式,可得:
4096*2/32000 = 0.256
所以,在采样率为 48000 Hz、单声道、每个样本 16 位且 bufferSize
为 4096的情况下,填满 bufferSize * 2
字节的缓冲区大约需要 0.02133 秒,即约 21.33 毫秒。
DTW
动态时间规整(DTW)算法概述
动态时间规整(Dynamic Time Warping,DTW)是一种用于衡量两个时间序列之间相似度的算法,在语音识别、手势识别等领域应用广泛。
当要比较两个时间序列时,由于它们的长度可能不同,或者时间上的伸缩不一致,直接比较可能会不准确。
DTW 算法通过寻找两个序列之间的最优匹配路径,从而计算出它们之间的相似度。
特征向量维度的意义
在语音处理场景中,通常会对语音信号进行特征提取,将语音信号转换为一系列的特征向量。每个特征向量包含了语音在某一时刻的特征信息,例如使用梅尔频率倒谱系数(MFCC)作为特征时,每个 MFCC 特征向量通常有一定的维度。
这里的 13
就表示每个特征向量的维度数量。也就是说,在进行 DTW 匹配时,输入的每个时间点上的特征向量都是一个 13 维的向量。比如,你提取了实时语音和模板语音的 MFCC 特征,每个 MFCC 特征向量有 13 个元素,在使用 DTW 算法比较这两个语音的特征序列时,就需要告诉 DTW 算法每个特征向量的维度是 13。