Dart, flutter, go, c-api blinding and example (#3202)

This commit is contained in:
Simon Law authored and GitHub committed 2026-02-23 14:47:19 +08:00
1 parent 3b6442ffdc
commit 6293cc7e33
7 files changed
+68 -12

No files matched your search

+8 -1
View File
@@ -49,6 +49,10 @@ int32_t main(int32_t argc, char *argv[]) {
"./sherpa-onnx-pocket-tts-int8-2026-01-26/vocab.json";
config.model.pocket.token_scores_json =
"./sherpa-onnx-pocket-tts-int8-2026-01-26/token_scores.json";
// Voice embedding cache capacity (default: 50)
// Increase this if you have many different reference audios to avoid
// recomputing voice embeddings
config.model.pocket.voice_embedding_cache_capacity = 50;
config.model.num_threads = 2;
@@ -82,7 +86,10 @@ int32_t main(int32_t argc, char *argv[]) {
cfg.reference_audio = wave->samples;
cfg.reference_audio_len = wave->num_samples;
cfg.reference_sample_rate = wave->sample_rate;
cfg.extra = "{\"max_reference_audio_len\": 10.0}";
// Extra parameters passed as JSON string
// - max_reference_audio_len: maximum length of reference audio in seconds
// - seed: random seed for reproducibility (optional, -1 for random)
cfg.extra = "{\"max_reference_audio_len\": 10.0, \"seed\": 42}";
#if 0
// If you don't want to use a callback, then please enable this branch
+17 -2
View File
@@ -19,7 +19,17 @@ void main(List<String> arguments) async {
..addOption('token-scores-json', help: 'Path to the token_scores.json file')
..addOption('reference-audio', help: 'Path to reference audio (wav)')
..addOption('text', help: 'Text to generate TTS for')
..addOption('output-wav', help: 'Filename to save the generated audio');
..addOption('output-wav', help: 'Filename to save the generated audio')
..addOption(
'voice-embedding-cache-capacity',
help: 'Voice embedding cache capacity (default: 50)',
defaultsTo: '50',
)
..addOption(
'seed',
help: 'Random seed for reproducibility (default: -1, random)',
defaultsTo: '-1',
);
final res = parser.parse(arguments);
@@ -47,6 +57,10 @@ void main(List<String> arguments) async {
final referenceAudioPath = res['reference-audio'] as String;
final text = res['text'] as String;
final outputWav = res['output-wav'] as String;
final voiceEmbeddingCacheCapacity = int.parse(
res['voice-embedding-cache-capacity'] as String,
);
final seed = int.parse(res['seed'] as String);
// ---------------- Pocket model config ----------------
final pocket = sherpa_onnx.OfflineTtsPocketModelConfig(
@@ -57,6 +71,7 @@ void main(List<String> arguments) async {
textConditioner: textConditioner,
vocabJson: vocabJson,
tokenScoresJson: tokenScoresJson,
voiceEmbeddingCacheCapacity: voiceEmbeddingCacheCapacity,
);
final modelConfig = sherpa_onnx.OfflineTtsModelConfig(
@@ -80,7 +95,7 @@ void main(List<String> arguments) async {
speed: 1.0,
referenceAudio: wave.samples,
referenceSampleRate: wave.sampleRate,
extra: {"max_reference_audio_len": 12},
extra: {"max_reference_audio_len": 12, if (seed >= 0) "seed": seed},
);
// If you don't want to use a callback
@@ -243,6 +243,9 @@ final class SherpaOnnxOfflineTtsPocketModelConfig extends Struct {
external Pointer<Utf8> textConditioner;
external Pointer<Utf8> vocabJson;
external Pointer<Utf8> tokenScoresJson;
@Int32()
external int voiceEmbeddingCacheCapacity;
}
final class SherpaOnnxOfflineTtsModelConfig extends Struct {
+8 -1
View File
@@ -352,6 +352,7 @@ class OfflineTtsPocketModelConfig {
this.textConditioner = '',
this.vocabJson = '',
this.tokenScoresJson = '',
this.voiceEmbeddingCacheCapacity = 50,
});
factory OfflineTtsPocketModelConfig.fromJson(Map<String, dynamic> json) {
@@ -363,6 +364,8 @@ class OfflineTtsPocketModelConfig {
textConditioner: json['textConditioner'] as String? ?? '',
vocabJson: json['vocabJson'] as String? ?? '',
tokenScoresJson: json['tokenScoresJson'] as String? ?? '',
voiceEmbeddingCacheCapacity:
json['voiceEmbeddingCacheCapacity'] as int? ?? 50,
);
}
@@ -374,11 +377,12 @@ class OfflineTtsPocketModelConfig {
'textConditioner': textConditioner,
'vocabJson': vocabJson,
'tokenScoresJson': tokenScoresJson,
'voiceEmbeddingCacheCapacity': voiceEmbeddingCacheCapacity,
};
@override
String toString() {
return 'OfflineTtsPocketModelConfig(lmFlow: $lmFlow, lmMain: $lmMain, encoder: $encoder, decoder: $decoder, textConditioner: $textConditioner, vocabJson: $vocabJson, tokenScoresJson: $tokenScoresJson)';
return 'OfflineTtsPocketModelConfig(lmFlow: $lmFlow, lmMain: $lmMain, encoder: $encoder, decoder: $decoder, textConditioner: $textConditioner, vocabJson: $vocabJson, tokenScoresJson: $tokenScoresJson, voiceEmbeddingCacheCapacity: $voiceEmbeddingCacheCapacity)';
}
final String lmFlow;
@@ -388,6 +392,7 @@ class OfflineTtsPocketModelConfig {
final String textConditioner;
final String vocabJson;
final String tokenScoresJson;
final int voiceEmbeddingCacheCapacity;
}
class OfflineTtsModelConfig {
@@ -569,6 +574,8 @@ class OfflineTts {
c.ref.model.pocket.vocabJson = config.model.pocket.vocabJson.toNativeUtf8();
c.ref.model.pocket.tokenScoresJson = config.model.pocket.tokenScoresJson
.toNativeUtf8();
c.ref.model.pocket.voiceEmbeddingCacheCapacity =
config.model.pocket.voiceEmbeddingCacheCapacity;
c.ref.model.numThreads = config.model.numThreads;
c.ref.model.debug = config.model.debug ? 1 : 0;
@@ -20,6 +20,8 @@ func main() {
config.ModelConfig.FunAsrNano.LLM = "./sherpa-onnx-funasr-nano-int8-2025-12-30/llm.int8.onnx"
config.ModelConfig.FunAsrNano.Embedding = "./sherpa-onnx-funasr-nano-int8-2025-12-30/embedding.int8.onnx"
config.ModelConfig.FunAsrNano.Tokenizer = "./sherpa-onnx-funasr-nano-int8-2025-12-30/Qwen3-0.6B"
// Seed for reproducibility (default: 42)
config.ModelConfig.FunAsrNano.Seed = 42
config.ModelConfig.Tokens = ""
@@ -94,6 +94,8 @@ func main() {
var referenceAudio string = "./sherpa-onnx-pocket-tts-int8-2026-01-26/test_wavs/bria.wav"
var outputFilename string = "./generated.wav"
var voiceEmbeddingCacheCapacity int = 50
var seed int = -1
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,
@@ -102,6 +104,8 @@ whatever he may be: a statesman, a businessman, an official, or a scholar.`
flag.StringVar(&referenceAudio, "reference-audio", referenceAudio, "Path to the reference audio")
flag.StringVar(&text, "text", text, "Text to be synthesized")
flag.StringVar(&outputFilename, "output-filename", outputFilename, "File to save the generated audio")
flag.IntVar(&voiceEmbeddingCacheCapacity, "voice-embedding-cache-capacity", voiceEmbeddingCacheCapacity, "Voice embedding cache capacity (default: 50)")
flag.IntVar(&seed, "seed", seed, "Random seed for reproducibility (default: -1, random)")
flag.Parse()
// ---------------- config ----------------
@@ -121,6 +125,7 @@ whatever he may be: a statesman, a businessman, an official, or a scholar.`
"./sherpa-onnx-pocket-tts-int8-2026-01-26/vocab.json"
config.Model.Pocket.TokenScoresJson =
"./sherpa-onnx-pocket-tts-int8-2026-01-26/token_scores.json"
config.Model.Pocket.VoiceEmbeddingCacheCapacity = voiceEmbeddingCacheCapacity
config.Model.NumThreads = 2
config.Model.Debug = 0
@@ -142,10 +147,16 @@ whatever he may be: a statesman, a businessman, an official, or a scholar.`
cfg.ReferenceAudio = wave.Samples
cfg.ReferenceSampleRate = wave.SampleRate
cfg.Extra = json.RawMessage(`{
"max_reference_audio_len": 10,
"temperature": 0.7
}`)
// Build extra config with optional seed
extraMap := map[string]interface{}{
"max_reference_audio_len": 10,
"temperature": 0.7,
}
if seed >= 0 {
extraMap["seed"] = seed
}
extraBytes, _ := json.Marshal(extraMap)
cfg.Extra = json.RawMessage(extraBytes)
log.Println("Start generating")
+15 -4
View File
@@ -13,6 +13,8 @@ func main() {
var referenceAudio string = "./sherpa-onnx-pocket-tts-int8-2026-01-26/test_wavs/bria.wav"
var outputFilename string = "./generated.wav"
var voiceEmbeddingCacheCapacity int = 50
var seed int = -1
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,
@@ -21,6 +23,8 @@ whatever he may be: a statesman, a businessman, an official, or a scholar.`
flag.StringVar(&referenceAudio, "reference-audio", referenceAudio, "Path to the reference audio")
flag.StringVar(&text, "text", text, "Text to be synthesized")
flag.StringVar(&outputFilename, "output-filename", outputFilename, "File to save the generated audio")
flag.IntVar(&voiceEmbeddingCacheCapacity, "voice-embedding-cache-capacity", voiceEmbeddingCacheCapacity, "Voice embedding cache capacity (default: 50)")
flag.IntVar(&seed, "seed", seed, "Random seed for reproducibility (default: -1, random)")
flag.Parse()
// ---------------- config ----------------
@@ -40,6 +44,7 @@ whatever he may be: a statesman, a businessman, an official, or a scholar.`
"./sherpa-onnx-pocket-tts-int8-2026-01-26/vocab.json"
config.Model.Pocket.TokenScoresJson =
"./sherpa-onnx-pocket-tts-int8-2026-01-26/token_scores.json"
config.Model.Pocket.VoiceEmbeddingCacheCapacity = voiceEmbeddingCacheCapacity
config.Model.NumThreads = 2
config.Model.Debug = 0
@@ -61,10 +66,16 @@ whatever he may be: a statesman, a businessman, an official, or a scholar.`
cfg.ReferenceAudio = wave.Samples
cfg.ReferenceSampleRate = wave.SampleRate
cfg.Extra = json.RawMessage(`{
"max_reference_audio_len": 10,
"temperature": 0.7
}`)
// Build extra config with optional seed
extraMap := map[string]interface{}{
"max_reference_audio_len": 10,
"temperature": 0.7,
}
if seed >= 0 {
extraMap["seed"] = seed
}
extraBytes, _ := json.Marshal(extraMap)
cfg.Extra = json.RawMessage(extraBytes)
log.Println("Start generating")