Texto a voz en C# y .NET sin conexión
La forma clásica de hablar desde C# es System.Speech: unas líneas, las voces de Windows, sin internet. Sigue funcionando, pero solo en Windows, las voces suenan anticuadas y cambian de una máquina a otra. Los servicios en la nube suenan mejor, pero envían cada texto fuera y cobran por carácter.
Esta guía muestra una tercera vía: el motor gratuito SuperClonica como servidor HTTP local al que cualquier app .NET puede llamar en Windows, Linux o macOS, con voces naturales y archivos WAV que conservas.
Tres formas de hablar desde .NET
Para un prototipo rápido en Windows basta System.Speech; para la voz de un producto que suene igual en todas partes, usa un motor.
- System.Speech: integrado en Windows, sin conexión, voces robóticas, solo Windows.
- API de voz en la nube: voces naturales, pero cuenta, clave, cobro por carácter y tu texto en sus servidores.
- SuperClonica: un servidor local con voces naturales, de personajes y propias, sin conexión, en cualquier sistema que ejecute 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 C#
Con System.Net.Http, System.Text y System.Text.Json.Nodes, una petición ocupa unas líneas en .NET 6 o posterior: using var http = new HttpClient(); var voice = JsonNode.Parse(File.ReadAllText("voice.json")); var body = new JsonObject { ["text"] = "¡Hola desde C#!", ["voice"] = voice, ["lang"] = "es", ["seed"] = 7 }; var res = await http.PostAsync("http://localhost:8000/synthesize", new StringContent(body.ToJsonString(), Encoding.UTF8, "application/json")); File.WriteAllBytes("hello.wav", await res.Content.ReadAsByteArrayAsync()); Para una voz de serie, pon ["voice"] = "F1" en lugar de cargar un archivo. El mismo texto, voz y seed dan siempre el mismo audio, así que cachea los archivos de las frases que se repiten y reprodúcelos con la librería de audio que ya usa tu app.
Hábitos para producción
Mantén un solo HttpClient durante toda la vida de la app. 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.