sherpa-onnx C#/.NET 示例实战:dotnet-examples 目录全解与 C# API 集成指南
【免费下载链接】sherpa-onnxSpeech-to-text, text-to-speech, speaker diarization, speech enhancement, source separation, and VAD using next-gen Kaldi with onnxruntime without Internet connection. Support embedded systems, Android, iOS, HarmonyOS, Raspberry Pi, RISC-V, RK NPU, Axera NPU, Ascend NPU, x86_64 servers, websocket server/client, support 12 programming languages项目地址: https://gitcode.com/GitHub_Trending/sh/sherpa-onnx
本文以 sherpa-onnx 仓库中的 dotnet-examples 目录为主体,系统讲解这套 C# API 示例工程的组成结构、NuGet 集成方式、各功能类别示例(离线/流式语音增强、零样本 TTS、离线 ASR 等)的运行方法,以及如何在解决方案中新增自己的示例项目,帮助 .NET 开发者快速完成 sherpa-onnx 在 C# 项目中的接入与调用。
一、这个目录解决什么问题
sherpa-onnx 是支持离线语音识别(ASR)、语音合成(TTS)、说话人分离、语音增强、声源分离与端点检测(VAD)的推理框架。dotnet-examples 目录提供了官方维护的 C# 端示例集合:每个功能点都是一个独立的可运行 console 项目,通过统一的Common项目引用 NuGet 包org.k2fsa.sherpa.onnx,配合各自的run.sh脚本一键下载模型并运行。
整个示例集以 Visual Studio 解决方案 sherpa-onnx.sln 组织,当前共包含 40 多个子项目,覆盖:
- 离线语音增强:speech-enhancement-gtcrn、speech-enhancement-dpdfnet
- 流式(在线)语音增强:streaming-speech-enhancement-gtcrn、streaming-speech-enhancement-dpdfnet
- 零样本 TTS:zipvoice-tts、zipvoice-tts-play(带播放),以及 pocket-tts-zero-shot、kokoro-tts、kitten-tts、supertonic-tts、offline-tts 等
- 离线 ASR:offline-decode-files(Paraformer、Whisper、SenseVoice 等多模型)、non-streaming-canary、non-streaming-cohere-transcribe、non-streaming-funasr-nano、non-streaming-moonshine-v2、non-streaming-qwen3-asr 等
- 流式 ASR:online-decode-files、streaming-hlg-decoding、speech-recognition-from-microphone
- VAD + ASR 组合:vad-non-streaming-asr-paraformer、vad-non-streaming-funasr-nano、vad-non-streaming-qwen3-asr
- 标点恢复:offline-punctuation、online-punctuation
- 说话人相关:speaker-identification、offline-speaker-diarization
- 其他:offline-audio-tagging、spoken-language-identification、keyword-spotting-from-files / keyword-spotting-from-microphone、source-separation-spleeter / source-separation-uvr、version-test
每个项目内的 Program.cs 文件头部通常都带有完整的操作注释(下载哪个模型、如何运行),是最直接的参考文档。
二、解决方案结构与 NuGet 集成方式
2.1 公共层:Common 项目
所有示例共享一个公共项目 Common.csproj,其内容非常精简:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup> <ItemGroup> <PackageReference Include="org.k2fsa.sherpa.onnx" Version="*" /> </ItemGroup> </Project>三个关键信息:
- 目标框架为 .NET 8.0,即所有示例的运行前提是安装了 .NET 8 SDK(
dotnet命令行工具); - C# API 通过 NuGet 包
org.k2fsa.sherpa.onnx引入,示例中版本号写作*(自动取最新版),实际生产项目中建议锁定具体版本以便复现; - 开启了
AllowUnsafeBlocks。从 C# 封装层源码(见 scripts/dotnet 下的DenoisedAudio.cs、WaveReader.cs等文件,它们就是 NuGet 包内 C# API 的原始实现)看,C# 层通过 P/Invoke 调用底层 C 库,因此需要 unsafe 块支持。
Common项目除引入 NuGet 包外,还包含 WaveHeader.cs,提供 WAV 文件头读写支持,供各示例直接读写.wav文件使用。
2.2 示例项目如何组织
以 speech-enhancement-gtcrn.csproj 为例,每个示例项目的 csproj 只有几行:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <RootNamespace>speech_enhancement_gtcrn</RootNamespace> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\Common\Common.csproj" /> </ItemGroup> </Project>要点:示例项目不直接引用 NuGet 包,而是通过ProjectReference依赖Common项目间接获得org.k2fsa.sherpa.onnx。这样统一升级版本时只需改一处(Common.csproj)。
三、标准运行流程:run.sh 脚本模式
每个示例目录下都有一个run.sh,遵循统一的"检查 → 下载 → 运行"模式。以 speech-enhancement-gtcrn/run.sh 为例:
#!/usr/bin/env bash set -ex if [ ! -f ./gtcrn_simple.onnx ]; then curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speech-enhancement-models/gtcrn_simple.onnx fi if [ ! -f ./inp_16k.wav ]; then curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speech-enhancement-models/inp_16k.wav fi dotnet run可以看到模式为:本地不存在模型/测试音频时才从 sherpa-onnx 官方 Releases 的speech-enhancement-models资产中下载,然后直接dotnet run。这意味着模型文件不进入版本库,首次运行会联网下载,之后离线可复现。
ASR 类示例的模型下载类似,例如 offline-decode-files/run-paraformer.sh 会下载 Paraformer 中文模型包并解压,再以命令行参数方式传给程序:
dotnet run \ --tokens=./sherpa-onnx-paraformer-zh-2023-09-14/tokens.txt \ --paraformer=./sherpa-onnx-paraformer-zh-2023-09-14/model.int8.onnx \ --num-threads=2 \ --files ./sherpa-onnx-paraformer-zh-2023-09-14/test_wavs/0.wav \ ./sherpa-onnx-paraformer-zh-2023-09-14/test_wavs/1.wav \ ./sherpa-onnx-paraformer-zh-2023-09-14/test_wavs/2.wav \ ./sherpa-onnx-paraformer-zh-2023-09-14/test_wavs/8k.wavoffline-decode-files是目录内参数最多的示例,Program.cs 使用 CommandLine 库定义了一组Options,通过--tokens、--paraformer、--whisper-encoder、--whisper-decoder、--nemo-ctc、--zipformer-ctc、--moonshine-*等参数适配 Transducer、Paraformer、Whisper、NeMo CTC、Moonshine 等不同模型族;同目录还配有 run-whisper.sh、run-sense-voice-ctc.sh、run-zipformer.sh 等十余个脚本,分别演示不同模型的参数组合。命令行参数方式适合需要灵活切换模型的批处理场景;而语音增强、TTS 类示例则把模型路径硬编码在Program.cs中,更适合阅读 API 用法。
四、代表性示例源码解析
4.1 离线语音增强(GTCRN)
speech-enhancement-gtcrn/Program.cs 展示了离线降噪 API 的最小调用链:
using SherpaOnnx; class OfflineSpeechEnhancementDemo { static void Main(string[] args) { var model = "./gtcrn_simple.onnx"; var config = new OfflineSpeechDenoiserConfig(); config.Model.Gtcrn.Model = model; // 指定 GTCRN 模型路径 config.Model.Debug = 1; // 打开调试日志 config.Model.NumThreads = 1; // 推理线程数 var sd = new OfflineSpeechDenoiser(config); WaveReader waveReader = new WaveReader("./inp_16k.wav"); var denoisedAudio = sd.Run(waveReader.Samples, waveReader.SampleRate); var outputFilename = "./enhanced.wav"; var ok = denoisedAudio.SaveToWaveFile(outputFilename); // ... } }调用要点:
- 配置对象为
OfflineSpeechDenoiserConfig,模型路径挂在config.Model.Gtcrn.Model上; WaveReader读入 wav 后得到float[]采样和采样率;sd.Run(samples, sampleRate)一次性处理整段音频,返回DenoisedAudio对象,再SaveToWaveFile输出enhanced.wav。
4.2 离线语音增强(DPDFNet)与模型选择
speech-enhancement-dpdfnet/Program.cs 与 GTCRN 示例结构完全一致,仅模型字段不同:
var config = new OfflineSpeechDenoiserConfig(); config.Model.Dpdfnet.Model = "./dpdfnet_baseline.onnx"; config.Model.Dpdfnet.AttenuationLimitDb = 12.0f; // DPDFNet 特有:增益限制(dB)README 与源码注释对 DPDFNet 模型的选择给出了明确指引:
| 模型文件 | 适用场景 |
|---|---|
dpdfnet_baseline.onnx、dpdfnet2.onnx、dpdfnet4.onnx、dpdfnet8.onnx | 16 kHz 输出,适合下游接 ASR/语音识别 |
dpdfnet2_48khz_hr.onnx | 48 kHz 增强输出,适合直接听感/高质量增强 |
AttenuationLimitDb用于限制增强时噪声衰减的幅度上限,避免人声被过度压制。
4.3 流式语音增强:按帧推送与 Flush
streaming-speech-enhancement-gtcrn/Program.cs 演示了在线(流式)降噪 API 的标准循环模式:
var config = new OnlineSpeechDenoiserConfig(); config.Model.Gtcrn.Model = "./gtcrn_simple.onnx"; config.Model.Debug = 1; config.Model.NumThreads = 1; var sd = new OnlineSpeechDenoiser(config); WaveReader waveReader = new WaveReader("./inp_16k.wav"); var samples = waveReader.Samples; var output = new List<float>(samples.Length); int frameShift = sd.FrameShiftInSamples; // 每次应推送的帧长(采样数) for (int start = 0; start < samples.Length; start += frameShift) { int count = Math.Min(frameShift, samples.Length - start); float[] chunk = new float[count]; Array.Copy(samples, start, chunk, 0, count); var audio = sd.Run(chunk, waveReader.SampleRate); output.AddRange(audio.Samples); } output.AddRange(sd.Flush().Samples); // 冲刷内部缓冲,拿到剩余输出 var ok = DenoisedAudio.SaveToWaveFile(output.ToArray(), sd.SampleRate, "./enhanced-online-gtcrn.wav");从源码结构看,流式 API 的三个关键点是:
- 通过
sd.FrameShiftInSamples属性获取引擎要求的帧长,而不是自己拍脑袋取 320/480 之类的值,保证与模型内部帧移严格一致; - 每次
Run传入一帧,返回值是这一帧对应的增强采样; - 输入结束后必须调用
Flush()取回内部缓冲区里剩余的音频,否则会丢失结尾片段。
streaming-speech-enhancement-dpdfnet示例是同一模式的 DPDFNet 版本,可直接对照阅读。
4.4 ZipVoice 中英文零样本 TTS
zipvoice-tts/Program.cs 演示了零样本(zero-shot)TTS:用一段参考音频"克隆"音色后合成新文本。核心配置:
var config = new OfflineTtsConfig(); config.Model.ZipVoice.Tokens = "./sherpa-onnx-zipvoice-distill-int8-zh-en-emilia/tokens.txt"; config.Model.ZipVoice.Encoder = "./sherpa-onnx-zipvoice-distill-int8-zh-en-emilia/encoder.int8.onnx"; config.Model.ZipVoice.Decoder = "./sherpa-onnx-zipvoice-distill-int8-zh-en-emilia/decoder.int8.onnx"; config.Model.ZipVoice.Vocoder = "./vocos_24khz.onnx"; config.Model.ZipVoice.DataDir = "./sherpa-onnx-zipvoice-distill-int8-zh-en-emilia/espeak-ng-data"; config.Model.ZipVoice.Lexicon = "./sherpa-onnx-zipvoice-distill-int8-zh-en-emilia/lexicon.txt"; config.Model.NumThreads = 2; config.Model.Debug = 1; config.Model.Provider = "cpu";ZipVoice 需要五件套:tokens、encoder、decoder、vocoder(独立下载的vocos_24khz.onnx)以及 espeak-ng 发音数据目录加 lexicon。
零样本音色由OfflineTtsGenerationConfig提供:
var reader = new WaveReader(referenceWaveFilename); // 参考音频 genConfig.ReferenceAudio = reader.Samples; genConfig.ReferenceSampleRate = reader.SampleRate; genConfig.ReferenceText = "那还是三十六年前, 一九八七年. 我呢考上了武汉大学的计算机系."; genConfig.NumSteps = 4; genConfig.Extra["min_char_in_sentence"] = "10"; // 分句时单句最少字数合成时还支持带进度回调的生成接口,回调中返回 1 表示继续、0 表示中止:
var myCallback = (IntPtr samples, int n, float progress, IntPtr arg) => { float[] data = new float[n]; Marshal.Copy(samples, data, 0, n); Console.WriteLine($"Progress {progress * 100}%"); return 1; // 1: 继续生成;0: 停止生成 }; var callback = new OfflineTtsCallbackProgressWithArg(myCallback); var audio = tts.GenerateWithConfig(text, genConfig, callback); var ok = audio.SaveToWaveFile("./generated-zipvoice-zh-en.wav");配套的 zipvoice-tts-play 在同样流程基础上增加了音频播放,pocket-tts-zero-shot、supertonic-tts、offline-tts-play等示例也遵循"OfflineTtsConfig + GenerateWithConfig + SaveToWaveFile"的一致套路,可按需对照切换模型。
五、在解决方案中新增自己的示例项目
dotnet-examples/README.md 给出了新增项目的两条标准命令(在dotnet-examples目录下执行):
dotnet new console -n offline-tts-play dotnet sln ./sherpa-onnx.sln add ./offline-tts-play即:先用dotnet new console创建 console 项目,再用dotnet sln add把它挂进现有解决方案。创建后按第二节的模式修改新项目的 csproj:目标框架设为net8.0,并添加对..\Common\Common.csproj的ProjectReference,即可获得完整的 C# API 依赖。
README 还给出了 NuGet 本地缓存的清理命令,用于排查包版本/缓存导致的异常:
dotnet nuget locals all --list dotnet nuget locals all --clear--list显示各缓存位置(全局包目录、http-cache、temp 等),--clear清空缓存,之后重新构建时会从 NuGet 源重新拉取org.k2fsa.sherpa.onnx包。
六、落地检查清单
- 环境:已安装 .NET 8 SDK(所有示例均为
net8.0),dotnet --version可正常输出; - 包:通过 Common.csproj 引用 NuGet 包
org.k2fsa.sherpa.onnx,生产项目建议把Version="*"固定为具体版本号; - 模型:各
run.sh会按需从 sherpa-onnx 官方 Releases 下载模型与测试音频(语音增强模型在speech-enhancement-models资产组、TTS 模型在tts-models/vocoder-models资产组、ASR 模型在asr-models资产组);首次运行需要网络; - 运行:
bash run.sh或手动dotnet run(ASR 类示例注意按脚本传入--tokens、--paraformer等参数); - 新示例:
dotnet new console -n <名称>+dotnet sln ./sherpa-onnx.sln add <名称>+ 引用 Common 项目; - 排障:模型参数(采样率、帧移、线程数)以示例
Program.cs中的配置为准;流式场景务必使用FrameShiftInSamples并按需调用Flush();遇到包引用异常先执行dotnet nuget locals all --clear。
整套dotnet-examples的价值在于:它把 sherpa-onnx 的 C# API 按功能拆成了可独立编译运行的最小工程,每个目录自带"下载 + 运行"脚本,既可以作为 API 参考手册直接阅读,也可以作为脚手架快速拷贝出适合自己业务的 C# 语音处理程序。
【免费下载链接】sherpa-onnxSpeech-to-text, text-to-speech, speaker diarization, speech enhancement, source separation, and VAD using next-gen Kaldi with onnxruntime without Internet connection. Support embedded systems, Android, iOS, HarmonyOS, Raspberry Pi, RISC-V, RK NPU, Axera NPU, Ascend NPU, x86_64 servers, websocket server/client, support 12 programming languages项目地址: https://gitcode.com/GitHub_Trending/sh/sherpa-onnx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考