导出库:C ABI、回调式流式与多语言示例

除了 CLI 和 HTTP 服务,s2.cpp 还可以作为库被其他语言/程序嵌入。s2_shared / s2_static 两个目标(见第 03 章)通过 s2_export_api.h 暴露一套 extern “C” 接口,759 行实现在 s2_export_api.cpp。本章说明这套 ABI 的设计约定、两类合成入口,以及 Python/C#/Go 示例。

1. 为什么需要专门的 C ABI

C++ 的 name mangling、类布局、异常机制跨编译器/跨语言都不稳定。直接导出 C++ 类意味着调用方必须用相同编译器、相同 STL,且一旦抛异常就可能直接崩溃。导出层的应对原则是:

  1. 不透明指针(opaque pointer):调用方只拿到 Pipeline*、GenerateParams* 等裸指针,所有对象由库内 new、由对应 Release delete,调用方不接触布局;
  2. 不跨边界抛异常:C ABI 函数全部 noexcept 边界,内部捕获后用整数返回码表达错误;
  3. 参数用 POD/基础类型:字符串用 const char*,配置用 C 风格 struct(S2StreamingParams)。

跨语言的 S2_Export 宏处理共享库符号可见性(Windows dllexport/import)。

2. Alloc / Release / Initialize 三件套

每个对象都遵循”分配 → 初始化 → 使用 → 释放”的固定生命周期,全部声明在头文件 :43-95:

对象 Alloc Initialize Release
Pipeline AllocS2Pipeline(:366) InitializeS2PipelineFromFiles(:395) ReleaseS2Pipeline
GenerateParams AllocS2GenerateParams InitializeS2GenerateParams(-1 表示保持默认) ReleaseS2GenerateParams
Model AllocS2Model(:440) InitializeS2ModelWithGpuLayers(:453) ReleaseS2Model
Tokenizer AllocS2Tokenizer InitializeS2Tokenizer ReleaseS2Tokenizer
AudioCodec AllocS2AudioCodec InitializeS2AudioCodecModelShared(:496) ReleaseS2AudioCodec
Prompt codes AllocS2AudioPromptCodes InitializeAudioPromptCodes(:524,一步完成编码) ReleaseS2AudioPromptCodes
Audio buffer AllocS2AudioBuffer — ReleaseS2AudioBuffer

一个工程细节:InitializeS2GenerateParams 等函数对每个字段用 -1 哨兵区分”未提供”与”显式设 0”(:58-65),只覆盖调用方真正指定的项,其余保留 C++ 侧默认值。整数后端码(-1/0/1/2)由 to_backend_type() 翻译回枚举,非法值一律落到 CPU。

3. S2Synthesize:一次性合成

S2Synthesize() 是一次性合成的统一入口,签名覆盖了全部输入方式。它接受三种参考来源(任选):

  • ReferenceAudioPath:现场编码参考音频文件(:597-602);
  • ReferenceAudioPromptCodes + ReferenceAudioTPrompt:调用方预先编好的码;
  • 两者都无:无参考默认音色。

输出也有两种去向:用户提供的 AudioBuffer(float 采样),和/或 OutputAudioPath(直接存成音频文件,:621-626)。

3.1 返回码约定

码 含义
1 成功
0 参数/管线无效(未初始化等)
-1 参考音频编码失败
-4 合成失败
-6 音频文件保存失败
-7 有参考音频/码但缺少参考转写(:590-592)
-8 提供了预置码但没有 T_prompt 指针(:593-595)

-7 和 -8 体现了克隆的硬约束:码必须与转写配对、长度必须可知,否则 prompt 无法构造。这些码让调用方能区分”输入问题”和”引擎内部失败”。

4. 回调式流式

流式不能用返回值(音频是持续产生的),于是导出层用回调集合 S2StreamingCallbacks:

on_wav_chunk(data, size, user_data)   每块音频(先 44 字节头,后 PCM16 块)
on_done(user_data)                    正常结束
on_error(message, user_data)          错误
is_cancelled(user_data)               调用方请求取消(返回非 0)

入口有两个:S2SynthesizeStreaming()(只传 stride)与 S2SynthesizeStreamingEx()(传完整的 S2StreamingParams:stride/holdback/context/low_latency/分句/voice)。前者只是包装后者。

4.1 CallbackStreamingSink

CallbackStreamingSink 是 Pipeline 与 C 回调之间的适配器:

  • on_header:直接把 44 字节 WAV 头作为第一个 chunk 推出(:289-291);
  • on_pcm_data:float → audio_to_pcm16,以 PCM16 字节推出(:283-287);
  • is_cancelled:每帧查询调用方回调,返回非 0 即令 Pipeline 中止;
  • chunk 尺寸钳在 int32 以内(:336-343),回调返回 0 被记为 aborted_by_callback。

这与 HTTP 的 HttpStreamSink 行为对齐,所以同一条流式管线能无差别地接三种出口。

4.2 voice-only 解析与分句

StreamingEx 比一次性函数多两段逻辑:

  • 仅凭 voice id 解析档案:当既无参考文件、也无预置码、但指定了 voice 时,调 resolve_prompt_reference 从 .s2voice 载入(:707-722),失败经 on_error 报错;
  • 分句合成:segment_sentences 开启时切句、逐段经 sink 拼接(:733-745)。

流式特有返回码:-9 缺少必需的 on_wav_chunk 回调(:665-667);-10 合成因取消而中止(:751-754),区别于 -4 的真失败。

5. 参数应用辅助

两个内部辅助函数把 C 结构翻译成 C++ 参数:

6. 多语言示例

仓库为三种语言提供了可直接参考的调用样例,全部基于这套 C ABI:

语言 示例文件 说明
Python ctypes_export_api.py 用标准库 ctypes 加载 libs2,无需任何第三方包
C# Program.cs、.csproj P/Invoke 声明结构体与回调
Go main.go、go.mod cgo 调用,含回调注册

Python 路径尤其能体现”零 Python 运行时依赖”的另一层含义:不是”用 Python 跑模型”,而是”Python 只当作调用方”通过 ctypes 驱动 C++ 引擎——计算仍全部发生在原生库中。

7. 全系列总结

至此,s2.cpp 的完整面貌已经展开:

  • 架构上,它以 11 行 token 矩阵统一文本与多码本音频,用带 KV cache 的 Slow-AR(36 层 4.13B)和无 cache 的 Fast-AR(4 层 0.42B)组成双 AR,再接卷积 codec(10×4096 RVQ,44.1 kHz,帧=2048 样本);
  • 工程上,它把权重放置(CUDA 留嵌入、Vulkan/Metal 可全卸载、按驱动上限切多 buffer)、图缓存(step 复用、prefill 分块、codec 按帧数缓存 fused 图)、流式窗口(stride/holdback/context 三参数)等问题都给出了显式而鲁棒的处理;
  • 交付上,CLI、单端点 HTTP 服务、C ABI 三种形态覆盖了本地使用、网络服务和语言嵌入三类场景。

它仍是一个标注 alpha、不承诺稳定的社区项目,且权重商业使用需另行授权——但作为”如何用纯 C++/ggml 完整落地一个现代 Dual-AR TTS 模型”的参考,其代码组织和工程取舍都值得细读。

关键文件

位置 职责
include/s2_export_api.h C ABI 全部声明
s2_export_api.cpp:278 CallbackStreamingSink
s2_export_api.cpp:395 从文件初始化 Pipeline
s2_export_api.cpp:561 S2Synthesize
s2_export_api.cpp:653 S2SynthesizeStreamingEx
examples/python/ctypes_export_api.py Python ctypes 示例

This site uses Just the Docs, a documentation theme for Jekyll.