Volver al blog
iagooglecloudffmpegbuildinpublic

Cambié mi motor TTS. La llamada a la API fue lo más sencillo.

Cómo integrar Google Chirp 3 HD en un pipeline de doblaje automático sin sacrificar la sincronización temporal ni la calidad de voz en 19 idiomas.

13 de septiembre de 2026

Cambié mi motor TTS. La llamada a la API fue lo más sencillo.

Katto ya tenía doblaje con IA. Un creador podía tomar un clip corto, elegir un idioma y recibir la versión traducida. La primera versión usaba Kokoro y cubría ocho idiomas.

Recientemente migré el motor principal de síntesis de voz a Google Cloud Text-to-Speech con Chirp 3 HD. El objetivo parecía directo: mejorar las voces y agregar más idiomas. Katto ahora expone 19 idiomas de doblaje y 12 voces seleccionadas en el editor.

Esperaba que la migración fuera básicamente un cambio de API.

No lo fue.

Generar una oración natural es fácil. Hacer que esa oración comience y termine exactamente en el espacio que dejó otro hablante es el verdadero problema del doblaje.

Si el hablante original dice algo en 2.4 segundos y la traducción toma 3.2 segundos, un buen modelo TTS no salva el clip. La voz se solapa con la siguiente oración, los subtítulos se desfasan o el audio tiene que acelerarse hasta sonar apresurado.

La solicitud TTS resultó ser la parte más pequeña del sistema.

El pipeline que terminé construyendo

timings de palabras en caché
        |
        v
segmentos de frases con ranuras de tiempo fijas
        |
        v
traducción consciente de la duración
        |
        v
Google Chirp 3 HD, una frase a la vez
        |
        v
alineación de audio acotada con FFmpeg
        |
        +----> subtítulos traducidos de los mismos segmentos
        |
        v
remux final a MP4

Cada etapa existe porque una versión más simple falló de otra manera.

Conservar el timing original como dato

Katto ya tiene marcas de tiempo de palabras desde su pipeline de transcripción. No envío el transcript completo a traducción y TTS como un solo bloque. Agrupo las palabras en frases.

Una frase termina en puntuación de oración, después de una pausa mayor a 0.6 segundos, o cuando excedería seis segundos. Cada segmento conserva su inicio y fin originales. Esos números se convierten en el contrato para cada etapa posterior.

Sintetizar el transcript completo puede sonar más fluido, pero elimina los anclajes necesarios para colocar el habla de vuelta en la línea de tiempo del video. La síntesis a nivel de frase preserva suficiente contexto para una voz natural mientras mantiene límites de tiempo útiles.

Traducir para duración hablada, no solo significado

Una traducción escrita correcta puede ser una mala traducción para doblaje. Algunos idiomas necesitan más sílabas para expresar la misma idea. Una versión literal puede preservar cada matiz y aún ser inutilizable porque no cabe en su ranura.

Para cada grupo de frases, le pido a Claude Haiku una traducción hablada natural que prefiera frases más cortas y menos sílabas. La respuesta preserva cada índice de segmento fuente.

El prompt es parte del sistema de audio. Su trabajo no es solo precisión lingüística. También reduce el estiramiento de tiempo necesario después.

Esto sigue siendo una heurística. Un LLM no puede garantizar duración porque la voz seleccionada también cambia el ritmo. La capa de audio aún mide el WAV generado. Una caché en memoria, indexada por idioma de destino y segmentos fuente, permite reutilizar la traducción mientras el worker siga activo.

Sintetizar una frase a la vez

Cada frase traducida va a la API REST de Google Cloud Text-to-Speech como audio LINEAR16 a 24 kHz. Los nombres de voz siguen el formato locale-Chirp3-HD-speaker documentado por Google.

Google soporta más locales Chirp 3 HD de los que Katto actualmente expone. Limité deliberadamente el producto a 19 idiomas cableados a través de la ruta completa: UI, mapeo de locale, fuentes, subtítulos y comportamiento de fallback. Una API que afirma soportar un idioma no significa que el producto circundante lo soporte correctamente.

Ajustar el habla en la ranura sin destruirla

Después de la síntesis, comparo la duración generada con la ranura original.

target_duration = segment["end"] - segment["start"]
ratio = generated_duration / target_duration

Si el habla es ligeramente demasiado larga, el filtro atempo de FFmpeg la acelera mientras preserva el tono. Limito la aceleración a 1.3x.

Ese límite importa. Un límite anterior de 1.6x hacía que más frases cupieran, pero algunas voces sonaban antinaturalmente apresuradas. La alineación perfecta no es útil si el resultado es desagradable de escuchar.

Cada frase ajustada se coloca en su offset original en una pista maestra. Las frases cortas dejan una pausa natural. Las frases más largas obtienen una corrección acotada. Esto no resuelve cada traducción patológica. Impone una regla más útil: preservar la inteligibilidad antes de perseguir un timing matemáticamente perfecto.

Dar al habla y los subtítulos el mismo reloj

La respuesta de síntesis me da audio, no marcas de tiempo confiables de palabras para el texto recién hablado. Inventar timing a nivel de palabra haría que los subtítulos se vean precisos mientras están equivocados.

Los clips doblados por lo tanto usan subtítulos a nivel de frase generados de los mismos segmentos traducidos usados para el habla. Sus tiempos de inicio y fin ya coinciden con la colocación del audio.

El renderizador también selecciona fuentes que cubren el script destino. Las fuentes latinas no son suficientes para japonés, chino, hindi o árabe. Los títulos de intro y hooks de IA siguen la misma ruta de localización, así que la pantalla no habla un idioma y muestra otro.

Los problemas ordinarios de producción también importaron

No todos los hablantes seleccionados funcionaron en cada locale que probé. Si una voz seleccionada no está disponible, Katto reintenta una vez con un default conocido para el género elegido. La vista previa en vivo del editor llama al mismo motor de Google. Una muestra de otro modelo permitiría al usuario elegir una voz que nunca recibe.

La clave de API de producción está restringida a la dirección IPv4 del VPS, pero el VPS prefería IPv6 al alcanzar Google. Las solicitudes válidas fueron rechazadas hasta que la llamada TTS fue forzada a través de IPv4. La API, clave y código eran correctos. La ruta de red no lo era.

El doblaje produce una variante de video separada. Si la traducción, síntesis, renderizado de subtítulos o remuxing falla, el clip original permanece intacto. Para los ocho idiomas originales, Kokoro sigue disponible cuando la ruta de Google está deshabilitada o no configurada.

Qué cambió y qué no

El resultado visible fue una expansión de 8 a 19 idiomas de doblaje, más voces seleccionables y vistas previas en vivo.

La mejora más profunda fue arquitectónica. Traducción, habla, subtítulos, overlays y renderizado de video ahora comparten una unidad temporal: el segmento de frase.

El sistema no clona al hablante original, no realiza sincronización labial ni inventa marcas de tiempo de palabras generadas. Las traducciones muy largas aún pueden exceder su ranura ideal. Esos límites son mejores que afirmar precisión que el pipeline no puede entregar.

Pensé que estaba reemplazando un motor de síntesis de voz. Terminé ajustando el contrato entre casi cada etapa del pipeline de medios.

La llamada a la API fue la parte fácil. Hacer que el resultado pertenezca a la línea de tiempo original fue el trabajo.

Katto convierte videos largos en clips verticales cortos y ahora puede doblar esos clips a 19 idiomas. Si estás construyendo video multilingüe, me interesaría saber cómo manejas el timing sin hacer que la voz suene apresurada.

Referencias

Google Cloud Text-to-Speech: voces Chirp 3 HD

Artículos relacionados

¿Listo para convertir tus vídeos en clips virales?

Katto recorta, subtitula y reencuadra automáticamente tus vídeos largos en contenido de formato corto.

Prueba Katto gratis
Cambié mi motor TTS. La llamada a la API fue lo más sencillo. | Katto