{"id":17030,"date":"2025-10-29T09:38:08","date_gmt":"2025-10-29T07:38:08","guid":{"rendered":"https:\/\/www.beseit.net\/?page_id=17030"},"modified":"2025-11-03T11:26:19","modified_gmt":"2025-11-03T09:26:19","slug":"tts_android_simple","status":"publish","type":"page","link":"https:\/\/www.beseit.net\/?page_id=17030","title":{"rendered":"tts_android_simple (codi)"},"content":{"rendered":"\n<p>configuration<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"914\" height=\"718\" src=\"https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/11\/image.png\" alt=\"\" class=\"wp-image-17062\" srcset=\"https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/11\/image.png 914w, https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/11\/image-300x236.png 300w, https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/11\/image-768x603.png 768w, https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/11\/image-382x300.png 382w\" sizes=\"auto, (max-width: 914px) 100vw, 914px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"952\" height=\"813\" src=\"https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-4.png\" alt=\"\" class=\"wp-image-17049\" srcset=\"https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-4.png 952w, https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-4-300x256.png 300w, https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-4-768x656.png 768w, https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-4-351x300.png 351w\" sizes=\"auto, (max-width: 952px) 100vw, 952px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">?\ufe0f Guia pas a pas: Primera app Android amb TTS en catal\u00e0<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. <strong>Obrir Android Studio<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si no el tens instal\u00b7lat, descarrega\u2019l des de <a href=\"https:\/\/developer.android.com\/studio\">developer.android.com\/studio<\/a>.<\/li>\n\n\n\n<li>Un cop obert, selecciona <strong>&#8220;New Project&#8221;<\/strong>.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. <strong>Crear un nou projecte<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Tria <strong>&#8220;Empty Activity&#8221;<\/strong>.<\/li>\n\n\n\n<li>Dona-li un nom, per exemple: urqtejmi_<code>TTSCatal\u00e0<\/code>.<\/li>\n\n\n\n<li>Assegura\u2019t que el llenguatge sigui <strong>Java<\/strong> (o Kotlin si ho prefereixes).<\/li>\n\n\n\n<li>Target SDK: tria <strong>API 21 o superior<\/strong> (TextToSpeech funciona des d\u2019API 21).<\/li>\n\n\n\n<li>Fes clic a <strong>Finish<\/strong>.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3. <strong>Editar la interf\u00edcie (<code>activity_main.xml<\/code>)<\/strong><\/h3>\n\n\n\n<p>Obre <code>res\/layout\/activity_main.xml<\/code> i enganxa aquest codi:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;LinearLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"24dp\"\n    android:gravity=\"center\">\n\n    &lt;EditText\n        android:id=\"@+id\/editText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"Escriu el text que vols escoltar\"\n        android:minLines=\"4\"\n        android:gravity=\"top\"\n        android:inputType=\"textMultiLine\" \/>\n\n    &lt;Button\n        android:id=\"@+id\/btnSpeak\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Escolta\"\n        android:layout_marginTop=\"16dp\"\/>\n&lt;\/LinearLayout>\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">4. <strong>Afegir la l\u00f2gica TTS (<code>MainActivity.java<\/code>)<\/strong><\/h3>\n\n\n\n<p>Obre <code>MainActivity.java<\/code> i enganxa aquest codi:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package com.exemple.ttscatala;\n\nimport android.os.Bundle;\nimport android.speech.tts.TextToSpeech;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.Toast;\nimport androidx.appcompat.app.AppCompatActivity;\nimport java.util.Locale;\n\npublic class MainActivity extends AppCompatActivity {\n\n    private TextToSpeech tts;\n    private EditText editText;\n    private Button btnSpeak;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        editText = findViewById(R.id.editText);\n        btnSpeak = findViewById(R.id.btnSpeak);\n\n        tts = new TextToSpeech(this, status -> {\n            if (status == TextToSpeech.SUCCESS) {\n                int result = tts.setLanguage(new Locale(\"ca\", \"ES\"));\n                if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {\n                    Toast.makeText(this, \"\u26a0\ufe0f Veu catalana no disponible\", Toast.LENGTH_LONG).show();\n                }\n            }\n        });\n\n        btnSpeak.setOnClickListener(v -> {\n            String text = editText.getText().toString();\n            if (!text.isEmpty()) {\n                tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);\n            }\n        });\n    }\n\n    @Override\n    protected void onDestroy() {\n        if (tts != null) {\n            tts.stop();\n            tts.shutdown();\n        }\n        super.onDestroy();\n    }\n}\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5. <strong>Executar l\u2019app<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Connecta el teu dispositiu Android amb cable USB i activa el mode <strong>Desenvolupador<\/strong>.<\/li>\n\n\n\n<li>Fes clic a <strong>Run \u25b6\ufe0f<\/strong> a Android Studio.<\/li>\n\n\n\n<li>Tria el teu dispositiu i espera que s\u2019instal\u00b7li.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">? Resultat<\/h2>\n\n\n\n<p>Ara podr\u00e0s escriure qualsevol text en catal\u00e0 i escoltar-lo amb la veu TTS del sistema (la mateixa que fa servir ReadEra).<\/p>\n\n\n\n<p>Vols que et gui\u00ef per afegir funcions com selector de veu, velocitat, o guardar l\u2019\u00faltim text llegit? Tamb\u00e9 podem modularitzar-ho per reutilitzar-ho en altres apps.<\/p>\n\n\n\n<p>aqui s&#8217;afegeix l&#8217;html<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!DOCTYPE html>\n&lt;html lang=\"ca\">\n&lt;head>\n  &lt;meta charset=\"UTF-8\">\n  &lt;title>Prova TTS Catal\u00e0&lt;\/title>\n  &lt;style>\n    body { font-family: sans-serif; padding: 2em; background: #f0f0f0; }\n    textarea { width: 100%; max-width: 600px; height: 150px; font-size: 1.2em; }\n    button { font-size: 1.2em; margin-top: 1em; }\n  &lt;\/style>\n&lt;\/head>\n&lt;body>\n  &lt;h2>Conversor de text a veu (Catal\u00e0)&lt;\/h2>\n  &lt;textarea id=\"text\" placeholder=\"Escriu el text que vols escoltar...\">Bon dia! Com est\u00e0s?&lt;\/textarea>&lt;br>\n  &lt;button onclick=\"speak()\">Escolta&lt;\/button>\n\n  &lt;script>\n    function speak() {\n      const text = document.getElementById('text').value;\n      const utterance = new SpeechSynthesisUtterance(text);\n      const voices = speechSynthesis.getVoices();\n      const catala = voices.find(v => v.lang === 'ca-ES');\n\n      if (catala) {\n        utterance.voice = catala;\n        utterance.lang = 'ca-ES';\n      } else {\n        alert(\"\u26a0\ufe0f No s'ha trobat cap veu catalana disponible.\");\n      }\n\n      speechSynthesis.speak(utterance);\n    }\n\n    \/\/ Carrega les veus (pot trigar una mica)\n    window.speechSynthesis.onvoiceschanged = () => {};\n  &lt;\/script>\n&lt;\/body>\n&lt;\/html>\n<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"485\" height=\"204\" src=\"https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-3.png\" alt=\"\" class=\"wp-image-17039\" srcset=\"https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-3.png 485w, https:\/\/www.beseit.net\/wp-content\/uploads\/2025\/10\/image-3-300x126.png 300w\" sizes=\"auto, (max-width: 485px) 100vw, 485px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><mark style=\"background-color:rgba(0, 0, 0, 0);color:#f90c0c\" class=\"has-inline-color\">MainActivity.kt amb veu english US<\/mark><\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package com.example.helloworld\n\nimport android.os.Bundle\nimport android.speech.tts.TextToSpeech\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.tooling.preview.Preview\nimport com.example.helloworld.ui.theme.HelloWorldTheme\nimport java.util.Locale\n\nclass MainActivity : ComponentActivity(), TextToSpeech.OnInitListener {\n\n    private var tts: TextToSpeech? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        \/\/ Inicialitza TextToSpeech\n        tts = TextToSpeech(this, this)\n\n        enableEdgeToEdge()\n        setContent {\n            HelloWorldTheme {\n                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->\n                    Greeting(\n                        name = \"Android\",\n                        modifier = Modifier.padding(innerPadding)\n                    )\n                }\n            }\n        }\n    }\n\n    override fun onInit(status: Int) {\n        if (status == TextToSpeech.SUCCESS) {\n            \/\/ Configura l'idioma (angl\u00e8s, per exemple)\n            val result = tts?.setLanguage(Locale.US)\n\n            if (result != TextToSpeech.LANG_MISSING_DATA &amp;&amp; result != TextToSpeech.LANG_NOT_SUPPORTED) {\n                \/\/ Digues el missatge\n                tts?.speak(\"Hello Android!\", TextToSpeech.QUEUE_FLUSH, null, null)\n            }\n        }\n    }\n\n    override fun onDestroy() {\n        \/\/ Allibera els recursos del TTS\n        tts?.stop()\n        tts?.shutdown()\n        super.onDestroy()\n    }\n}\n\n@Composable\nfun Greeting(name: String, modifier: Modifier = Modifier) {\n    Text(\n        text = \"Hello $name!\",\n        modifier = modifier\n    )\n}\n\n@Preview(showBackground = true)\n@Composable\nfun GreetingPreview() {\n    HelloWorldTheme {\n        Greeting(\"Android\")\n    }\n}\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><mark>MainActivity.kt amb veu catalana<\/mark> ATENCI\u00d3 AMB EL THEME!!!<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package com.example.helloworld\n\nimport android.os.Bundle\nimport android.speech.tts.TextToSpeech\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.tooling.preview.Preview\nimport com.example.helloworld.ui.theme.HelloWorldTheme\nimport java.util.Locale\n\nclass MainActivity : ComponentActivity(), TextToSpeech.OnInitListener {\n\n    private var tts: TextToSpeech? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        \/\/ Inicialitza TextToSpeech\n        tts = TextToSpeech(this, this)\n\n        enableEdgeToEdge()\n        setContent {\n            HelloWorldTheme {\n                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->\n                    Greeting(\n                        name = \"Android\",\n                        modifier = Modifier.padding(innerPadding)\n                    )\n                }\n            }\n        }\n    }\n\n    override fun onInit(status: Int) {\n        if (status == TextToSpeech.SUCCESS) {\n            \/\/ Prova d'establir catal\u00e0 (pot dependre del motor de TTS del dispositiu)\n            val localeCa = Locale(\"ca\", \"ES\")\n            val result = tts?.setLanguage(localeCa)\n\n            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {\n                \/\/ Si no hi ha catal\u00e0, fem servir l\u2019idioma per defecte\n                tts?.setLanguage(Locale.getDefault())\n                tts?.speak(\"El catal\u00e0 no est\u00e0 disponible al teu dispositiu.\", TextToSpeech.QUEUE_FLUSH, null, null)\n            } else {\n                \/\/ Parla en catal\u00e0\n                tts?.speak(\"Hola Android! Benvingut a l\u2019aplicaci\u00f3.\", TextToSpeech.QUEUE_FLUSH, null, null)\n            }\n        }\n    }\n\n    override fun onDestroy() {\n        tts?.stop()\n        tts?.shutdown()\n        super.onDestroy()\n    }\n}\n\n@Composable\nfun Greeting(name: String, modifier: Modifier = Modifier) {\n    Text(\n        text = \"Hola $name!\",\n        modifier = modifier\n    )\n}\n\n@Preview(showBackground = true)\n@Composable\nfun GreetingPreview() {\n    HelloWorldTheme {\n        Greeting(\"Android\")\n    }\n}\n<\/pre>\n\n\n\n<p><mark>MainActivity.kt amb veu <\/mark>espanyola<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package com.example.helloworld\n\nimport android.os.Bundle\nimport android.speech.tts.TextToSpeech\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.tooling.preview.Preview\nimport com.example.helloworld.ui.theme.HelloWorldTheme\nimport java.util.Locale\n\nclass MainActivity : ComponentActivity(), TextToSpeech.OnInitListener {\n\n    private var tts: TextToSpeech? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        \/\/ Inicializa TextToSpeech\n        tts = TextToSpeech(this, this)\n\n        enableEdgeToEdge()\n        setContent {\n            HelloWorldTheme {\n                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->\n                    Greeting(\n                        name = \"Android\",\n                        modifier = Modifier.padding(innerPadding)\n                    )\n                }\n            }\n        }\n    }\n\n    override fun onInit(status: Int) {\n        if (status == TextToSpeech.SUCCESS) {\n            \/\/ Establece el idioma espa\u00f1ol (Espa\u00f1a)\n            val localeEs = Locale(\"es\", \"ES\")\n            val result = tts?.setLanguage(localeEs)\n\n            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {\n                \/\/ Si no est\u00e1 disponible, usa el idioma por defecto\n                tts?.setLanguage(Locale.getDefault())\n                tts?.speak(\"El idioma espa\u00f1ol no est\u00e1 disponible en tu dispositivo.\", TextToSpeech.QUEUE_FLUSH, null, null)\n            } else {\n                \/\/ Habla en espa\u00f1ol\n                tts?.speak(\"\u00a1Hola Android! Bienvenido a la aplicaci\u00f3n.\", TextToSpeech.QUEUE_FLUSH, null, null)\n            }\n        }\n    }\n\n    override fun onDestroy() {\n        tts?.stop()\n        tts?.shutdown()\n        super.onDestroy()\n    }\n}\n\n@Composable\nfun Greeting(name: String, modifier: Modifier = Modifier) {\n    Text(\n        text = \"\u00a1Hola $name!\",\n        modifier = modifier\n    )\n}\n\n@Preview(showBackground = true)\n@Composable\nfun GreetingPreview() {\n    HelloWorldTheme {\n        Greeting(\"Android\")\n    }\n}\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>configuration ?\ufe0f Guia pas a pas: Primera app Android amb TTS en catal\u00e0 1. Obrir Android Studio 2. Crear un nou projecte 3. Editar la interf\u00edcie (activity_main.xml) Obre res\/layout\/activity_main.xml i enganxa aquest codi: 4. Afegir la l\u00f2gica TTS (MainActivity.java) Obre &hellip; <a href=\"https:\/\/www.beseit.net\/?page_id=17030\">Continua llegint <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":8179,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"categories":[],"class_list":["post-17030","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages\/17030","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=17030"}],"version-history":[{"count":17,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages\/17030\/revisions"}],"predecessor-version":[{"id":17070,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/pages\/17030\/revisions\/17070"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=\/wp\/v2\/media\/8179"}],"wp:attachment":[{"href":"https:\/\/www.beseit.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=17030"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.beseit.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=17030"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}