Clonar voces con F5-TTS en Linux: cuando 15 segundos de muestra son suficientes
Hace una semana descubrí que para clonar la voz de alguien con calidad de "no se nota que es IA" no necesitas pagar a ElevenLabs ni montar una infraestructura de cluster GPU. Necesitas un audio de WhatsApp de 15 segundos, una RTX modesta y un domingo por la tarde. Y software libre.
Lo que empezó como un "voy a probar a clonar mi propia voz para Ambrosio" terminó con audios mandados al Telegram con la voz de mi mujer dictándome la lista de tareas de casa, y la de un amigo respondiéndose a sí mismo en grupo. El resultado: nadie ha sabido distinguir el audio real del clonado en una primera escucha.
Este post es la receta completa: qué herramientas necesitas, cómo seleccionar una buena muestra, cómo procesarla, y los detalles que separan una clonación plana de una que asusta.
Por qué F5-TTS y no otra cosa
Antes de meternos en barro, contexto. El paisaje de TTS en abril de 2026 está dominado por:
- ElevenLabs: cloud, de pago (~22 dólares/mes para voice cloning serio). Calidad excelente. Tu voz pasa por sus servidores.
- OpenAI TTS / Azure: cloud, de pago, sin clonación zero-shot real.
- Coqui TTS: open source pero muerto. La empresa cerró en 2024.
- Piper: rápido, ONNX, voces preset. No clona. Suena a robot decente.
- Kokoro: 82M parámetros, neural, voces preset bonitas. No clona.
- F5-TTS: clonación zero-shot a partir de una muestra. Open source. Local.
Si lo que quieres es clonar una voz concreta sin mandar el audio a un servidor que no controlas, F5-TTS es ahora mismo la mejor opción libre. Es lo que vamos a montar.
Lo que F5-TTS hace bien
- Zero-shot: con una muestra de unos segundos clona tu voz. No hay que entrenar nada.
- Multi-idioma: hay un fork específico en español
(
jpgallegoar/F5-Spanish) entrenado a fondo, y el resultado es excelente. - Local: corre en tu GPU. La muestra de tu mujer no se va a OpenAI.
- MIT: úsalo para lo que quieras (con cabeza, ya hablaremos de eso).
Lo que F5-TTS hace mal
- Necesita GPU. CUDA preferentemente. CPU técnicamente funciona pero es inviable.
- Es lento. Para generar un minuto de audio en una RTX 2060 tardas alrededor de un minuto. Para tiempo real, ni te molestes.
- Inglés y español sólidos, otros idiomas: depende del checkpoint que uses.
- Textos largos: por encima de unos 2000 caracteres puede empezar a degenerar o mezclar voces.
El stack completo
La cadena de herramientas que monté en NixOS:
| Herramienta | Función |
|---|---|
| F5-TTS | El motor de clonación zero-shot |
ffmpeg |
Convertir audios al formato que F5 quiere |
whisper.cpp=| Transcribir muestras automáticamente | | =ffprobe |
Inspeccionar duraciones, formatos, codecs |
| PipeWire | Capturar audio del sistema en directo |
paplay |
Reproducir resultados |
uv (Python) |
Gestor de venv y deps |
Todo libre, todo local. Lo único de pago aquí podría ser la electricidad y la GPU.
Hardware necesario
He probado en una RTX 2060 con 6GB de VRAM. Funciona sin problemas para muestras de hasta 20 segundos y textos de hasta unos 2000 caracteres. Cualquier GPU NVIDIA con 4GB o más debería ir.
Sin GPU, olvídate. Pasa a Kokoro o Piper.
Instalación
F5-TTS se instala con pip en un venv.
Yo lo dejé fuera del flake de NixOS para no atarme las manos con el
sistema de paquetes. Lo encapsulé en un script bash que hace el setup
automático la primera vez.
El proceso de instalación:
# 1. Venv con Python 3.11
uv venv --python 3.11 ~/f5-tts/venv
# 2. F5-TTS (arrastra torch, transformers, etc — son ~5 GB)
VIRTUAL_ENV=~/f5-tts/venv uv pip install f5-tts
# 3. Modelo en español (~1.3 GB de checkpoint + vocab)
~/f5-tts/venv/bin/python3 -c "
from huggingface_hub import hf_hub_download
hf_hub_download(repo_id='jpgallegoar/F5-Spanish',
filename='model_1200000.safetensors',
local_dir='/home/user/f5-tts/es-model')
hf_hub_download(repo_id='jpgallegoar/F5-Spanish',
filename='vocab.txt',
local_dir='/home/user/f5-tts/es-model')
"Espacio total en disco: unos 7 GB la primera vez. Tiempo: 5 a 15 minutos según tu conexión.
Whisper para transcripciones
Si vas a clonar voces necesitas transcribir las muestras (lo veremos
en un momento). Para eso uso whisper.cpp
con el modelo small en español. En
NixOS:
environment.systemPackages = [ pkgs.whisper-cpp ];Y descargas el modelo:
mkdir -p ~/.local/share/whisper/models
curl -L -o ~/.local/share/whisper/models/ggml-small.bin \
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.binCómo funciona F5-TTS por dentro
Antes de la receta, dos minutos de teoría que ahorran muchos intentos fallidos.
F5-TTS es un modelo basado en flow matching. Le das dos cosas:
- Audio de referencia (
ref_audio): una muestra de la voz que quieres clonar. - Texto de referencia (
ref_text): la transcripción EXACTA de ese audio.
A partir de ahí, le pides un texto nuevo (gen_text) y genera audio que suena como la
persona del ref_audio leyendo ese gen_text.
La clave que cuesta entender al principio: el ref_text no es un parámetro opcional.
Es la herramienta que el modelo usa para alinear los fonemas de la
muestra con el espacio de embeddings. Si la transcripción no coincide
con el audio palabra por palabra, la clonación pierde calidad
rápido.
Esto explica un comportamiento que te volverá loco si no lo sabes: si transcribes "hola que tal" y en el audio dice "hola qué tal", el modelo se desorienta. Yo aprendí esto a base de hostias.
La regla de oro: 12 a 15 segundos
La duración de la muestra es probablemente la decisión más importante de todo el proceso. Después de probar de todo, esta es la tabla:
| Duración | Resultado |
|---|---|
| Menos de 8s | Voz plana, robótica, sin entonación |
| 8 a 10s | Aceptable pero pierde matices |
| 12 a 15s | Óptimo: timbre + prosodia + naturalidad |
| 15 a 18s | Bien, pero F5 puede empezar a truncar internamente |
| Más de 18s | F5 trunca o degrada. Cortar. |
Pero hay un detalle más importante que la duración: el rango prosódico de la muestra. Una frase de 12 segundos con declarativa, énfasis, pausa y pregunta vale infinitamente más que un monólogo plano de 20 segundos.
La mejor muestra que conseguí tenía 11 segundos y contenía:
- una afirmación rotunda con palabrota
- una pregunta retórica
- una muletilla coloquial ("vamos")
- una interrogación final con tono ascendente ("¿vale?")
Resultado: la clonación capturó el carácter de la persona, no solo el timbre.
El flujo completo, paso a paso
Lo que sigue es la receta que llevo aplicando con éxito a varias voces. Asumo que ya tienes una muestra (puede ser un guasap descargado, un fragmento de YouTube, una grabación tuya).
Paso 1: inspeccionar la muestra
Lo primero, ver qué tienes entre manos.
ffprobe -hide_banner /tmp/sample.ogg 2>&1 | grep -E "Duration|Stream"Si dura menos de 8 segundos, descártala o pide otra. Si dura más de 30, prepárate para recortarla.
Paso 2: convertir a WAV completo (intermedio)
F5-TTS quiere el audio como WAV mono a 16 kHz, 16 bits PCM. Aunque luego vas a recortar un fragmento, conviene primero convertir el audio entero al formato bueno.
ffmpeg -y -i /tmp/sample.ogg \
-ac 1 -ar 16000 -sample_fmt s16 \
/tmp/full.wavPaso 3: transcribir con timestamps
Aquí es donde Whisper se vuelve imprescindible. Necesitamos no solo qué dice la muestra, sino cuándo lo dice, para poder elegir el mejor fragmento.
whisper-cli -m ~/.local/share/whisper/models/ggml-small.bin \
-f /tmp/full.wav -l es -t 16Esto te da algo como:
[00:00:00.000 --> 00:00:04.180] Voy a echar más fotos ahí en el espejo, pero es que claro la gente entra
[00:00:04.180 --> 00:00:08.300] con la puerta y que me da, entonces me asusto yo, asusto a la gente
[00:00:08.300 --> 00:00:12.620] y ya no me echan más fotos
[00:00:12.620 --> 00:00:17.820] escúchame, hay huevos y te va a subir a comer
Con esto delante puedes identificar tramos limpios y elegir el mejor.
Paso 4: elegir un buen fragmento
Esta es la decisión clave. Yo aplico tres reglas:
- Duración entre 12 y 15 segundos. Si tienes 11 o 16, no pasa nada, pero apunta a 13.
- Variedad prosódica. Busca un tramo con cambios de tono. Una afirmación seguida de una pregunta es oro. Un monólogo monocorde es plomo.
- Sin ruido ni solapamiento. Si hay música de fondo, F5 intentará reproducirla. Si hay otra voz interrumpiendo, la mezclará con la tuya.
Marca el fragmento por timestamps. En el ejemplo de arriba podría ser
04.18 a 17.82.
Paso 5: cortar el fragmento
mkdir -p ~/dotfiles/data/tts-voices/menganita
ffmpeg -y -i /tmp/full.wav -ss 4.18 -to 17.82 \
-ac 1 -ar 16000 -sample_fmt s16 \
~/dotfiles/data/tts-voices/menganita/audio.wavAhora tienes un audio.wav de unos 13
segundos en el formato exacto que F5 quiere.
Paso 6: escribir el text.txt EXACTO
Esto es lo que más se le suele pasar a la gente. La transcripción tiene que ser palabra por palabra, signo por signo, lo que dice exactamente el audio del paso 5.
cat > ~/dotfiles/data/tts-voices/menganita/text.txt <<'EOF'
con la puerta y que me da, entonces me asusto yo, asusto a la gente y ya no me echan más fotos. Escúchame, hay huevos y te va a subir a comer.
EOFCopia tal cual del transcript de Whisper, corrigiendo solo errores obvios del transcriptor (no del hablante). Si el hablante dice "asusto a la jente" con seseo, transcribe "asusto a la gente" igualmente: F5 funciona con ortografía estándar, no con transcripción fonética.
Paso 7: probar
~/f5-tts/venv/bin/f5-tts_infer-cli \
--model F5TTS_Base \
--ckpt_file ~/f5-tts/es-model/model_1200000.safetensors \
--vocab_file ~/f5-tts/es-model/vocab.txt \
--ref_audio ~/dotfiles/data/tts-voices/menganita/audio.wav \
--ref_text "$(cat ~/dotfiles/data/tts-voices/menganita/text.txt)" \
--gen_text "Hola, soy menganita hablando desde el ordenador. ¿Te suena raro? A mí también." \
--device cuda \
--output_dir /tmp \
--output_file menganita_prueba.wav
paplay /tmp/menganita_prueba.wavTiempo de generación en RTX 2060: unos 8 a 12 segundos para una frase corta. La primera vez carga el modelo y tarda más (60 a 90 segundos).
Si suena plana, vuelve al paso 4 y elige otro fragmento más
expresivo. Si suena distorsionada, comprueba que el text.txt coincide con lo que dice el audio.
Un wrapper para no escribir tanto
Tener que recordar la línea anterior cada vez es absurdo. Lo
encapsulé en un script f5-say que
acepta:
f5-say menganita "lo que sea"
echo "lo que sea" | f5-say menganita -
f5-say -o salida.wav menganita "..." # a fichero, no reproduce
f5-say -l # lista voces disponiblesEl script vive en ~/dotfiles/scripts/f5-say, hace auto-instalación
si falta el venv o el modelo, y carga las librerías de FFmpeg 4 que
F5-TTS exige (en NixOS las librerías nuevas dan problemas con
torchaudio).
Bonus 1: capturar voces al vuelo en una reunión
Aquí es donde la cosa se pone interesante. Si estás en un Meet o Zoom y quieres clonar la voz de alguien que está hablando, no necesitas pedirle un audio. Puedes grabar el monitor del sink de PipeWire (lo que sale por tus altavoces).
Mi script capture-talker:
#!/usr/bin/env bash
set -euo pipefail
NAME="${1:-talker}"
SECS="${2:-15}"
# Sink activo (RUNNING, lo que ahora mismo está sonando)
MONITOR=$(pactl list short sources \
| awk '$NF=="RUNNING" && /monitor/ {print $2; exit}')
OUT="/tmp/${NAME}_$(date +%H%M%S).wav"
ffmpeg -hide_banner -loglevel error \
-f pulse -i "$MONITOR" \
-ac 1 -ar 16000 -sample_fmt s16 \
-t "$SECS" "$OUT"
echo "$OUT"Uso:
capture-talker # 15 segundos del monitor activo
capture-talker fulano # 15 segundos, archivo /tmp/fulano_HHMMSS.wav
capture-talker fulano 20 # 20 segundosEl truco está en pactl list short sources | awk '$NF="RUNNING"
&& monitor'=. Eso identifica el sink que ahora mismo
está sacando audio (mis altavoces, en mi caso un FiiO K7), y ffmpeg
graba directamente de su monitor source.
Resultado: durante la reunión, cuando alguien interesante esté
hablando, capture-talker fulano y tienes
una muestra perfecta lista para clonar. Después aplicas el flujo de los
pasos 3 al 7.
Implicaciones éticas obvias. Hablamos de ello al final.
Bonus 2: mandar el audio generado al Telegram
El uso real de todo esto, para mí, no es generar audios para guardarlos. Es mandárselos a alguien. La cadena completa que uso:
# 1. Generar
echo "el texto que quiero que diga" | f5-say -o /tmp/v.wav menganita -
# 2. Convertir a OGG/Opus (Telegram exige este formato para voice notes)
ffmpeg -y -i /tmp/v.wav -c:a libopus -b:a 64k /tmp/v.ogg
# 3. Mandar como nota de voz (no como audio adjunto)
BOT=$(cat /run/agenix/telegram-bot-token)
CHAT=$(cat /run/agenix/telegram-chat-id)
curl -sf -X POST "https://api.telegram.org/bot${BOT}/sendVoice" \
-F chat_id="$CHAT" -F voice=@/tmp/v.ogg
# 4. Limpiar
rm -f /tmp/v.wav /tmp/v.oggLo importante: sendVoice con un
OGG/Opus produce la burbuja típica de WhatsApp/Telegram, no un audio
reproducible con player. Si mandas un WAV o MP3 con sendAudio, se ve como un archivo adjunto y
delata que es generado. La burbuja de voz pasa desapercibida.
Lecciones que aprendí a base de hostias
Algunas cosas que no están en la documentación oficial pero que te ahorran mucho tiempo:
No leas URLs, IDs ni hashes en el audio
Si pides al modelo que genere "el commit es 7f3a9b21", va a leer literal "siete efe tres a nueve be dos uno". Suena horrible y no se entiende. Pon esos detalles en el caption del mensaje, no en el audio. El audio es narrativo, no técnico.
Transcribe foneticamente las siglas y números
"F5" se lee mejor como "efe cinco". "RTX 2060" como "ere te equis dos mil sesenta". "IA" como "Inteligencia Artificial" o "i a" si quieres letras. F5-TTS no tiene un módulo de letrear siglas; lee lo que pones.
Cuidado con los textos largos
Por encima de 1500-2000 caracteres, F5 puede empezar a:
- Truncar el final
- Cambiar la voz a media generación
- Mezclar timbres si tienes varias voces cargadas
Si necesitas un audio largo, trocea el texto en chunks de unos 1000
caracteres, genera cada uno y concaténalos con ffmpeg.
El modelo en español es CRUCIAL
El modelo base de F5-TTS es bilingüe (inglés + chino). Para español,
jpgallegoar/F5-Spanish marca la diferencia
entre "se entiende lo que dice" y "parece nativo". No te molestes con el
modelo base si vas a generar en español.
La primera generación tarda mucho
La primera vez que invocas F5 carga el modelo en VRAM y eso lleva entre 30 y 90 segundos en una RTX 2060. Después, mientras el proceso sigue vivo, las generaciones son rápidas. Si vas a hacer batch, mantén el proceso abierto.
Implicaciones éticas
No puedo cerrar este post sin decirlo: clonar la voz de alguien sin su permiso es una putada y, en muchas jurisdicciones, ilegal. La tecnología que acabo de explicar permite generar audios indistinguibles de los reales, y eso tiene consecuencias.
La regla simple que aplico:
- La voz de mi mujer: con su permiso explícito, para mandarle bromas y avisarle del cambio.
- La voz de un amigo: con su permiso explícito, para reírnos en el grupo y avisarle del cambio.
- Voces de figuras públicas, jefes, desconocidos: no.
Si vas a hacer esto para cachondear con alguien cercano, avisa antes y enseña el resultado. Si lo vas a usar para algo serio (un asistente personal con tu propia voz, por ejemplo), pues adelante. Pero no clones la voz del CEO para mandar audios fraudulentos: hay gente cumpliendo condena por menos.
Las plataformas grandes (ElevenLabs, OpenAI) tienen detección de voces clonadas y filtros activos. Las herramientas locales como F5-TTS no tienen nada. La responsabilidad está entera en ti.
Conclusión
En 2026, clonar una voz con calidad alta es un fin de semana de cacharreo, una RTX modesta y software MIT. La barrera técnica es prácticamente nula. La barrera real es ética y de criterio.
Si quieres usarlo bien: pídele permiso a la persona, hazle reír con el resultado, y guarda los samples para el futuro. Es una forma curiosa de archivar voces de gente cercana en un formato del que se pueden generar mensajes nuevos.
Si quieres usarlo mal: te recomiendo que no.
Recursos
- F5-TTS oficial: github.com/SWivid/F5-TTS
- Modelo en español: huggingface.co/jpgallegoar/F5-Spanish
- whisper.cpp: github.com/ggerganov/whisper.cpp
- Mis dotfiles (incluyen
f5-say,capture-talkery todo el módulo TTS de NixOS): github.com/pascualmg/dotfiles
Comentarios (0)
Sin comentarios todavia. Se el primero!
Deja un comentario