Texto a voz en Java sin conexión
Java nunca incluyó síntesis de voz en su biblioteca estándar, así que los proyectos recurren a motores antiguos como FreeTTS o MaryTTS, que suenan robóticos frente a las voces neuronales, o a un SDK en la nube que cobra por carácter y ve cada texto.
Esta guía muestra una alternativa moderna: el motor gratuito SuperClonica como servidor HTTP local, llamado con el HttpClient integrado en Java 11 y posteriores. Obtienes voces naturales, archivos WAV que conservas y ninguna tarifa por petición, en cualquier plataforma.
Formas de hablar desde Java
El motor no se ejecuta dentro de la JVM: tu código Java le habla por HTTP, como a cualquier otro servicio.
- FreeTTS y MaryTTS: Java puro y sin conexión, pero robóticos frente a las voces neuronales.
- SDK en la nube: voces naturales, pero cuenta, clave, cobro por carácter y tu texto en sus servidores.
- SuperClonica: un servidor HTTP local con voces naturales, de personajes y propias, sin conexión, donde funcione Docker.
- Habla 31 idiomas; el chino aún no está disponible.
Escucha las voces gratis
Antes de escribir código, abre la página de cualquier voz, escribe una frase de 30 a 100 caracteres, elige el idioma y pulsa el botón para generarla. En unos segundos oyes la voz que podría tener tu app, sin cuenta.
Arranca el servidor de voz
Una tarjeta gráfica NVIDIA lo acelera con la imagen cuda, pero no es obligatoria.
- Arranca el servidor en cualquier CPU: docker run -d -p 8000:8000 -v superclonica-models:/models superclonica/superclonica:cpu.
- El primer arranque descarga el modelo Supertonic 3, unos 385 MB, en el volumen; GET /health indica cuándo está listo.
- POST /synthesize recibe JSON con text, voice, lang, seed y normalize, y responde con un WAV mono de 16 bits.
- voice es un nombre de serie de M1 a M5 y de F1 a F5, o el contenido JSON de un archivo de voz.
Llámalo desde Java
Con java.net.http, java.net.URI y java.nio.file, una petición ocupa unas líneas en Java 11 o posterior: var voice = Files.readString(Path.of("voice.json")); var json = "{\"text\": \"¡Hola desde Java!\", \"lang\": \"es\", \"seed\": 7, \"voice\": " + voice + "}"; var request = HttpRequest.newBuilder(URI.create("http://localhost:8000/synthesize")).header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(json)).build(); HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofFile(Path.of("hello.wav"))); La respuesta se escribe directamente en un archivo WAV. Para una voz de serie, envía "voice": "F1" en lugar del contenido del archivo. El mismo texto, voz y seed dan siempre el mismo audio, así que cachea los archivos de frases repetidas; en proyectos grandes, una librería JSON como Jackson mantiene ordenada la petición.
Hábitos para producción
Reutiliza un único HttpClient y pon un tiempo de espera a las peticiones. No expongas el puerto 8000 a internet tal cual: define SUPERCLONICA_API_KEY y envíala como token Bearer, o mantén el servidor en una red privada. Si llegan muchas peticiones a la vez, ejecuta más copias del modelo con SUPERCLONICA_LANES, y mide en tu hardware: en nuestras pruebas una frase corta tardó 0,12 s en una RTX 5070 Ti y 0,43 s con cuatro hilos de CPU.