cut-rough
Resserrement mécanique : silences, mots de remplissage, retakes, hygiène des coupures. Tout ici est réversible et chaque décision porte une provenance.
L'argument $project est le slug ; la requête complète est dans $ARGUMENTS. Un $-placeholer vide signifie que la compétence s'est déclenchée automatiquement plutôt que par slash ; prenez le projet depuis PIPELINE_STATE dans le contexte de session et dites lequel vous avez choisi. Les noms de verbes suivent le contrat de build ; python engine/ve.py --help l'emporte en cas de conflit.
Préconditions, et pourquoi elles sont strictes
Exécutez cut-story d'abord. Si story.blocks est absent, dites-le et proposez cut-story plutôt que de continuer — couper mécaniquement du matériel qui va être supprimé en bloc fait perdre du temps sur la détection des retakes et des bafouillages que personne n'entendra.
Si l'utilisateur veut explicitement un passage mécanique sur tout (« einfach nur die Ähms raus »), c'est légitime. Faites-le, et dites qu'aucune sélection de contenu n'a eu lieu.
La règle des trames
Les points de coupe s'alignent sur des trames entières. Ce n'est pas du souci — des points de coupe hors de la grille font accumuler 8,33 ms de dérive A/V par coupe avec le filtre concat, soit 1250 ms pour 150 coupes. Alignés, les mêmes 150 coupes dérivent exactement de 0 échantillons.
in_frame = floor(t_in * fps + 0.5) # arrondi vers le haut à 0,5 -> les ex-aequo vont plus tard
out_frame = ceil(t_out * fps - 0.5) # arrondi vers le bas à 0,5 -> les ex-aequo vont plus tôt
if out_frame <= in_frame: out_frame = in_frame + 1
out est exclusif — ffmpeg implémente trim=end comme un strict <, et le demi-intervalle [in, out) est ce qui rend la concaténation exacte. Si vous vous trompez sur l'arrondi de OUT, chaque segment devient long d'une trame ; 200 coupes donnent 6,7 s de dérive et une synchronisation audiblement cassée.
Ne faites jamais ce calcul à la main. vedit/timebase.py le possède : snap_in / snap_out.
Étape 1 — Exécuter les passes
python engine/ve.py cut $project
Quatre passes sur la liste de mots aplatie, puis l'alignement :
- Hiérarchisation des silences. Les écarts en dessous de
min_gapne sont jamais coupés. Au-dessus, la pause conservée dépend de la ponctuation du mot précédent :.?!x1,5 (minimum 0,40 s),,;:x1,0, milieu de proposition x0,7 (minimum 0,20 s), changement de sujet x2,0 (minimum 0,60 s). Une longueur de pause uniforme est le signe le plus reconnaissable d'un montage automatique — l'oreille s'attend à une respiration plus longue après un point final. - Hiérarchisation des bafouillages. Voir ci-dessous.
- Détection des retakes. N-grammes répétés où la prise ultérieure remplace la précédente.
- Hygiène des coupures. Padding, fondus enchaînés, alignement sur passage par zéro, limitation de la densité de coupes.
Étape 2 — Niveaux de bafouillages, et celui qui ne doit pas être automatisé
- Niveau A — non lexical (
äh ähm hm mh uh um er) : suppression automatique. Personne n'en veut. - Niveau B — bafouillages lexicaux (
weißt du, sozusagen, quasi, im Prinzip, you know, I mean) : suppression automatique avec gardes — pas en début de phrase, pas quand la suppression laisse un fragment inférieur àmin_clip. - Niveau C — particules modales :
also halt eben ja mal doch schon eigentlich genau, et en anglaislike just well right so basically actually. Signalez-les uniquement. Ne les supprimez jamais automatiquement.
Le niveau C est l'endroit où les éditeurs automatiques ruinent le discours allemand. doch, eben, halt et ja portent une attitude et une structure de discours ; les supprimer ne rend pas le locuteur plus concis, cela le fait ressembler à une traduction. Si l'utilisateur demande de les supprimer quand même, faites-le — mais dites une fois ce que cela coûte, puis arrêtez d'en parler.
Ordre du signal de détection : correspondance lexicale, puis durée/caractère >= 0,12 s, puis écart adjacent >= 0,10 s, puis énergie à moins de 6 dB du discours environnant.
N'utilisez jamais le score de WhisperX comme signal de bafouillage. Il mesure l'alignement, pas l'hésitation. Les scores faibles se concentrent sur les mots rares et les noms propres — l'inverse des bafouillages. Utilisez-le uniquement comme indicateur de fiabilité des horodatages : score < 0,35 élargit le padding de 60 ms et interdit une coupe à l'intérieur de ce mot.
Étape 3 — Les valeurs par défaut et leur statut
| paramètre | défaut | remarque |
|---|---|---|
pad_in | 0,08 s | fermeture plosive avant /p t k b d g/ |
pad_out | 0,10 s | les relâchements de /t k s/ dépassent le end de l'aligneur |
keep_pause | minimum 0,18 s | le souffle laissé là où il y avait du silence |
min_gap | 0,55 s | en dessous, jamais coupé |
min_removal | 0,20 s | les suppressions plus courtes ne valent pas une coupure |
max_cut_density | 1 par 1,5 s | fatigue des jump-cuts |
min_clip | 0,35 s | les clips conservés plus courts fusionnent avec un voisin |
| fondu enchaîné | 20 ms (10 min, 40 max) | curve=tri même prise, qsin entre prises |
| recherche de passage par zéro | +/-5 ms (240 échantillons) | audio uniquement, ne déplace jamais la vidéo |
Ces valeurs sont dérivées de la recherche, non testées perceptuellement. Tant que project.json a "calibrated": false, dites-le à chaque fois que vous défendez une coupe. Ne présentez pas un seuil non calibré comme un seuil réglé. Le hook de session remonte ce drapeau à chaque session pour cette raison.
L'alignement sur passage par zéro mérite d'être compris : une coupure brutale à un non-passage par zéro produit un saut d'échantillon 29,5 fois plus grand que le maximum naturel du signal — un clic audible. Un alignement sur passage par zéro et un fondu enchaîné de 20 ms le ramènent à la normale. Utilisez les deux. L'alignement ne déplace que l'audio, jamais la vidéo ; un décalage vidéo sous-trame n'est pas représentable.
Étape 4 — Coupes J/L
4 à 12 trames est la plage utile ; défaut 6.
Rejetez toute coupe J/L où les deux côtés partagent un source_id et aucun n'est couvert par un B-roll ou un overlay plein écran. Sur une bouche visible qui n'est pas une coupe J, c'est une erreur de synchronisation labiale, et cela se lit comme un défaut technique plutôt que comme un montage.
Étape 5 — Écrire les segments
Les segments sont écrits dans segments[] avec src_in_frames (inclusif) et src_out_frames (exclusif) comme seule autorité. Aussi requis sur chaque segment :
enabled— le matériel rejeté estfalseavec une raison, jamais supprimé. Chaque décision automatique doit être réversible en retournant un booléen. C'est la propriété qui rend une valeur par défaut agressive sûre.order— ordre de sortie explicite, dense sur les segments activés.provenance—stage(contentpour les suppressions au niveau du récit,silence,filler,retake),rule,confidence,applied_by, et la valeur mesurée qui l'a déclenché (original_gap_s). La provenance permet à l'utilisateur de dire « annuler toutes les suppressions de niveau B ».word_rangeettextdénormalisé. Le texte est pour la lecture seulement et n'est jamais faisant autorité — s'il est en désaccord avecword_range, la plage de mots prévaut.
Les positions temporelles sont dérivées, jamais stockées. Elles sont une somme courante sur les segments activés écrite dans _computed au chargement. N'écrivez jamais _computed à la main.
Définissez stage sur "rough_cut".
Étape 6 — Rendre compte comme un monteur, pas comme un script
Rapport : durée source, durée coupée, pourcentage supprimé, nombre de coupes, densité de coupes (coupes par minute), et le nombre par règle de provenance. Signalez ensuite tout ce qui ressemble à une surcoupe : un tronçon avec plus d'une coupe par 1,5 s, tout clip conservé proche de min_clip, et le nombre de bafouillages de niveau C signalés mais laissés intacts.
Proposez trois prochaines étapes : prévisualiser une section, ajuster un seuil, ou passer aux graphiques/sous-titres.
Modes d'échec
| Symptôme | Cause | Correctif |
|---|---|---|
| Chaque segment fait 1 trame | OUT arrondi vers le haut au lieu du bas | Utilisez snap_out ; jamais de calcul inline |
| Clics audibles aux coupures | Alignement sur passage par zéro sauté | Snap plus un fondu enchaîné de 20 ms |
| Parole hachée et sans souffle | Pause conservée uniforme | Appliquez le tableau de mise à l'échelle selon la ponctuation |
| Locuteur robotique et non allemand | Niveau C supprimé | Le niveau C est signalé uniquement ; restaurez par provenance |
| Coupes atterrissent en milieu de mot | La transcription est de niveau 3 (jetons BPE) | Re-transcrivez ; les horodatages de jetons ne peuvent pas être coupés |
| Dérive A/V croît dans la vidéo | Points de coupe non alignés sur trame | Alignez chaque point de coupe, puis relancez la vérification QC (a) |