{"id":"0df42138-6886-4449-a311-daa88a9e8bc6","headline":"Clonar voces con F5-TTS en Linux: cuando 15 segundos de muestra son suficientes","slug":"clonar-voces-con-f5-tts-en-linux-cuando-15-segundos-de-muestra-son-suficientes","articleBody":"<p>Hace una semana descubr\u00ed que para clonar la voz de alguien con\ncalidad de \"no se nota que es IA\" no necesitas pagar a ElevenLabs ni\nmontar una infraestructura de cluster GPU. Necesitas un audio de\nWhatsApp de 15 segundos, una RTX modesta y un domingo por la tarde. Y\nsoftware libre.<\/p>\n<p>Lo que empez\u00f3 como un \"voy a probar a clonar mi propia voz para\nAmbrosio\" termin\u00f3 con audios mandados al Telegram con la voz de mi mujer\ndict\u00e1ndome la lista de tareas de casa, y la de un amigo respondi\u00e9ndose a\ns\u00ed mismo en grupo. El resultado: nadie ha sabido distinguir el audio\nreal del clonado en una primera escucha.<\/p>\n<p>Este post es la receta completa: qu\u00e9 herramientas necesitas, c\u00f3mo\nseleccionar una buena muestra, c\u00f3mo procesarla, y los detalles que\nseparan una clonaci\u00f3n plana de una que asusta.<\/p>\n<h1 id=\"por-qu\u00e9-f5-tts-y-no-otra-cosa\">Por qu\u00e9 F5-TTS y no otra\ncosa<\/h1>\n<p>Antes de meternos en barro, contexto. El paisaje de TTS en abril de\n2026 est\u00e1 dominado por:<\/p>\n<ul>\n<li><strong>ElevenLabs<\/strong>: cloud, de pago (~22 d\u00f3lares\/mes para\nvoice cloning serio). Calidad excelente. Tu voz pasa por sus\nservidores.<\/li>\n<li><strong>OpenAI TTS \/ Azure<\/strong>: cloud, de pago, sin clonaci\u00f3n\nzero-shot real.<\/li>\n<li><strong>Coqui TTS<\/strong>: open source pero muerto. La empresa\ncerr\u00f3 en 2024.<\/li>\n<li><strong>Piper<\/strong>: r\u00e1pido, ONNX, voces preset. No clona. Suena\na robot decente.<\/li>\n<li><strong>Kokoro<\/strong>: 82M par\u00e1metros, neural, voces preset\nbonitas. No clona.<\/li>\n<li><strong>F5-TTS<\/strong>: clonaci\u00f3n zero-shot a partir de una\nmuestra. Open source. Local.<\/li>\n<\/ul>\n<p>Si lo que quieres es <strong>clonar una voz concreta<\/strong> sin\nmandar el audio a un servidor que no controlas, F5-TTS es ahora mismo la\nmejor opci\u00f3n libre. Es lo que vamos a montar.<\/p>\n<h2 id=\"lo-que-f5-tts-hace-bien\">Lo que F5-TTS hace bien<\/h2>\n<ul>\n<li><strong>Zero-shot<\/strong>: con una muestra de unos segundos clona\ntu voz. No hay que entrenar nada.<\/li>\n<li><strong>Multi-idioma<\/strong>: hay un fork espec\u00edfico en espa\u00f1ol\n(<code class=\"verbatim\">jpgallegoar\/F5-Spanish<\/code>) entrenado a\nfondo, y el resultado es excelente.<\/li>\n<li><strong>Local<\/strong>: corre en tu GPU. La muestra de tu mujer no\nse va a OpenAI.<\/li>\n<li><strong>MIT<\/strong>: \u00fasalo para lo que quieras (con cabeza, ya\nhablaremos de eso).<\/li>\n<\/ul>\n<h2 id=\"lo-que-f5-tts-hace-mal\">Lo que F5-TTS hace mal<\/h2>\n<ul>\n<li><strong>Necesita GPU<\/strong>. CUDA preferentemente. CPU\nt\u00e9cnicamente funciona pero es inviable.<\/li>\n<li><strong>Es lento<\/strong>. Para generar un minuto de audio en una\nRTX 2060 tardas alrededor de un minuto. Para tiempo real, ni te\nmolestes.<\/li>\n<li><strong>Ingl\u00e9s y espa\u00f1ol s\u00f3lidos, otros idiomas<\/strong>: depende\ndel checkpoint que uses.<\/li>\n<li><strong>Textos largos<\/strong>: por encima de unos 2000 caracteres\npuede empezar a degenerar o mezclar voces.<\/li>\n<\/ul>\n<h1 id=\"el-stack-completo\">El stack completo<\/h1>\n<p>La cadena de herramientas que mont\u00e9 en NixOS:<\/p>\n<table>\n<thead>\n<tr>\n<th>Herramienta<\/th>\n<th>Funci\u00f3n<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>F5-TTS<\/td>\n<td>El motor de clonaci\u00f3n zero-shot<\/td>\n<\/tr>\n<tr>\n<td><code class=\"verbatim\">ffmpeg<\/code><\/td>\n<td>Convertir audios al formato que F5 quiere<\/td>\n<\/tr>\n<tr>\n<td><code\nclass=\"verbatim\">whisper.cpp=| Transcribir muestras autom\u00e1ticamente       | | =ffprobe<\/code><\/td>\n<td>Inspeccionar duraciones, formatos, codecs<\/td>\n<\/tr>\n<tr>\n<td>PipeWire<\/td>\n<td>Capturar audio del sistema en directo<\/td>\n<\/tr>\n<tr>\n<td><code class=\"verbatim\">paplay<\/code><\/td>\n<td>Reproducir resultados<\/td>\n<\/tr>\n<tr>\n<td><code class=\"verbatim\">uv<\/code> (Python)<\/td>\n<td>Gestor de venv y deps<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Todo libre, todo local. Lo \u00fanico de pago aqu\u00ed podr\u00eda ser la\nelectricidad y la GPU.<\/p>\n<h2 id=\"hardware-necesario\">Hardware necesario<\/h2>\n<p>He probado en una RTX 2060 con 6GB de VRAM. Funciona sin problemas\npara muestras de hasta 20 segundos y textos de hasta unos 2000\ncaracteres. Cualquier GPU NVIDIA con 4GB o m\u00e1s deber\u00eda ir.<\/p>\n<p>Sin GPU, olv\u00eddate. Pasa a Kokoro o Piper.<\/p>\n<h1 id=\"instalaci\u00f3n\">Instalaci\u00f3n<\/h1>\n<p>F5-TTS se instala con <code class=\"verbatim\">pip<\/code> en un venv.\nYo lo dej\u00e9 fuera del flake de NixOS para no atarme las manos con el\nsistema de paquetes. Lo encapsul\u00e9 en un script bash que hace el setup\nautom\u00e1tico la primera vez.<\/p>\n<p>El proceso de instalaci\u00f3n:<\/p>\n<div class=\"sourceCode\" id=\"cb1\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb1-1\"><a href=\"#cb1-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># 1. Venv con Python 3.11<\/span><\/span>\n<span id=\"cb1-2\"><a href=\"#cb1-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">uv<\/span> venv <span class=\"at\">--python<\/span> 3.11 ~\/f5-tts\/venv<\/span>\n<span id=\"cb1-3\"><a href=\"#cb1-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb1-4\"><a href=\"#cb1-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># 2. F5-TTS (arrastra torch, transformers, etc \u2014 son ~5 GB)<\/span><\/span>\n<span id=\"cb1-5\"><a href=\"#cb1-5\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">VIRTUAL_ENV<\/span><span class=\"op\">=<\/span>~\/f5-tts\/venv <span class=\"ex\">uv<\/span> pip install f5-tts<\/span>\n<span id=\"cb1-6\"><a href=\"#cb1-6\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb1-7\"><a href=\"#cb1-7\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># 3. Modelo en espa\u00f1ol (~1.3 GB de checkpoint + vocab)<\/span><\/span>\n<span id=\"cb1-8\"><a href=\"#cb1-8\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">~\/f5-tts\/venv\/bin\/python3<\/span> <span class=\"at\">-c<\/span> <span class=\"st\">&quot;<\/span><\/span>\n<span id=\"cb1-9\"><a href=\"#cb1-9\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">from huggingface_hub import hf_hub_download<\/span><\/span>\n<span id=\"cb1-10\"><a href=\"#cb1-10\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">hf_hub_download(repo_id=&#39;jpgallegoar\/F5-Spanish&#39;,<\/span><\/span>\n<span id=\"cb1-11\"><a href=\"#cb1-11\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">                filename=&#39;model_1200000.safetensors&#39;,<\/span><\/span>\n<span id=\"cb1-12\"><a href=\"#cb1-12\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">                local_dir=&#39;\/home\/user\/f5-tts\/es-model&#39;)<\/span><\/span>\n<span id=\"cb1-13\"><a href=\"#cb1-13\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">hf_hub_download(repo_id=&#39;jpgallegoar\/F5-Spanish&#39;,<\/span><\/span>\n<span id=\"cb1-14\"><a href=\"#cb1-14\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">                filename=&#39;vocab.txt&#39;,<\/span><\/span>\n<span id=\"cb1-15\"><a href=\"#cb1-15\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">                local_dir=&#39;\/home\/user\/f5-tts\/es-model&#39;)<\/span><\/span>\n<span id=\"cb1-16\"><a href=\"#cb1-16\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>Espacio total en disco: unos 7 GB la primera vez. Tiempo: 5 a 15\nminutos seg\u00fan tu conexi\u00f3n.<\/p>\n<h2 id=\"whisper-para-transcripciones\">Whisper para transcripciones<\/h2>\n<p>Si vas a clonar voces necesitas transcribir las muestras (lo veremos\nen un momento). Para eso uso <code class=\"verbatim\">whisper.cpp<\/code>\ncon el modelo <code class=\"verbatim\">small<\/code> en espa\u00f1ol. En\nNixOS:<\/p>\n<div class=\"sourceCode\" id=\"cb2\"><pre\nclass=\"sourceCode nix\"><code class=\"sourceCode nix\"><span id=\"cb2-1\"><a href=\"#cb2-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>environment<span class=\"op\">.<\/span>systemPackages = <span class=\"op\">[<\/span> pkgs<span class=\"op\">.<\/span>whisper-cpp <span class=\"op\">]<\/span>;<\/span><\/code><\/pre><\/div>\n<p>Y descargas el modelo:<\/p>\n<div class=\"sourceCode\" id=\"cb3\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb3-1\"><a href=\"#cb3-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"fu\">mkdir<\/span> <span class=\"at\">-p<\/span> ~\/.local\/share\/whisper\/models<\/span>\n<span id=\"cb3-2\"><a href=\"#cb3-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">curl<\/span> <span class=\"at\">-L<\/span> <span class=\"at\">-o<\/span> ~\/.local\/share\/whisper\/models\/ggml-small.bin <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb3-3\"><a href=\"#cb3-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  https:\/\/huggingface.co\/ggerganov\/whisper.cpp\/resolve\/main\/ggml-small.bin<\/span><\/code><\/pre><\/div>\n<h1 id=\"c\u00f3mo-funciona-f5-tts-por-dentro\">C\u00f3mo funciona F5-TTS por\ndentro<\/h1>\n<p>Antes de la receta, dos minutos de teor\u00eda que ahorran muchos intentos\nfallidos.<\/p>\n<p>F5-TTS es un modelo basado en <code\nclass=\"verbatim\">flow matching<\/code>. Le das dos cosas:<\/p>\n<ol>\n<li><strong>Audio de referencia<\/strong> (<code\nclass=\"verbatim\">ref_audio<\/code>): una muestra de la voz que quieres\nclonar.<\/li>\n<li><strong>Texto de referencia<\/strong> (<code\nclass=\"verbatim\">ref_text<\/code>): la transcripci\u00f3n EXACTA de ese\naudio.<\/li>\n<\/ol>\n<p>A partir de ah\u00ed, le pides un texto nuevo (<code\nclass=\"verbatim\">gen_text<\/code>) y genera audio que suena como la\npersona del <code class=\"verbatim\">ref_audio<\/code> leyendo ese <code\nclass=\"verbatim\">gen_text<\/code>.<\/p>\n<p>La clave que cuesta entender al principio: <strong>el <code\nclass=\"verbatim\">ref_text<\/code> no es un par\u00e1metro opcional<\/strong>.\nEs la herramienta que el modelo usa para alinear los fonemas de la\nmuestra con el espacio de embeddings. Si la transcripci\u00f3n no coincide\ncon el audio palabra por palabra, la clonaci\u00f3n pierde calidad\nr\u00e1pido.<\/p>\n<p>Esto explica un comportamiento que te volver\u00e1 loco si no lo sabes: si\ntranscribes \"hola que tal\" y en el audio dice \"hola qu\u00e9 tal\", el modelo\nse desorienta. Yo aprend\u00ed esto a base de hostias.<\/p>\n<h1 id=\"la-regla-de-oro-12-a-15-segundos\">La regla de oro: 12 a 15\nsegundos<\/h1>\n<p>La duraci\u00f3n de la muestra es probablemente la decisi\u00f3n m\u00e1s importante\nde todo el proceso. Despu\u00e9s de probar de todo, esta es la tabla:<\/p>\n<table>\n<thead>\n<tr>\n<th>Duraci\u00f3n<\/th>\n<th>Resultado<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Menos de 8s<\/td>\n<td>Voz plana, rob\u00f3tica, sin entonaci\u00f3n<\/td>\n<\/tr>\n<tr>\n<td>8 a 10s<\/td>\n<td>Aceptable pero pierde matices<\/td>\n<\/tr>\n<tr>\n<td><strong>12 a 15s<\/strong><\/td>\n<td><strong>\u00d3ptimo: timbre + prosodia + naturalidad<\/strong><\/td>\n<\/tr>\n<tr>\n<td>15 a 18s<\/td>\n<td>Bien, pero F5 puede empezar a truncar internamente<\/td>\n<\/tr>\n<tr>\n<td>M\u00e1s de 18s<\/td>\n<td>F5 trunca o degrada. Cortar.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Pero hay un detalle m\u00e1s importante que la duraci\u00f3n: el <strong>rango\npros\u00f3dico<\/strong> de la muestra. Una frase de 12 segundos con\ndeclarativa, \u00e9nfasis, pausa y pregunta vale infinitamente m\u00e1s que un\nmon\u00f3logo plano de 20 segundos.<\/p>\n<p>La mejor muestra que consegu\u00ed ten\u00eda 11 segundos y conten\u00eda:<\/p>\n<ul>\n<li>una afirmaci\u00f3n rotunda con palabrota<\/li>\n<li>una pregunta ret\u00f3rica<\/li>\n<li>una muletilla coloquial (\"vamos\")<\/li>\n<li>una interrogaci\u00f3n final con tono ascendente (\"\u00bfvale?\")<\/li>\n<\/ul>\n<p>Resultado: la clonaci\u00f3n captur\u00f3 el car\u00e1cter de la persona, no solo el\ntimbre.<\/p>\n<h1 id=\"el-flujo-completo-paso-a-paso\">El flujo completo, paso a\npaso<\/h1>\n<p>Lo que sigue es la receta que llevo aplicando con \u00e9xito a varias\nvoces. Asumo que ya tienes una muestra (puede ser un guasap descargado,\nun fragmento de YouTube, una grabaci\u00f3n tuya).<\/p>\n<h2 id=\"paso-1-inspeccionar-la-muestra\">Paso 1: inspeccionar la\nmuestra<\/h2>\n<p>Lo primero, ver qu\u00e9 tienes entre manos.<\/p>\n<div class=\"sourceCode\" id=\"cb4\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb4-1\"><a href=\"#cb4-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">ffprobe<\/span> <span class=\"at\">-hide_banner<\/span> \/tmp\/sample.ogg <span class=\"dv\">2<\/span><span class=\"op\">&gt;&amp;<\/span><span class=\"dv\">1<\/span> <span class=\"kw\">|<\/span> <span class=\"fu\">grep<\/span> <span class=\"at\">-E<\/span> <span class=\"st\">&quot;Duration|Stream&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>Si dura menos de 8 segundos, desc\u00e1rtala o pide otra. Si dura m\u00e1s de\n30, prep\u00e1rate para recortarla.<\/p>\n<h2 id=\"paso-2-convertir-a-wav-completo-intermedio\">Paso 2: convertir a\nWAV completo (intermedio)<\/h2>\n<p>F5-TTS quiere el audio como WAV mono a 16 kHz, 16 bits PCM. Aunque\nluego vas a recortar un fragmento, conviene primero convertir el audio\nentero al formato bueno.<\/p>\n<div class=\"sourceCode\" id=\"cb5\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb5-1\"><a href=\"#cb5-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">ffmpeg<\/span> <span class=\"at\">-y<\/span> <span class=\"at\">-i<\/span> \/tmp\/sample.ogg <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb5-2\"><a href=\"#cb5-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-ac<\/span> 1 <span class=\"at\">-ar<\/span> 16000 <span class=\"at\">-sample_fmt<\/span> s16 <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb5-3\"><a href=\"#cb5-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  \/tmp\/full.wav<\/span><\/code><\/pre><\/div>\n<h2 id=\"paso-3-transcribir-con-timestamps\">Paso 3: transcribir con\ntimestamps<\/h2>\n<p>Aqu\u00ed es donde Whisper se vuelve imprescindible. Necesitamos no solo\nqu\u00e9 dice la muestra, sino <strong>cu\u00e1ndo<\/strong> lo dice, para poder\nelegir el mejor fragmento.<\/p>\n<div class=\"sourceCode\" id=\"cb6\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb6-1\"><a href=\"#cb6-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">whisper-cli<\/span> <span class=\"at\">-m<\/span> ~\/.local\/share\/whisper\/models\/ggml-small.bin <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb6-2\"><a href=\"#cb6-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-f<\/span> \/tmp\/full.wav <span class=\"at\">-l<\/span> es <span class=\"at\">-t<\/span> 16<\/span><\/code><\/pre><\/div>\n<p>Esto te da algo como:<\/p>\n<pre class=\"text\"><code>[00:00:00.000 --&gt; 00:00:04.180]   Voy a echar m\u00e1s fotos ah\u00ed en el espejo, pero es que claro la gente entra\n[00:00:04.180 --&gt; 00:00:08.300]   con la puerta y que me da, entonces me asusto yo, asusto a la gente\n[00:00:08.300 --&gt; 00:00:12.620]   y ya no me echan m\u00e1s fotos\n[00:00:12.620 --&gt; 00:00:17.820]   esc\u00fachame, hay huevos y te va a subir a comer\n<\/code><\/pre>\n<p>Con esto delante puedes identificar tramos limpios y elegir el\nmejor.<\/p>\n<h2 id=\"paso-4-elegir-un-buen-fragmento\">Paso 4: elegir un buen\nfragmento<\/h2>\n<p>Esta es la decisi\u00f3n clave. Yo aplico tres reglas:<\/p>\n<ol>\n<li><strong>Duraci\u00f3n entre 12 y 15 segundos<\/strong>. Si tienes 11 o 16,\nno pasa nada, pero apunta a 13.<\/li>\n<li><strong>Variedad pros\u00f3dica<\/strong>. Busca un tramo con cambios de\ntono. Una afirmaci\u00f3n seguida de una pregunta es oro. Un mon\u00f3logo\nmonocorde es plomo.<\/li>\n<li><strong>Sin ruido ni solapamiento<\/strong>. Si hay m\u00fasica de fondo,\nF5 intentar\u00e1 reproducirla. Si hay otra voz interrumpiendo, la mezclar\u00e1\ncon la tuya.<\/li>\n<\/ol>\n<p>Marca el fragmento por timestamps. En el ejemplo de arriba podr\u00eda ser\n<code class=\"verbatim\">04.18 a 17.82<\/code>.<\/p>\n<h2 id=\"paso-5-cortar-el-fragmento\">Paso 5: cortar el fragmento<\/h2>\n<div class=\"sourceCode\" id=\"cb8\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb8-1\"><a href=\"#cb8-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"fu\">mkdir<\/span> <span class=\"at\">-p<\/span> ~\/dotfiles\/data\/tts-voices\/menganita<\/span>\n<span id=\"cb8-2\"><a href=\"#cb8-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb8-3\"><a href=\"#cb8-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">ffmpeg<\/span> <span class=\"at\">-y<\/span> <span class=\"at\">-i<\/span> \/tmp\/full.wav <span class=\"at\">-ss<\/span> 4.18 <span class=\"at\">-to<\/span> 17.82 <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb8-4\"><a href=\"#cb8-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-ac<\/span> 1 <span class=\"at\">-ar<\/span> 16000 <span class=\"at\">-sample_fmt<\/span> s16 <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb8-5\"><a href=\"#cb8-5\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  ~\/dotfiles\/data\/tts-voices\/menganita\/audio.wav<\/span><\/code><\/pre><\/div>\n<p>Ahora tienes un <code class=\"verbatim\">audio.wav<\/code> de unos 13\nsegundos en el formato exacto que F5 quiere.<\/p>\n<h2 id=\"paso-6-escribir-el-text.txt-exacto\">Paso 6: escribir el <code\nclass=\"verbatim\">text.txt<\/code> EXACTO<\/h2>\n<p>Esto es lo que m\u00e1s se le suele pasar a la gente. La transcripci\u00f3n\ntiene que ser palabra por palabra, signo por signo, lo que dice\nexactamente el audio del paso 5.<\/p>\n<div class=\"sourceCode\" id=\"cb9\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb9-1\"><a href=\"#cb9-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"fu\">cat<\/span> <span class=\"op\">&gt;<\/span> ~\/dotfiles\/data\/tts-voices\/menganita\/text.txt <span class=\"op\">&lt;&lt;&#39;EOF&#39;<\/span><\/span>\n<span id=\"cb9-2\"><a href=\"#cb9-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"st\">con la puerta y que me da, entonces me asusto yo, asusto a la gente y ya no me echan m\u00e1s fotos. Esc\u00fachame, hay huevos y te va a subir a comer.<\/span><\/span>\n<span id=\"cb9-3\"><a href=\"#cb9-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"op\">EOF<\/span><\/span><\/code><\/pre><\/div>\n<p>Copia tal cual del transcript de Whisper, corrigiendo solo errores\nobvios del transcriptor (no del hablante). Si el hablante dice \"asusto a\nla jente\" con seseo, transcribe \"asusto a la gente\" igualmente: F5\nfunciona con ortograf\u00eda est\u00e1ndar, no con transcripci\u00f3n fon\u00e9tica.<\/p>\n<h2 id=\"paso-7-probar\">Paso 7: probar<\/h2>\n<div class=\"sourceCode\" id=\"cb10\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb10-1\"><a href=\"#cb10-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">~\/f5-tts\/venv\/bin\/f5-tts_infer-cli<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-2\"><a href=\"#cb10-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--model<\/span> F5TTS_Base <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-3\"><a href=\"#cb10-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--ckpt_file<\/span> ~\/f5-tts\/es-model\/model_1200000.safetensors <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-4\"><a href=\"#cb10-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--vocab_file<\/span> ~\/f5-tts\/es-model\/vocab.txt <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-5\"><a href=\"#cb10-5\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--ref_audio<\/span> ~\/dotfiles\/data\/tts-voices\/menganita\/audio.wav <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-6\"><a href=\"#cb10-6\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--ref_text<\/span> <span class=\"st\">&quot;<\/span><span class=\"va\">$(<\/span><span class=\"fu\">cat<\/span> ~\/dotfiles\/data\/tts-voices\/menganita\/text.txt<span class=\"va\">)<\/span><span class=\"st\">&quot;<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-7\"><a href=\"#cb10-7\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--gen_text<\/span> <span class=\"st\">&quot;Hola, soy menganita hablando desde el ordenador. \u00bfTe suena raro? A m\u00ed tambi\u00e9n.&quot;<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-8\"><a href=\"#cb10-8\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--device<\/span> cuda <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-9\"><a href=\"#cb10-9\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--output_dir<\/span> \/tmp <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb10-10\"><a href=\"#cb10-10\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--output_file<\/span> menganita_prueba.wav<\/span>\n<span id=\"cb10-11\"><a href=\"#cb10-11\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb10-12\"><a href=\"#cb10-12\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">paplay<\/span> \/tmp\/menganita_prueba.wav<\/span><\/code><\/pre><\/div>\n<p>Tiempo de generaci\u00f3n en RTX 2060: unos 8 a 12 segundos para una frase\ncorta. La primera vez carga el modelo y tarda m\u00e1s (60 a 90\nsegundos).<\/p>\n<p>Si suena plana, vuelve al paso 4 y elige otro fragmento m\u00e1s\nexpresivo. Si suena distorsionada, comprueba que el <code\nclass=\"verbatim\">text.txt<\/code> coincide con lo que dice el audio.<\/p>\n<h1 id=\"un-wrapper-para-no-escribir-tanto\">Un wrapper para no escribir\ntanto<\/h1>\n<p>Tener que recordar la l\u00ednea anterior cada vez es absurdo. Lo\nencapsul\u00e9 en un script <code class=\"verbatim\">f5-say<\/code> que\nacepta:<\/p>\n<div class=\"sourceCode\" id=\"cb11\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb11-1\"><a href=\"#cb11-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">f5-say<\/span> menganita <span class=\"st\">&quot;lo que sea&quot;<\/span><\/span>\n<span id=\"cb11-2\"><a href=\"#cb11-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"bu\">echo<\/span> <span class=\"st\">&quot;lo que sea&quot;<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">f5-say<\/span> menganita <span class=\"at\">-<\/span><\/span>\n<span id=\"cb11-3\"><a href=\"#cb11-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">f5-say<\/span> <span class=\"at\">-o<\/span> salida.wav menganita <span class=\"st\">&quot;...&quot;<\/span>   <span class=\"co\"># a fichero, no reproduce<\/span><\/span>\n<span id=\"cb11-4\"><a href=\"#cb11-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">f5-say<\/span> <span class=\"at\">-l<\/span>                              <span class=\"co\"># lista voces disponibles<\/span><\/span><\/code><\/pre><\/div>\n<p>El script vive en <code\nclass=\"verbatim\">~\/dotfiles\/scripts\/f5-say<\/code>, hace auto-instalaci\u00f3n\nsi falta el venv o el modelo, y carga las librer\u00edas de FFmpeg 4 que\nF5-TTS exige (en NixOS las librer\u00edas nuevas dan problemas con\ntorchaudio).<\/p>\n<h1 id=\"bonus-1-capturar-voces-al-vuelo-en-una-reuni\u00f3n\">Bonus 1:\ncapturar voces al vuelo en una reuni\u00f3n<\/h1>\n<p>Aqu\u00ed es donde la cosa se pone interesante. Si est\u00e1s en un Meet o Zoom\ny quieres clonar la voz de alguien que est\u00e1 hablando, no necesitas\npedirle un audio. Puedes grabar el monitor del sink de PipeWire (lo que\nsale por tus altavoces).<\/p>\n<p>Mi script <code class=\"verbatim\">capture-talker<\/code>:<\/p>\n<div class=\"sourceCode\" id=\"cb12\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb12-1\"><a href=\"#cb12-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\">#!\/usr\/bin\/env bash<\/span><\/span>\n<span id=\"cb12-2\"><a href=\"#cb12-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"bu\">set<\/span> <span class=\"at\">-euo<\/span> pipefail<\/span>\n<span id=\"cb12-3\"><a href=\"#cb12-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb12-4\"><a href=\"#cb12-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">NAME<\/span><span class=\"op\">=<\/span><span class=\"st\">&quot;<\/span><span class=\"va\">${1<\/span><span class=\"op\">:-<\/span>talker<span class=\"va\">}<\/span><span class=\"st\">&quot;<\/span><\/span>\n<span id=\"cb12-5\"><a href=\"#cb12-5\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">SECS<\/span><span class=\"op\">=<\/span><span class=\"st\">&quot;<\/span><span class=\"va\">${2<\/span><span class=\"op\">:-<\/span>15<span class=\"va\">}<\/span><span class=\"st\">&quot;<\/span><\/span>\n<span id=\"cb12-6\"><a href=\"#cb12-6\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb12-7\"><a href=\"#cb12-7\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># Sink activo (RUNNING, lo que ahora mismo est\u00e1 sonando)<\/span><\/span>\n<span id=\"cb12-8\"><a href=\"#cb12-8\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">MONITOR<\/span><span class=\"op\">=<\/span><span class=\"va\">$(<\/span><span class=\"ex\">pactl<\/span> list short sources <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb12-9\"><a href=\"#cb12-9\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>          <span class=\"kw\">|<\/span> <span class=\"fu\">awk<\/span> <span class=\"st\">&#39;$NF==&quot;RUNNING&quot; &amp;&amp; \/monitor\/ {print $2; exit}&#39;<\/span><span class=\"va\">)<\/span><\/span>\n<span id=\"cb12-10\"><a href=\"#cb12-10\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb12-11\"><a href=\"#cb12-11\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">OUT<\/span><span class=\"op\">=<\/span><span class=\"st\">&quot;\/tmp\/<\/span><span class=\"va\">${NAME}<\/span><span class=\"st\">_<\/span><span class=\"va\">$(<\/span><span class=\"fu\">date<\/span> +%H%M%S<span class=\"va\">)<\/span><span class=\"st\">.wav&quot;<\/span><\/span>\n<span id=\"cb12-12\"><a href=\"#cb12-12\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb12-13\"><a href=\"#cb12-13\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">ffmpeg<\/span> <span class=\"at\">-hide_banner<\/span> <span class=\"at\">-loglevel<\/span> error <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb12-14\"><a href=\"#cb12-14\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-f<\/span> pulse <span class=\"at\">-i<\/span> <span class=\"st\">&quot;<\/span><span class=\"va\">$MONITOR<\/span><span class=\"st\">&quot;<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb12-15\"><a href=\"#cb12-15\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-ac<\/span> 1 <span class=\"at\">-ar<\/span> 16000 <span class=\"at\">-sample_fmt<\/span> s16 <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb12-16\"><a href=\"#cb12-16\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-t<\/span> <span class=\"st\">&quot;<\/span><span class=\"va\">$SECS<\/span><span class=\"st\">&quot;<\/span> <span class=\"st\">&quot;<\/span><span class=\"va\">$OUT<\/span><span class=\"st\">&quot;<\/span><\/span>\n<span id=\"cb12-17\"><a href=\"#cb12-17\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb12-18\"><a href=\"#cb12-18\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"bu\">echo<\/span> <span class=\"st\">&quot;<\/span><span class=\"va\">$OUT<\/span><span class=\"st\">&quot;<\/span><\/span><\/code><\/pre><\/div>\n<p>Uso:<\/p>\n<div class=\"sourceCode\" id=\"cb13\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb13-1\"><a href=\"#cb13-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">capture-talker<\/span>             <span class=\"co\"># 15 segundos del monitor activo<\/span><\/span>\n<span id=\"cb13-2\"><a href=\"#cb13-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">capture-talker<\/span> fulano      <span class=\"co\"># 15 segundos, archivo \/tmp\/fulano_HHMMSS.wav<\/span><\/span>\n<span id=\"cb13-3\"><a href=\"#cb13-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">capture-talker<\/span> fulano 20   <span class=\"co\"># 20 segundos<\/span><\/span><\/code><\/pre><\/div>\n<p>El truco est\u00e1 en <code\nclass=\"verbatim\">pactl list short sources | awk '$NF=<\/code>\"RUNNING\"\n&amp;&amp; <em>monitor<\/em>'=. Eso identifica el sink que ahora mismo\nest\u00e1 sacando audio (mis altavoces, en mi caso un FiiO K7), y ffmpeg\ngraba directamente de su monitor source.<\/p>\n<p>Resultado: durante la reuni\u00f3n, cuando alguien interesante est\u00e9\nhablando, <code class=\"verbatim\">capture-talker fulano<\/code> y tienes\nuna muestra perfecta lista para clonar. Despu\u00e9s aplicas el flujo de los\npasos 3 al 7.<\/p>\n<p>Implicaciones \u00e9ticas obvias. Hablamos de ello al final.<\/p>\n<h1 id=\"bonus-2-mandar-el-audio-generado-al-telegram\">Bonus 2: mandar el\naudio generado al Telegram<\/h1>\n<p>El uso real de todo esto, para m\u00ed, no es generar audios para\nguardarlos. Es mand\u00e1rselos a alguien. La cadena completa que uso:<\/p>\n<div class=\"sourceCode\" id=\"cb14\"><pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb14-1\"><a href=\"#cb14-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># 1. Generar<\/span><\/span>\n<span id=\"cb14-2\"><a href=\"#cb14-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"bu\">echo<\/span> <span class=\"st\">&quot;el texto que quiero que diga&quot;<\/span> <span class=\"kw\">|<\/span> <span class=\"ex\">f5-say<\/span> <span class=\"at\">-o<\/span> \/tmp\/v.wav menganita <span class=\"at\">-<\/span><\/span>\n<span id=\"cb14-3\"><a href=\"#cb14-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb14-4\"><a href=\"#cb14-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># 2. Convertir a OGG\/Opus (Telegram exige este formato para voice notes)<\/span><\/span>\n<span id=\"cb14-5\"><a href=\"#cb14-5\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">ffmpeg<\/span> <span class=\"at\">-y<\/span> <span class=\"at\">-i<\/span> \/tmp\/v.wav <span class=\"at\">-c:a<\/span> libopus <span class=\"at\">-b:a<\/span> 64k \/tmp\/v.ogg<\/span>\n<span id=\"cb14-6\"><a href=\"#cb14-6\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb14-7\"><a href=\"#cb14-7\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># 3. Mandar como nota de voz (no como audio adjunto)<\/span><\/span>\n<span id=\"cb14-8\"><a href=\"#cb14-8\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">BOT<\/span><span class=\"op\">=<\/span><span class=\"va\">$(<\/span><span class=\"fu\">cat<\/span> \/run\/agenix\/telegram-bot-token<span class=\"va\">)<\/span><\/span>\n<span id=\"cb14-9\"><a href=\"#cb14-9\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">CHAT<\/span><span class=\"op\">=<\/span><span class=\"va\">$(<\/span><span class=\"fu\">cat<\/span> \/run\/agenix\/telegram-chat-id<span class=\"va\">)<\/span><\/span>\n<span id=\"cb14-10\"><a href=\"#cb14-10\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">curl<\/span> <span class=\"at\">-sf<\/span> <span class=\"at\">-X<\/span> POST <span class=\"st\">&quot;https:\/\/api.telegram.org\/bot<\/span><span class=\"va\">${BOT}<\/span><span class=\"st\">\/sendVoice&quot;<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb14-11\"><a href=\"#cb14-11\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">-F<\/span> chat_id=<span class=\"st\">&quot;<\/span><span class=\"va\">$CHAT<\/span><span class=\"st\">&quot;<\/span> <span class=\"at\">-F<\/span> voice=@\/tmp\/v.ogg<\/span>\n<span id=\"cb14-12\"><a href=\"#cb14-12\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb14-13\"><a href=\"#cb14-13\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># 4. Limpiar<\/span><\/span>\n<span id=\"cb14-14\"><a href=\"#cb14-14\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"fu\">rm<\/span> <span class=\"at\">-f<\/span> \/tmp\/v.wav \/tmp\/v.ogg<\/span><\/code><\/pre><\/div>\n<p>Lo importante: <code class=\"verbatim\">sendVoice<\/code> con un\nOGG\/Opus produce la burbuja t\u00edpica de WhatsApp\/Telegram, no un audio\nreproducible con player. Si mandas un WAV o MP3 con <code\nclass=\"verbatim\">sendAudio<\/code>, se ve como un archivo adjunto y\ndelata que es generado. La burbuja de voz pasa desapercibida.<\/p>\n<h1 id=\"lecciones-que-aprend\u00ed-a-base-de-hostias\">Lecciones que aprend\u00ed a\nbase de hostias<\/h1>\n<p>Algunas cosas que no est\u00e1n en la documentaci\u00f3n oficial pero que te\nahorran mucho tiempo:<\/p>\n<h2 id=\"no-leas-urls-ids-ni-hashes-en-el-audio\">No leas URLs, IDs ni\nhashes en el audio<\/h2>\n<p>Si pides al modelo que genere \"el commit es 7f3a9b21\", va a leer\nliteral \"siete efe tres a nueve be dos uno\". Suena horrible y no se\nentiende. Pon esos detalles en el caption del mensaje, no en el audio.\nEl audio es narrativo, no t\u00e9cnico.<\/p>\n<h2 id=\"transcribe-foneticamente-las-siglas-y-n\u00fameros\">Transcribe\nfoneticamente las siglas y n\u00fameros<\/h2>\n<p>\"F5\" se lee mejor como \"efe cinco\". \"RTX 2060\" como \"ere te equis dos\nmil sesenta\". \"IA\" como \"Inteligencia Artificial\" o \"i a\" si quieres\nletras. F5-TTS no tiene un m\u00f3dulo de letrear siglas; lee lo que\npones.<\/p>\n<h2 id=\"cuidado-con-los-textos-largos\">Cuidado con los textos\nlargos<\/h2>\n<p>Por encima de 1500-2000 caracteres, F5 puede empezar a:<\/p>\n<ul>\n<li>Truncar el final<\/li>\n<li>Cambiar la voz a media generaci\u00f3n<\/li>\n<li>Mezclar timbres si tienes varias voces cargadas<\/li>\n<\/ul>\n<p>Si necesitas un audio largo, trocea el texto en chunks de unos 1000\ncaracteres, genera cada uno y concat\u00e9nalos con <code\nclass=\"verbatim\">ffmpeg<\/code>.<\/p>\n<h2 id=\"el-modelo-en-espa\u00f1ol-es-crucial\">El modelo en espa\u00f1ol es\nCRUCIAL<\/h2>\n<p>El modelo base de F5-TTS es biling\u00fce (ingl\u00e9s + chino). Para espa\u00f1ol,\n<code class=\"verbatim\">jpgallegoar\/F5-Spanish<\/code> marca la diferencia\nentre \"se entiende lo que dice\" y \"parece nativo\". No te molestes con el\nmodelo base si vas a generar en espa\u00f1ol.<\/p>\n<h2 id=\"la-primera-generaci\u00f3n-tarda-mucho\">La primera generaci\u00f3n tarda\nmucho<\/h2>\n<p>La primera vez que invocas F5 carga el modelo en VRAM y eso lleva\nentre 30 y 90 segundos en una RTX 2060. Despu\u00e9s, mientras el proceso\nsigue vivo, las generaciones son r\u00e1pidas. Si vas a hacer batch, mant\u00e9n\nel proceso abierto.<\/p>\n<h1 id=\"implicaciones-\u00e9ticas\">Implicaciones \u00e9ticas<\/h1>\n<p>No puedo cerrar este post sin decirlo: clonar la voz de alguien sin\nsu permiso es una putada y, en muchas jurisdicciones, ilegal. La\ntecnolog\u00eda que acabo de explicar permite generar audios indistinguibles\nde los reales, y eso tiene consecuencias.<\/p>\n<p>La regla simple que aplico:<\/p>\n<ul>\n<li><strong>La voz de mi mujer<\/strong>: con su permiso expl\u00edcito, para\nmandarle bromas y avisarle del cambio.<\/li>\n<li><strong>La voz de un amigo<\/strong>: con su permiso expl\u00edcito, para\nre\u00edrnos en el grupo y avisarle del cambio.<\/li>\n<li><strong>Voces de figuras p\u00fablicas, jefes, desconocidos<\/strong>:\nno.<\/li>\n<\/ul>\n<p>Si vas a hacer esto para cachondear con alguien cercano, avisa antes\ny ense\u00f1a el resultado. Si lo vas a usar para algo serio (un asistente\npersonal con tu propia voz, por ejemplo), pues adelante. Pero no clones\nla voz del CEO para mandar audios fraudulentos: hay gente cumpliendo\ncondena por menos.<\/p>\n<p>Las plataformas grandes (ElevenLabs, OpenAI) tienen detecci\u00f3n de\nvoces clonadas y filtros activos. Las herramientas locales como F5-TTS\nno tienen nada. La responsabilidad est\u00e1 entera en ti.<\/p>\n<h1 id=\"conclusi\u00f3n\">Conclusi\u00f3n<\/h1>\n<p>En 2026, clonar una voz con calidad alta es un fin de semana de\ncacharreo, una RTX modesta y software MIT. La barrera t\u00e9cnica es\npr\u00e1cticamente nula. La barrera real es \u00e9tica y de criterio.<\/p>\n<p>Si quieres usarlo bien: p\u00eddele permiso a la persona, hazle re\u00edr con\nel resultado, y guarda los samples para el futuro. Es una forma curiosa\nde archivar voces de gente cercana en un formato del que se pueden\ngenerar mensajes nuevos.<\/p>\n<p>Si quieres usarlo mal: te recomiendo que no.<\/p>\n<h1 id=\"recursos\">Recursos<\/h1>\n<ul>\n<li>F5-TTS oficial: <a\nhref=\"https:\/\/github.com\/SWivid\/F5-TTS\">github.com\/SWivid\/F5-TTS<\/a><\/li>\n<li>Modelo en espa\u00f1ol: <a\nhref=\"https:\/\/huggingface.co\/jpgallegoar\/F5-Spanish\">huggingface.co\/jpgallegoar\/F5-Spanish<\/a><\/li>\n<li>whisper.cpp: <a\nhref=\"https:\/\/github.com\/ggerganov\/whisper.cpp\">github.com\/ggerganov\/whisper.cpp<\/a><\/li>\n<li>Mis dotfiles (incluyen <code class=\"verbatim\">f5-say<\/code>, <code\nclass=\"verbatim\">capture-talker<\/code> y todo el m\u00f3dulo TTS de NixOS):\n<a\nhref=\"https:\/\/github.com\/pascualmg\/dotfiles\">github.com\/pascualmg\/dotfiles<\/a><\/li>\n<\/ul>\n","author":"Pascual","datePublished":"2026-04-28T00:26:17+00:00","orgSource":"#+TITLE: Clonar voces con F5-TTS en Linux: cuando 15 segundos de muestra son suficientes\n#+AUTHOR: Pascual\n#+DATE: 2026-04-28\n\nHace una semana descubr\u00ed 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.\n\nLo que empez\u00f3 como un \"voy a probar a clonar mi propia voz para Ambrosio\" termin\u00f3 con audios mandados al Telegram con la voz de mi mujer dict\u00e1ndome la lista de tareas de casa, y la de un amigo respondi\u00e9ndose a s\u00ed mismo en grupo. El resultado: nadie ha sabido distinguir el audio real del clonado en una primera escucha.\n\nEste post es la receta completa: qu\u00e9 herramientas necesitas, c\u00f3mo seleccionar una buena muestra, c\u00f3mo procesarla, y los detalles que separan una clonaci\u00f3n plana de una que asusta.\n\n* Por qu\u00e9 F5-TTS y no otra cosa\n\nAntes de meternos en barro, contexto. El paisaje de TTS en abril de 2026 est\u00e1 dominado por:\n\n- *ElevenLabs*: cloud, de pago (~22 d\u00f3lares\/mes para voice cloning serio). Calidad excelente. Tu voz pasa por sus servidores.\n- *OpenAI TTS \/ Azure*: cloud, de pago, sin clonaci\u00f3n zero-shot real.\n- *Coqui TTS*: open source pero muerto. La empresa cerr\u00f3 en 2024.\n- *Piper*: r\u00e1pido, ONNX, voces preset. No clona. Suena a robot decente.\n- *Kokoro*: 82M par\u00e1metros, neural, voces preset bonitas. No clona.\n- *F5-TTS*: clonaci\u00f3n zero-shot a partir de una muestra. Open source. Local.\n\nSi 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\u00f3n libre. Es lo que vamos a montar.\n\n** Lo que F5-TTS hace bien\n\n- *Zero-shot*: con una muestra de unos segundos clona tu voz. No hay que entrenar nada.\n- *Multi-idioma*: hay un fork espec\u00edfico en espa\u00f1ol (=jpgallegoar\/F5-Spanish=) entrenado a fondo, y el resultado es excelente.\n- *Local*: corre en tu GPU. La muestra de tu mujer no se va a OpenAI.\n- *MIT*: \u00fasalo para lo que quieras (con cabeza, ya hablaremos de eso).\n\n** Lo que F5-TTS hace mal\n\n- *Necesita GPU*. CUDA preferentemente. CPU t\u00e9cnicamente funciona pero es inviable.\n- *Es lento*. Para generar un minuto de audio en una RTX 2060 tardas alrededor de un minuto. Para tiempo real, ni te molestes.\n- *Ingl\u00e9s y espa\u00f1ol s\u00f3lidos, otros idiomas*: depende del checkpoint que uses.\n- *Textos largos*: por encima de unos 2000 caracteres puede empezar a degenerar o mezclar voces.\n\n* El stack completo\n\nLa cadena de herramientas que mont\u00e9 en NixOS:\n\n| Herramienta  | Funci\u00f3n                                    |\n|--------------+--------------------------------------------|\n| F5-TTS       | El motor de clonaci\u00f3n zero-shot            |\n| =ffmpeg=     | Convertir audios al formato que F5 quiere  |\n| =whisper.cpp=| Transcribir muestras autom\u00e1ticamente       |\n| =ffprobe=    | Inspeccionar duraciones, formatos, codecs  |\n| PipeWire     | Capturar audio del sistema en directo      |\n| =paplay=     | Reproducir resultados                      |\n| =uv= (Python)| Gestor de venv y deps                      |\n\nTodo libre, todo local. Lo \u00fanico de pago aqu\u00ed podr\u00eda ser la electricidad y la GPU.\n\n** Hardware necesario\n\nHe 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\u00e1s deber\u00eda ir.\n\nSin GPU, olv\u00eddate. Pasa a Kokoro o Piper.\n\n* Instalaci\u00f3n\n\nF5-TTS se instala con =pip= en un venv. Yo lo dej\u00e9 fuera del flake de NixOS para no atarme las manos con el sistema de paquetes. Lo encapsul\u00e9 en un script bash que hace el setup autom\u00e1tico la primera vez.\n\nEl proceso de instalaci\u00f3n:\n\n#+begin_src bash\n# 1. Venv con Python 3.11\nuv venv --python 3.11 ~\/f5-tts\/venv\n\n# 2. F5-TTS (arrastra torch, transformers, etc \u2014 son ~5 GB)\nVIRTUAL_ENV=~\/f5-tts\/venv uv pip install f5-tts\n\n# 3. Modelo en espa\u00f1ol (~1.3 GB de checkpoint + vocab)\n~\/f5-tts\/venv\/bin\/python3 -c \"\nfrom huggingface_hub import hf_hub_download\nhf_hub_download(repo_id='jpgallegoar\/F5-Spanish',\n                filename='model_1200000.safetensors',\n                local_dir='\/home\/user\/f5-tts\/es-model')\nhf_hub_download(repo_id='jpgallegoar\/F5-Spanish',\n                filename='vocab.txt',\n                local_dir='\/home\/user\/f5-tts\/es-model')\n\"\n#+end_src\n\nEspacio total en disco: unos 7 GB la primera vez. Tiempo: 5 a 15 minutos seg\u00fan tu conexi\u00f3n.\n\n** Whisper para transcripciones\n\nSi vas a clonar voces necesitas transcribir las muestras (lo veremos en un momento). Para eso uso =whisper.cpp= con el modelo =small= en espa\u00f1ol. En NixOS:\n\n#+begin_src nix\nenvironment.systemPackages = [ pkgs.whisper-cpp ];\n#+end_src\n\nY descargas el modelo:\n\n#+begin_src bash\nmkdir -p ~\/.local\/share\/whisper\/models\ncurl -L -o ~\/.local\/share\/whisper\/models\/ggml-small.bin \\\n  https:\/\/huggingface.co\/ggerganov\/whisper.cpp\/resolve\/main\/ggml-small.bin\n#+end_src\n\n* C\u00f3mo funciona F5-TTS por dentro\n\nAntes de la receta, dos minutos de teor\u00eda que ahorran muchos intentos fallidos.\n\nF5-TTS es un modelo basado en =flow matching=. Le das dos cosas:\n\n1. *Audio de referencia* (=ref_audio=): una muestra de la voz que quieres clonar.\n2. *Texto de referencia* (=ref_text=): la transcripci\u00f3n EXACTA de ese audio.\n\nA partir de ah\u00ed, le pides un texto nuevo (=gen_text=) y genera audio que suena como la persona del =ref_audio= leyendo ese =gen_text=.\n\nLa clave que cuesta entender al principio: *el =ref_text= no es un par\u00e1metro opcional*. Es la herramienta que el modelo usa para alinear los fonemas de la muestra con el espacio de embeddings. Si la transcripci\u00f3n no coincide con el audio palabra por palabra, la clonaci\u00f3n pierde calidad r\u00e1pido.\n\nEsto explica un comportamiento que te volver\u00e1 loco si no lo sabes: si transcribes \"hola que tal\" y en el audio dice \"hola qu\u00e9 tal\", el modelo se desorienta. Yo aprend\u00ed esto a base de hostias.\n\n* La regla de oro: 12 a 15 segundos\n\nLa duraci\u00f3n de la muestra es probablemente la decisi\u00f3n m\u00e1s importante de todo el proceso. Despu\u00e9s de probar de todo, esta es la tabla:\n\n| Duraci\u00f3n    | Resultado                                         |\n|-------------+---------------------------------------------------|\n| Menos de 8s | Voz plana, rob\u00f3tica, sin entonaci\u00f3n              |\n| 8 a 10s     | Aceptable pero pierde matices                    |\n| *12 a 15s*  | *\u00d3ptimo: timbre + prosodia + naturalidad*        |\n| 15 a 18s    | Bien, pero F5 puede empezar a truncar internamente|\n| M\u00e1s de 18s  | F5 trunca o degrada. Cortar.                     |\n\nPero hay un detalle m\u00e1s importante que la duraci\u00f3n: el *rango pros\u00f3dico* de la muestra. Una frase de 12 segundos con declarativa, \u00e9nfasis, pausa y pregunta vale infinitamente m\u00e1s que un mon\u00f3logo plano de 20 segundos.\n\nLa mejor muestra que consegu\u00ed ten\u00eda 11 segundos y conten\u00eda:\n\n- una afirmaci\u00f3n rotunda con palabrota\n- una pregunta ret\u00f3rica\n- una muletilla coloquial (\"vamos\")\n- una interrogaci\u00f3n final con tono ascendente (\"\u00bfvale?\")\n\nResultado: la clonaci\u00f3n captur\u00f3 el car\u00e1cter de la persona, no solo el timbre.\n\n* El flujo completo, paso a paso\n\nLo que sigue es la receta que llevo aplicando con \u00e9xito a varias voces. Asumo que ya tienes una muestra (puede ser un guasap descargado, un fragmento de YouTube, una grabaci\u00f3n tuya).\n\n** Paso 1: inspeccionar la muestra\n\nLo primero, ver qu\u00e9 tienes entre manos.\n\n#+begin_src bash\nffprobe -hide_banner \/tmp\/sample.ogg 2>&1 | grep -E \"Duration|Stream\"\n#+end_src\n\nSi dura menos de 8 segundos, desc\u00e1rtala o pide otra. Si dura m\u00e1s de 30, prep\u00e1rate para recortarla.\n\n** Paso 2: convertir a WAV completo (intermedio)\n\nF5-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.\n\n#+begin_src bash\nffmpeg -y -i \/tmp\/sample.ogg \\\n  -ac 1 -ar 16000 -sample_fmt s16 \\\n  \/tmp\/full.wav\n#+end_src\n\n** Paso 3: transcribir con timestamps\n\nAqu\u00ed es donde Whisper se vuelve imprescindible. Necesitamos no solo qu\u00e9 dice la muestra, sino *cu\u00e1ndo* lo dice, para poder elegir el mejor fragmento.\n\n#+begin_src bash\nwhisper-cli -m ~\/.local\/share\/whisper\/models\/ggml-small.bin \\\n  -f \/tmp\/full.wav -l es -t 16\n#+end_src\n\nEsto te da algo como:\n\n#+begin_src text\n[00:00:00.000 --> 00:00:04.180]   Voy a echar m\u00e1s fotos ah\u00ed en el espejo, pero es que claro la gente entra\n[00:00:04.180 --> 00:00:08.300]   con la puerta y que me da, entonces me asusto yo, asusto a la gente\n[00:00:08.300 --> 00:00:12.620]   y ya no me echan m\u00e1s fotos\n[00:00:12.620 --> 00:00:17.820]   esc\u00fachame, hay huevos y te va a subir a comer\n#+end_src\n\nCon esto delante puedes identificar tramos limpios y elegir el mejor.\n\n** Paso 4: elegir un buen fragmento\n\nEsta es la decisi\u00f3n clave. Yo aplico tres reglas:\n\n1. *Duraci\u00f3n entre 12 y 15 segundos*. Si tienes 11 o 16, no pasa nada, pero apunta a 13.\n2. *Variedad pros\u00f3dica*. Busca un tramo con cambios de tono. Una afirmaci\u00f3n seguida de una pregunta es oro. Un mon\u00f3logo monocorde es plomo.\n3. *Sin ruido ni solapamiento*. Si hay m\u00fasica de fondo, F5 intentar\u00e1 reproducirla. Si hay otra voz interrumpiendo, la mezclar\u00e1 con la tuya.\n\nMarca el fragmento por timestamps. En el ejemplo de arriba podr\u00eda ser =04.18 a 17.82=.\n\n** Paso 5: cortar el fragmento\n\n#+begin_src bash\nmkdir -p ~\/dotfiles\/data\/tts-voices\/menganita\n\nffmpeg -y -i \/tmp\/full.wav -ss 4.18 -to 17.82 \\\n  -ac 1 -ar 16000 -sample_fmt s16 \\\n  ~\/dotfiles\/data\/tts-voices\/menganita\/audio.wav\n#+end_src\n\nAhora tienes un =audio.wav= de unos 13 segundos en el formato exacto que F5 quiere.\n\n** Paso 6: escribir el =text.txt= EXACTO\n\nEsto es lo que m\u00e1s se le suele pasar a la gente. La transcripci\u00f3n tiene que ser palabra por palabra, signo por signo, lo que dice exactamente el audio del paso 5.\n\n#+begin_src bash\ncat > ~\/dotfiles\/data\/tts-voices\/menganita\/text.txt <<'EOF'\ncon la puerta y que me da, entonces me asusto yo, asusto a la gente y ya no me echan m\u00e1s fotos. Esc\u00fachame, hay huevos y te va a subir a comer.\nEOF\n#+end_src\n\nCopia 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\u00eda est\u00e1ndar, no con transcripci\u00f3n fon\u00e9tica.\n\n** Paso 7: probar\n\n#+begin_src bash\n~\/f5-tts\/venv\/bin\/f5-tts_infer-cli \\\n  --model F5TTS_Base \\\n  --ckpt_file ~\/f5-tts\/es-model\/model_1200000.safetensors \\\n  --vocab_file ~\/f5-tts\/es-model\/vocab.txt \\\n  --ref_audio ~\/dotfiles\/data\/tts-voices\/menganita\/audio.wav \\\n  --ref_text \"$(cat ~\/dotfiles\/data\/tts-voices\/menganita\/text.txt)\" \\\n  --gen_text \"Hola, soy menganita hablando desde el ordenador. \u00bfTe suena raro? A m\u00ed tambi\u00e9n.\" \\\n  --device cuda \\\n  --output_dir \/tmp \\\n  --output_file menganita_prueba.wav\n\npaplay \/tmp\/menganita_prueba.wav\n#+end_src\n\nTiempo de generaci\u00f3n en RTX 2060: unos 8 a 12 segundos para una frase corta. La primera vez carga el modelo y tarda m\u00e1s (60 a 90 segundos).\n\nSi suena plana, vuelve al paso 4 y elige otro fragmento m\u00e1s expresivo. Si suena distorsionada, comprueba que el =text.txt= coincide con lo que dice el audio.\n\n* Un wrapper para no escribir tanto\n\nTener que recordar la l\u00ednea anterior cada vez es absurdo. Lo encapsul\u00e9 en un script =f5-say= que acepta:\n\n#+begin_src bash\nf5-say menganita \"lo que sea\"\necho \"lo que sea\" | f5-say menganita -\nf5-say -o salida.wav menganita \"...\"   # a fichero, no reproduce\nf5-say -l                              # lista voces disponibles\n#+end_src\n\nEl script vive en =~\/dotfiles\/scripts\/f5-say=, hace auto-instalaci\u00f3n si falta el venv o el modelo, y carga las librer\u00edas de FFmpeg 4 que F5-TTS exige (en NixOS las librer\u00edas nuevas dan problemas con torchaudio).\n\n* Bonus 1: capturar voces al vuelo en una reuni\u00f3n\n\nAqu\u00ed es donde la cosa se pone interesante. Si est\u00e1s en un Meet o Zoom y quieres clonar la voz de alguien que est\u00e1 hablando, no necesitas pedirle un audio. Puedes grabar el monitor del sink de PipeWire (lo que sale por tus altavoces).\n\nMi script =capture-talker=:\n\n#+begin_src bash\n#!\/usr\/bin\/env bash\nset -euo pipefail\n\nNAME=\"${1:-talker}\"\nSECS=\"${2:-15}\"\n\n# Sink activo (RUNNING, lo que ahora mismo est\u00e1 sonando)\nMONITOR=$(pactl list short sources \\\n          | awk '$NF==\"RUNNING\" && \/monitor\/ {print $2; exit}')\n\nOUT=\"\/tmp\/${NAME}_$(date +%H%M%S).wav\"\n\nffmpeg -hide_banner -loglevel error \\\n  -f pulse -i \"$MONITOR\" \\\n  -ac 1 -ar 16000 -sample_fmt s16 \\\n  -t \"$SECS\" \"$OUT\"\n\necho \"$OUT\"\n#+end_src\n\nUso:\n\n#+begin_src bash\ncapture-talker             # 15 segundos del monitor activo\ncapture-talker fulano      # 15 segundos, archivo \/tmp\/fulano_HHMMSS.wav\ncapture-talker fulano 20   # 20 segundos\n#+end_src\n\nEl truco est\u00e1 en =pactl list short sources | awk '$NF==\"RUNNING\" && \/monitor\/'=. Eso identifica el sink que ahora mismo est\u00e1 sacando audio (mis altavoces, en mi caso un FiiO K7), y ffmpeg graba directamente de su monitor source.\n\nResultado: durante la reuni\u00f3n, cuando alguien interesante est\u00e9 hablando, =capture-talker fulano= y tienes una muestra perfecta lista para clonar. Despu\u00e9s aplicas el flujo de los pasos 3 al 7.\n\nImplicaciones \u00e9ticas obvias. Hablamos de ello al final.\n\n* Bonus 2: mandar el audio generado al Telegram\n\nEl uso real de todo esto, para m\u00ed, no es generar audios para guardarlos. Es mand\u00e1rselos a alguien. La cadena completa que uso:\n\n#+begin_src bash\n# 1. Generar\necho \"el texto que quiero que diga\" | f5-say -o \/tmp\/v.wav menganita -\n\n# 2. Convertir a OGG\/Opus (Telegram exige este formato para voice notes)\nffmpeg -y -i \/tmp\/v.wav -c:a libopus -b:a 64k \/tmp\/v.ogg\n\n# 3. Mandar como nota de voz (no como audio adjunto)\nBOT=$(cat \/run\/agenix\/telegram-bot-token)\nCHAT=$(cat \/run\/agenix\/telegram-chat-id)\ncurl -sf -X POST \"https:\/\/api.telegram.org\/bot${BOT}\/sendVoice\" \\\n  -F chat_id=\"$CHAT\" -F voice=@\/tmp\/v.ogg\n\n# 4. Limpiar\nrm -f \/tmp\/v.wav \/tmp\/v.ogg\n#+end_src\n\nLo importante: =sendVoice= con un OGG\/Opus produce la burbuja t\u00edpica 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.\n\n* Lecciones que aprend\u00ed a base de hostias\n\nAlgunas cosas que no est\u00e1n en la documentaci\u00f3n oficial pero que te ahorran mucho tiempo:\n\n** No leas URLs, IDs ni hashes en el audio\n\nSi 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\u00e9cnico.\n\n** Transcribe foneticamente las siglas y n\u00fameros\n\n\"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\u00f3dulo de letrear siglas; lee lo que pones.\n\n** Cuidado con los textos largos\n\nPor encima de 1500-2000 caracteres, F5 puede empezar a:\n\n- Truncar el final\n- Cambiar la voz a media generaci\u00f3n\n- Mezclar timbres si tienes varias voces cargadas\n\nSi necesitas un audio largo, trocea el texto en chunks de unos 1000 caracteres, genera cada uno y concat\u00e9nalos con =ffmpeg=.\n\n** El modelo en espa\u00f1ol es CRUCIAL\n\nEl modelo base de F5-TTS es biling\u00fce (ingl\u00e9s + chino). Para espa\u00f1ol, =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\u00f1ol.\n\n** La primera generaci\u00f3n tarda mucho\n\nLa primera vez que invocas F5 carga el modelo en VRAM y eso lleva entre 30 y 90 segundos en una RTX 2060. Despu\u00e9s, mientras el proceso sigue vivo, las generaciones son r\u00e1pidas. Si vas a hacer batch, mant\u00e9n el proceso abierto.\n\n* Implicaciones \u00e9ticas\n\nNo puedo cerrar este post sin decirlo: clonar la voz de alguien sin su permiso es una putada y, en muchas jurisdicciones, ilegal. La tecnolog\u00eda que acabo de explicar permite generar audios indistinguibles de los reales, y eso tiene consecuencias.\n\nLa regla simple que aplico:\n\n- *La voz de mi mujer*: con su permiso expl\u00edcito, para mandarle bromas y avisarle del cambio.\n- *La voz de un amigo*: con su permiso expl\u00edcito, para re\u00edrnos en el grupo y avisarle del cambio.\n- *Voces de figuras p\u00fablicas, jefes, desconocidos*: no.\n\nSi vas a hacer esto para cachondear con alguien cercano, avisa antes y ense\u00f1a 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.\n\nLas plataformas grandes (ElevenLabs, OpenAI) tienen detecci\u00f3n de voces clonadas y filtros activos. Las herramientas locales como F5-TTS no tienen nada. La responsabilidad est\u00e1 entera en ti.\n\n* Conclusi\u00f3n\n\nEn 2026, clonar una voz con calidad alta es un fin de semana de cacharreo, una RTX modesta y software MIT. La barrera t\u00e9cnica es pr\u00e1cticamente nula. La barrera real es \u00e9tica y de criterio.\n\nSi quieres usarlo bien: p\u00eddele permiso a la persona, hazle re\u00edr 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.\n\nSi quieres usarlo mal: te recomiendo que no.\n\n* Recursos\n\n- F5-TTS oficial: [[https:\/\/github.com\/SWivid\/F5-TTS][github.com\/SWivid\/F5-TTS]]\n- Modelo en espa\u00f1ol: [[https:\/\/huggingface.co\/jpgallegoar\/F5-Spanish][huggingface.co\/jpgallegoar\/F5-Spanish]]\n- whisper.cpp: [[https:\/\/github.com\/ggerganov\/whisper.cpp][github.com\/ggerganov\/whisper.cpp]]\n- Mis dotfiles (incluyen =f5-say=, =capture-talker= y todo el m\u00f3dulo TTS de NixOS): [[https:\/\/github.com\/pascualmg\/dotfiles][github.com\/pascualmg\/dotfiles]]\n"}