- 音视频
- 音频处理
【免费下载链接】NAudio
Audio and MIDI library for .NET
重采样(Resampling)是音频处理中最常见的需求之一:混音前要把不同采样率的文件统一,ASIO 等设备输出前要把数据转换到设备当前的采样率。本文以 NAudio 仓库中的 Docs/Resampling.md 为骨架,系统讲解 NAudio 提供的四种重采样方案(Windows 的 Media Foundation、macOS 的 AudioConverter、跨平台的 WDL、遗留的 ACM),逐一给出可直接复制的代码示例、参数取值范围与质量档位说明,并结合仓库源码(MediaFoundationResampler.cs、MacAudioConverter.cs、WdlResamplingSampleProvider.cs 等)解释每种方案的底层工作原理、适用平台与限制。读完本文,你将能够在混音、设备播放、文件转码等场景中准确选择并正确使用 NAudio 的重采样器。
什么时候需要重采样
在 NAudio 中,几乎所有下游处理环节都对 WaveFormat(采样率、位深度、声道数)有严格要求,因此重采样通常出现在以下两类场景:
- 混音前的统一采样率:将两个采样率不同的文件(例如一个 44.1kHz、一个 48kHz)混合到一起,必须先通过重采样让它们处于同一采样率,否则混音结果会出现音高与节奏错位。
- 设备输出前的格式匹配:通过 ASIO 这类 API 播放时,数据必须以设备当前的采样率送入设备。若源文件采样率与设备不匹配,就必须先重采样。
需要注意的是,重采样并非简单的"插值补点",它暗藏一个经典陷阱——混叠(Aliasing)。
重采样前必须了解:混叠(Aliasing)问题
根据奈奎斯特定理,某采样率能正确表示的频率上限为采样率的一半。当降低采样率时,源音频中高于目标采样率一半的高频成分无法被正确表示,它们不会消失,而是会"折叠"回可听频段,形成失真,这就是混叠。
文档给出的核心结论是:
如果降低采样率,应当先使用低通滤波器滤除在低采样率下无法正确表示的高频,然后再做重采样。
好消息是:NAudio 提供的几个官方重采样器(Media Foundation、AudioConverter、WDL)内部都内置了高质量的滤波/抗混叠处理,因此日常使用时你通常无需手动挂低通滤波器;但如果你选择"自己动手"写重采样算法,就必须自行处理低通滤波,否则几乎必然产生明显的混叠。
Option 1:MediaFoundationResampler(Windows)
这是 NAudio 中功能最强大的重采样器,包装了 Windows 自带的 Media Foundation 重采样 MFT(CLSID_CResamplerMediaObject,GUID 为f447b69e-1884-4a7e-8055-346f74d6edb3,见 MediaFoundationResampler.cs),在 Windows 10 及之后所有受支持的 Windows 版本上均可使用。
能力与特点
- 可调质量:
ResamplerQuality取值 1~60,60 为最高质量,1 为线性插值;默认已是 60。它对应底层 MFT 的IWMResamplerProps.SetHalfFilterLength,即半滤波器长度(见 MediaFoundationResampler.cs)。 - 足够快:官方文档说明其速度足以在最高质量档位下实时运行。
- 灵活:可以在重采样同时改变声道数与位深度(仅限 PCM 与 IEEE float 输入/输出,源码中
IsPcmOrIeeeFloat会校验这一点并抛出ArgumentException,见 MediaFoundationResampler.cs)。 - 输入输出约束:构造函数要求输入输出均为 PCM 或 IEEE float;若传入非此类格式会立即抛异常,同时会在构造时探测 COM 对象,若系统缺少重采样 DLL 会快速失败(fail fast),而不是等到第一次 Read 才报错(见 MediaFoundationResampler.cs)。
使用示例:MP3(44.1kHz)重采样到 16kHz
using NAudio.Wave; int outRate = 16000; var inFile = @"test.mp3"; var outFile = @"test resampled MF.wav"; using var reader = new MediaFoundationReader(inFile); var outFormat = new WaveFormat(outRate, reader.WaveFormat.Channels); using var resampler = new MediaFoundationResampler(reader, outFormat); // resampler.ResamplerQuality = 60; // default 已经是 60(最高质量) WaveFileWriter.CreateWaveFile(outFile, resampler);要点说明:
- 它接受
IWaveProvider作为输入,输出格式由传入的WaveFormat决定。示例中outFormat保持源文件的声道数,只改采样率。 - 构造器还有一个便捷重载
MediaFoundationResampler(sourceProvider, outputSampleRate),只指定目标采样率,会按源格式自动构造输出 WaveFormat(PCM 保持位深度、IEEE float 输出 float 格式,见 MediaFoundationResampler.cs)。 - 若同时想改变位深度或声道数,把
outFormat改成对应的WaveFormat(sampleRate, bitsPerSample, channels)即可,例如输出 16kHz/16bit/单声道。 - 需要在重采样开始前设置
ResamplerQuality,其 setter 会对 1~60 范围做校验(见 MediaFoundationResampler.cs)。
Option 2:MacAudioConverter(macOS)
macOS 的 wrappers 包(NAudio.MacOS)中提供了与MediaFoundationResampler同等强大的平台级重采样器MacAudioConverter,它包装了 macOS Audio Toolbox 的 AudioConverter。文档明确提示该包目前仅以预发布(pre-release)形式提供,安装时需要--prerelease参数:
dotnet add package NAudio.MacOS --prerelease前提:此方案必须运行在 macOS 上(源码以
[SupportedOSPlatform("ios2.0")]与[SupportedOSPlatform("macos10.2")]标注,见 MacAudioConverter.cs)。
能力与特点
- 质量与 Windows Media 重采样器相当,并且更灵活:可以显式选择重采样算法、质量档位与抖动(dithering)算法。
- 唯一的限制:不能在重采样过程中随时更改输入流的任何格式属性(这是与
MediaFoundationResampler的主要差异,见 MacAudioConverter.cs)。 - 通道映射:支持把输入声道映射到不同输出声道,甚至用
-1禁用某些输入声道。 - 格式约束:与 Windows 版本一致,只接受 PCM 与 IEEE float 格式(
VerifyFormatIsIeeeFloatOrPCM校验,见 MacAudioConverter.cs)。
核心可配置项(源码枚举)
| 属性 | 可选值 | 说明 |
|---|---|---|
Quality | AudioConverterQuality.Min(0)、Low(0x20)、Medium(0x40)、High(0x60)、Max(0x7F) | 默认 Normal;质量档位见 AudioConverterQuality.cs |
Complexity | Linear(线性插值,最低质量最便宜)、Normal(默认)、Mastering(更高品质,更昂贵)、MinimumPhase(最小相位脉冲响应,具体噪底随质量档位变化,Low≈-96dB、Medium≈-144dB、High≈-160dB 且内部使用双精度) | 重采样算法,见 AudioConverterSampleRateComplexity.cs |
Dithering | None(默认)、TPDF(三角概率密度白噪声抖动)、NoiseShaping(感知加权噪声整形抖动) | 仅 macOS 支持,见 AudioConverterDitheringAlgorithm.cs |
DitheringBitLength | uint | 对指定位长度应用预设抖动算法,仅 macOS 支持 |
Complexity与Quality的交互值得注意:文档强调"重采样质量还取决于你使用的重采样算法",例如MinimumPhase模式下同样的Low/Medium/High档位对应不同的噪声底水平,且MinimumPhase High比Mastering Low快数倍。另外Linear模式下InitialPhase与PrimeMethod属性不生效。
SetChannelMap(int[] channelMap)用于自定义声道映射:数组长度必须等于输出声道数,每个元素是源格式的声道索引,-1表示该输出声道不使用任何输入声道。源码注释中给出的示例是"立体声输入复制到四声道输出的后两个声道":
int[] chMap = [ 0, 1, 0, 1 ]; theConverter.SetChannelMap(chMap);另外,MacAudioConverter构造器内置了一个贴心处理:当源为单声道、目标为多声道时,默认的 AudioConverter 行为是只把单声道数据送到第一个声道、其余声道静音,因此源码会自动把通道映射表填为全 0,让单声道信号铺满所有输出声道(见 MacAudioConverter.cs)。如果遇到源端数据流不连续(discontinuity),可调用Reset()重置转换器内部缓冲状态。
使用示例:MP3 重采样到 16kHz
using NAudio.Wave; using NAudio.MacOS.AudioToolbox; int outRate = 16000; var inFile = @"test.mp3"; var outFile = @"test resampled AudioConverter.wav"; using var reader = ExtendedAudioFileReaderFromURL.CreateFromFile(inFile); var outFormat = new WaveFormat(outRate, reader.WaveFormat.Channels); using var resampler = new MacAudioConverter(reader, outFormat); // 默认是 Normal,Min 是最低,Max 是最高。 // 重采样质量同时也取决于所使用的重采样算法。 // resampler.Quality = AudioConverterQuality.Max; WaveFileWriter.CreateWaveFile(outFile, resampler);要点说明:
- 输入读取使用 macOS 包的
ExtendedAudioFileReaderFromURL(继承自ExtendedAudioFileServicesReader,见 ExtendedAudioFileReaderFromURL.cs),而非 Windows 专用的MediaFoundationReader。 - 如需更高质量,可组合设置,例如:
resampler.Quality = AudioConverterQuality.Max; resampler.Complexity = AudioConverterSampleRateComplexityConstants.Mastering; Read方法要求缓冲长度不小于目标格式的块对齐(BlockAlign),否则抛出ArgumentException(见 MacAudioConverter.cs)。
Option 3:WdlResamplingSampleProvider(跨平台)
第三种方案基于Cockos WDL resampler(NAudio 获得了作者 Justin Frankel 的许可使用)。它工作在浮点样本域,因此输入需要ISampleProvider。这是唯一一个完全托管(fully managed)代码实现的重采样器,可在没有 Media Foundation 的任何跨平台环境(Linux、macOS、移动端等)中使用。
底层原理(源码级)
- 核心算法位于 WdlResampler.cs,由 C++ 版 WDL resampler 移植为 C#,默认使用
float作为样本类型与 sinc 滤波器系数类型。 - 包装类 WdlResamplingSampleProvider.cs 构造时:保留源声道数,目标格式固定为
WaveFormat.CreateIeeeFloatWaveFormat(newSampleRate, channels);随后配置 WDL 引擎——SetMode(true, 2, false)开启插值并使用 2 个滤波器、SetFilterParms()采用默认滤波参数(filterpos 0.693、filterq 0.707)、SetFeedMode(false)设为输出驱动(pull 模式)、最后SetRates(sourceRate, newSampleRate)设定源/目标采样率(见 WdlResamplingSampleProvider.cs)。 - 读取时按"输出帧数 → ResamplePrepare 计算需要的输入帧数 → 从源读取 → ResampleOut 生成输出"的流程驱动,天然适合链式 SampleProvider 管道(见 WdlResamplingSampleProvider.cs)。
使用示例:MP3 重采样到 16kHz 并写出 16bit WAV
int outRate = 16000; var inFile = @"test.mp3"; var outFile = @"test resampled WDL.wav"; using (var reader = new AudioFileReader(inFile)) { var resampler = new WdlResamplingSampleProvider(reader, outRate); WaveFileWriter.CreateWaveFile16(outFile, resampler); }要点说明:
AudioFileReader负责把任意格式解码为浮点,正好满足ISampleProvider要求。WaveFileWriter.CreateWaveFile16会在写文件时把浮点样本转换为 16bit,因此无需额外处理位深度。- 与媒体框架方案不同,WDL 方案没有
Quality之类的公开设置;WdlResamplingSampleProvider固定采用 2 滤波器 + 插值的默认配置(更底层的WdlResampler.SetMode/SetFilterParms均带可选参数,供进阶用户直接操作 Dsp 层)。
优点与不足
- 优点:纯托管、跨平台,逻辑上只需引入 NAudio.Core 即可,不依赖操作系统组件。
- 不足:性能不一定比
MediaFoundationResampler(或 macOS 的MacAudioConverter)更快。在追求极致吞吐的 Windows 实时场景,优先考虑平台原生方案。
Option 4:ACM 重采样器(Windows,遗留方案)
WaveFormatConversionStream是 NAudio 从早期版本就提供的 ACM(Audio Compression Manager) 重采样器,属于遗留方案;文档明确建议新代码优先使用MediaFoundationResampler或WdlResamplingSampleProvider。
限制
- 只能重采样16bit 音频;
- 不能同时改变声道数;
- 输入必须是
WaveStream(不是IWaveProvider)。
其实现是"把 WaveStream 包装成走 ACM Codec 的WaveFormatConversionProvider",并基于源/目标格式的AverageBytesPerSecond估算转换后长度与位置映射(见 WaveFormatConversionStream.cs)。正因如此,它的长度/位置只是估算值,不适合需要精确 seek 的场景。
使用示例:MP3 重采样到 16kHz
int outRate = 16000; var inFile = @"test.mp3"; var outFile = @"test resampled ACM.wav"; using (var reader = new Mp3FileReader(inFile)) { var outFormat = new WaveFormat(outRate, reader.WaveFormat.Channels); using (var resampler = new WaveFormatConversionStream(outFormat, reader)) { WaveFileWriter.CreateWaveFile(outFile, resampler); } }该方案位于NAudio.WinMM程序集中(WaveFormatConversionStream.cs),仅适用于 Windows。同一程序集中还有WaveFormatConversionProvider可直接处理IWaveProvider,但同样的 16bit、不可改声道数限制依然适用。
Option 5:自己动手实现重采样
由于 NAudio 让开发者直接访问原始样本(ISampleProvider.Read(Span<float>)、IWaveProvider.Read(Span<byte>)),你完全可以自行编写重采样算法,例如线性插值或更复杂的多项式插值。
但文档给出了明确的警告:
如果不同时编写低通滤波器,你几乎必然会遇到严重的混叠问题。既然 NAudio 已经内置了 WDL 重采样器,所有需要托管重采样器的场景都应该直接使用它。
换句话说,自己实现通常只在教学、实验或对算法有特殊定制需求时才有意义;生产代码应优先复用官方方案。
方案选择速查
| 方案 | 平台 | 输入类型 | 质量 | 是否可同时改声道/位深 | 状态 |
|---|---|---|---|---|---|
MediaFoundationResampler | Windows 10+ | IWaveProvider(PCM/IEEE float) | 1~60 可调,默认 60 | 是 | 推荐 |
MacAudioConverter | macOS(iOS 部分功能受限) | IWaveProvider(PCM/IEEE float) | Min/Max等五档 + 算法/抖动可选 | 是(含通道映射) | 推荐(需--prerelease安装) |
WdlResamplingSampleProvider | 跨平台(纯托管) | ISampleProvider(浮点) | 固定默认配置,品质良好 | 否(仅采样率) | 推荐(跨平台首选) |
WaveFormatConversionStream(ACM) | Windows | WaveStream | 依赖 ACM codec | 否(仅采样率,限 16bit) | 遗留,仅旧代码 |
选型建议一句话总结:Windows 实时/高性能场景用MediaFoundationResampler,macOS 场景用MacAudioConverter,需要跨平台或纯托管的场景用WdlResamplingSampleProvider,ACM 留给历史代码维护。
延伸阅读
- 重采样的典型实战场景:MixTwoAudioFilesToWav.md(混音前统一采样率)、Resampling.md(本文档原文)
- 输出设备采样率匹配相关:AsioPlayback.md、OutputDeviceTypes.md
- 相关实现源码:MediaFoundationResampler.cs、MacAudioConverter.cs、WdlResamplingSampleProvider.cs、WdlResampler.cs、WaveFormatConversionStream.cs
- 测试与示例:可在 NAudio.Windows.Tests 与 NAudio.Core.Tests 中检索重采样相关用例,结合真实项目验证各方案行为。
- 音视频
- 音频处理
【免费下载链接】NAudio
Audio and MIDI library for .NET
相关推荐
Jest ES6 类 Mock 完全指南:四种方式与源码级原理剖析
Jest ES6 类 Mock 完全指南:四种方式与源码级原理剖析 导读:ES6 class 本质上是带语法糖的构造函数,因此 Jest 中一切 ES6 cla
测试质量保障代码覆盖率开发工具React-Vis 样式控制完全指南:四种策略与源码级原理
React Vis 样式控制完全指南:四种策略与源码级原理 本指南围绕 docs/style.md https://link.gitcode.com/i/43c
数据可视化图表库前端nnU-Net v2 推理完全指南:nnUNetPredictor 四种预测模式与源码级原理剖析
nnU Net v2 推理完全指南:nnUNetPredictor 四种预测模式与源码级原理剖析 导读 :本文围绕 nnU Net v2 推理模块( nnune
人工智能深度学习计算机视觉医疗健康
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考