Program.cs
4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) 2025 Xiaomi Corporation
//
// This file shows how to use a non-streaming Kokoro TTS model
// for text-to-speech
// Please refer to
// https://k2-fsa.github.io/sherpa/onnx/pretrained_models/index.html
// and
// https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models
// to download pre-trained models
using SherpaOnnx;
using System.Runtime.InteropServices;
class OfflineTtsDemo
{
static void Main(string[] args)
{
TestZhEn();
TestEn();
}
static void TestZhEn()
{
var config = new OfflineTtsConfig();
config.Model.Kokoro.Model = "./kokoro-multi-lang-v1_0/model.onnx";
config.Model.Kokoro.Voices = "./kokoro-multi-lang-v1_0/voices.bin";
config.Model.Kokoro.Tokens = "./kokoro-multi-lang-v1_0/tokens.txt";
config.Model.Kokoro.DataDir = "./kokoro-multi-lang-v1_0/espeak-ng-data";
config.Model.Kokoro.DictDir = "./kokoro-multi-lang-v1_0/dict";
config.Model.Kokoro.Lexicon = "./kokoro-multi-lang-v1_0/lexicon-us-en.txt,./kokoro-multi-lang-v1_0/lexicon-zh.txt";
config.Model.NumThreads = 2;
config.Model.Debug = 1;
config.Model.Provider = "cpu";
var tts = new OfflineTts(config);
var speed = 1.0f;
var text = "中英文语音合成测试。This is generated by next generation Kaldi using Kokoro without Misaki. 你觉得中英文说的如何呢?";
var sid = 50;
var MyCallback = (IntPtr samples, int n, float progress) =>
{
float[] data = new float[n];
Marshal.Copy(samples, data, 0, n);
// You can process samples here, e.g., play them.
// See ../kokoro-tts-playback for how to play them
Console.WriteLine($"Progress {progress*100}%");
// 1 means to keep generating
// 0 means to stop generating
return 1;
};
var callback = new OfflineTtsCallbackProgress(MyCallback);
var audio = tts.GenerateWithCallbackProgress(text, speed, sid, callback);
var outputFilename = "./generated-kokoro-zh-en.wav";
var ok = audio.SaveToWaveFile(outputFilename);
if (ok)
{
Console.WriteLine($"Wrote to {outputFilename} succeeded!");
}
else
{
Console.WriteLine($"Failed to write {outputFilename}");
}
}
static void TestEn()
{
var config = new OfflineTtsConfig();
config.Model.Kokoro.Model = "./kokoro-en-v0_19/model.onnx";
config.Model.Kokoro.Voices = "./kokoro-en-v0_19/voices.bin";
config.Model.Kokoro.Tokens = "./kokoro-en-v0_19/tokens.txt";
config.Model.Kokoro.DataDir = "./kokoro-en-v0_19/espeak-ng-data";
config.Model.NumThreads = 2;
config.Model.Debug = 1;
config.Model.Provider = "cpu";
var tts = new OfflineTts(config);
var speed = 1.0f;
var 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.";
// 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
var sid = 0;
var MyCallback = (IntPtr samples, int n, float progress) =>
{
float[] data = new float[n];
Marshal.Copy(samples, data, 0, n);
// You can process samples here, e.g., play them.
// See ../kokoro-tts-playback for how to play them
Console.WriteLine($"Progress {progress*100}%");
// 1 means to keep generating
// 0 means to stop generating
return 1;
};
var callback = new OfflineTtsCallbackProgress(MyCallback);
var audio = tts.GenerateWithCallbackProgress(text, speed, sid, callback);
var outputFilename = "./generated-kokoro-en.wav";
var ok = audio.SaveToWaveFile(outputFilename);
if (ok)
{
Console.WriteLine($"Wrote to {outputFilename} succeeded!");
}
else
{
Console.WriteLine($"Failed to write {outputFilename}");
}
}
}