Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/c-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,41 @@ jobs:
otool -L ./install/lib/libsherpa-onnx-c-api.dylib
fi

- name: Test KittenTTS
shell: bash
run: |
name=kitten-tts-en-c-api
gcc -o $name ./c-api-examples/$name.c \
-I ./build/install/include \
-L ./build/install/lib/ \
-l sherpa-onnx-c-api \
-l onnxruntime

ls -lh $name

if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then
ldd ./$name
echo "----"
readelf -d ./$name
fi

curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
tar xf kitten-nano-en-v0_1-fp16.tar.bz2
rm kitten-nano-en-v0_1-fp16.tar.bz2

export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH

./$name

rm $name
rm -rf kitten-nano-en-v0_1-fp16

- uses: actions/upload-artifact@v4
with:
name: kitten-tts-wavs-${{ matrix.os }}
path: ./generated-kitten-en.wav

Comment on lines +88 to +122

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

Harden the KittenTTS CI step (fail fast, robust downloads, rpath, artifact existence)

  • Add set -euo pipefail so failures propagate.
  • Use curl -fSL to fail on HTTP errors.
  • Optionally embed rpath so LD/DYLD_LIBRARY_PATH isn’t required.
  • Verify the WAV exists before uploading.

Apply this diff within the step:

       - name: Test KittenTTS
         shell: bash
         run: |
-          name=kitten-tts-en-c-api
+          set -euo pipefail
+          name=kitten-tts-en-c-api
           gcc -o $name ./c-api-examples/$name.c \
             -I ./build/install/include \
             -L ./build/install/lib/ \
-            -l sherpa-onnx-c-api \
-            -l onnxruntime
+            -l sherpa-onnx-c-api \
+            -l onnxruntime \
+            -Wl,-rpath,'$ORIGIN/build/install/lib'
 
           ls -lh $name
 
           if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then
             ldd ./$name
             echo "----"
             readelf -d ./$name
           fi
 
-          curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
+          curl -fSL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
           tar xf kitten-nano-en-v0_1-fp16.tar.bz2
           rm kitten-nano-en-v0_1-fp16.tar.bz2
 
           export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
           export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH
 
           ./$name
+          test -f generated-kitten-en.wav
 
           rm $name
           rm -rf kitten-nano-en-v0_1-fp16

Note: If macOS fails due to $ORIGIN, replace it with @loader_path in the rpath flag for Darwin.


Harden the “Test KittenTTS” Bash step

Introduce early‐exit, strict shell flags, robust download checks, embedded rpath, and artifact validation:

  • Prepend set -euo pipefail at the top of the run: block to fail fast on any error or unset variable.
  • Switch curl -SL to curl -fSL so HTTP errors abort the script.
  • Add -Wl,-rpath,'$ORIGIN/build/install/lib' to the gcc command line (use @loader_path on macOS) to avoid relying on LD_LIBRARY_PATH/DYLD_LIBRARY_PATH.
  • After running the binary, verify the WAV was actually created with test -f generated-kitten-en.wav before uploading.
   - name: Test KittenTTS
     shell: bash
     run: |
+      set -euo pipefail
       name=kitten-tts-en-c-api
       gcc -o $name ./c-api-examples/$name.c \
         -I ./build/install/include \
         -L ./build/install/lib/ \
-        -l sherpa-onnx-c-api \
-        -l onnxruntime
+        -l sherpa-onnx-c-api \
+        -l onnxruntime \
+        -Wl,-rpath,'$ORIGIN/build/install/lib'

       ls -lh $name

       if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then
         ldd ./$name
         echo "----"
         readelf -d ./$name
       fi

-      curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
+      curl -fSL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
       tar xf kitten-nano-en-v0_1-fp16.tar.bz2
       rm kitten-nano-en-v0_1-fp16.tar.bz2

       export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
       export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH

       ./$name
+      test -f generated-kitten-en.wav

       rm $name
       rm -rf kitten-nano-en-v0_1-fp16

Note: On Darwin replace $ORIGIN with @loader_path in the rpath flag.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Test KittenTTS
shell: bash
run: |
name=kitten-tts-en-c-api
gcc -o $name ./c-api-examples/$name.c \
-I ./build/install/include \
-L ./build/install/lib/ \
-l sherpa-onnx-c-api \
-l onnxruntime
ls -lh $name
if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then
ldd ./$name
echo "----"
readelf -d ./$name
fi
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
tar xf kitten-nano-en-v0_1-fp16.tar.bz2
rm kitten-nano-en-v0_1-fp16.tar.bz2
export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH
./$name
rm $name
rm -rf kitten-nano-en-v0_1-fp16
- uses: actions/upload-artifact@v4
with:
name: kitten-tts-wavs-${{ matrix.os }}
path: ./generated-kitten-en.wav
- name: Test KittenTTS
shell: bash
run: |
set -euo pipefail
name=kitten-tts-en-c-api
gcc -o $name ./c-api-examples/$name.c \
-I ./build/install/include \
-L ./build/install/lib/ \
-l sherpa-onnx-c-api \
-l onnxruntime \
-Wl,-rpath,'$ORIGIN/build/install/lib'
ls -lh $name
if [[ ${{ matrix.os }} == ubuntu-latest || ${{ matrix.os }} == ubuntu-22.04-arm ]]; then
ldd ./$name
echo "----"
readelf -d ./$name
fi
curl -fSL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
tar xf kitten-nano-en-v0_1-fp16.tar.bz2
rm kitten-nano-en-v0_1-fp16.tar.bz2
export LD_LIBRARY_PATH=$PWD/build/install/lib:$LD_LIBRARY_PATH
export DYLD_LIBRARY_PATH=$PWD/build/install/lib:$DYLD_LIBRARY_PATH
./$name
test -f generated-kitten-en.wav
rm $name
rm -rf kitten-nano-en-v0_1-fp16
- uses: actions/upload-artifact@v4
with:
name: kitten-tts-wavs-${{ matrix.os }}
path: ./generated-kitten-en.wav
🤖 Prompt for AI Agents
In .github/workflows/c-api.yaml between lines 88 and 122, enhance the "Test
KittenTTS" bash step by adding `set -euo pipefail` at the start of the run block
to enable strict error handling and fail fast on unset variables. Modify the
curl command to use `curl -fSL` to ensure HTTP errors cause the script to abort.
Update the gcc command to include the rpath linker flag: use
`-Wl,-rpath,'$ORIGIN/build/install/lib'` on Linux and
`-Wl,-rpath,@loader_path/build/install/lib` on macOS to embed the library path
and avoid relying on environment variables. Finally, after executing the binary,
add a check with `test -f generated-kitten-en.wav` to confirm the WAV file was
created before uploading the artifact.

- name: Test streaming zipformer with homophone replacer
shell: bash
run: |
Expand Down
3 changes: 3 additions & 0 deletions c-api-examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ if(SHERPA_ONNX_ENABLE_TTS)
add_executable(kokoro-tts-en-c-api kokoro-tts-en-c-api.c)
target_link_libraries(kokoro-tts-en-c-api sherpa-onnx-c-api)

add_executable(kitten-tts-en-c-api kitten-tts-en-c-api.c)
target_link_libraries(kitten-tts-en-c-api sherpa-onnx-c-api)

add_executable(kokoro-tts-zh-en-c-api kokoro-tts-zh-en-c-api.c)
target_link_libraries(kokoro-tts-zh-en-c-api sherpa-onnx-c-api)
endif()
Expand Down
83 changes: 83 additions & 0 deletions c-api-examples/kitten-tts-en-c-api.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// c-api-examples/kitten-tts-en-c-api.c
//
// Copyright (c) 2025 Xiaomi Corporation

// This file shows how to use sherpa-onnx C API
// for English TTS with Kitten.
//
// clang-format off
/*
Usage

wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2
tar xf kitten-nano-en-v0_1-fp16.tar.bz2
rm kitten-nano-en-v0_1-fp16.tar.bz2

./kitten-tts-en-c-api

*/
// clang-format on

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sherpa-onnx/c-api/c-api.h"

static int32_t ProgressCallback(const float *samples, int32_t num_samples,
float progress) {
fprintf(stderr, "Progress: %.3f%%\n", progress * 100);
// return 1 to continue generating
// return 0 to stop generating
return 1;
}

int32_t main(int32_t argc, char *argv[]) {
SherpaOnnxOfflineTtsConfig config;
memset(&config, 0, sizeof(config));
config.model.kitten.model = "./kitten-nano-en-v0_1-fp16/model.fp16.onnx";
config.model.kitten.voices = "./kitten-nano-en-v0_1-fp16/voices.bin";
config.model.kitten.tokens = "./kitten-nano-en-v0_1-fp16/tokens.txt";
config.model.kitten.data_dir = "./kitten-nano-en-v0_1-fp16/espeak-ng-data";

config.model.num_threads = 2;

// If you don't want to see debug messages, please set it to 0
config.model.debug = 1;

Comment thread
coderabbitai[bot] marked this conversation as resolved.
const char *filename = "./generated-kitten-en.wav";
const char *text =
"Today as always, men fall into two groups: slaves and free men. Whoever "
"does not have two-thirds of his day for himself, is a slave, whatever "
"he may be: a statesman, a businessman, an official, or a scholar. "
"Friends fell out often because life was changing so fast. The easiest "
"thing in the world was to lose touch with someone.";

const SherpaOnnxOfflineTts *tts = SherpaOnnxCreateOfflineTts(&config);
// mapping of sid to voice name
// 0->af, 1->af_bella, 2->af_nicole, 3->af_sarah, 4->af_sky, 5->am_adam
// 6->am_michael, 7->bf_emma, 8->bf_isabella, 9->bm_george, 10->bm_lewis
int32_t sid = 0;
float speed = 1.0; // larger -> faster in speech speed

#if 0
// If you don't want to use a callback, then please enable this branch
const SherpaOnnxGeneratedAudio *audio =
SherpaOnnxOfflineTtsGenerate(tts, text, sid, speed);
#else
const SherpaOnnxGeneratedAudio *audio =
SherpaOnnxOfflineTtsGenerateWithProgressCallback(tts, text, sid, speed,
ProgressCallback);
#endif

SherpaOnnxWriteWave(audio->samples, audio->n, audio->sample_rate, filename);

SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio);
SherpaOnnxDestroyOfflineTts(tts);

fprintf(stderr, "Input text is: %s\n", text);
fprintf(stderr, "Speaker ID is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename);

return 0;
}
2 changes: 1 addition & 1 deletion c-api-examples/kokoro-tts-en-c-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ int32_t main(int32_t argc, char *argv[]) {
SherpaOnnxDestroyOfflineTts(tts);

fprintf(stderr, "Input text is: %s\n", text);
fprintf(stderr, "Speaker ID is is: %d\n", sid);
fprintf(stderr, "Speaker ID is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename);

return 0;
Expand Down
2 changes: 1 addition & 1 deletion c-api-examples/kokoro-tts-zh-en-c-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ int32_t main(int32_t argc, char *argv[]) {
SherpaOnnxDestroyOfflineTts(tts);

fprintf(stderr, "Input text is: %s\n", text);
fprintf(stderr, "Speaker ID is is: %d\n", sid);
fprintf(stderr, "Speaker ID is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename);

return 0;
Expand Down
2 changes: 1 addition & 1 deletion c-api-examples/matcha-tts-en-c-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ int32_t main(int32_t argc, char *argv[]) {
SherpaOnnxDestroyOfflineTts(tts);

fprintf(stderr, "Input text is: %s\n", text);
fprintf(stderr, "Speaker ID is is: %d\n", sid);
fprintf(stderr, "Speaker ID is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename);

return 0;
Expand Down
2 changes: 1 addition & 1 deletion c-api-examples/matcha-tts-zh-c-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ int32_t main(int32_t argc, char *argv[]) {
SherpaOnnxDestroyOfflineTts(tts);

fprintf(stderr, "Input text is: %s\n", text);
fprintf(stderr, "Speaker ID is is: %d\n", sid);
fprintf(stderr, "Speaker ID is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename);

return 0;
Expand Down
2 changes: 1 addition & 1 deletion c-api-examples/offline-tts-c-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ int32_t main(int32_t argc, char *argv[]) {
SherpaOnnxDestroyOfflineTts(tts);

fprintf(stderr, "Input text is: %s\n", text);
fprintf(stderr, "Speaker ID is is: %d\n", sid);
fprintf(stderr, "Speaker ID is: %d\n", sid);
fprintf(stderr, "Saved to: %s\n", filename);

free((void *)filename);
Expand Down
12 changes: 12 additions & 0 deletions sherpa-onnx/c-api/c-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,18 @@ static sherpa_onnx::OfflineTtsConfig GetOfflineTtsConfig(
SHERPA_ONNX_OR(config->model.kokoro.lexicon, "");
tts_config.model.kokoro.lang = SHERPA_ONNX_OR(config->model.kokoro.lang, "");

// kitten
tts_config.model.kitten.model =
SHERPA_ONNX_OR(config->model.kitten.model, "");
tts_config.model.kitten.voices =
SHERPA_ONNX_OR(config->model.kitten.voices, "");
tts_config.model.kitten.tokens =
SHERPA_ONNX_OR(config->model.kitten.tokens, "");
tts_config.model.kitten.data_dir =
SHERPA_ONNX_OR(config->model.kitten.data_dir, "");
tts_config.model.kitten.length_scale =
SHERPA_ONNX_OR(config->model.kitten.length_scale, 1.0);

Copilot AI Aug 8, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SHERPA_ONNX_OR macro is being used with a float value (1.0) as the default, but this macro appears to be designed for pointer/string checks based on its usage with string fields above. This may not work correctly for float values and could cause compilation errors or unexpected behavior.

Suggested change
SHERPA_ONNX_OR(config->model.kitten.length_scale, 1.0);
(config->model.kitten.length_scale != 0.0 ? config->model.kitten.length_scale : 1.0);

Copilot uses AI. Check for mistakes.

tts_config.model.num_threads = SHERPA_ONNX_OR(config->model.num_threads, 1);
tts_config.model.debug = config->model.debug;
tts_config.model.provider = SHERPA_ONNX_OR(config->model.provider, "cpu");
Expand Down
10 changes: 10 additions & 0 deletions sherpa-onnx/c-api/c-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1032,13 +1032,23 @@ SHERPA_ONNX_API typedef struct SherpaOnnxOfflineTtsKokoroModelConfig {
const char *lang;
} SherpaOnnxOfflineTtsKokoroModelConfig;

SHERPA_ONNX_API typedef struct SherpaOnnxOfflineTtsKittenModelConfig {
const char *model;
const char *voices;
const char *tokens;
const char *data_dir;

float length_scale; // < 1, faster in speech speed; > 1, slower in speed
} SherpaOnnxOfflineTtsKittenModelConfig;

SHERPA_ONNX_API typedef struct SherpaOnnxOfflineTtsModelConfig {
SherpaOnnxOfflineTtsVitsModelConfig vits;
int32_t num_threads;
int32_t debug;
const char *provider;
SherpaOnnxOfflineTtsMatchaModelConfig matcha;
SherpaOnnxOfflineTtsKokoroModelConfig kokoro;
SherpaOnnxOfflineTtsKittenModelConfig kitten;
} SherpaOnnxOfflineTtsModelConfig;

SHERPA_ONNX_API typedef struct SherpaOnnxOfflineTtsConfig {
Expand Down