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
6 changes: 6 additions & 0 deletions .github/workflows/pascal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ jobs:
ls -lh
echo "---"

./run-supertonic-en.sh
rm -rf sherpa-onnx-supertonic-*
rm supertonic-en
ls -lh
echo "---"

popd

- uses: actions/upload-artifact@v4
Expand Down
1 change: 1 addition & 0 deletions pascal-api-examples/tts/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ kitten-en-playback
kokoro-zh-en
kokoro-zh-en-playback
pocket-en
supertonic-en

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

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

The example script downloads and extracts a sherpa-onnx-supertonic-tts-* model directory under pascal-api-examples/tts/. Consider ignoring that extracted directory pattern as well to reduce the chance of accidentally committing large model artifacts (similar to how other example assets are typically handled).

Suggested change
supertonic-en
supertonic-en
sherpa-onnx-supertonic-tts-*

Copilot uses AI. Check for mistakes.
43 changes: 43 additions & 0 deletions pascal-api-examples/tts/run-supertonic-en.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash

set -ex

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
SHERPA_ONNX_DIR=$(cd $SCRIPT_DIR/../.. && pwd)
Comment on lines +5 to +6

Copilot AI Mar 11, 2026

Copy link

Choose a reason for hiding this comment

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

Quote variable expansions to avoid word-splitting/globbing issues if the repository path contains spaces (e.g., cd \"$SCRIPT_DIR/../..\").

Copilot uses AI. Check for mistakes.

echo "SHERPA_ONNX_DIR: $SHERPA_ONNX_DIR"

if [[ ! -f ../../build/install/lib/libsherpa-onnx-c-api.dylib && ! -f ../../build/install/lib/libsherpa-onnx-c-api.so && ! -f ../../build/install/lib/sherpa-onnx-c-api.dll ]]; then
mkdir -p ../../build
pushd ../../build
cmake \
-DCMAKE_INSTALL_PREFIX=./install \
-DSHERPA_ONNX_ENABLE_PYTHON=OFF \
-DSHERPA_ONNX_ENABLE_TESTS=OFF \
-DSHERPA_ONNX_ENABLE_CHECK=OFF \
-DBUILD_SHARED_LIBS=ON \
-DSHERPA_ONNX_ENABLE_PORTAUDIO=OFF \
..

cmake --build . --target install --config Release
popd
fi

# please visit
# https://k2-fsa.github.io/sherpa/onnx/tts/supertonic.html
if [ ! -f ./sherpa-onnx-supertonic-tts-int8-2026-03-06/duration_predictor.int8.onnx ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
tar xvf sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
rm sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
Comment on lines +29 to +31

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "run-supertonic-en.sh" -type f

Repository: k2-fsa/sherpa-onnx

Length of output: 108


🏁 Script executed:

sed -n '29,31p' ./pascal-api-examples/tts/run-supertonic-en.sh

Repository: k2-fsa/sherpa-onnx

Length of output: 310


🌐 Web query:

curl -S flag behavior HTTP errors silent error handling

💡 Result:

  • -s, --silent hides the progress meter and error messages (but still prints the response body unless you redirect it). [1]
  • -S, --show-error only matters when combined with -s: it re-enables printing an error message if curl fails. [1]
  • By default, HTTP 4xx/5xx are not “curl errors”—curl can return exit code 0 even for 404/500 if the transfer succeeded. [2]
  • To make HTTP 4xx/5xx produce a non-zero exit code, use -f, --fail (or --fail-with-body). [2] When curl exits non-zero it prints an error message unless --silent is used (and -sS is the common combo to stay quiet except on errors). [3]

Common “silent but fail on HTTP errors” pattern:

curl -fsS https://example.com/resource

Sources: [1] curl man page (-s / -S) [2] curl FAQ on HTTP non-200 behavior and -f [3] everything.curl.dev on exit codes and --silent suppressing error output.


🌐 Web query:

curl --fail flag HTTP error codes differences

💡 Result:

  • By default, curl returns exit code 0 even if the server replies with an HTTP error status (e.g., 404, 401). curl treats that as a successful transfer unless you tell it otherwise. [1]
  • -f, --fail: for HTTP status codes ≥ 400, curl exits non‑zero (specifically exit code 22) and suppresses the response body (“no output at all”); intended for scripts. Note: some non-success codes can “slip through,” especially with 401/407 in some auth scenarios. [2]
  • --fail-with-body: same fail condition (HTTP ≥ 400) and exit code 22, but still outputs/saves the response body, which is useful for error details (JSON/HTML). [2]

So the key difference is: --fail hides the body; --fail-with-body keeps it—both fail on HTTP ≥ 400 with exit code 22. [2]


Harden model download: fail fast and bound network retries/timeouts.

The current curl -SL -O silently accepts HTTP errors (curl returns exit code 0 for 4xx/5xx responses by default) and has no retry/timeout limits, making downloads brittle in CI environments.

The proposed hardening adds:

  • --fail: exits non-zero on HTTP errors (≥400)
  • --retry 3 --retry-delay 2: retries transient failures
  • --connect-timeout 30 --max-time 1200: bounds network delays and total execution time
🛡️ Proposed hardening
-  curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
+  curl --fail --show-error --location \
+    --retry 3 --retry-delay 2 --connect-timeout 30 --max-time 1200 \
+    -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
📝 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
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
tar xvf sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
rm sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
curl --fail --show-error --location \
--retry 3 --retry-delay 2 --connect-timeout 30 --max-time 1200 \
-O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
tar xvf sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
rm sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pascal-api-examples/tts/run-supertonic-en.sh` around lines 29 - 31, Replace
the existing curl invocation "curl -SL -O
https://github.com/...sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2" with a
hardened curl command that fails on HTTP errors and bounds retries/timeouts
(e.g., add --fail --show-error --retry 3 --retry-delay 2 --connect-timeout 30
--max-time 1200) so the download exits non-zero on 4xx/5xx, retries transient
failures, and limits connection/total time; ensure the script still removes and
extracts the same tar file if the download succeeds.

fi
Comment on lines +28 to +32

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The model name sherpa-onnx-supertonic-tts-int8-2026-03-06 is hardcoded and repeated multiple times. To improve maintainability and make it easier to update the model version in the future, consider defining it as a variable.

Suggested change
if [ ! -f ./sherpa-onnx-supertonic-tts-int8-2026-03-06/duration_predictor.int8.onnx ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
tar xvf sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
rm sherpa-onnx-supertonic-tts-int8-2026-03-06.tar.bz2
fi
MODEL_DIR="sherpa-onnx-supertonic-tts-int8-2026-03-06"
if [ ! -f ./$MODEL_DIR/duration_predictor.int8.onnx ]; then
curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/$MODEL_DIR.tar.bz2
tar xvf $MODEL_DIR.tar.bz2
rm $MODEL_DIR.tar.bz2
fi


fpc \
-dSHERPA_ONNX_USE_SHARED_LIBS \
-Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
-Fl$SHERPA_ONNX_DIR/build/install/lib \
./supertonic-en.pas

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

./supertonic-en
63 changes: 63 additions & 0 deletions pascal-api-examples/tts/supertonic-en.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{ Copyright (c) 2026 Xiaomi Corporation }
program supertonic_en;
{
This file shows how to use the text to speech API of sherpa-onnx
with Supertonic TTS models.

It generates speech from text and saves it to a wave file.

Please visit
https://k2-fsa.github.io/sherpa/onnx/tts/supertonic.html
to download the model.
}

{$mode objfpc}

uses
SysUtils,
sherpa_onnx;

function GetOfflineTts: TSherpaOnnxOfflineTts;
var
Config: TSherpaOnnxOfflineTtsConfig;
begin
Config.Model.Supertonic.DurationPredictor := './sherpa-onnx-supertonic-tts-int8-2026-03-06/duration_predictor.int8.onnx';
Config.Model.Supertonic.TextEncoder := './sherpa-onnx-supertonic-tts-int8-2026-03-06/text_encoder.int8.onnx';
Config.Model.Supertonic.VectorEstimator := './sherpa-onnx-supertonic-tts-int8-2026-03-06/vector_estimator.int8.onnx';
Config.Model.Supertonic.Vocoder := './sherpa-onnx-supertonic-tts-int8-2026-03-06/vocoder.int8.onnx';
Config.Model.Supertonic.TtsJson := './sherpa-onnx-supertonic-tts-int8-2026-03-06/tts.json';
Config.Model.Supertonic.UnicodeIndexer := './sherpa-onnx-supertonic-tts-int8-2026-03-06/unicode_indexer.bin';
Config.Model.Supertonic.VoiceStyle := './sherpa-onnx-supertonic-tts-int8-2026-03-06/voice.bin';
Config.Model.NumThreads := 2;
Config.Model.Debug := True;
Config.MaxNumSentences := 1;
Comment on lines +21 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The model directory path './sherpa-onnx-supertonic-tts-int8-2026-03-06/' is hardcoded and repeated multiple times. To improve maintainability and make it easier to update the model version, you could define it as a constant and reuse it.

const
  ModelDir = './sherpa-onnx-supertonic-tts-int8-2026-03-06/';
var
  Config: TSherpaOnnxOfflineTtsConfig;
begin
  Config.Model.Supertonic.DurationPredictor := ModelDir + 'duration_predictor.int8.onnx';
  Config.Model.Supertonic.TextEncoder := ModelDir + 'text_encoder.int8.onnx';
  Config.Model.Supertonic.VectorEstimator := ModelDir + 'vector_estimator.int8.onnx';
  Config.Model.Supertonic.Vocoder := ModelDir + 'vocoder.int8.onnx';
  Config.Model.Supertonic.TtsJson := ModelDir + 'tts.json';
  Config.Model.Supertonic.UnicodeIndexer := ModelDir + 'unicode_indexer.bin';
  Config.Model.Supertonic.VoiceStyle := ModelDir + 'voice.bin';
  Config.Model.NumThreads := 2;
  Config.Model.Debug := True;
  Config.MaxNumSentences := 1;


Result := TSherpaOnnxOfflineTts.Create(Config);
end;

var
Tts: TSherpaOnnxOfflineTts;
GenerationConfig: TSherpaOnnxGenerationConfig;
Audio: TSherpaOnnxGeneratedAudio;
Text: AnsiString;

begin
Tts := GetOfflineTts;

WriteLn('There are ', Tts.GetNumSpeakers, ' speakers');

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.';

GenerationConfig.Sid := 6;
GenerationConfig.NumSteps := 5;
GenerationConfig.Speed := 1.25;
GenerationConfig.Extra := '{"lang": "en"}';

Audio := Tts.Generate(Text, GenerationConfig, NIL, NIL);
SherpaOnnxWriteWave('./supertonic-tts-en.wav', Audio.Samples, Audio.SampleRate);
WriteLn('Saved to ./supertonic-tts-en.wav');

FreeAndNil(Tts);
end.
52 changes: 50 additions & 2 deletions sherpa-onnx/pascal-api/sherpa_onnx.pas
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ TSherpaOnnxOfflineTtsPocketModelConfig = record
class operator Initialize({$IFDEF FPC}var{$ELSE}out{$ENDIF} Dest: TSherpaOnnxOfflineTtsPocketModelConfig);
end;

TSherpaOnnxOfflineTtsSupertonicModelConfig = record
DurationPredictor: AnsiString;
TextEncoder: AnsiString;
VectorEstimator: AnsiString;
Vocoder: AnsiString;
TtsJson: AnsiString;
UnicodeIndexer: AnsiString;
VoiceStyle: AnsiString;

function ToString: AnsiString;
end;

TSherpaOnnxOfflineTtsModelConfig = record
Vits: TSherpaOnnxOfflineTtsVitsModelConfig;
NumThreads: Integer;
Expand All @@ -160,6 +172,7 @@ TSherpaOnnxOfflineTtsModelConfig = record
Kitten: TSherpaOnnxOfflineTtsKittenModelConfig;
ZipVoice: TSherpaOnnxOfflineTtsZipVoiceModelConfig;
Pocket: TSherpaOnnxOfflineTtsPocketModelConfig;
Supertonic: TSherpaOnnxOfflineTtsSupertonicModelConfig;

function ToString: AnsiString;
class operator Initialize({$IFDEF FPC}var{$ELSE}out{$ENDIF} Dest: TSherpaOnnxOfflineTtsModelConfig);
Expand Down Expand Up @@ -1120,6 +1133,16 @@ SherpaOnnxOfflineTtsPocketModelConfig = record
VoiceEmbeddingCacheCapacity: cint32;
end;

SherpaOnnxOfflineTtsSupertonicModelConfig = record
DurationPredictor: PAnsiChar;
TextEncoder: PAnsiChar;
VectorEstimator: PAnsiChar;
Vocoder: PAnsiChar;
TtsJson: PAnsiChar;
UnicodeIndexer: PAnsiChar;
VoiceStyle: PAnsiChar;
end;

SherpaOnnxOfflineTtsModelConfig = record
Vits: SherpaOnnxOfflineTtsVitsModelConfig;
NumThreads: cint32;
Expand All @@ -1130,6 +1153,7 @@ SherpaOnnxOfflineTtsModelConfig = record
Kitten: SherpaOnnxOfflineTtsKittenModelConfig;
ZipVoice: SherpaOnnxOfflineTtsZipVoiceModelConfig;
Pocket: SherpaOnnxOfflineTtsPocketModelConfig;
Supertonic: SherpaOnnxOfflineTtsSupertonicModelConfig;
end;

SherpaOnnxOfflineTtsConfig = record
Expand Down Expand Up @@ -2686,6 +2710,21 @@ function TSherpaOnnxOfflineTtsPocketModelConfig.ToString: AnsiString;
Self.VocabJson, Self.TokenScoresJson, Self.VoiceEmbeddingCacheCapacity]);
end;

function TSherpaOnnxOfflineTtsSupertonicModelConfig.ToString: AnsiString;
begin
Result := Format('TSherpaOnnxOfflineTtsSupertonicModelConfig(' +
'DurationPredictor := %s, ' +
'TextEncoder := %s, ' +
'VectorEstimator := %s, ' +
'Vocoder := %s, ' +
'TtsJson := %s, ' +
'UnicodeIndexer := %s, ' +
'VoiceStyle := %s' +
')',
[Self.DurationPredictor, Self.TextEncoder, Self.VectorEstimator, Self.Vocoder,
Self.TtsJson, Self.UnicodeIndexer, Self.VoiceStyle]);
end;

function TSherpaOnnxOfflineTtsModelConfig.ToString: AnsiString;
begin
Result := Format('TSherpaOnnxOfflineTtsModelConfig(' +
Expand All @@ -2697,11 +2736,12 @@ function TSherpaOnnxOfflineTtsModelConfig.ToString: AnsiString;
'Kokoro := %s, ' +
'Kitten := %s, ' +
'ZipVoice := %s, ' +
'Pocket := %s' +
'Pocket := %s, ' +
'Supertonic := %s' +
')',
[Self.Vits.ToString, Self.NumThreads, Self.Debug.ToString, Self.Provider,
Self.Matcha.ToString, Self.Kokoro.ToString, Self.Kitten.ToString,
Self.ZipVoice.ToString, Self.Pocket.ToString
Self.ZipVoice.ToString, Self.Pocket.ToString, Self.Supertonic.ToString
]);
end;

Expand Down Expand Up @@ -2788,6 +2828,14 @@ constructor TSherpaOnnxOfflineTts.Create(Config: TSherpaOnnxOfflineTtsConfig);
C.Model.Pocket.TokenScoresJson := PAnsiChar(Config.Model.Pocket.TokenScoresJson);
C.Model.Pocket.VoiceEmbeddingCacheCapacity := Config.Model.Pocket.VoiceEmbeddingCacheCapacity;

C.Model.Supertonic.DurationPredictor := PAnsiChar(Config.Model.Supertonic.DurationPredictor);
C.Model.Supertonic.TextEncoder := PAnsiChar(Config.Model.Supertonic.TextEncoder);
C.Model.Supertonic.VectorEstimator := PAnsiChar(Config.Model.Supertonic.VectorEstimator);
C.Model.Supertonic.Vocoder := PAnsiChar(Config.Model.Supertonic.Vocoder);
C.Model.Supertonic.TtsJson := PAnsiChar(Config.Model.Supertonic.TtsJson);
C.Model.Supertonic.UnicodeIndexer := PAnsiChar(Config.Model.Supertonic.UnicodeIndexer);
C.Model.Supertonic.VoiceStyle := PAnsiChar(Config.Model.Supertonic.VoiceStyle);

C.Model.NumThreads := Config.Model.NumThreads;
C.Model.Provider := PAnsiChar(Config.Model.Provider);
C.Model.Debug := Ord(Config.Model.Debug);
Expand Down