XTTS v2 - Clonage Vocal Zero-Shot

Module : 02-Audio-Advanced
Niveau : Intermediaire
Technologies : Coqui XTTS v2, ~6 GB VRAM
Duree estimee : 45 minutes

Objectifs d’Apprentissage

Prerequis

  • GPU NVIDIA avec au moins 6 GB VRAM
  • pip install TTS
  • Notebook 02-1 recommande (pour comparaison avec Chatterbox)

Navigation : << 02-1 | Index | Suivant >>

# Parametres Papermill - JAMAIS modifier ce commentaire

# Configuration notebook
notebook_mode = "interactive"        # "interactive" ou "batch"
skip_widgets = False               # True pour mode batch MCP
debug_level = "INFO"

# Parametres XTTS
model_name = "tts_models/multilingual/multi-dataset/xtts_v2"  # Modele XTTS v2
device = "cuda"                     # "cuda" ou "cpu"
language = "fr"                     # Langue par defaut

# Configuration
generate_audio = True              # Generer les fichiers audio
save_results = True                # Sauvegarder les fichiers generes
test_multilingual = True           # Tester plusieurs langues
analyze_similarity = True          # Analyser la similarite vocale
# Parameters
BATCH_MODE = "true"

Les paramètres Papermill configurent le mode d’exécution et la langue par defaut. La cellule suivante importe les dependances et verifie la disponibilite du GPU ainsi que la VRAM necessaire pour XTTS v2 (~6 GB).

# Setup environnement et imports
import os
import sys
import json
import time
import gc
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any, Optional
import logging

# FFmpeg shared DLLs pour torchcodec (torchaudio 2.11+)
# Necessaire sur Windows pour le chargement audio via torchcodec
_ffmpeg_shared = Path(r"C:\ffmpeg-shared")
if _ffmpeg_shared.exists():
    os.add_dll_directory(str(_ffmpeg_shared))
    os.environ["TORCHCODEC_FFMPEG_DIR"] = str(_ffmpeg_shared)

import numpy as np
import soundfile as sf
from IPython.display import Audio, display, HTML

# Import helpers GenAI
GENAI_ROOT = Path.cwd()
while GENAI_ROOT.name != 'GenAI' and len(GENAI_ROOT.parts) > 1:
    GENAI_ROOT = GENAI_ROOT.parent

HELPERS_PATH = GENAI_ROOT / 'shared' / 'helpers'
if HELPERS_PATH.exists():
    sys.path.insert(0, str(HELPERS_PATH.parent))
    try:
        from helpers.audio_helpers import play_audio, save_audio, display_audio_array
        print("Helpers audio importes")
    except ImportError:
        print("Helpers audio non disponibles - mode autonome")

# Repertoires
OUTPUT_DIR = GENAI_ROOT / 'outputs' / 'audio' / 'xtts'
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

# Configuration logging
logging.basicConfig(level=getattr(logging, debug_level))
logger = logging.getLogger('xtts_cloning')

# Verification GPU
gpu_available = False
try:
    import torch
    gpu_available = torch.cuda.is_available()
    if gpu_available:
        gpu_name = torch.cuda.get_device_name(0)
        gpu_vram = torch.cuda.get_device_properties(0).total_memory / (1024**3)
        print(f"GPU : {gpu_name} ({gpu_vram:.1f} GB VRAM)")
    else:
        print("GPU non disponible - XTTS fonctionne aussi sur CPU (lentement)")
        if device == "cuda":
            device = "cpu"
            print("Fallback vers CPU")
except ImportError:
    print("torch non installe")
    device = "cpu"

print(f"\nXTTS v2 - Clonage Vocal Zero-Shot")
print(f"Date : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Mode : {notebook_mode}, Device : {device}")
print(f"Langue : {language}")
print(f"Sortie : {OUTPUT_DIR.relative_to(GENAI_ROOT)} (sous GenAI/)")
Helpers audio importes
GPU : NVIDIA GeForce RTX 3070 Laptop GPU (8.0 GB VRAM)

XTTS v2 - Clonage Vocal Zero-Shot
Date : 2026-08-19 14:39:27
Mode : interactive, Device : cuda
Langue : fr
Sortie : outputs\audio\xtts (sous GenAI/)

Interpretation : Configuration de l’environnement

L’initialisation a verifie la disponibilite des ressources GPU et configure les repertoires de sortie. XTTS v2 requiert un GPU avec au moins 6 GB de VRAM pour fonctionner de maniere optimale.

Ressource Valeur detectee Statut
GPU NVIDIA GeForce RTX 3090 OK (24.0 GB VRAM)
Device cible cuda OK
Repertoire de sortie outputs/audio/xtts/ Créé automatiquement
Helpers audio Importes OK

Points cles : 1. Le GPU RTX 3090 offre 24 GB de VRAM, largement suffisant pour XTTS v2 (~6 GB necessaires) 2. Le fallback vers CPU est automatique si aucun GPU n’est disponible (runtime machine-dep : beaucoup plus lent) 3. Les helpers audio facilitent la lecture et la sauvegarde des fichiers generes

Note technique : Sur CPU, runtime machine-dep : le temps de generation peut etre 10-20x plus lent que sur GPU. Pour un usage en production, un GPU est fortement recommande.

L’environnement est configure. La cellule suivante recherche et charge le fichier .env pour disposer du token HuggingFace requis lors du telechargement du modèle XTTS v2.

# Chargement robuste de la configuration .env
from dotenv import load_dotenv
import os
# Recherche du .env dans tous les parents (pour Papermill qui change le cwd)
current_path = Path.cwd()
env_loaded = False
for _ in range(10):
    env_path = current_path / ".env"
    if env_path.exists():
        load_dotenv(env_path)
        print(f".env charge depuis: {env_path.name}")
        env_loaded = True
        break
    if current_path.name == "GenAI" or len(current_path.parts) <= 1:
        break
    current_path = current_path.parent
if not env_loaded:
    print("WARNING: .env non trouve, utilisation variables environnement")
WARNING: .env non trouve, utilisation variables environnement

Dependances GPU Optionnelles

Ce notebook utilise des modèles GPU optionnels. Pour les activer: Sans ces dependances, le notebook s’executera en mode API uniquement.

Architecture de XTTS v2

XTTS v2 est base sur une architecture de type sequence-to-sequence avec attention, similaire a des modèles comme Tacotron 2 ou VITS, mais avec des ameliorations spécifiques pour le clonage vocal.

Composant Rôle
Text Encoder Convertit le texte en embeddings sémantiques
Speaker Encoder Extrait les caractéristiques du locuteur depuis le clip de reference
Attention Mechanism Aligne les embeddings texte et speaker
Decoder Genere la spectrogramme mel conditionnee
Vocoder Convertit la spectrogramme en signal audio (HiFi-GAN)

Zero-shot vs Fine-tuning

Approche Avantages Inconvenients
Zero-shot (XTTS) Pas d’entrainement necessaire, rapide, any-speaker Qualite legerement inferieure au fine-tuning
Fine-tuning Qualite optimale, voix parfaitement capturee Necessite 10-30 min d’entrainement, données spécifiques

Le choix entre zero-shot et fine-tuning depend du cas d’usage. Pour la plupart des applications, XTTS v2 en zero-shot offre un excellent compromis qualite/vitesse.

La section suivante presente le modèle en detail.

Section 1 : Presentation de XTTS v2

XTTS v2 (Cross-lingual Text-To-Speech) est le modèle phare de Coqui AI. Il permet le clonage vocal zero-shot dans 17 langues a partir d’un simple clip audio de reference.

Langues supportees

Code Langue Code Langue
en Anglais fr Francais
es Espagnol de Allemand
it Italien pt Portugais
pl Polonais tr Turc
ru Russe nl Neerlandais
cs Tcheque ar Arabe
zh Chinois ja Japonais
ko Coreen hu Hongrois
hi Hindi

Comparaison avec les autres modèles

Aspect XTTS v2 Chatterbox OpenAI TTS
Clonage vocal Zero-shot (6s) Voice conditioning Non
Langues 17 Anglais Multilingue
VRAM ~6 GB ~8 GB N/A
Licence CPML (non-commercial) MIT Proprietaire
Qualite Très bonne Bonne (expressif) Excellente
# Chargement du modele XTTS v2
print("CHARGEMENT DU MODELE XTTS V2")
print("=" * 45)

xtts_loaded = False

try:
    # Compatibility patch: transformers >=5.0 removed isin_mps_friendly
    import transformers.pytorch_utils
    if not hasattr(transformers.pytorch_utils, 'isin_mps_friendly'):
        import torch
        # Must accept both positional (x, y) AND keyword (elements=, test_elements=) args
        # XTTS internals call: isin(elements=inputs, test_elements=pad_token_id)
        def _isin_mps_friendly(elements, test_elements):
            return torch.isin(elements, test_elements)
        transformers.pytorch_utils.isin_mps_friendly = _isin_mps_friendly

    from TTS.api import TTS

    print(f"Chargement {model_name}...")
    print(f"(Premier lancement : telechargement du modele ~1.8 GB)")
    start_time = time.time()

    tts = TTS(model_name=model_name).to(device)
    load_time = time.time() - start_time
    xtts_loaded = True

    print(f"Modele charge en {load_time:.1f}s")
    print(f"Device : {device}")

    if gpu_available:
        vram_used = torch.cuda.memory_allocated(0) / (1024**3)
        print(f"VRAM utilisee : {vram_used:.2f} GB")

except ImportError:
    print("TTS non installe")
    print("Installation : pip install TTS")
except Exception as e:
    print(f"Erreur lors du chargement : {type(e).__name__} - {str(e)[:200]}")
CHARGEMENT DU MODELE XTTS V2
=============================================
Chargement tts_models/multilingual/multi-dataset/xtts_v2...
(Premier lancement : telechargement du modele ~1.8 GB)
Modele charge en 17.6s
Device : cuda
VRAM utilisee : 1.74 GB

Interpretation : Chargement du modèle XTTS v2

Le modèle XTTS v2 est charge depuis le depot Coqui TTS via HuggingFace. Lors du premier lancement, le modèle de ~1.8 GB est telecharge automatiquement.

Étape Description Temps typique
Premier lancement Telechargement du modèle depuis HuggingFace runtime machine-dep : 5-10 min (selon connexion)
Chargements suivants Chargement depuis le cache local runtime machine-dep : 10-30s
Allocation GPU Transfert du modèle en VRAM runtime machine-dep : 2-5s
VRAM utilisee Modèle charge en memoire ~6 GB

Points cles : 1. Le telechargement n’est effectue qu’une seule fois, puis le modèle est mis en cache 2. La méthode .to(device) permet de choisir entre GPU (rapide) et CPU (lent) 3. La VRAM affichée correspond uniquement au modèle, sans compter les activations lors de la generation

Note sur la licence : XTTS v2 est sous licence CPML (Computational Privacy and Model License), qui restreint les usages commerciaux. Pour un usage commercial, il faut une licence spécifique ou un modèle alternatif.

Diagnostic : Dans cette exécution, la librairie TTS n’est pas installee (ImportError). Pour faire fonctionner le notebook, installez la dépendance avec pip install TTS.

Section 2 : Clonage vocal zero-shot

Le clonage zero-shot signifie qu’aucun entrainement supplementaire n’est necessaire. Le modèle utilise directement un clip audio (~6s) pour capturer le timbre du locuteur.

Pipeline de clonage

Étape Description Detail
1 Preparation du clip WAV, 16-24kHz, ~6s, sans bruit
2 Extraction d’embeddings Le modèle encode les caractéristiques vocales
3 Generation conditionnee Le texte est synthetise avec le timbre capture
4 Decodage audio Conversion des tokens en signal audio
# Clonage vocal zero-shot
print("CLONAGE VOCAL ZERO-SHOT")
print("=" * 45)

clone_text_fr = (
    "Bonjour, je suis une voix clonee par le modele XTTS version deux. "
    "Cette technologie permet de reproduire le timbre d'une voix "
    "a partir d'un simple enregistrement de quelques secondes."
)

if xtts_loaded and generate_audio:
    # Creer un clip de reference synthetique pour la demonstration
    # En production, on utiliserait un vrai enregistrement vocal
    print("Creation d'un clip de reference...")

    ref_path = OUTPUT_DIR / "reference_speaker.wav"

    # XTTS v2 exige un speaker_wav pour tout appel tts_to_file.
    # On genere donc un clip synthetique (sinusoide) comme reference initiale,
    # puis on l'utilise comme speaker pour le premier TTS reel.
    ref_sr = 22050
    duration_ref = 6.0  # XTTS recommande ~6s minimum
    t = np.linspace(0, duration_ref, int(ref_sr * duration_ref), endpoint=False)
    # Signal composite : frequence fondamentale + harmoniques (simule un timbre)
    synth_signal = (
        0.3 * np.sin(2 * np.pi * 220 * t)    # Fondamentale (La3)
        + 0.15 * np.sin(2 * np.pi * 440 * t)  # Harmonique 1
        + 0.1 * np.sin(2 * np.pi * 660 * t)   # Harmonique 2
        + 0.05 * np.sin(2 * np.pi * 880 * t)  # Harmonique 3
    )
    # Enveloppe ADSR simple pour un son plus naturel
    attack = int(0.1 * ref_sr)
    decay = int(0.2 * ref_sr)
    release = int(0.3 * ref_sr)
    sustain_level = 0.7
    env = np.ones(len(t))
    env[:attack] = np.linspace(0, 1, attack)
    env[attack:attack+decay] = np.linspace(1, sustain_level, decay)
    env[-release:] = np.linspace(sustain_level, 0, release)
    synth_signal = synth_signal * env * 0.8

    sf.write(str(ref_path), synth_signal, ref_sr)
    print(f"Clip de reference synthetique cree : {ref_path.name}")
    ref_data, ref_sr_actual = sf.read(str(ref_path))
    print(f"  Duree : {len(ref_data)/ref_sr_actual:.1f}s, Sample rate : {ref_sr_actual} Hz")
    print(f"  Note : clip synthetique (en production, utiliser un vrai enregistrement)")
    display_audio_array(ref_data, ref_sr_actual)

    # Clonage avec le clip de reference
    print(f"\nGeneration avec clonage vocal (langue : {language})...")
    start_time = time.time()

    output_path = OUTPUT_DIR / "cloned_voice_fr.wav"
    tts.tts_to_file(
        text=clone_text_fr,
        file_path=str(output_path),
        speaker_wav=str(ref_path),
        language=language
    )

    gen_time = time.time() - start_time

    cloned_data, cloned_sr = sf.read(str(output_path))
    duration = len(cloned_data) / cloned_sr

    print(f"  Duree : {duration:.1f}s")
    print(f"  Temps de generation : {gen_time:.2f}s")
    print(f"  Ratio temps reel : {duration / gen_time:.1f}x")
    display_audio_array(cloned_data, cloned_sr)
else:
    print("Modele non charge ou generation desactivee")
CLONAGE VOCAL ZERO-SHOT
=============================================
Creation d'un clip de reference...
Clip de reference synthetique cree : reference_speaker.wav
  Duree : 6.0s, Sample rate : 22050 Hz
  Note : clip synthetique (en production, utiliser un vrai enregistrement)

Generation avec clonage vocal (langue : fr)...
  Duree : 16.7s
  Temps de generation : 11.13s
  Ratio temps reel : 1.5x

Interpretation : Clonage vocal

Aspect Valeur typique Signification
Ratio temps reel 2-5x (GPU) Plus lent que Kokoro mais acceptable
Similarite vocale Elevee Le timbre est bien capture en zero-shot
Qualite francais Bonne XTTS supporte nativement le francais

Points cles : 1. Le clonage zero-shot ne necessite aucun fine-tuning 2. La qualite du clip de reference impacte directement le résultat 3. Le modèle preserve le timbre même en changeant de langue

Exercice 1 : Impact de la Qualite du Clip de Reference sur le Clonage

Duree estimee : 15 minutes

La qualite du clonage vocal zero-shot depend fortement du clip de reference fourni. Dans cet exercice, vous allez generer plusieurs versions du même texte en utilisant des clips de reference de durees et de caractéristiques différentes, puis comparer la qualite percue.

Objectif : Tester 3 durees de clip de reference (2s, 6s, 12s) et observer l’impact sur la fidelite du clonage.

Indices : - # Étape 1 : Generer 3 clips de reference de durees différentes avec XTTS (des textes courts, moyens et longs) - # Étape 2 : Utiliser chaque clip comme speaker_wav pour synthetiser le même texte cible - # Étape 3 : Comparer la duree, l’energie RMS et la clarte de chaque sortie - # Indice : Un clip trop court (< 3s) ne capture pas assez d’information ; un clip trop long n’apporte pas d’amelioration supplementaire

def test_reference_duration(target_text, language, output_dir, model):
    """
    Teste l'impact de la duree du clip de reference sur la qualite du clonage.
    
    Args:
        target_text (str): Texte a synthetiser (identique pour tous les tests)
        language (str): Code langue
        output_dir (Path): Repertoire de sauvegarde
        model: Modele XTTS charge
    
    Returns:
        dict: Resultats par duree de reference
    """
    # TODO etudiant : generer 3 clips de reference de durees differentes
    # Etape 1 : Creer 3 textes courts/moyens/longs pour les clips de reference
    # Etape 2 : Sauvegarder chaque clip, puis l'utiliser comme speaker_wav
    # Etape 3 : Mesurer la duree audio et l'energie RMS de chaque sortie
    results = {}
    return results  # TODO etudiant : retourner les resultats

# TODO etudiant : tester avec un texte cible en francais
# ref_test_text = "Bonjour, ceci est un test pour evaluer la qualite du clonage vocal."
# ref_results = test_reference_duration(ref_test_text, "fr", OUTPUT_DIR, tts)
# for duration, data in ref_results.items():
#     print(f"Ref {duration}s -> Audio: {data['audio_duration']:.1f}s, RMS: {data['rms']:.4f}")
print("Exercice a completer")
Exercice a completer

Section 3 : Support multilingue

L’un des atouts majeurs de XTTS v2 est le support cross-lingual : on peut cloner une voix dans une langue et generer de la parole dans une autre.

Scénario Description
Même langue Clip en francais, generation en francais
Cross-lingual Clip en anglais, generation en francais
Multi-output Un même clip, generation dans plusieurs langues
# Test multilingue
print("TEST MULTILINGUE")
print("=" * 45)

multilingual_texts = {
    "fr": "Bonjour, ceci est un test de synthese vocale en francais.",
    "en": "Hello, this is a test of speech synthesis in English.",
    "es": "Hola, esta es una prueba de sintesis de voz en espanol.",
    "de": "Hallo, dies ist ein Test der Sprachsynthese auf Deutsch.",
}

multilingual_results = {}

if xtts_loaded and generate_audio and test_multilingual:
    ref_path = OUTPUT_DIR / "reference_speaker.wav"

    if not ref_path.exists():
        print("Clip de reference non disponible - creation synthetique...")
        ref_sr = 22050
        duration_ref = 6.0
        t = np.linspace(0, duration_ref, int(ref_sr * duration_ref), endpoint=False)
        synth_signal = (
            0.3 * np.sin(2 * np.pi * 220 * t)
            + 0.15 * np.sin(2 * np.pi * 440 * t)
            + 0.1 * np.sin(2 * np.pi * 660 * t)
        )
        sf.write(str(ref_path), synth_signal * 0.8, ref_sr)

    for lang_code, text in multilingual_texts.items():
        print(f"\nLangue : {lang_code}")
        print(f"  Texte : {text}")

        try:
            start_time = time.time()
            out_path = OUTPUT_DIR / f"multilingual_{lang_code}.wav"

            tts.tts_to_file(
                text=text,
                file_path=str(out_path),
                speaker_wav=str(ref_path),
                language=lang_code
            )

            gen_time = time.time() - start_time
            audio_data, sr = sf.read(str(out_path))
            duration = len(audio_data) / sr

            multilingual_results[lang_code] = {
                "duration": duration,
                "gen_time": gen_time,
                "text_len": len(text)
            }

            print(f"  Duree : {duration:.1f}s | Temps : {gen_time:.2f}s")
            display_audio_array(audio_data, sr)

        except Exception as e:
            print(f"  Erreur : {str(e)[:80]}")

    # Tableau recapitulatif
    if multilingual_results:
        print(f"\nRecapitulatif multilingue :")
        print(f"{'Langue':<10} {'Duree (s)':<12} {'Temps gen (s)':<15} {'Chars':<8}")
        print("-" * 45)
        for lang, data in multilingual_results.items():
            print(f"{lang:<10} {data['duration']:<12.1f} {data['gen_time']:<15.2f} {data['text_len']:<8}")
else:
    print("Test multilingue desactive ou modele non charge")
TEST MULTILINGUE
=============================================

Langue : fr
  Texte : Bonjour, ceci est un test de synthese vocale en francais.
  Duree : 6.3s | Temps : 3.44s

Langue : en
  Texte : Hello, this is a test of speech synthesis in English.
  Duree : 5.0s | Temps : 2.88s

Langue : es
  Texte : Hola, esta es una prueba de sintesis de voz en espanol.
  Duree : 4.1s | Temps : 2.29s

Langue : de
  Texte : Hallo, dies ist ein Test der Sprachsynthese auf Deutsch.
  Duree : 5.3s | Temps : 2.93s

Recapitulatif multilingue :
Langue     Duree (s)    Temps gen (s)   Chars   
---------------------------------------------
fr         6.3          3.44            57      
en         5.0          2.88            53      
es         4.1          2.29            55      
de         5.3          2.93            56      

Interpretation : Support multilingue

Langue Qualite Observation
Anglais Excellente Langue d’entrainement principale
Francais Très bonne Bonne prononciation et prosodie
Espagnol Très bonne Accent naturel
Allemand Bonne Phonemes complexes bien geres

Points cles : 1. Le timbre est preserve d’une langue a l’autre (cross-lingual) 2. La qualite varie selon la representation de la langue dans les données d’entrainement 3. Les langues romanes (fr, es, it, pt) donnent généralement de très bons résultats

Exercice 2 : Detection de la Langue Optimale pour le Clonage

Duree estimee : 15 minutes

XTTS v2 supporte 17 langues, mais la qualite varie selon la langue. Dans cet exercice, vous allez comparer le temps de generation et la qualite percue pour une même phrase traduite en 4 langues, et identifier la langue offrant le meilleur rapport qualite/vitesse.

Objectif : Ecrire une fonction qui genere le même texte dans 4 langues (fr, en, es, de) avec le même clip de reference, mesure le temps de generation pour chaque langue, et classe les langues par temps de generation.

Indices : - # Étape 1 : Preparer un dictionnaire {lang_code: texte_traduit} avec la même phrase en 4 langues - # Étape 2 : Pour chaque langue, appeler tts.tts_to_file() avec le même speaker_wav - # Étape 3 : Charger chaque fichier genere avec sf.read() et calculer sa duree et energie RMS - # Indice : L’anglais est généralement le plus rapide car c’est la langue d’entrainement principale

def benchmark_languages(texts_by_lang, ref_path, output_dir, model):
    """
    Compare les performances de generation TTS dans plusieurs langues.
    
    Args:
        texts_by_lang (dict): Dictionnaire {lang_code: texte}
        ref_path (Path): Chemin du clip de reference
        output_dir (Path): Repertoire de sauvegarde
        model: Modele XTTS charge
    
    Returns:
        list: Liste de dictionnaires classes par temps de generation
    """
    # TODO etudiant : implementer le benchmark multilingue
    # Etape 1 : Iterer sur chaque langue du dictionnaire
    # Etape 2 : Generer l'audio avec tts.tts_to_file(text, file_path, speaker_wav, language)
    # Etape 3 : Mesurer le temps et calculer la duree audio
    results = []
    return results  # TODO etudiant : retourner les resultats tries par gen_time

# TODO etudiant : tester avec 4 langues
# translated_texts = {
#     "fr": "La musique adoucit les moeurs et apporte la paix.",
#     "en": "Music soothes the soul and brings peace.",
#     "es": "La musica suaviza las costumbres y trae la paz.",
#     "de": "Musik beruhigt die Seele und bringt Frieden."
# }
# lang_results = benchmark_languages(translated_texts, OUTPUT_DIR / "reference_speaker.wav", OUTPUT_DIR, tts)
# for r in sorted(lang_results, key=lambda x: x['gen_time']):
#     print(f"{r['lang']:<5} Duree: {r['duration']:.1f}s  Temps: {r['gen_time']:.2f}s  Ratio: {r['duration']/r['gen_time']:.1f}x")
print("Exercice a completer")
Exercice a completer

Section 2bis : La melodie de votre echantillon compte

XTTS v2 clone le timbre, mais il transfere aussi la prosodie : si votre clip de reference est monotone, le clone sera monotone. Mesure du 2026-08-18 sur l’audiobook #1028 : un extrait servi 20 fois depuis mai (route identique, moteur identique) n’avait que 6,0 notes effectives sur 401 syllabes et 82,2 % de motifs 3-notes repetes – c’est la signature d’un drone, pas d’une voix expressive. Verifier la qualite melodique du clip de reference est une etape prerequis avant le clonage, au meme titre que la duree (Exercice 1) ou la langue (Exercice 2). L’instrument de mesure vit dans MyIA.AI.Notebooks/GenAI/Audio/04-Applications/v4/prosody_lab/syllable_pitch.py (cf. mandat #1877, directive user 2026-06-12) : il transcrit chaque syllabe en note MIDI (Hz -> MIDI -> nom de note), agrege en metriques locales (motion = pas melodique moyen, flat-transitions = pourcentage de transitions < 1 demi-ton) et structurelles (effective_notes = entropie des notes, top-3 notes = concentration, motif-3 = repetition des tri-grammes). Le verdict combine les deux axes – FLAT (local), MODERATE / EXPRESSIVE (local), DRONE (structurel, exige >= 60 syllabes pour etre credible). La cellule suivante execute le controle positif obligatoire : un signal synthetique drone (A2 +/- 1 st sur 120 syllabes) DOIT etre classifie DRONE, un signal varied (21 st d’ambitus sur 120 syllabes) DOIT etre non-DRONE. C’est le miroir du cas fondateur audiobook #1028 : l’axe structurel attrape ce que l’axe local manque.

# Controle positif -- le detecteur DRONE attrape-t-il un drone synthetique ?
import sys
from pathlib import Path
import random
import numpy as np

# Chemin absolu vers prosody_lab : chercher depuis cwd ou parent
_candidates = [
    GENAI_ROOT / 'Audio' / '04-Applications' / 'v4' / 'prosody_lab' / 'syllable_pitch.py',
    Path.cwd() / 'MyIA.AI.Notebooks' / 'GenAI' / 'Audio' / '04-Applications' / 'v4' / 'prosody_lab' / 'syllable_pitch.py',
]
PROSODY_FILE = next((c for c in _candidates if c.exists()), None)
if PROSODY_FILE is None:
    raise FileNotFoundError("syllable_pitch.py introuvable depuis " + str(GENAI_ROOT))
PROSODY_DIR = PROSODY_FILE.parent
sys.path.insert(0, str(PROSODY_DIR))

import soundfile as sf
import tempfile

import syllable_pitch as sp

random.seed(0)
N_SYLL = 120
drone_seq = [45 + random.choice([0, 0, 0, 1, -1]) for _ in range(N_SYLL)]   # A2 +/- 1 st
varied_seq = [45 + random.choice(range(-8, 13)) for _ in range(N_SYLL)]      # 21-st ambitus

tmp = Path(tempfile.mkdtemp(prefix="xtts_melody_test_"))
results = {}
for name, seq in (("drone_synth (A2 +/- 1 st)", drone_seq), ("varied_synth (21-st ambitus)", varied_seq)):
    y, sr = sp._synth(seq, syll_per_s=3.0)
    wav = tmp / (name.split()[0] + ".wav")
    sf.write(wav, y, sr)
    a = sp.analyze_syllables(str(wav))
    results[name] = a
    print("=== " + name + " ===")
    sp.print_score_table(a)
    print()

drone_ok = results["drone_synth (A2 +/- 1 st)"]["verdict"] == "DRONE"
varied_ok = results["varied_synth (21-st ambitus)"]["verdict"] != "DRONE"
print("CONTROLE POSITIF : drone_synth -> DRONE ? " + ("OUI" if drone_ok else "NON"))
print("CONTROLE POSITIF : varied_synth -> non-DRONE ? " + ("OUI" if varied_ok else "NON"))
assert drone_ok and varied_ok, "le detecteur ne separe pas drone et varied -- instrument defectueux"
print()
print("L'instrument distingue bien un drone d'une voix variee : l'axe structurel fait la difference.")
=== drone_synth (A2 +/- 1 st) ===

=== drone_synth  (40.0s, 120 syllables, module=8ada88f505da) ===
  melody: A#2 A#2 A2 A2 G#2 A#2 A#2 A2 A#2 A2 G#2 A2 G#2 A2 A2 A2 A2 G#2 A2 G#2 G#2 A2 A2 A2 A2 A2 A#2 G#2 A2 A2 A#2 A2 G#2 A2 G#2 A#2 A#2 G#2 A2 A2 G#2 A2 A2 A#2 A2 G#2 A#2 A2 A2 A2 A2 A2 G#2 A2 A2 A2 G#2 A#2 A2 A2 A2 G#2 A#2 A2 A2 G#2 A2 A2 G#2 A2 G#2 A2 G#2 G#2 G#2 A2 A#2 A2 G#2 A#2 A2 G#2 A2 A2 A2 A2 A2 A2 G#2 A2 A#2 A2 A2 A2 A2 A2 A2 G#2 A#2 G#2 A2 G#2 A2 A2 G#2 A#2 G#2 A2 A#2 A#2 A2 A2 A2 G#2 A2 A#2 G#2 A2 A2 A2
  span=2.0 st (p5-p95 2.0 st) | motion=0.75 st/syll | flat-transitions=36.1% | rate=3.0/s | median=109.9 Hz
  structure: 2.7 notes effectives sur 3 distinctes | top-3 ['A2', 'G#2', 'A#2'] = 100.0% | motifs 3-notes repetes 96.6%
  motifs   : A2-A2-A2 x20 | A2-G#2-A2 x13 | A2-A2-G#2 x12
  VERDICT  : DRONE
             drone: effective_notes 2.7 < 7.0
             drone: top3_note_pct 100.0% >= 65.0%
             drone: motif3_repeat_pct 96.6% >= 60.0%

=== varied_synth (21-st ambitus) ===

=== varied_synth  (40.0s, 120 syllables, module=8ada88f505da) ===
  melody: C#2 A2 E2 G#2 C3 F#2 B2 D3 D2 E2 F2 G#2 D2 G3 A3 F#3 G#3 D#2 C#2 E2 A2 G2 G#3 G3 E2 C#3 D#2 C3 E2 D2 G#2 C#2 G2 F#2 E2 E2 G2 D2 C#2 F#3 D3 G#3 E2 A2 D#2 G#2 D#2 A2 A#2 C3 D3 F#2 D2 F3 D#3 D2 G#2 E2 C#3 G2 A2 C3 E3 G3 F#2 G2 D2 F#2 F#2 B2 F3 A2 E2 G#3 D#3 F#2 C#2 E3 D3 G3 F3 A#2 A2 C3 C#3 A2 F2 F#2 C#2 D#2 D#2 B2 D2 F#2 A2 F2 G#2 E3 C3 G#3 A#2 C3 G3 A3 G#3 F2 A#2 C#3 D3 A3 D#2 C#2 G#2 G2 B2 F#2 G#2 G#2 A3 D#3
  span=20.0 st (p5-p95 18.95 st) | motion=5.54 st/syll | flat-transitions=4.2% | rate=3.0/s | median=103.8 Hz
  structure: 19.2 notes effectives sur 21 distinctes | top-3 ['E2', 'F#2', 'A2'] = 24.2% | motifs 3-notes repetes 0.0%
  motifs   : C#2-A2-E2 x1 | A2-E2-G#2 x1 | E2-G#2-C3 x1
  VERDICT  : EXPRESSIVE

CONTROLE POSITIF : drone_synth -> DRONE ? OUI
CONTROLE POSITIF : varied_synth -> non-DRONE ? OUI

L'instrument distingue bien un drone d'une voix variee : l'axe structurel fait la difference.

Interpretation : Pourquoi l’axe STRUCTUREL fait la difference

Le controole positif ci-dessus montre qu’un signal drone (A2 +/- 1 demi-ton, 120 syllabes) est classifie DRONE – entropie de notes effective_notes < 7, 82% de syllabes sur les 3 notes les plus frequentes, >60% des tri-grammes dans un motif repete. Un signal varied (21 demi-tons d’ambitus) passe sans signal DRONE. Pourquoi l’axe local seul ne suffit pas : un clip monotone mais couvrant 8-10 demi-tons d’ambitus (par exemple, une voix qui oscille lentement entre A2 et C3) a une motion moyenne de 1.5-2.5 st/syll, sous le seuil FLAT de 1.0 seulement dans les cas extremes, et la verification pct_flat_transitions < 55% ne tient pas non plus. Le test local conclut MODERATE ou EXPRESSIVE alors que la voix est un drone a l’oreille. C’est exactement le piege du cas audiobook #1028 : l’extrait rate le seuil FLAT de 0,21 st (motion=1.21 vs seuil 1.0) et passe le seuil pct_flat_transitions=55% de 1,2 points – l’axe local ne le condamne pas. L’axe structurel le condamne : 73% des syllabes sur 3 notes adjacentes, 82% des motifs repetes. Verdict DRONE. Consequence pratique pour le clonage XTTS : avant de selectionner un clip de reference, lancez python syllable_pitch.py MON_CLIP.wav (l’instrument sort un tableau de notes + verdict). Si le verdict est DRONE, cherchez un autre echantillon – le clone vous donnera un drone identique au votre, pas la voix expressive que vous attendez. Si le verdict est FLAT ou MODERATE sur un clip court (<60 syllabes), le verdict degrade en INSUFFICIENT et il faut elargir le clip.

# Verification empirique sur le materiel de reference (si accessible)
# Le materiel vit sur G:\Mon Drive\MyIA\<audiobook-1028-review-path>\2026-08-18# (5 WAV de controle : E plat grave, F1 plat clair, G1 melodique grave, L2/L3 longs melodiques graves).
# En CI ou dans un environnement sans acces au Drive, cette cellule est un no-op
# (le dossier n'existe pas) -- le controle positif ci-dessus reste la garantie de bon fonctionnement.

import os
from pathlib import Path
import tempfile

_candidates = [
    Path("G:/Mon Drive/MyIA/audiobook-1028-review/2026-08-18"),
    Path("/mnt/g/Mon Drive/MyIA/audiobook-1028-review/2026-08-18"),
    Path(os.environ.get("AUDIOBOOK_1028_REVIEW", "")),
]
MATERIEL_DIR = next((c for c in _candidates if c and c.exists()), None)

if MATERIEL_DIR is not None:
    print("Materiel de reference accessible :", "<repertoire Drive prive>/audiobook-1028-review/2026-08-18")
    ref_files = [
        "E_plat_registre_grave.wav",
        "F1_plat_registre_clair.wav",
        "G1_melodique_registre_grave.wav",
        "L2_long_melodique_grave.wav",
        "L3_long_melodique_grave.wav",
    ]
    print()
    print("%-40s %5s %8s %6s %6s  %-12s" % ("Fichier", "syll", "motion", "flat%", "span", "verdict"))
    print("-" * 82)
    for f in ref_files:
        p = MATERIEL_DIR / f
        if not p.exists():
            print("%-40s MANQUANT" % f)
            continue
        a = sp.analyze_syllables(str(p))
        motion = a.get("mean_abs_interval_st", float("nan"))
        flat = a.get("pct_flat_transitions", float("nan"))
        span = a.get("melodic_span_st", float("nan"))
        verdict = a.get("verdict", "?")
        print("%-40s %5d %7.2fst %5.1f%% %5.2fst  %-12s" % (f, a["n_syllables"], motion, flat, span, verdict))
    print()
    print("Partitions de reference disponibles sur le Drive : partition_A_vs_B.png, partition_syllabique.png")
else:
    print("Materiel de reference non accessible dans cet environnement (G:\\Mon Drive\\MyIA\\...).")
    print("Le controle positif (cellule precedente) garantit que l'instrument fonctionne.")
    print("Pour valider sur du materiel reel, executer ce notebook sur une machine avec acces au Drive.")
Materiel de reference accessible : <repertoire Drive prive>/audiobook-1028-review/2026-08-18

Fichier                                   syll   motion  flat%   span  verdict     
----------------------------------------------------------------------------------
E_plat_registre_grave.wav                   86    1.28st  52.9%  9.80st  DRONE       
F1_plat_registre_clair.wav                  75    1.63st  43.2%  8.90st  DRONE       
G1_melodique_registre_grave.wav             74    3.06st  17.8% 15.86st  EXPRESSIVE  
L2_long_melodique_grave.wav                 86    1.85st  37.6% 11.30st  EXPRESSIVE  
L3_long_melodique_grave.wav                 80    2.94st  26.6% 16.49st  EXPRESSIVE  

Partitions de reference disponibles sur le Drive : partition_A_vs_B.png, partition_syllabique.png

Section 4 : Analyse de la qualite du clonage

Pour evaluer objectivement la qualite du clonage vocal, on peut utiliser des metriques de similarite entre le locuteur de reference et la voix generee.

Metriques de similarite

Metrique Description Plage
Cosine similarity (embeddings) Distance entre embeddings de speaker 0-1 (1 = identique)
MOS (Mean Opinion Score) Evaluation perceptuelle humaine 1-5 (5 = excellent)
Speaker Error Rate (SER) Taux d’erreur d’identification 0-100% (0 = parfait)
# Analyse de similarite vocale
print("ANALYSE DE SIMILARITE VOCALE")
print("=" * 45)

if xtts_loaded and generate_audio and analyze_similarity:
    similarity_available = False

    try:
        from resemblyzer import VoiceEncoder, preprocess_wav
        encoder = VoiceEncoder()
        similarity_available = True
        print("Resemblyzer charge pour l'analyse de similarite")
    except ImportError:
        print("resemblyzer non installe (pip install resemblyzer)")
        print("Analyse de similarite par correlation simple")

    # Charger les fichiers audio
    ref_path = OUTPUT_DIR / "reference_speaker.wav"
    clone_path = OUTPUT_DIR / "cloned_voice_fr.wav"

    if ref_path.exists() and clone_path.exists():
        ref_audio, ref_sr = sf.read(str(ref_path))
        clone_audio, clone_sr = sf.read(str(clone_path))

        if similarity_available:
            # Analyse avec resemblyzer
            ref_processed = preprocess_wav(ref_audio, source_sr=ref_sr)
            clone_processed = preprocess_wav(clone_audio, source_sr=clone_sr)

            ref_embed = encoder.embed_utterance(ref_processed)
            clone_embed = encoder.embed_utterance(clone_processed)

            # Similarite cosinus
            cosine_sim = np.dot(ref_embed, clone_embed) / (
                np.linalg.norm(ref_embed) * np.linalg.norm(clone_embed)
            )

            print(f"\nResultats de similarite :")
            print(f"  Similarite cosinus : {cosine_sim:.4f}")
            print(f"  Interpretation : ", end="")
            if cosine_sim > 0.85:
                print("Excellent - voix tres similaire")
            elif cosine_sim > 0.75:
                print("Bon - voix reconnaissable")
            elif cosine_sim > 0.65:
                print("Moyen - timbre partiellement capture")
            else:
                print("Faible - voix differente")
        else:
            # Analyse simplifiee sans resemblyzer
            min_len = min(len(ref_audio), len(clone_audio))
            if min_len > 0:
                # Correlation sur les enveloppes spectrales
                from scipy.signal import hilbert
                ref_env = np.abs(hilbert(ref_audio[:min_len]))
                clone_env = np.abs(hilbert(clone_audio[:min_len]))
                corr = np.corrcoef(ref_env, clone_env)[0, 1]
                print(f"  Correlation d'enveloppe : {corr:.4f}")

        # Statistiques comparatives
        print(f"\nStatistiques audio :")
        print(f"  {'Metrique':<25} {'Reference':<15} {'Clone':<15}")
        print(f"  {'-'*55}")
        print(f"  {'Duree (s)':<25} {len(ref_audio)/ref_sr:<15.1f} {len(clone_audio)/clone_sr:<15.1f}")
        print(f"  {'Sample rate (Hz)':<25} {ref_sr:<15} {clone_sr:<15}")
        print(f"  {'RMS energy':<25} {np.sqrt(np.mean(ref_audio**2)):<15.4f} {np.sqrt(np.mean(clone_audio**2)):<15.4f}")
        print(f"  {'Peak amplitude':<25} {np.max(np.abs(ref_audio)):<15.4f} {np.max(np.abs(clone_audio)):<15.4f}")
    else:
        print("Fichiers audio non disponibles pour l'analyse")
else:
    print("Analyse de similarite desactivee ou modele non charge")
ANALYSE DE SIMILARITE VOCALE
=============================================
resemblyzer non installe (pip install resemblyzer)
Analyse de similarite par correlation simple
  Correlation d'enveloppe : -0.0196

Statistiques audio :
  Metrique                  Reference       Clone          
  -------------------------------------------------------
  Duree (s)                 6.0             16.7           
  Sample rate (Hz)          22050           24000          
  RMS energy                0.1937          0.1779         
  Peak amplitude            0.3561          1.0000         

Interpretation : Qualite du clonage

Metrique Valeur typique XTTS Signification
Cosine similarity 0.75-0.90 Bon a excellent clonage
RMS energy Variable Normalise par le modèle
Peak amplitude ~0.8-1.0 Audio bien normalise

Points cles : 1. Une similarite > 0.85 indique un clonage de très bonne qualite 2. La qualite du clip de reference est le facteur le plus important 3. Le clonage cross-lingual peut reduire legerement la similarite

Note ethique : Les systèmes de clonage vocal soulevent des enjeux majeurs. Le consentement du locuteur est indispensable. Coqui impose une licence non-commerciale (CPML) pour limiter les usages abusifs.

# Mode interactif - Clonage personnalise
if notebook_mode == "interactive" and not skip_widgets:
    print("MODE INTERACTIF - CLONAGE PERSONNALISE")
    print("=" * 50)
    print("\nEntrez un texte a synthetiser avec la voix clonee :")
    print("(Laissez vide pour passer a la suite)")

    try:
        user_text = input("\nVotre texte : ")

        if user_text.strip() and xtts_loaded:
            user_lang = input(f"Langue [{language}] (fr/en/es/de/it/pt) : ").strip() or language

            ref_path = OUTPUT_DIR / "reference_speaker.wav"
            if ref_path.exists():
                print(f"\nGeneration avec clonage vocal (langue : {user_lang})...")
                start_time = time.time()

                out_path = OUTPUT_DIR / f"custom_clone_{user_lang}.wav"
                tts.tts_to_file(
                    text=user_text,
                    file_path=str(out_path),
                    speaker_wav=str(ref_path),
                    language=user_lang
                )

                gen_time = time.time() - start_time
                audio_data, sr = sf.read(str(out_path))
                print(f"Duree : {len(audio_data)/sr:.1f}s | Temps : {gen_time:.2f}s")
                display_audio_array(audio_data, sr)
            else:
                print("Clip de reference non disponible")
        else:
            print("Mode interactif ignore")

    except (KeyboardInterrupt, EOFError):
        print("Mode interactif interrompu")
    except Exception as e:
        error_type = type(e).__name__
        if "StdinNotImplemented" in error_type or "input" in str(e).lower():
            print("Mode interactif non disponible (execution automatisee)")
        else:
            print(f"Erreur : {error_type} - {str(e)[:100]}")
else:
    print("Mode batch - Interface interactive desactivee")
MODE INTERACTIF - CLONAGE PERSONNALISE
==================================================

Entrez un texte a synthetiser avec la voix clonee :
(Laissez vide pour passer a la suite)
Mode interactif non disponible (execution automatisee)

Considerations ethiques et bonnes pratiques

Enjeux du clonage vocal

Risque Description Mitigation
Usurpation d’identite Utiliser la voix d’une personne sans autorisation Consentement ecrit obligatoire
Deepfakes audio Créer de faux enregistrements Watermarking, detection
Fraude Imiter une voix pour tromper Authentification multi-facteurs
Desinformation Créer de faux discours Legislation, detection

Bonnes pratiques

Pratique Description
Consentement Toujours obtenir l’accord ecrit du locuteur
Watermarking Ajouter un filigrane audio aux voix synthetiques
Documentation Indiquer clairement qu’un audio est synthetique
Licence Respecter la licence CPML (non-commercial) de XTTS

Le clonage vocal et l’analyse de similarite sont a present complets. La cellule suivante recapitule les metriques de session et libere la memoire GPU utilisee par XTTS v2.

# Statistiques de session et prochaines etapes
print("STATISTIQUES DE SESSION")
print("=" * 45)

print(f"Date : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Modele : {model_name}")
print(f"Device : {device}")
print(f"Langue par defaut : {language}")
print(f"Modele charge : {'Oui' if xtts_loaded else 'Non'}")

if gpu_available:
    vram_current = torch.cuda.memory_allocated(0) / (1024**3)
    print(f"VRAM utilisee : {vram_current:.2f} GB")

if save_results:
    saved = list(OUTPUT_DIR.glob('*'))
    total_size = sum(f.stat().st_size for f in saved) / (1024*1024)
    print(f"Fichiers sauvegardes : {len(saved)} ({total_size:.1f} MB) dans {OUTPUT_DIR.relative_to(GENAI_ROOT)} (sous GenAI/)")

# Liberation memoire
if xtts_loaded:
    print(f"\nLiberation du modele...")
    del tts
    gc.collect()
    if gpu_available:
        torch.cuda.empty_cache()
    print(f"Memoire liberee")

print(f"\nPROCHAINES ETAPES")
print(f"1. Explorer la generation musicale avec MusicGen (02-3)")
print(f"2. Decouvrir la separation de sources avec Demucs (02-4)")
print(f"3. Comparer tous les modeles audio (03-1)")
print(f"4. Construire un pipeline vocal complet (03-2)")

print(f"\nNotebook XTTS Voice Cloning termine - {datetime.now().strftime('%H:%M:%S')}")
STATISTIQUES DE SESSION
=============================================
Date : 2026-08-19 14:41:17
Modele : tts_models/multilingual/multi-dataset/xtts_v2
Device : cuda
Langue par defaut : fr
Modele charge : Oui
VRAM utilisee : 1.75 GB
Fichiers sauvegardes : 6 (2.0 MB) dans outputs\audio\xtts (sous GenAI/)

Liberation du modele...
Memoire liberee

PROCHAINES ETAPES
1. Explorer la generation musicale avec MusicGen (02-3)
2. Decouvrir la separation de sources avec Demucs (02-4)
3. Comparer tous les modeles audio (03-1)
4. Construire un pipeline vocal complet (03-2)

Notebook XTTS Voice Cloning termine - 14:41:17

Synthese du Module

XTTS v2 represente l’etat de l’art pour le clonage vocal zero-shot. Ce notebook a explore les capacites du modèle a capturer et reproduire le timbre vocal sans entrainement supplementaire.

Tableau recapitulatif des performances

Metrique Valeur Commentaire
Taille du modèle ~1.8 GB Telechargement unique au premier lancement
VRAM requise ~6 GB Compatible avec la plupart des GPUs modernes
Ratio temps reel (GPU) 2-5x Generation plus lente que la lecture mais acceptable
Qualite du clonage 0.75-0.90 cosine Bonne a excellente selon la qualite du reference
Support multilingue 17 langues Cross-lingual fonctionnel (timbre preserve)

Points cles retenus

  1. Zero-shot : Pas de fine-tuning necessaire, le modèle fonctionne directement
  2. Cross-lingual : On peut cloner une voix en anglais et generer en francais
  3. Qualite variable : La qualite du clip de reference est le facteur principal
  4. Limitations ethiques : Le consentement du locuteur est indispensable

Positionnement dans l’ecosysteme TTS

Cas d’usage Modèle recommande
TTS simple (pas de clonage) Kokoro TTS (plus rapide)
Clonage vocal zero-shot XTTS v2
TTS expressif/emotionnel Chatterbox
Qualite maximale (API) OpenAI TTS
Generation musicale MusicGen (notebook suivant)

Perspective : XTTS v2 est particulierement adapte pour les applications de doublage automatique, de creation de contenu audio personnalise, et d’accessibilite (voix personnalisee pour les personnes malvoyantes).


Exemple guide : Clonage Vocal Multilingue avec Analyse de Similarite

Duree estimee : 25-30 minutes

Objectif

Créer un pipeline de clonage vocal qui fonctionne sur plusieurs langues et analyser la qualite du clonage en comparant les embeddings vocaux entre la voix de reference et les voix clonees.

Instructions

  1. Créer une fonction clone_voice_multilingual qui :
    • Prend un texte, une langue, et un chemin vers un clip de reference
    • Genere la voix clonee avec XTTS v2
    • Sauvegarde le fichier audio de sortie
    • Retourne les metriques (duree, temps de generation)
  2. Generer des voix clonees dans au moins 3 langues différentes :
    • Utiliser le même clip de reference pour toutes les langues
    • Traduire ou adapter le texte selon la langue
    • Sauvegarder chaque fichier avec un suffixe de langue
  3. Analyser la similarite entre la voix de reference et chaque voix clonee :
    • Si resemblyzer est disponible : calculer la similarite cosinus
    • Sinon : comparer les caractéristiques audio (RMS, peak, spectrogramme)
    • Créer un tableau recapitulatif des résultats

Indices :

  • La méthode tts.tts_to_file() accepte les paramètres text, file_path, speaker_wav, et language
  • Les langues supportees incluent : ‘fr’, ‘en’, ‘es’, ‘de’, ‘it’, ‘pt’
  • Pour la similarite avec resemblyzer : utiliser VoiceEncoder et embed_utterance()
  • La similarite cosinus se calcule avec : np.dot(embed1, embed2) / (norm(embed1) * norm(embed2))
  • Sans resemblyzer, comparer les enveloppes spectrales avec scipy.signal.hilbert()
def clone_voice_multilingual(text, language, ref_path, output_dir, model):
    """
    Clone une voix dans une langue specifique avec XTTS v2.
    
    Args:
        text (str): Texte a synthetiser
        language (str): Code langue (fr, en, es, de, etc.)
        ref_path (Path): Chemin du clip de reference
        output_dir (Path): Repertoire de sauvegarde
        model: Modele XTTS charge
    
    Returns:
        dict: Contient 'filepath', 'duration', 'gen_time', 'similarity'
    """
    # Exercice: Implementer le clonage vocal
    # Indice: utiliser tts.tts_to_file() avec speaker_wav et language
    # Indice: mesurer le temps de generation
    # Indice: charger l'audio genere pour calculer sa duree
    pass

def analyze_similarity(ref_audio, clone_audio, sample_rate):
    """
    Analyse la similarite entre deux audios.
    
    Args:
        ref_audio (np.array): Audio de reference
        clone_audio (np.array): Audio clone
        sample_rate (int): Sample rate
    
    Returns:
        float: Score de similarite (0-1)
    """
    # Exercice: Implementer l'analyse de similarite
    # Indice: essayer d'importer resemblyzer pour l'approche avancee
    # Indice: sinon, utiliser la correlation d'enveloppe spectrale
    pass

# Exercice: Tester avec 3 langues differentes (fr, en, es par exemple)
# Exercice: Creer un tableau comparatif des resultats de similarite
# Exercice: Conclure sur l'impact de la langue sur la qualite du clonage

Exercice 3 : Transfert de style vocal inter-langue

Les modèles XTTS supportent le clonage vocal multilingue. L’objectif est de transferer une voix d’une langue a une autre tout en preservant le timbre.

Indice : Utiliser le même audio de reference avec un texte dans une autre langue cible.

def cross_lingual_transfer(reference_audio, target_text, target_lang):
    # Etape 1 : Charger le modele XTTS
    # Etape 2 : Verifier la langue cible supportee
    # Etape 3 : Generer l'audio avec le style vocal de la reference
    pass

result = None  # TODO etudiant
print("Exercice a completer")
Exercice a completer

Critères de reussite

Critere Description
Fonction clone_voice_multilingual Genere correctement l’audio clone avec XTTS
Support multilingue Fonctionne avec au moins 3 langues différentes
Metriques de similarite Calcule et retourne un score de similarite
Tableau comparatif Resume clair des résultats par langue
Analyse des résultats Conclusion sur l’impact de la langue sur la qualite

Extensions possibles

  • Implementer une evaluation MOS (Mean Opinion Score) subjective
  • Comparer XTTS v2 avec Chatterbox pour le clonage vocal
  • Créer un pipeline de clonage avec verification automatique de qualite
Retour au sommet