基于 sherpa-onnx 与 Lazarus 开发离线字幕生成工具:VAD + 离线 ASR 全流程实战

基于 sherpa-onnx 与 Lazarus 开发离线字幕生成工具:VAD + 离线 ASR 全流程实战 基于 sherpa-onnx 与 Lazarus 开发离线字幕生成工具VAD 离线 ASR 全流程实战【免费下载链接】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本指南以仓库中 lazarus-examples/generate_subtitles 示例工程为核心讲解如何用 Lazarus IDE 与 Object Pascal 语言调用 sherpa-onnx 的 Pascal API构建一个选择一段 16kHz 单声道 wav 音频 → 自动切分语音片段 → 离线识别 → 输出带时间戳字幕文本的桌面 GUI 应用。读完本文你将掌握该工程的目录结构与构建模式、七种离线 ASR 模型的自动探测与装载方式、Silero VAD 的参数语义与默认值以及后台线程 GUI 界面协同的完整实现思路。一、工程定位Lazarus 生态中的字幕生成示例在 sherpa-onnx 仓库中lazarus-examples 目录集中展示了如何使用 Lazarus IDE 与 Object Pascal API 开发语音相关应用而generate_subtitles是该目录下唯一一个面向字幕生成场景的完整可编译工程。其技术路线非常清晰VAD语音活动检测负责把长音频切分成一个个语音片段离线识别器负责把每个片段转写为文字再利用 VAD 返回的起止采样点换算成时间戳最终得到逐行开始时间 -- 结束时间 文本的字幕式输出。整个过程完全离线运行CPU 推理不依赖网络连接这也是 sherpa-onnx 项目一贯的定位——使用 next-gen Kaldi 与 onnxruntime 在本地完成语音转文字、文字转语音、说话人分离、语音增强、音源分离与 VAD 等任务并支持 Android、iOS、HarmonyOS、Raspberry Pi、x86_64 服务器等多种平台与十余种编程语言。本示例对应的底层语言绑定是 sherpa-onnx/pascal-api/sherpa_onnx.pas全部对外能力都由这一份 Object Pascal 单元提供。二、工程文件结构每个单元负责什么generate_subtitles目录共包含 8 个文件职责划分如下文件职责generate_subtitles.lprLazarus 工程主程序program 入口负责初始化 LCL 窗体并创建主窗体Form1generate_subtitles.lpi工程配置文件定义了四个构建模式Default / Debug / Release / Release-Linux及库搜索路径unit1.pas主窗体逻辑按钮事件、文件选择、进度刷新、结果展示、资源路径定位unit1.lfm窗体布局描述按钮、编辑框、进度条、结果多行文本框的坐标与尺寸my_init.pasTMyInitThread初始化线程探测并装载 VAD 与离线识别器模型my_worker.pasTMyWorkerThread工作线程读取 wav、VAD 切分、逐段识别、回报进度与结果generate_subtitles.ico应用程序图标README.md构建说明与开发者注意事项工程依赖LCLLazarus Component Library组件包generate_subtitles.lpi的RequiredPackages一节对此有明确声明。主程序 generate_subtitles.lpr 的写法是标准 LCL 应用骨架在 UNIX 平台启用cthreads与cmem多线程应用必需随后Application.Initialize、创建Form1并进入消息循环。三、构建方法静态库与共享库两种模式原文档README.md对开发者给出的关键注意事项是默认情况下Linux 与 macOS 使用静态库链接如需改用共享库需要在 Lazarus IDE 中打开Project → Project options → Compiler options将Build modes切换为Release-Linux。从 generate_subtitles.lpi 可以看到这四个构建模式的具体差异Default / Debug / Release默认链接方案。库搜索路径为..\..\build-static\install\lib;..\..\build\install\lib即优先使用仓库根目录下build-static构建产物中的静态库。Release-Linux与前三个模式的唯一代码差异在于Other节中的CustomOptions为-dSHERPA_ONNX_USE_SHARED_LIBS——这是一个传给 Free Pascal 编译器的宏定义Pascal API 单元 sherpa_onnx.pas 会依据该宏决定加载静态库还是动态共享库。此外工程通过OtherUnitFiles指定了..\..\sherpa-onnx\pascal-api作为 Object Pascal 单元搜索路径这意味着你的 sherpa-onnx 构建产物build或build-static目录下的库与 pascal-api 目录必须相对工程目录保持../..的层级关系即遵循仓库默认的目录布局。Debug 模式还额外开启了 IO、Range、Overflow、Stack 四类运行时检查便于开发期定位越界等问题Release 与 Release-Linux 则启用OptimizationLevel3并剥离符号追求运行性能与体积。四、模型准备下载后必须按规范重命名工程通过固定文件名探测的方式装载模型初始化线程把模型目录中是否存在特定文件作为选择识别器类型的依据。因此下载模型后必须严格按照下表重命名否则对应的识别器不会被选中。模型文件必须存在于模型目录对应识别器备注silero_vad.onnxSilero VAD必需缺失则直接报错退出tokens.txt词表所有识别器共用必需缺失则提示先下载 ASR 模型whisper-encoder.onnxwhisper-decoder.onnxWhisper优先级最高同时存在即被选中sense-voice.onnxSenseVoice第二优先级paraformer.onnxParaformer第三优先级telespeech.onnxTeleSpeech CTC第四优先级transducer-encoder.onnxtransducer-decoder.onnxtransducer-joiner.onnxZipformer transducericefall第五优先级nemo-transducer-encoder.onnxnemo-transducer-decoder.onnxnemo-transducer-joiner.onnxNeMo transducer第六优先级moonshine-preprocessor.onnxmoonshine-encoder.onnxmoonshine-uncached-decoder.onnxmoonshine-cached-decoder.onnxMoonshine第七优先级各模型在 my_init.pas 中都有对应的重命名示例注释例如 Whisper 下载后需要mv tiny.en-tokens.txt tokens.txt mv tiny.en-encoder.onnx whisper-encoder.onnx mv tiny.en-decoder.onnx whisper-decoder.onnx # 或使用 int8 量化版 mv tiny.en-encoder.int8.onnx whisper-encoder.onnx mv tiny.en-decoder.int8.onnx whisper-decoder.onnxSenseVoice 需要mv model.onnx sense-voice.onnx或mv model.int8.onnx sense-voice.onnxParaformer 需要cp model.onnx paraformer.onnx或 int8 版TeleSpeech 需要mv model.onnx telespeech.onnxMoonshine 需要分别把 preprocess / encode / uncached_decode / cached_decode 重命名为moonshine-preprocessor.onnx、moonshine-encoder.onnx、moonshine-uncached-decoder.onnx、moonshine-cached-decoder.onnx。模型目录的默认位置在非 macOS 平台是程序运行目录./在 macOS 上则是应用 Bundle 的资源目录见下文。五、源码核心流程解析5.1 初始化线程VAD 与识别器的装载my_init.pas 定义了TMyInitThread它在后台线程中完成模型装载避免阻塞 GUI。其Execute的执行顺序是拼接各模型文件的完整路径模型目录 固定文件名校验silero_vad.onnx是否存在不存在则通过Synchronize(ShowStatus)回到主线程提示错误并退出创建 VADForm1.Vad : CreateVad(...)校验tokens.txt是否存在按 5.4 节所述的优先级顺序探测识别器模型命中即调用对应的工厂函数创建TSherpaOnnxOfflineRecognizer并记录命中模型名称如Whisper、SenseVoice、Zipformer transducer、NeMo transducer、Moonshine通过Synchronize在主线程提示模型初始化成功。所有Synchronize(ShowStatus)的用法都是 Free Pascal 多线程编程中子线程更新主线程 GUI的标准模式ShowStatus内部调用Form1.UpdateInitStatus。5.2 工作线程wav 读取、VAD 切分、离线识别my_worker.pas 是字幕生成的核心流水线TMyWorkerThread.Execute的流程为读 wav调用SherpaOnnxReadWave读取文件为TSherpaOnnxWave若采样数为空或采样率不为 16000则报错退出。注意SherpaOnnxReadWave在 sherpa_onnx.pas 中是对 C 接口SherpaOnnxReadWave的封装。计算总时长TotalDuration : Length(Wave.Samples) / Wave.SampleRate。VAD 切分主循环以WindowSize512 个采样点为步长调用Form1.Vad.AcceptWaveform(Wave.Samples, Offset, WindowSize)逐块喂入音频每累积 20480 个采样点约 1.28 秒通过Synchronize(ShowProgress)刷新一次进度条。取出语音片段当Form1.Vad.IsEmpty为假时Form1.Vad.Front取出队首的TSherpaOnnxSpeechSegment内含Samples与Start起始采样点Pop弹出。离线识别Form1.OfflineRecognizer.CreateStream创建流Stream.AcceptWaveform(SpeechSegment.Samples, Wave.SampleRate)喂入片段Decode(Stream)解码GetResult(Stream)取回RecognitionResult结构体定义见 sherpa_onnx.pas 中TSherpaOnnxOfflineRecognizerResult包含Text、Tokens、Timestamps字段。换算时间戳StartTime : SpeechSegment.Start / Wave.SampleRateDuration : Length(SpeechSegment.Samples) / Wave.SampleRateStopTime : StartTime Duration然后把RecognitionResult.Text与起止时间一起Synchronize(ShowStatus)送回主线程展示。收尾循环结束后调用Form1.Vad.Flush把 VAD 内部缓冲区残留的尾部语音也取出识别一遍最后输出DONE!若线程被终止则输出Cancelled!。这里值得注意的是边切分边识别的在线式处理VAD 片段一旦产生就立即送入离线识别器而不是等整段音频切分完毕再统一识别这在长音频场景下能显著降低峰值内存占用。5.3 主窗体交互与结果展示unit1.pas 定义了TForm1其关键行为包括界面控件与 unit1.lfm 对应InitBtn初始化模型按钮、SelectFileBtnFileNameEdt选择/显示 wav 文件、StartBtn开始/停止点击后标题在Start与Stop间切换、ResultMemo结果多行文本、ProgressBarProgressLabel进度展示。输入约束窗体创建时在结果区提示两条硬性限制——仅支持 1 通道、16 位、16000Hz 的 wav 文件、文件路径中不能包含中文字符这是为了规避 Windows/跨平台路径编码问题源码注释与提示语均有体现。SelectFileDlg的文件过滤器也被设为All Files|*.wav。Start 按钮状态机FileNameEdtChange中检查文件是否存在来决定StartBtn是否可用点击Start时若正处于运行中则Terminate工作线程否则清空结果区、重置进度条并创建TMyWorkerThread。结果格式化UpdateResult把非结束类消息格式化为%.3f -- %.3f %s开始秒 -- 结束秒 文本而DONE!、Cancelled!以及各类错误消息则原样显示UpdateProgress按StopTime / TotalDuration * 100计算百分比并刷新进度条。资源路径处理在 macOSDARWIN宏下通过 Objective-C 桥接调用NSBundle.mainBundle.resourcePath获取应用资源目录作为模型目录其他平台则使用./。这一逻辑体现了跨平台 GUI 应用打包资源时的常见差异处理。窗体关闭清理FormClose中先终止并WaitFor工作线程再FreeAndNil释放 VAD 与识别器保证退出时无悬挂线程与内存泄漏。5.4 识别器工厂函数与优先级my_init.pas 提供了 7 个工厂函数统一通过Initialize(Config)Pascal 记录类型的class operator Initialize见 sherpa_onnx.pas初始化配置结构再调用TSherpaOnnxOfflineRecognizer.Create(Config)创建实例CreateOfflineRecognizerTransducer配置ModelConfig.Transducer.Encoder/Decoder/JoinerModelType参数分别为transducerZipformer或nemo_transducerNeMoCreateOfflineRecognizerTeleSpeech配置ModelConfig.TeleSpeechCtcCreateOfflineRecognizerParaformer配置ModelConfig.Paraformer.ModelCreateOfflineRecognizerSenseVoice配置ModelConfig.SenseVoice.Model并额外设置Language : auto自动语言识别与UseItn : True开启逆文本正则化把数字、日期等口语表达还原为书面形式CreateOfflineRecognizerWhisper配置ModelConfig.Whisper.Encoder/DecoderCreateOfflineRecognizerMoonshine配置ModelConfig.Moonshine.Preprocessor/Encoder/UncachedDecoder/CachedDecoder。这些配置字段在 sherpa_onnx.pas 的TSherpaOnnxOfflineModelConfig记录中有完整定义除上述模型外还预留了 NeMoCtc、Tdnn、ZipformerCtc、Canary、WenetCtc、Omnilingual、MedAsr、FunAsrNano、FireRedAsr(Ctc)、Qwen3Asr、CohereTranscribe 等更多模型族说明该 Pascal API 的覆盖面与 Python/C 接口保持一致。所有工厂函数统一设置Provider : cpu、NumThreads : 2即纯 CPU 双线程推理。六、Silero VAD 参数详解含义、默认值与调优建议CreateVadmy_init.pas是 VAD 配置的权威示例它与 sherpa_onnx.pas 中TSherpaOnnxSileroVadModelConfig.Initialize给出的默认值完全一致参数示例值 / 默认值含义与调优方向SileroVad.Modelsilero_vad.onnx路径Silero VAD 模型文件sherpa_onnx.pas 中TSherpaOnnxVadModelConfig同时支持SileroVad与TenVad两套子配置本工程使用前者SileroVad.MinSpeechDuration0.25秒最短语音时长短于此的片段视为噪声被丢弃SileroVad.MinSilenceDuration0.5秒最短静音时长决定两个语音片段之间的切断间隔SileroVad.MaxSpeechDuration5.0秒单片段最大语音时长超长语音会被强制切分避免单次离线解码的输入过长SileroVad.Threshold0.5VAD 判定阈值调低更灵敏更易检测到语音、调高更保守SileroVad.WindowSize512采样点滑窗步长源码注释明确提示除非清楚原理否则不要修改与 16kHz 采样率配套SampleRate16000VAD 输入采样率同样被注释锁定NumThreads2VAD 推理线程数Providercpu推理后端本工程固定为 CPUTSherpaOnnxVoiceActivityDetector.Create(Config, 30)的第二个参数30表示内部环形缓冲区的时长上限为 30 秒即 VAD 内部最多缓存 30 秒的未决音频超出后必然产出片段。工程实际使用中建议按需调整MinSilenceDuration字幕场景若希望句子更连贯少切碎可适当调大该值若希望字幕行更短更紧凑则调小。七、运行与使用要点输入音频必须是 1 通道、16 位 PCM、16000Hz 的 wav 文件路径不得包含中文字符测试阶段可以使用仓库发布包中的示例音频如中英文测试 wav。操作流程启动程序 → 点击Click me to initialize models before you start等待模型装载成功 → 点击Select a file...选择 wav → 点击Start开始生成字幕。运行中按钮变为Stop可随时终止进度条与百分比随处理进度实时刷新。输出格式结果区逐行输出开始秒 -- 结束秒 识别文本例如1.230 -- 2.450 你好世界可直接作为生成 srt/ass 字幕文件的中间数据识别器返回的Timestamps字段还保留了词级时间戳若需要更细粒度的时间对齐可在此基础上进一步加工。模型目录非 macOS 平台把模型文件放在程序运行目录下./macOS 平台需把模型放入 .app Bundle 的 Resources 目录程序会自动定位。构建产物选择Linux/macOS 默认静态链接如需动态链接共享库在 Lazarus IDE 中把 Build Mode 切换到Release-Linux其宏SHERPA_ONNX_USE_SHARED_LIBS定义于 generate_subtitles.lpi。八、总结generate_subtitles是理解Lazarus Object Pascal sherpa-onnx组合的极佳范本它把 VAD 切分、离线识别、多线程 GUI 协作、跨平台资源路径处理与多模型自动探测完整地串联在一起。对希望用 Free Pascal 生态构建桌面语音工具的开发者而言本文所梳理的构建模式静态/共享库切换、模型重命名规范、TSherpaOnnxVadModelConfig参数语义以及TSherpaOnnxOfflineRecognizer的使用流程可以直接迁移到自己的项目中更底层的接口声明则可随时回到 sherpa-onnx/pascal-api/sherpa_onnx.pas 中查阅其中每个配置记录都带有ToString与默认值初始化实现便于调试时打印验证配置是否正确生效。【免费下载链接】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),仅供参考