Kotlin text to speech for Android with natural voices
Android has text to speech built in: the TextToSpeech class reads any text with the engine installed on the phone, offline and free. Which voice the user hears depends on the device, the engine and the voices downloaded, so the same app sounds different on every phone.
The free SuperClonica engine gives an Android app one natural voice everywhere, in two ways: audio files voiced in advance and shipped as resources, or a speech server the app calls. This guide shows both with ready Kotlin code and says when the system engine is still the right tool.
Three ways to make an Android app speak
Many apps combine them: resources for the interface, the server for user text, the system engine as a fallback.
- TextToSpeech: the engine installed on the phone, offline and free, with voices that vary by device.
- Raw resources: every fixed line voiced once with SuperClonica and shipped in the app.
- A speech server: the app sends text to your SuperClonica server and plays the WAV it returns.
- SuperClonica speaks 31 languages; Chinese is not supported yet.
Pick a voice free online
On the page of any voice, type a line of your app, 30 to 100 characters, choose the language and press Voice it. In a few seconds you hear whether it fits, with no account, right on your phone.
Ship pre-voiced lines as resources
Resources work offline with no delay; a change means a new app version.
- Voice each line on your computer with the engine: python -m pip install superclonica-cpu, then superclonica --text "Welcome back!" --voice F1 --lang en --output welcome.mp3.
- Put the files into res/raw; resource names may use only lowercase letters, digits and underscores.
- Play a line: MediaPlayer.create(context, R.raw.welcome).start()
- Release the player when it finishes, for example in setOnCompletionListener.
Call your own speech server
Run the server on a machine you control: docker run -d -p 8000:8000 -v superclonica-models:/models superclonica/superclonica:cpu. Android blocks plain HTTP by default, so put the server behind HTTPS, and set SUPERCLONICA_API_KEY so only your app can use it. With OkHttp, a line is one request, made off the main thread, for example in a coroutine on Dispatchers.IO: val body = """{"text": "Your order is on its way.", "voice": "F1", "lang": "en"}""".toRequestBody("application/json".toMediaType()); val bytes = client.newCall(Request.Builder().url("https://tts.example.com/synthesize").post(body).build()).execute().body!!.bytes(); val file = File(cacheDir, "line.wav").apply { writeBytes(bytes) }; MediaPlayer().apply { setDataSource(file.path); prepare(); start() } Add an Authorization header with the key, and cache the files of lines that repeat.
When the system TextToSpeech is enough
The system engine is enough when the voice only has to be understood: reading a notification, an accessibility helper, a prototype, or an app that must speak without any network. Choose SuperClonica when the voice is part of the product: a language tutor, a game character, a guided meditation, a brand that must sound the same on every phone.