Fangjun Kuang
Committed by GitHub

Build Android TTS APKs for coqui-ai/TTS models (#704)

@@ -186,6 +186,12 @@ class MainActivity : AppCompatActivity() { @@ -186,6 +186,12 @@ class MainActivity : AppCompatActivity() {
186 // ruleFsts = "vits-zh-aishell3/rule.fst" 186 // ruleFsts = "vits-zh-aishell3/rule.fst"
187 // lexicon = "lexicon.txt" 187 // lexicon = "lexicon.txt"
188 188
  189 + // Example 4:
  190 + // https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-coqui-de-css10.tar.bz2
  191 + // modelDir = "vits-coqui-de-css10"
  192 + // modelName = "model.onnx"
  193 + // lang = "deu"
  194 +
189 if (dataDir != null) { 195 if (dataDir != null) {
190 val newDir = copyDataDir(modelDir) 196 val newDir = copyDataDir(modelDir)
191 modelDir = newDir + "/" + modelDir 197 modelDir = newDir + "/" + modelDir
@@ -6,15 +6,18 @@ import androidx.appcompat.app.AppCompatActivity @@ -6,15 +6,18 @@ import androidx.appcompat.app.AppCompatActivity
6 import android.os.Bundle 6 import android.os.Bundle
7 import android.speech.tts.TextToSpeech 7 import android.speech.tts.TextToSpeech
8 8
9 -class GetSampleText : Activity() {  
10 - override fun onCreate(savedInstanceState: Bundle?) {  
11 - super.onCreate(savedInstanceState)  
12 - var result = TextToSpeech.LANG_AVAILABLE  
13 - var text: String = ""  
14 - when(TtsEngine.lang) { 9 +fun getSampleText(lang: String): String {
  10 + var text = ""
  11 + when (lang) {
15 "ara" -> { 12 "ara" -> {
16 text = "هذا هو محرك تحويل النص إلى كلام باستخدام الجيل القادم من كالدي" 13 text = "هذا هو محرك تحويل النص إلى كلام باستخدام الجيل القادم من كالدي"
17 } 14 }
  15 + "ben" -> {
  16 + text = "এটি একটি টেক্সট-টু-স্পীচ ইঞ্জিন যা পরবর্তী প্রজন্মের কালডি ব্যবহার করে"
  17 + }
  18 + "bul" -> {
  19 + text = "Това е машина за преобразуване на текст в реч, използваща Kaldi от следващо поколение"
  20 + }
18 "cat" -> { 21 "cat" -> {
19 text = "Aquest és un motor de text a veu que utilitza Kaldi de nova generació" 22 text = "Aquest és un motor de text a veu que utilitza Kaldi de nova generació"
20 } 23 }
@@ -33,11 +36,20 @@ class GetSampleText : Activity() { @@ -33,11 +36,20 @@ class GetSampleText : Activity() {
33 "eng" -> { 36 "eng" -> {
34 text = "This is a text-to-speech engine using next generation Kaldi" 37 text = "This is a text-to-speech engine using next generation Kaldi"
35 } 38 }
  39 + "est" -> {
  40 + text = "See on teksti kõneks muutmise mootor, mis kasutab järgmise põlvkonna Kaldi"
  41 + }
36 "fin" -> { 42 "fin" -> {
37 text = "Tämä on tekstistä puheeksi -moottori, joka käyttää seuraavan sukupolven kaldia" 43 text = "Tämä on tekstistä puheeksi -moottori, joka käyttää seuraavan sukupolven kaldia"
38 } 44 }
39 "fra" -> { 45 "fra" -> {
40 - text = "Il s'agit d'un moteur de synthèse vocale utilisant Kaldi de nouvelle génération." 46 + text = "Il s'agit d'un moteur de synthèse vocale utilisant Kaldi de nouvelle génération"
  47 + }
  48 + "gle" -> {
  49 + text = "Is inneall téacs-go-hurlabhra é seo a úsáideann Kaldi den chéad ghlúin eile"
  50 + }
  51 + "hrv" -> {
  52 + text = "Ovo je mehanizam za pretvaranje teksta u govor koji koristi Kaldi sljedeće generacije"
41 } 53 }
42 "hun" -> { 54 "hun" -> {
43 text = "Ez egy szövegfelolvasó motor a következő generációs kaldi használatával" 55 text = "Ez egy szövegfelolvasó motor a következő generációs kaldi használatával"
@@ -54,6 +66,15 @@ class GetSampleText : Activity() { @@ -54,6 +66,15 @@ class GetSampleText : Activity() {
54 "kaz" -> { 66 "kaz" -> {
55 text = "Бұл келесі буын kaldi көмегімен мәтіннен сөйлеуге арналған қозғалтқыш" 67 text = "Бұл келесі буын kaldi көмегімен мәтіннен сөйлеуге арналған қозғалтқыш"
56 } 68 }
  69 + "mlt" -> {
  70 + text = "Din hija magna text-to-speech li tuża Kaldi tal-ġenerazzjoni li jmiss"
  71 + }
  72 + "lav" -> {
  73 + text = "Šis ir teksta pārvēršanas runā dzinējs, kas izmanto nākamās paaudzes Kaldi"
  74 + }
  75 + "lit" -> {
  76 + text = "Tai teksto į kalbą variklis, kuriame naudojamas naujos kartos Kaldi"
  77 + }
57 "ltz" -> { 78 "ltz" -> {
58 text = "Dëst ass en Text-zu-Speech-Motor mat der nächster Generatioun Kaldi" 79 text = "Dëst ass en Text-zu-Speech-Motor mat der nächster Generatioun Kaldi"
59 } 80 }
@@ -81,6 +102,9 @@ class GetSampleText : Activity() { @@ -81,6 +102,9 @@ class GetSampleText : Activity() {
81 "slk" -> { 102 "slk" -> {
82 text = "Toto je nástroj na prevod textu na reč využívajúci kaldi novej generácie" 103 text = "Toto je nástroj na prevod textu na reč využívajúci kaldi novej generácie"
83 } 104 }
  105 + "slv" -> {
  106 + text = "To je mehanizem za pretvorbo besedila v govor, ki uporablja Kaldi naslednje generacije"
  107 + }
84 "spa" -> { 108 "spa" -> {
85 text = "Este es un motor de texto a voz que utiliza kaldi de próxima generación." 109 text = "Este es un motor de texto a voz que utiliza kaldi de próxima generación."
86 } 110 }
@@ -105,9 +129,17 @@ class GetSampleText : Activity() { @@ -105,9 +129,17 @@ class GetSampleText : Activity() {
105 "zho", "cmn" -> { 129 "zho", "cmn" -> {
106 text = "使用新一代卡尔迪的语音合成引擎" 130 text = "使用新一代卡尔迪的语音合成引擎"
107 } 131 }
108 - else -> {  
109 - result = TextToSpeech.LANG_NOT_SUPPORTED  
110 } 132 }
  133 + return text
  134 +}
  135 +
  136 +class GetSampleText : Activity() {
  137 + override fun onCreate(savedInstanceState: Bundle?) {
  138 + super.onCreate(savedInstanceState)
  139 + var result = TextToSpeech.LANG_AVAILABLE
  140 + var text: String = getSampleText(TtsEngine.lang ?: "")
  141 + if (text.isEmpty()) {
  142 + result = TextToSpeech.LANG_NOT_SUPPORTED
111 } 143 }
112 144
113 val intent = Intent().apply{ 145 val intent = Intent().apply{
@@ -73,109 +73,7 @@ class MainActivity : ComponentActivity() { @@ -73,109 +73,7 @@ class MainActivity : ComponentActivity() {
73 ) 73 )
74 } 74 }
75 75
76 - var testTextContent = ""  
77 -  
78 - when(TtsEngine.lang) {  
79 - "ara" -> {  
80 - testTextContent = "هذا هو محرك تحويل النص إلى كلام باستخدام الجيل القادم من كالدي"  
81 - }  
82 - "cat" -> {  
83 - testTextContent = "Aquest és un motor de testText a veu que utilitza Kaldi de nova generació"  
84 - }  
85 - "ces" -> {  
86 - testTextContent = "Toto je převodník testTextu na řeč využívající novou generaci kaldi"  
87 - }  
88 - "dan" -> {  
89 - testTextContent = "Dette er en tekst til tale-motor, der bruger næste generation af kaldi"  
90 - }  
91 - "deu" -> {  
92 - testTextContent = "Dies ist eine testText-to-Speech-Engine, die Kaldi der nächsten Generation verwendet"  
93 - }  
94 - "ell" -> {  
95 - testTextContent = "Αυτή είναι μια μηχανή κειμένου σε ομιλία που χρησιμοποιεί kaldi επόμενης γενιάς"  
96 - }  
97 - "eng" -> {  
98 - testTextContent = "This is a testText-to-speech engine using next generation Kaldi"  
99 - }  
100 - "fas" -> {  
101 - testTextContent = "این یک موتور تبدیل متن به گفتار است برپایه نسخه پیشگام کالدی"  
102 - }  
103 - "fin" -> {  
104 - testTextContent = "Tämä on tekstistä puheeksi -moottori, joka käyttää seuraavan sukupolven kaldia"  
105 - }  
106 - "fra" -> {  
107 - testTextContent = "Il s'agit d'un moteur de synthèse vocale utilisant Kaldi de nouvelle génération."  
108 - }  
109 - "hun" -> {  
110 - testTextContent = "Ez egy szövegfelolvasó motor a következő generációs kaldi használatával"  
111 - }  
112 - "isl" -> {  
113 - testTextContent = "Þetta er testTexta í tal vél sem notar næstu kynslóð kaldi"  
114 - }  
115 - "ita" -> {  
116 - testTextContent = "Questo è un motore di sintesi vocale che utilizza kaldi di nuova generazione"  
117 - }  
118 - "kat" -> {  
119 - testTextContent = "ეს არის ტექსტიდან მეტყველების ძრავა შემდეგი თაობის კალდის გამოყენებით"  
120 - }  
121 - "kaz" -> {  
122 - testTextContent = "Бұл келесі буын kaldi көмегімен мәтіннен сөйлеуге арналған қозғалтқыш"  
123 - }  
124 - "ltz" -> {  
125 - testTextContent = "Dëst ass en testText-zu-Speech-Motor mat der nächster Generatioun Kaldi"  
126 - }  
127 - "nep" -> {  
128 - testTextContent = "यो अर्को पुस्ता काल्डी प्रयोग गरेर स्पीच इन्जिनको पाठ हो"  
129 - }  
130 - "nld" -> {  
131 - testTextContent = "Dit is een tekst-naar-spraak-engine die gebruik maakt van Kaldi van de volgende generatie"  
132 - }  
133 - "nor" -> {  
134 - testTextContent = "Dette er en tekst til tale-motor som bruker neste generasjons kaldi"  
135 - }  
136 - "pol" -> {  
137 - testTextContent = "Jest to silnik syntezatora mowy wykorzystujący Kaldi nowej generacji"  
138 - }  
139 - "por" -> {  
140 - testTextContent = "Este é um mecanismo de conversão de testTexto em fala usando Kaldi de próxima geração"  
141 - }  
142 - "ron" -> {  
143 - testTextContent = "Acesta este un motor testText to speech care folosește generația următoare de kadi"  
144 - }  
145 - "rus" -> {  
146 - testTextContent = "Это движок преобразования текста в речь, использующий Kaldi следующего поколения."  
147 - }  
148 - "slk" -> {  
149 - testTextContent = "Toto je nástroj na prevod testTextu na reč využívajúci kaldi novej generácie"  
150 - }  
151 - "spa" -> {  
152 - testTextContent = "Este es un motor de testTexto a voz que utiliza kaldi de próxima generación."  
153 - }  
154 - "srp" -> {  
155 - testTextContent = "Ово је механизам за претварање текста у говор који користи калди следеће генерације"  
156 - }  
157 - "swa" -> {  
158 - testTextContent = "Haya ni maandishi kwa injini ya hotuba kwa kutumia kizazi kijacho kaldi"  
159 - }  
160 - "swe" -> {  
161 - testTextContent = "Detta är en testText till tal-motor som använder nästa generations kaldi"  
162 - }  
163 - "tur" -> {  
164 - testTextContent = "Bu, yeni nesil kaldi'yi kullanan bir metinden konuşmaya motorudur"  
165 - }  
166 - "ukr" -> {  
167 - testTextContent = "Це механізм перетворення тексту на мовлення, який використовує kaldi нового покоління"  
168 - }  
169 - "vie" -> {  
170 - testTextContent = "Đây là công cụ chuyển văn bản thành giọng nói sử dụng kaldi thế hệ tiếp theo"  
171 - }  
172 - "zho", "cmn" -> {  
173 - testTextContent = "使用新一代卡尔迪的语音合成引擎"  
174 - }  
175 - else -> {  
176 - testTextContent = ""  
177 - }  
178 - } 76 + val testTextContent = getSampleText(TtsEngine.lang ?: "")
179 77
180 var testText by remember { mutableStateOf(testTextContent) } 78 var testText by remember { mutableStateOf(testTextContent) }
181 79
@@ -57,6 +57,7 @@ object TtsEngine { @@ -57,6 +57,7 @@ object TtsEngine {
57 // Please enable one and only one of the examples below 57 // Please enable one and only one of the examples below
58 58
59 // Example 1: 59 // Example 1:
  60 + // https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-vctk.tar.bz2
60 // modelDir = "vits-vctk" 61 // modelDir = "vits-vctk"
61 // modelName = "vits-vctk.onnx" 62 // modelName = "vits-vctk.onnx"
62 // lexicon = "lexicon.txt" 63 // lexicon = "lexicon.txt"
@@ -71,11 +72,19 @@ object TtsEngine { @@ -71,11 +72,19 @@ object TtsEngine {
71 // lang = "eng" 72 // lang = "eng"
72 73
73 // Example 3: 74 // Example 3:
  75 + // https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-icefall-zh-aishell3.tar.bz2
74 // modelDir = "vits-zh-aishell3" 76 // modelDir = "vits-zh-aishell3"
75 // modelName = "vits-aishell3.onnx" 77 // modelName = "vits-aishell3.onnx"
76 // ruleFsts = "vits-zh-aishell3/rule.fst" 78 // ruleFsts = "vits-zh-aishell3/rule.fst"
77 // lexicon = "lexicon.txt" 79 // lexicon = "lexicon.txt"
78 // lang = "zho" 80 // lang = "zho"
  81 +
  82 + // Example 4:
  83 + // https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-coqui-de-css10.tar.bz2
  84 + // This model does not need lexicon or dataDir
  85 + // modelDir = "vits-coqui-de-css10"
  86 + // modelName = "model.onnx"
  87 + // lang = "deu"
79 } 88 }
80 89
81 90
@@ -59,7 +59,7 @@ sed -i.bak s/"lang = null"/"lang = \"$lang_iso_639_3\""/ ./TtsEngine.kt @@ -59,7 +59,7 @@ sed -i.bak s/"lang = null"/"lang = \"$lang_iso_639_3\""/ ./TtsEngine.kt
59 {% if tts_model.data_dir %} 59 {% if tts_model.data_dir %}
60 data_dir={{ tts_model.data_dir }} 60 data_dir={{ tts_model.data_dir }}
61 sed -i.bak s%"dataDir = null"%"dataDir = \"$data_dir\""% ./TtsEngine.kt 61 sed -i.bak s%"dataDir = null"%"dataDir = \"$data_dir\""% ./TtsEngine.kt
62 -{% else %} 62 +{% elif not tts_model.is_char %}
63 sed -i.bak s/"lexicon = null"/"lexicon = \"lexicon.txt\""/ ./TtsEngine.kt 63 sed -i.bak s/"lexicon = null"/"lexicon = \"lexicon.txt\""/ ./TtsEngine.kt
64 {% endif %} 64 {% endif %}
65 65
@@ -57,7 +57,7 @@ sed -i.bak s/"modelName = null"/"modelName = \"$model_name\""/ ./MainActivity.kt @@ -57,7 +57,7 @@ sed -i.bak s/"modelName = null"/"modelName = \"$model_name\""/ ./MainActivity.kt
57 {% if tts_model.data_dir %} 57 {% if tts_model.data_dir %}
58 data_dir={{ tts_model.data_dir }} 58 data_dir={{ tts_model.data_dir }}
59 sed -i.bak s%"dataDir = null"%"dataDir = \"$data_dir\""% ./MainActivity.kt 59 sed -i.bak s%"dataDir = null"%"dataDir = \"$data_dir\""% ./MainActivity.kt
60 -{% else %} 60 +{% elif not tts_model.is_char %}
61 sed -i.bak s/"lexicon = null"/"lexicon = \"lexicon.txt\""/ ./MainActivity.kt 61 sed -i.bak s/"lexicon = null"/"lexicon = \"lexicon.txt\""/ ./MainActivity.kt
62 {% endif %} 62 {% endif %}
63 63
@@ -34,6 +34,7 @@ class TtsModel: @@ -34,6 +34,7 @@ class TtsModel:
34 lang: str = "" # en, zh, fr, de, etc. 34 lang: str = "" # en, zh, fr, de, etc.
35 rule_fsts: Optional[List[str]] = None 35 rule_fsts: Optional[List[str]] = None
36 data_dir: Optional[str] = None 36 data_dir: Optional[str] = None
  37 + is_char: bool = False
37 lang_iso_639_3: str = "" 38 lang_iso_639_3: str = ""
38 39
39 40
@@ -57,7 +58,35 @@ def get_coqui_models() -> List[TtsModel]: @@ -57,7 +58,35 @@ def get_coqui_models() -> List[TtsModel]:
57 m.model_name = "model.onnx" 58 m.model_name = "model.onnx"
58 m.lang = "en" 59 m.lang = "en"
59 60
60 - return models 61 + character_models = [
  62 + TtsModel(model_dir="vits-coqui-bg-cv", lang="bg"),
  63 + TtsModel(model_dir="vits-coqui-bn-custom_female", lang="bn"),
  64 + TtsModel(model_dir="vits-coqui-cs-cv", lang="cs"),
  65 + TtsModel(model_dir="vits-coqui-da-cv", lang="da"),
  66 + TtsModel(model_dir="vits-coqui-de-css10", lang="de"),
  67 + TtsModel(model_dir="vits-coqui-es-css10", lang="es"),
  68 + TtsModel(model_dir="vits-coqui-et-cv", lang="et"),
  69 + TtsModel(model_dir="vits-coqui-fi-css10", lang="fi"),
  70 + TtsModel(model_dir="vits-coqui-fr-css10", lang="fr"),
  71 + TtsModel(model_dir="vits-coqui-ga-cv", lang="ga"),
  72 + TtsModel(model_dir="vits-coqui-hr-cv", lang="hr"),
  73 + TtsModel(model_dir="vits-coqui-lt-cv", lang="lt"),
  74 + TtsModel(model_dir="vits-coqui-lv-cv", lang="lv"),
  75 + TtsModel(model_dir="vits-coqui-mt-cv", lang="mt"),
  76 + TtsModel(model_dir="vits-coqui-nl-css10", lang="nl"),
  77 + TtsModel(model_dir="vits-coqui-pl-mai_female", lang="pl"),
  78 + TtsModel(model_dir="vits-coqui-pt-cv", lang="pt"),
  79 + TtsModel(model_dir="vits-coqui-ro-cv", lang="ro"),
  80 + TtsModel(model_dir="vits-coqui-sk-cv", lang="sk"),
  81 + TtsModel(model_dir="vits-coqui-sl-cv", lang="sl"),
  82 + TtsModel(model_dir="vits-coqui-sv-cv", lang="sv"),
  83 + TtsModel(model_dir="vits-coqui-uk-mai", lang="uk"),
  84 + ]
  85 + for m in character_models:
  86 + m.is_char = True
  87 + m.model_name = "model.onnx"
  88 +
  89 + return models + character_models
61 90
62 91
63 def get_piper_models() -> List[TtsModel]: 92 def get_piper_models() -> List[TtsModel]: