Montage et matriçage de podcast
Transforme les enregistrements de podcast ou de voix off de l’utilisateur en épisodes prêts à être diffusés : débruitage, suppression des silences de début/fin, égalisation et compression de la voix, normalisation de la sonie à environ -16 LUFS, export en MP3. Ajoute en option des musiques d’intro/outro et de fond segmentées, et propose des suggestions de montage (longues pauses à resserrer, passages redites) que l’utilisateur confirme avant de couper.
Les scripts scripts/, references/ se trouvent dans le répertoire de cette compétence. Lors de l’exécution, utilisez le chemin complet, par exemple : bash <répertoire_de_la_compétence>/scripts/edit_podcast.sh.
1. À clarifier avec l’utilisateur avant de commencer
- ffmpeg doit être installé (outil audio gratuit et open source). S’il n’est pas présent, demandez à l’utilisateur de l’installer :
brew install ffmpegsur macOS, via le gestionnaire de paquets sur Linux (ex.apt install ffmpeg). Le script cherche dans l’ordre : variable d’environnementFFMPEG→ffmpegdans le PATH → emplacements courants/opt/homebrew/bin,/usr/local/bin. Testé avec les versions 6.0 et 8.1. - Bash et Python 3.9 ou supérieur sont nécessaires, uniquement avec la bibliothèque standard, pas d’installation de paquets Python supplémentaires.
- macOS et Linux uniquement : testé sur macOS ; Linux devrait fonctionner ; Windows via WSL non testé.
- Lors de la première exécution, un modèle de débruitage RNNoise (environ 300 Ko) sera téléchargé depuis Internet et stocké dans
~/.cache/ethan-podcast-post/, avec vérification SHA-256. Si le téléchargement échoue ou que la somme de contrôle est incorrecte, le script utilise automatiquement le filtre afftdn intégré à ffmpeg. Le script indique la méthode utilisée, vous devez en informer l’utilisateur. La source du modèle est dansreferences/third-party.md. - Tout le traitement se fait en local : aucun téléchargement de l’enregistrement, aucun frais.
- Ce qui n’est pas fait : génération ou clonage de voix, doublage, transcription (l’utilisateur peut fournir un fichier SRT pour les sous-titres), publication sur aucune plateforme, fourniture de musique (l’utilisateur doit fournir sa propre musique et confirmer qu’il a les droits d’utilisation).
2. Sécurité des fichiers (obligatoire)
- L’enregistrement original est en lecture seule : le script ne fait que lire, il ne modifie, ne déplace ni ne supprime rien.
- Les sorties sont toujours écrites dans un nouveau répertoire : créez un nouveau répertoire à côté de l’enregistrement (ex.
Épisode3_PostProd/), ne le mettez pas dans le même répertoire que l’enregistrement ou la musique. Le script s’arrête si le répertoire de sortie est dans le même répertoire que le fichier d’entrée. - Ne pas écraser sans autorisation : si le répertoire de sortie contient déjà
final.mp3,audio_raw.wavouvoice_master.wav, le script s’arrête. Pour écraser, informez d’abord l’utilisateur des fichiers concernés et du fait qu’ils seront perdus, puis exécutez à nouveau avecOVERWRITE=1après accord. Même logique pour les suggestions de montage, les coupes et le traitement de la voix : le script s’arrête si des fichiers portant le même nom existent déjà ; l’utilisateur doit accepter avant d’ajouter--overwrite. - Confirmation avant toute suppression : toute suppression (y compris le nettoyage de gros fichiers comme
audio_raw.wav) doit être expliquée à l’utilisateur (quel fichier, pourquoi) avant d’être effectuée. Les fichiers intermédiaires sont placés dans un sous-répertoire temporaire dédié à l’exécution courante, nettoyé à la fin. - Ce qui est coupé est choisi par l’utilisateur : les suggestions de montage sont une simple liste de candidats ; rien n’est coupé sans confirmation.
3. Flux de traitement
Exécutez d’abord une vérification de l’environnement et informez l’utilisateur du résultat :
bash <répertoire_de_la_compétence>/scripts/edit_podcast.sh --check
Ceci affichera : le chemin et la version de ffmpeg trouvée, si l’égalisation dynamique à 250 Hz est activée (voir section 6), et si le modèle de débruitage est prêt. Si ffmpeg n’est pas trouvé, des instructions d’installation sont données. Installez d’abord, puis continuez.
Étape 1 : Première passe, génération du master voix et de la version d’écoute
KEEP_MASTER=1 bash <répertoire_de_la_compétence>/scripts/edit_podcast.sh <fichier_enregistrement> <répertoire_sortie>/pass1 <nom>
- L’enregistrement peut être au format wav, m4a, mp3, mp4, ou tout format lisible par ffmpeg. Pour les dialogues à deux ou plusieurs personnes, ajoutez
INTERVIEW_MODE=1(compression plus forte et égalisation automatique des niveaux entre les intervenants). - Ordre de traitement : conversion en WAV 48 kHz → contrôle qualité → suppression des silences de début/fin (les pauses entre les phrases ne sont pas touchées) → déclick des lèvres/dents → filtre passe-haut à 80 Hz → débruitage → égalisation dynamique à 250 Hz → dé-esseur → compression → accentuation à 5 kHz → gain linéaire jusqu’à -16 LUFS → limiteur → export MP3 → nouvelle mesure de sonie.
- Productions :
<nom>_final.mp3: version finale sans musique (également version d’écoute).voice_master.wav: master voix (après suppression des silences de début/fin), utilisé pour la transcription, les suggestions de montage et les coupes.audio_raw.wav: copie WAV de l’enregistrement original (écrite seulement si tout s’est bien passé), utile pour refaire le traitement plus tard ; fichier volumineux.
- Vérifiez ces points dans la sortie et informez l’utilisateur :
- Niveau de la fin inférieur à -80 dB : l’enregistrement s’est peut-être interrompu ; confirmez avec l’utilisateur.
- Méthode de débruitage : RNNoise ou afftdn.
- La sonie de la version finale doit être comprise entre -16 LUFS ±1, avec un pic vrai ne dépassant pas -1,5 dBTP. Si ce n’est pas le cas, le script l’indique ; rapportez-le honnêtement à l’utilisateur.
- Si l’enregistrement est trop faible ou vide, le script s’arrête avec une erreur, sans produire de fichier vide. Le message d’erreur suggère une valeur de gain : confirmez d’abord que l’enregistrement contient bien de la parole, puis ajoutez
INPUT_GAIN=<valeur_suggérée>(en dB, déjà calculée en tenant compte duINPUT_GAINactuel) pour augmenter le niveau global, puis relancez. Aucun fichier n’est laissé dans le répertoire de sortie en cas d’erreur, vous pouvez réutiliser le même répertoire. Conseillez également à l’utilisateur d’augmenter le volume d’entrée lors de futurs enregistrements.
Étape 2 : Suggestions de montage (liste uniquement, pas de coupes)
La transcription doit être faite à partir du voice_master.wav de l’étape 1 (ou du MP3 final sans musique de l’étape 1 ; les deux ont la même ligne temporelle). N’utilisez pas la transcription de l’enregistrement original : les silences de début/fin n’étant pas supprimés, les positions seraient décalées.
Trouver les longues pauses à resserrer :
python3 <répertoire_de_la_compétence>/scripts/edit_cuts.py suggest <répertoire_sortie>/pass1/voice_master.wav \
[--srt sous-titres.srt] [--protect 15:00.0-15:03.0 ...]
- Par défaut, les pauses de plus de 1,5 seconde sont listées comme candidates, avec suggestion de les resserrer à 1,2 seconde (la moitié de la pause est conservée de chaque côté pour préserver l’ambiance de la pièce).
- Les pauses intentionnelles de l’utilisateur (ex. silence après une phrase importante) sont marquées avec
--protect début-finpour ne pas être suggérées (avec un tampon de 0,5 seconde de chaque côté). - Si des longues pauses évidentes ne sont pas trouvées, le bruit de fond est probablement élevé : ajustez
--noisede la valeur par défaut -45 à -40, puis relancez. - Si, pour 40 minutes de contenu, plus de 15 candidats ou un cumul de plus de 60 secondes sont trouvés, le script avertit que les paramètres sont trop stricts : augmentez
--min-pause; ne coupez pas tout en bloc.
Trouver les passages redites (nécessite une transcription) :
python3 <répertoire_de_la_compétence>/scripts/edit_cuts.py retakes <répertoire_sortie>/pass1/voice_master.wav --srt sous-titres.srt [--phrase votre_phrase_de_reprise]
- Convention d’enregistrement : une erreur → pause d’au moins 1 seconde → dire calmement une phrase de reprise → pause d’au moins 1 seconde → répéter la phrase depuis le début.
- La phrase de reprise par défaut est « erreur erreur » (adaptez en fonction de la langue). Pour changer, utilisez
--phrase; si le logiciel de transcription écrit souvent la phrase de reprise avec des homophones, listez plusieurs variantes avec plusieurs--phrase. Choisissez une phrase qui n’apparaît pas dans le texte normal ; la répéter deux fois réduit encore les fausses détections. - Le script cherche la phrase de reprise dans la transcription et remonte à la phrase d’erreur précédente pour déterminer la zone à couper, avec un niveau de confiance (high/mid/low). Pour les zones « low », l’utilisateur doit absolument écouter avant de valider.
Les deux commandes produisent respectivement voice_master_suggested_cuts.tsv et voice_master_retake_cuts.tsv (n’écrase pas les fichiers existants ; ajoutez --overwrite après accord de l’utilisateur). Expliquez chaque candidat à l’utilisateur (temps, contexte, durée économisée). Après confirmation, copiez les lignes dans un nouveau fichier cuts.tsv (séparé par tabulations : début, fin, note ; temps au format MM:SS.s).
Étape 3 : Application des coupes
python3 <répertoire_de_la_compétence>/scripts/edit_cuts.py apply <répertoire_sortie>/pass1/voice_master.wav --cuts cuts.tsv [--srt sous-titres.srt]
- Les coupes sont effectuées à l’échantillon près, avec un crossfade à puissance égale de 15 ms aux jonctions. Produit un fichier
voice_master_edited.wav(24 bits) et un fichiervoice_master_edited.edit_map.json(liste des segments audio conservés avec leurs positions d’origine). - Si
--srtest fourni, les sous-titres intacts sont décalés en conséquence. Si un sous-titre est coupé en deux, le script refuse de continuer : retirez--srt, effectuez les coupes, puis demandez à l’utilisateur de retranscrire le master édité. - Après les coupes, demandez à l’utilisateur d’écouter quelques secondes avant et après chaque jonction : pas de clic, pas de double inspiration, pas de changement de timbre.
Étape 4 (optionnelle) : Appliquer un effet de voix différent à des segments (citations, souvenirs, etc.)
python3 <répertoire_de_la_compétence>/scripts/voice_fx.py <master_voix_coupé.wav> --fx fx.tsv
python3 <répertoire_de_la_compétence>/scripts/voice_fx.py --list # Liste des cinq préréglages
- Préréglages :
quote(lecture de lettres, textes d’autrui),archive(journaux anciens, documents officiels),telephone(citation téléphonique),memory(souvenir, rêve),radio(ancienne émission radio, au maximum une fois par épisode). - fx.tsv : chaque ligne contient : préréglage, début, fin, fondu entrant, fondu sortant, remarque (séparés par tabulations ; écrivez
-pour utiliser les valeurs par défaut des fondus). - La durée et la sonie du fichier restent inchangées après traitement ; le fichier de sortie est nommé
<nom_original>_fx.wav.
Étape 5 (optionnelle) : Ajout de musique et table de repères (cue sheet)
Ne se fait que si l’utilisateur fournit une musique de fond. Commencez par écrire la table de repères, puis effectuez une pré-vérification. Placez la table dans le répertoire de la deuxième passe ; le nom doit être <nom>_cues.tsv.
La table de repères : 7 colonnes séparées par des tabulations. Les lignes commençant par # sont ignorées. Écrivez - pour utiliser la valeur par défaut. Les temps sont au format MM:SS.s, par rapport à la ligne temporelle du master voix. Exemples :
# type time src dur vol fade_in fade_out
stinger 02:00.0 - 3 - - -
break 12:00.0 -@20 8 0.5 2 2
bed 18:00.0 -@40 30 0.08 - -
ending 40:00.0 -@90 - - - -
| Type | Effet | dur | Volume par défaut |
|---|---|---|---|
| stinger | Court motif musical superposé à la voix | 6 s par défaut | 0,12 |
| bed / post | Musique de fond sous la voix ; le volume baisse automatiquement quand la voix apparaît | Obligatoire | 0,12 |
| break | Coupe la voix à ce point, insère un extrait musical, puis reprend la voix ; l’épisode s’allonge de la durée indiquée | Obligatoire | 0,5 |
| ending | Musique de fin : volume baissé pendant la voix, remonte à la fin de la voix, puis fondu sortant final | Écrivez - | 0,22 |
src:-signifie utiliser la musique de fond fournie ;-@20signifie démarrer à partir de la 20e seconde de cette musique. Vous pouvez aussi mettre le chemin complet d’un autre fichier musical, éventuellement avec@secondes(sans@, démarre au début).- Pour stinger, si
srcest-sans@, il prend un extrait à partir de la 60e seconde de la musique de fond par défaut ; pour les autres types, sans@, il commence au début. - Après avoir écrit la table, faites une pré-vérification ; corrigez si des ❌ apparaissent :
python3 <répertoire_de_la_compétence>/scripts/cues_lint.py <nom>_cues.tsv --master <master_voix_coupé.wav> --bg <musique_de_fond>
Ceci vérifie la syntaxe, les dépassements de durée, l’existence des fichiers musicaux, les chevauchements de fenêtres, le ratio musical total (conseillé ≤ 15%), et fournit une table de conversion « master → épisode final » pour faciliter la création de la timeline.
Étape 6 : Deuxième passe – Génération de l’épisode final
MASTER_WAV=<master_voix_coupé.wav> bash <répertoire_de_la_compétence>/scripts/edit_podcast.sh - [musique_de_fond] <répertoire_sortie>/final <nom>
- Le premier paramètre est
-. SiMASTER_WAVest défini, le script saute l’extraction, le débruitage et la normalisation, et applique directement les repères musicaux et le mixage. - Si une musique de fond est fournie et que l’audio dure plus de 80 secondes, une intro/outro automatique est ajoutée : la musique d’intro démarre 3 secondes avant la voix, la voix s’arrête et la musique continue environ 7 secondes avant de fondre ; le volume de la musique baisse automatiquement quand la voix apparaît.
- S’il n’y a ni montage ni musique, le MP3 de l’étape 1 est la version finale ; cette étape n’est pas nécessaire.
Étape 7 : Vérification finale
Le script effectue déjà une mesure finale. Pour une mesure indépendante (avec le chemin ffmpeg affiché par --check) :
"<chemin_ffmpeg>" -hide_banner -nostats -i <épisode_final.mp3> -filter_complex ebur128=peak=true -f null - 2>&1 | tail -12
- Critères : Integrated entre -16 LUFS ±1, True peak ≤ -1,5 dBFS (dBTP).
- Demandez à l’utilisateur d’écouter avec un casque : la musique ne couvre pas la voix ; la musique ne revient pas brusquement pendant les pauses ; chaque point de coupe est naturel ; la fin n’est pas coupée ; les pauses intentionnelles sont conservées.
- À la livraison, informez l’utilisateur : emplacement de l’épisode final, méthode de débruitage, valeurs mesurées de sonie et de pic, liste des coupes appliquées. Si les critères ne sont pas atteints, dites-le honnêtement, ne dites pas que c’est bon.
4. Principes de montage
- Ne couper que les accidents, pas les respirations : coupez les erreurs de diction, les lectures de notes, les passages redites. Ne coupez pas les respirations, les « euh » de réflexion, les hésitations entre phrases, les silences intentionnels. En cas de doute, gardez.
- Les pauses de moins de 0,8 seconde ne sont pas touchées ; les pauses de 0,8 à 1,5 seconde sont conservées par défaut ; les pauses plus longues ne sont resserrées que s’il y a des preuves de gêne ou de perte de fil.
- Le point de coupe doit se trouver à une pause naturelle (fin de respiration), sans couper le début ou la fin d’un mot. Gardez une respiration entière ou supprimez-la entièrement.
- La musique de fond doit être moins forte que la voix ; évitez les morceaux avec des voix ou beaucoup de fréquences médium (1–3 kHz). Les morceaux mélodiques sont de préférence placés entre les sections (break), pas sous la voix. La durée totale de la musique ne devrait pas dépasser 15 % de l’épisode.
- Pour plus de détails, voir
references/editing-style-guide.md(style et habillage),references/editing-essentials.md(exécution et validation), etreferences/audio-glossary.md(glossaire).
5. Variables d’environnement (toutes optionnelles)
| Variable | Valeur par défaut | Effet |
|---|---|---|
FFMPEG | Recherche automatique | Chemin spécifique vers ffmpeg |
DENOISE | rnnoise | rnnoise / afftdn / off |
RNNOISE_MODEL | ~/.cache/ethan-podcast-post/bd.rnnn | Emplacement du modèle de débruitage ; peut pointer vers un fichier existant |
RNNOISE_URL | Modèle public sur GitHub | URL miroir en cas de problème réseau (la somme SHA-256 est toujours vérifiée) |
INPUT_GAIN | 0 | Gain global appliqué avant traitement (dB) ; à utiliser si l’enregistrement est trop faible (voir valeur suggérée dans l’erreur) |
TRIM_THRESHOLD | -50 | Seuil de suppression des silences de début/fin (dB) ; ajustez à -60 si des sons faibles sont coupés |
INTERVIEW_MODE | 0 | 1 = dialogue entre deux personnes ou plus |
KEEP_MASTER | 0 | 1 = conserver le master voix voice_master.wav |
MASTER_WAV | vide | Master voix utilisé pour la deuxième passe |
MUSIC_VOLUME | 0,12 | Volume de la musique de fond en proportion |
INTRO_DURATION | 40 | Fenêtre de musique d’intro/outro en secondes ; aucune si l’audio est plus court que 2× cette valeur |
PREROLL / TAIL | 3 / 7 | Secondes de musique avant le début de la voix / après la fin de la voix |
OUTRO_SEEK | vide | Point de départ dans la musique pour l’outro |
MP3_BITRATE | 160k | Débit binaire du MP3 final |
OVERWRITE | 0 | 1 = autoriser l’écrasement des fichiers existants (après consentement de l’utilisateur) |
6. Problèmes courants
- ffmpeg introuvable : demandez à l’utilisateur de l’installer (
brew install ffmpegsur macOS, gestionnaire de paquets sur Linux), ou spécifiez le chemin viaFFMPEG=/chemin/complet/ffmpeg. - Version de ffmpeg : le script lit la version. Les paramètres du filtre d’égalisation dynamique à 250 Hz diffèrent entre ffmpeg 6 et 8 ; les deux versions sont calibrées avec un signal sinusoïdal pour un résultat identique. Avec une version 7.x ou non testée, ce filtre est désactivé et un avertissement est émis ; le reste du traitement est inchangé. Les paramètres de suppression des silences de début/fin sont également adaptés à la nouvelle version ; les versions 6.x et 8.x donnent le même résultat.
- Erreur « Il ne reste presque rien après suppression des silences » ou « Sonie non mesurable après traitement » : l’enregistrement est trop faible ou vide. Confirmez qu’il y a bien de la parole, puis appliquez la valeur de
INPUT_GAINsuggérée dans le message d’erreur (la sonie n’est pas mesurable en dessous de -70 LUFS ; ajuster seulement le seuil de coupure ne suffit pas). Si le fichier ne contient vraiment pas de son, l’erreur persistera et aucun fichier final ne sera produit. - Débruitage via afftdn : le modèle RNNoise n’a pas été téléchargé. Vous pouvez définir
RNNOISE_URLvers un miroir, ouRNNOISE_MODELvers un fichier modèle existant, puis relancer (après avoir demandé l’autorisation d’écraser les fichiers existants). - Niveau de fin inférieur à -80 dB : l’enregistrement s’est probablement interrompu ; confirmez d’abord avec l’utilisateur, ne le traitez pas comme un problème de montage.
- Aucune reprise trouvée : vérifiez que la transcription provient bien de
voice_master.wav, puis examinez dans la transcription comment la phrase de reprise a été transcrite et ajoutez cette variante avec--phrase. - Voir chaque commande exécutée :
bash -x <répertoire_de_la_compétence>/scripts/edit_podcast.sh .... - Dans zsh, pour construire des paramètres de filtre ffmpeg : écrivez
${VAR}:...si la variable est suivie directement d’un deux-points, sinon zsh traite$VAR:aou$VAR:rcomme des modificateurs et modifie silencieusement les paramètres.
Licence : Code MIT, Documentation CC BY 4.0.