Skip to content
 
 

Repository files navigation

Get Supertonic for Android

Supertonic is a Text-to-Speech (TTS) engine available across multiple platforms. This repository is for the Systemwide TTS implementation on Android specifically, supporting most/all ARM ABIs on Play Store and GitHub releases APKs. On F-Droid release currently only arm64-v8a is implemented.

Please note that functionality and bug fixes may vary slightly between the F-Droid and Play Store builds as there can be version difference as they get submitted and approved following different timetables.

Download Options


Note: This repository currently tracks both versions of the application.


Adding or Improving Language Support (Submit a PR)

We welcome community contributions to support new languages or improve existing ones. The text-processing pipeline works as follows:

  1. Kotlin Text Normalizer: Expands shorthand notations (numbers, currency, percentages, ranges) into full spoken words (in the target language).
  2. JNI / Rust Chunker: Receives the normalized text and splits it into optimal sentences and audio chunks (maximum 300 characters, or 120 for CJK languages).

To add or improve support for a language, follow these steps:

1. High-Level Text Normalization (Kotlin)

Text normalization prevents the engine from reading symbols literally (e.g. pronouncing "3" as English "three" instead of Hindi "तीन").

// Inside TextNormalizer.normalize()
if (lowerLang.startsWith("hi")) {
    return normalizeHindi(processedText)
}
// Example: Implementation of normalizeHindi
private fun normalizeHindi(text: String): String {
    // 1. Convert native scripts digits to latin digits (e.g. ०-९ -> 0-9)
    var normalized = convertDevanagariDigits(text)
    
    // 2. Format ranges (e.g. "10-15" -> "10 से 15")
    val rangePattern = Pattern.compile("\\b(\\d+)\\s*[-–—]\\s*(\\d+)\\b")
    // Replace logic ...

    // 3. Format currency (e.g. "₹500" -> "500 रुपये")
    val currencyPattern = Pattern.compile("(?:\\bINR|₹)\\s*(\\d+(?:\\.\\d+)?)\\b")
    // Replace logic ...

    // 4. Convert remaining digits to words using NumberUtils
    val numberPattern = Pattern.compile("\\b(\\d+(?:\\.\\d+)?)\\b")
    // Replace each match using NumberUtils.convertHindi or NumberUtils.convertHindiDouble
    return normalized
}

2. Number to Word Expansion (Kotlin)

// Example signature:
fun convertHindi(n: Long): String
fun convertHindiDouble(d: Double): String

3. Sentence Splitting and Chunking (Rust)

The JNI layer delegates text chunking to Rust, ensuring the display UI in PlaybackActivity matches the underlying audio chunks.

  • Paths:
    • rust/src/lang/mod.rs (Language Normalizer Registry)
    • rust/src/lang/<lang_code>.rs (Language normalizer implementation)
    • rust/src/lang/configs/<lang_code>.json (JSON config for abbreviations)
  • Action:
    1. Add your language configuration JSON containing punctuation splits, abbreviations, and rules.
    2. Implement the LanguageNormalizer trait for your language:
      pub struct HindiNormalizer;
      impl LanguageNormalizer for HindiNormalizer {
          fn preprocess(&self, text: &str) -> String { ... }
          fn split_sentences(&self, text: &str) -> Vec<String> { ... }
          fn max_chunk_len(&self) -> usize { 300 }
          fn should_wrap_tags(&self) -> bool { false }
      }
    3. Register your normalizer in the get_normalizer factory function in rust/src/lang/mod.rs.

4. Language Selection UI and Resources (Kotlin)

5. Writing and Running Tests

Always write tests for the normalization expansions and chunking rules to prevent regressions.


Credits

Supertonic for creating lightweight and great-sounding TTS models for edge compute.

About

Initial setup for a F-droid release.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages