Rough Cut: Textbasierte Videobearbeitung
Cut-Profis nennen diesen Schritt Assembly und Rough Cut. Jede verwertbare Zeile kommt in der richtigen Reihenfolge hinein, alles, was sich nicht seinen Platz verdient, fliegt heraus. Es ist nicht das fertige Video. Es ist die Version, in der jede Sekunde der Sprecher die Zeile gut sagt, damit die späteren Durchgänge (Rhythmus, Farbe, Grafik, Ton) mit gutem Material arbeiten können.
Die Idee dahinter: Bearbeite die Wörter, nicht die Wellenform. Erstelle ein Transkript, in dem jedes Wort eine Start- und Endzeit hat, entscheide durch Lesen, was behalten werden soll, und die Schnitte ergeben sich aus den Zeitangaben. Descript und die textbasierte Bearbeitung in Premiere und Resolve arbeiten so. Dieses Skill fügt zwei Dinge hinzu, die jene nicht können: Es rastet jeden Schnitt auf den tatsächlichen Ton ein und überprüft das Rendering durch erneutes Abhören.
Einrichtung (einmalig)
sh ~/simcraft/skills/rough-cut/setup.sh
Erzeugt .venv neben dieser Datei mit Whisper (mlx-whisper auf Apple Silicon, faster-whisper sonst). Benötigt ffmpeg: ffmpeg im PATH, oder $FFMPEG, oder ~/neatlogs-motion/ffmpeg. Führe jedes folgende Skript mit ~/simcraft/skills/rough-cut/.venv/bin/python aus.
Arbeitsbereich
Ein Ordner pro Video. Falls der Benutzer noch keinen erstellt hat, erstelle ~/Movies/edits/YYYY-MM-DD-<slug>/ und kopiere (niemals verschieben) die Rohdateien in raw/. Skripte schreiben audio/, cuts/ und renders/ daneben. In raw/ wird niemals etwas verändert.
Der Durchlauf in der richtigen Reihenfolge
1. Transkribieren
python scripts/transcribe.py <workspace> [--lang de]
Schreibt audio/words.json (jedes Wort: Start, Ende, Text, Konfidenz) und audio/transcript.txt (eine Zeile pro Take). Dauer: etwa 1 Minute pro 2 Minuten Filmmaterial auf einem M-Series-Mac.
Übergib --lang de für Deutsch (genauer). Für gemischte Sprachen (z.B. Deutsch/Englisch) lasse die Option weg.
So bleibt es genau (jeder Punkt behebt ein Problem, das bei echtem Filmmaterial auftrat):
- Jeder Take wird einzeln transkribiert. Das Audio wird bei jeder Pause von 0,5s oder länger geteilt. Bei Transkription der gesamten Datei auf einmal schreibt Whisper eine fünfmal gesagte Zeile nur einmal, sodass die zusätzlichen Takes keine Wörter haben und nicht geschnitten werden können.
- Füllwörter bleiben im Transkript erhalten. Whisper lässt standardmäßig „ähm“ und „hm“ weg. Ein Prompt mit vielen Füllwörtern bringt sie zurück, damit sie geschnitten werden können.
- Transkriptionsschleifen werden entfernt. Whisper wiederholt manchmal dutzende Male eine Phrase über Rauschen („da ist es da ist es ...“). Mehr als 7 Wörter pro Sekunde sind unmöglich, daher werden diese Zeilen verworfen.
2. Schnitte finden
python scripts/find_cuts.py <workspace> [--gap 0.35] [--keep-fillers]
Schreibt cuts/edl.json (Stücke, die behalten werden, in Reihenfolge) und cuts/cut_sheet.md (jeder Schnitt mit Begründung, plus Wörter mit niedriger Konfidenz, die geprüft werden sollten).
| Schnitt | Regel |
|---|---|
| Tote Luft | Jede Pause länger als --gap (0,35s). Auch Stille am Anfang und Ende. |
| Füllwörter | ähm, hm, mm, ah, oh, also, halt, quasi, irgendwie, sozusagen, ne, ja (als Füllwort) |
| Wiederholungen | Ein Wort oder ein Block von bis zu 4 Wörtern, zweimal hintereinander gesagt („also das also das“): behält das zweite. |
| Retakes | Dieselbe Zeile innerhalb von 20s erneut gesagt, durch Buchstaben abgeglichen, sodass auch Fehlhörungen erfasst werden („Panda“/„Band”, „eins“/„1“): behält den letzten Take. |
| Fehlstarts | Eine Zeile abgebrochen und dann vollständig gesagt („Eine 300 Milliarden.“ dann „Ein 300 Millionen Dollar Geschäft.“). |
| Gleiches Ende | Eine Zeile am Anfang umformuliert, aber gleich endend („Das ist, es ist der eigene Gründer von Vanta“ dann „Und das sage nicht ich, es ist der eigene Gründer von Vanta“). |
| Geisterwörter | Ein Wort allein ohne darunterliegende Stimme. Whisper erfindet sie in Stille („Danke.“, „Halleluja“). |
Wo jeder Schnitt landet:
- Jede Kante wird an den tatsächlichen Beginn und das Ende der Stimme ausgerichtet, gemessen an der Lautstärke in 10ms-Schritten mit einem Schwellwert, der sich an den Raum anpasst. Whisper-Zeiten können um 0,1–0,3s abweichen.
- Eine Kante kann sich nur um maximal 0,12s nach hinten verschieben, denn ein abgeschnittenes Wort ist schlimmer als ein Atemzug, der erhalten bleibt.
- Es bleiben 0,06s Raum vor der Stimme und 0,10s danach.
- Wenn keine echte Lücke vorhanden ist, z.B. ein „äh“ direkt am nächste Wort angehängt, geht der Schnitt an den leisesten 10ms-Punkt dazwischen.
- Eine Pause, die in einem langen Whisper-„Wort“ versteckt ist, wird trotzdem gefunden und geschnitten.
3. Beurteilungsdurchgang (der eigentliche Schnitt, niemals überspringen)
Lies cuts/cut_sheet.md zusammen mit audio/transcript.txt und korrigiere cuts/edl.json von Hand. Ein Skript kann Folgendes nicht beurteilen:
- Welcher Take der Beste ist. Standardmäßig wird der letzte Take behalten, aber der beste ist der mit Energie, einem sauberen Ende und ohne einbrechendes Lachen. Manchmal ist die erste Hälfte eines Takes plus das Ende eines anderen am besten.
- Füllwörter, die Teil des Witzes sind. Ein bewusstes „ähm“ vor einer Pointe bleibt erhalten.
- „irgendwie“, „quasi“, „also“, „halt“, „ja“. Diese werden nie automatisch geschnitten. Schneide nur die, die reines Zögern sind. Wenn alle entfernt werden, klingt der Sprecher nicht mehr wie er selbst.
- Pausen als dramaturgisches Mittel. Eine Pause vor einer Pointe, einer Reaktion oder einem Blick in die Kamera bleibt. Nicht jede Stille ist tote Luft.
- Denselben Punkt zweimal mit anderen Worten sagen. Schneide ganze Sätze.
- Nicht-Sprachmomente, wie ein Lied, ein visueller Gag oder ein Reaktionsshot. Nur Sprache bleibt erhalten, also füge diese Stücke von Hand hinzu.
- Reihenfolge. Die Stücke folgen der Dateireihenfolge. Verschiebe die stärkste Zeile nach oben für einen Cold Open, wenn der Benutzer einen wünscht.
- Die Liste der zu prüfenden Wörter. Niedrige Konfidenz bedeutet oft Gemurmel. Wenn die Zeile unklar ist, suche nach einem saubereren Take.
Jedes Stück hat {"clip", "in", "out", "text"}, und "speed" ist optional. Behalte Schnitte zwischen Wörtern.
4. Tempo (vorher fragen)
Das Cut-Sheet gibt die Wörter pro Sekunde an. Schnelle Talking-Head-Inhalte liegen bei etwa 3,3–3,8. Wenn der Sprecher langsamer ist, schlage eine Geschwindigkeit von 1,05–1,2 vor und setze "speed" in edl.json für das gesamte Video oder pro Stück. Die Tonhöhe bleibt gleich. Beschleunige niemals Musik oder Reaktionen.
5. Vorschau-Rendering
python scripts/render.py <workspace> --w 854 --v 1 [--aspect 9:16]
Eine 480p-Vorschau wird in renders/v1_854.mp4 abgelegt. Erhöhe --v für jede Runde von Anmerkungen, damit alte Versionen erhalten bleiben.
- Jedes Stück wird mit exakter Frame-Anzahl und unkomprimiertem Audio gerendert, dann werden alle Stücke per Dekodierung zusammengefügt. Stream-Copy-Joins lassen Frames an Schnitten fallen und der Ton driftet über einige Minuten um etwa 2s.
- Jedes Stück erhält einen 12ms-Einblender und einen 20ms-Ausblender, damit Schnitte nicht knallen.
- Clips mit einem anderen Seitenverhältnis liegen auf einer unscharfen Kopie ihrer selbst anstatt auf schwarzen Balken.
6. Verifizieren (immer, bevor es dem Benutzer gezeigt wird)
python scripts/verify.py <workspace> --v 1 [--lang de]
Es hört sich das Rendering erneut an, Stück für Stück, vergleicht es mit der Schnittliste und schreibt cuts/verify_v1.md. Der Bericht hat vier Abschnitte:
- Schnitte, die während der laufenden Stimme landen: ein Soundtest, der nicht von Whisper abhängt. Dies ist der echte Detektor für abgeschnittene Wörter. Korrigiere jeden, indem du die entsprechende Kante in edl.json verschiebst.
- Fehlende Wörter: erwartet, aber nicht gehört.
- Unerwartete Wörter: ein Füllwort oder ein Teil eines Retakes, der durchsickert.
- Fehlhörungen: die beiden Transkripte stimmen im Wortlaut nicht überein. Das ist meist Gemurmel, kein Schnittproblem.
Bei sauberem Audio ist das Ziel 100% der Wörter vorhanden, 0 Schnitte innerhalb des Tons und 0 unerwartete Wörter. Bei verrauschtem oder undeutlichem Audio ergeben sich einige Paare von fehlenden/unerwarteten Wörtern, die eigentlich Fehlhörungen sind. Vertraue dem Soundtest mehr als ihnen.
Behebe, was gefunden wird, rendere erneut und verifiziere erneut.
7. Dem Benutzer zeigen, dann den finalen Export
- Teile dem Benutzer mit: die Länge vorher und nachher, die Anzahl der Schnitte, das Verifikationsergebnis und alle Entscheidungen, die du getroffen hast (welchen Take du behalten hast, eine bewusst beibehaltene Pause).
- Notiere seine Anmerkungen, bevor du die nächste Version erstellst.
- Erst nachdem er die Vorschau genehmigt hat:
python scripts/render.py <workspace> --w <source-width> --v N.
Ergebnisse mit echtem Filmmaterial
Bei 3 Minuten rohem Talking-Head-Material mit vielen Retakes (9 Takes einer Zeile, 4 einer anderen) wurden aus 2:55 Minuten Redezeit 0:36 Minuten. Es behielt den letzten sauberen Take jeder Zeile, und die Verifikation ergab 100% der Wörter vorhanden, 0 Schnitte innerhalb des Tons und 0 Durchsickerer.
Der Geschmack des Benutzers
- Knackig. Jump Cuts an Wortlücken sind gut; ständig wechselnde Nahaufnahmen (Punch-in-Zooms) sind es nicht.
- Behalte Kraftausdrücke, Geplänkel und lustige Stellen. Die Persönlichkeit wird nie geglättet.
- Keine Übergangssounds (Whooshes) und kein Farbgrading in dieser Phase.
- Wenn der Benutzer nach „nur den guten Stellen, maximal X Minuten“ fragt, schneide ganze Momente, nicht nur Pausen.