This directory contains a modernized C# example for the current exported s2.cpp library API.
S2ExportApiExample.csproj: minimal .NET console projectProgram.cs: P/Invoke bindings for every current exported function plus sample flows
The sample supports five modes:
smoke: validates that the exported symbols can be loaded and basic allocators workfrom-files: initializes the pipeline directly withInitializeS2PipelineFromFiles()and runs one-shot synthesismodular: mirrors the original SubSpecs design by creating tokenizer/model/codec separately, syncing tokenizer config from the model, binding them into a reusable pipeline, optionally precomputing prompt codes, and synthesizinglegacy-stream: demonstratesS2SynthesizeStreaming()stream-ex: demonstratesS2SynthesizeStreamingEx()with the current extended options such as low latency, sentence segmentation, and.s2voice
One-shot modular flow close to the original idea:
dotnet run --project examples/csharp/S2ExportApiExample.csproj -- \
--mode modular \
--library build-vulkan/libs2.so \
--model /path/to/s2-pro-q2_K.gguf \
--tokenizer /path/to/tokenizer.json \
--backend vulkan \
--gpu-device 0 \
--threads 8 \
--reference-audio /path/to/reference.wav \
--reference-text "Transcript of the reference audio." \
--text "Hello from the modular C# example." \
--output /tmp/s2_csharp_modular.wavStreaming with the current extended API, using a saved .s2voice profile:
dotnet run --project examples/csharp/S2ExportApiExample.csproj -- \
--mode stream-ex \
--library build-vulkan/libs2.so \
--model /path/to/s2-pro-q2_K.gguf \
--tokenizer /path/to/tokenizer.json \
--backend vulkan \
--gpu-device 0 \
--threads 8 \
--text "First sentence. Second, longer sentence to confirm the pause." \
--segment-sentences \
--sentence-pause-ms 180 \
--voice /path/to/voices/hope.s2voice \
--output /tmp/s2_csharp_stream.wav \
--log-level infoWhat stayed the same:
- The example still treats
Pipeline,Tokenizer,Model,AudioCodec, prompt codes, and audio buffers as opaque handles owned by the native library. - The modular flow is still first-class: load the components separately, synchronize tokenizer config from the model, bind them into a pipeline, and reuse precomputed prompt codes.
- The C# side still maps well to
DllImportand pointer-style FFI usage rather than requiring a pure-C header redesign.
What changed in the updated example:
- The sample now binds every current export, not just the original one-shot subset.
- Error handling reflects the current return codes instead of the older
-2/-3/-5assumptions from the early sample. - A runtime library-path resolver replaced the original hardcoded DLL path, so the example can load
libs2.so,s2.dll, orlibs2.dylibfrom a command-line argument. InitializeS2PipelineFromFiles()is covered as a convenience path in addition to the original modular path.- The new example covers
S2SynthesizeStreaming()andS2SynthesizeStreamingEx(), including low-latency streaming, sentence segmentation, and saved.s2voiceloading.
What is still intentionally not "pure C":
- Handles are still modeled as opaque native objects owned by the C++ library, which matches the original intent.
- The example is designed for practical C# /
DllImportinterop, not for compiling the public header as strict C.