初剪:去除多餘部分
編輯們稱之為組合和初剪。每一段可用的台詞都被放入,按順序排列,而所有不值得保留的內容都被刪除。這不是最終完成的影片,而是每個畫面都是說話者清楚表達的版本,以便後續的步驟(節奏、調色、圖形、音效)能夠在良好的素材上進行。
背後的理念是:編輯文字,而不是波形。 取得一份逐字稿,其中每個字都有開始和結束時間,透過閱讀來決定保留哪些內容,然後根據時間碼進行剪輯。Descript 以及 Premiere 和 Resolve 中的文字型編輯就是這樣運作的。此技能增加了兩個它們沒有的功能:它會將每個剪輯點精確對齊到真實的聲音,並透過再次聆聽來檢查渲染結果。
設定(一次性)
sh ~/simcraft/skills/rough-cut/setup.sh
在該檔案旁邊創建一個 .venv 環境,其中包含 Whisper(Apple Silicon 上使用 mlx-whisper,其他地方使用 faster-whisper)。需要 ffmpeg:確保 ffmpeg 在 PATH 中,或設定 $FFMPEG 環境變數,或使用 ~/neatlogs-motion/ffmpeg。使用以下命令執行所有腳本:~/simcraft/skills/rough-cut/.venv/bin/python。
工作區
每個影片一個資料夾。如果使用者尚未建立,請建立 ~/Movies/edits/YYYY-MM-DD-<slug>/,並將原始檔案複製(切勿移動)到 raw/ 中。腳本會在其旁邊寫入 audio/、cuts/ 和 renders/。raw/ 中的任何內容都不會被更改。
處理流程,依序進行
1. 轉錄
python scripts/transcribe.py <workspace> [--lang en]
寫入 audio/words.json(每個字:開始時間、結束時間、文字、信心度)和 audio/transcript.txt(每個拍攝行一行)。在 M 系列 Mac 上,每 2 分鐘的影片大約需要 1 分鐘。
如果是英文,請加上 --lang en(更準確)。如果是印地語/英語混合語音,則不加。
保持準確性的方法(每個方法都解決了我們在真實素材上遇到的一個問題):
- 每個拍攝行單獨轉錄。 音頻會在任何停頓達到 0.5 秒或更長時被分割。如果一次轉錄整個檔案,Whisper 會將說了五次的同一行只寫一次,這樣額外的拍攝行就沒有文字,從而無法被剪掉。
- 語助詞保留在轉錄稿中。 Whisper 預設會忽略「嗯」和「啊」。使用充滿猶豫提示的 prompt 可以讓它們重新出現,以便後續剪掉。
- 刪除轉錄循環。 Whisper 有時會在雜訊中重複一個短語數十次(例如「there you go there you go ...」)。每秒超過 7 個字是不可能的,因此這些行會被丟棄。
2. 尋找剪輯點
python scripts/find_cuts.py <workspace> [--gap 0.35] [--keep-fillers]
寫入 cuts/edl.json(要保留的片段,按順序)和 cuts/cut_sheet.md(每個剪輯點及其原因,以及需要檢查的低信心度詞彙)。
| 剪輯類型 | 規則 |
|---|---|
| 停頓 | 任何長於 --gap(0.35 秒)的暫停。也包括開頭和結尾的靜音。 |
| 語助詞 | um, uh, erm, hmm, mm, ah。 |
| 重複 | 一個字或最多 4 個字的片段連續出現兩次(例如「so the so the」):保留第二個。 |
| 重拍 | 在 20 秒內再次說出的相同台詞,透過字母比對,因此聽錯的情況仍能匹配(例如「Vanta」/「Wanda」、「1」/「one」):保留最後一次拍攝。 |
| 錯誤開頭 | 中途放棄然後又完整說出的台詞(例如先說「A 300 billion.」然後又說「A 300 million dollar business.」。) |
| 相同結尾 | 開頭重新措辭但結尾相同的台詞(例如先說「That's, it's Vanta's own founder」然後又說「And that's not me saying it, it's Vanta's own founder」。) |
| 幽靈字詞 | 單獨出現且沒有聲音襯托的字。Whisper 會在靜音中偽造這些字(例如「Thank you.」、「hallelujah」)。 |
每個剪輯點的落點:
- 每個邊緣都會根據聲音真正的開始和結束位置進行對齊,透過以 10 毫秒為步長測量響度來實現,並使用根據環境自適應的閾值。Whisper 的字詞時間可能偏差 0.1–0.3 秒。
- 邊緣最多只能向後移動 0.12 秒,因為裁切到單詞比保留呼吸聲更糟。
- 在聲音開始前保留 0.06 秒的緩衝,聲音結束後保留 0.10 秒。
- 當沒有真正的間隙時,例如「uh」黏在下一個字上,剪輯點會落在它們之間最安靜的 10 毫秒位置。
- 隱藏在 Whisper 一個長「字」內部的暫停也會被找到並裁切。
3. 判斷過濾(真正的編輯,絕不可跳過)
將 cuts/cut_sheet.md 與 audio/transcript.txt 對照閱讀,並手動修正 cuts/edl.json。腳本無法判斷以下情況:
- 哪個拍攝最好。 預設保留最後一次拍攝,但最好的拍攝應該是有活力、結尾乾淨且沒有笑場的那個。有時一個拍攝的前半段加上另一個拍攝的後半段組合起來最好。
- 作為笑點一部分的語助詞。 在笑點前故意加的「呃」應予保留。
- 「like」、「you know」、「I mean」、「basically」。 這些永遠不會自動刪除。只刪除那些純屬拖延時間的詞。全部刪除會讓說話者聽起來不像他們自己。
- 作為節奏的停頓。 笑點前的停頓、反應或看向鏡頭的停頓應予保留。並非所有沉默都是無效的。
- 用不同詞語表達的相同觀點。 刪除整個句子。
- 非說話時刻,例如歌曲、視覺笑點或反應鏡頭。只保留說話內容,因此需手動添加這些片段。
- 順序。 片段遵循檔案順序。如果使用者想要冷開場,將最有力的台詞移到最前面。
- 「檢查這些詞」清單。 低信心度通常意味著含糊不清。如果台詞不清楚,尋找更清晰的拍攝。
每個片段包含 {"clip", "in", "out", "text"},"speed" 是可選的。剪輯點應位於字詞之間。
4. 節奏(先詢問)
剪輯表報告每秒字數。流暢的 talking-head 內容大約在 3.3–3.8 之間。如果說話者速度較慢,建議使用 1.05–1.2 的速度,並在 edl.json 中為整個影片或每個片段設定 "speed"。音高保持不變。切勿加快音樂或反應的速度。
5. 預覽渲染
python scripts/render.py <workspace> --w 854 --v 1 [--aspect 9:16]
一個 480p 的預覽畫面會輸出到 renders/v1_854.mp4。每次修改意見時增加 --v 的數值,以便保留舊版本。
- 每個片段以精確的幀數和未壓縮音頻渲染,然後所有片段透過解碼方式連接。使用串流複製連接會在剪輯點產生掉幀,並且音頻在幾分鐘內會漂移約 2 秒。
- 每個片段有 12 毫秒的淡入和 20 毫秒的淡出,以避免剪輯點產生爆音。
- 形狀不同的片段會顯示在自身模糊的副本上,而不是黑邊。
6. 驗證(顯示給使用者之前務必執行)
python scripts/verify.py <workspace> --v 1 [--lang en]
它會再次聆聽渲染結果,逐個片段進行,並與剪輯清單進行比較,寫入 cuts/verify_v1.md。報告包含四個部分:
- 在聲音仍在進行時落點的剪輯: 一個不依賴 Whisper 的聲音測試。這是真正的裁切到字詞的偵測器。透過在 edl.json 中移動該邊緣來修正每個問題。
- 缺少的字詞: 預期聽到但沒有的。
- 意外的字詞: 語助詞或重拍的殘留物滲入。
- 聽錯: 兩個轉錄稿對措辭不一致。這通常是含糊不清,而非剪輯問題。
在乾淨的音頻上,目標是 100% 的字詞出現、0 個剪輯點在聲音內部、0 個意外字詞。嘈雜或含糊的音頻會產生一些缺少/意外的配對,這些其實是聽錯。優先相信聲音測試的結果。
修正驗證發現的問題,重新渲染,然後再次驗證。
7. 展示給使用者,然後進行最終渲染
- 告知使用者:剪輯前後的長度、剪輯數量、驗證結果,以及你做出的任何判斷決定(保留了哪個拍攝、刻意保留的停頓等)。
- 在製作下一個版本之前記錄他們的意見。
- 只有在他們批准預覽之後:
python scripts/render.py <workspace> --w <source width> --v N。
真實素材的結果
在 3 分鐘的原始 talking-head 素材上,經過大量重拍(同一句台詞拍了 9 次,另一句拍了 4 次),2 分 55 秒的說話內容減少到 36 秒。它保留了每句台詞最後一次清晰的拍攝,驗證結果顯示 100% 的詞彙都存在,0 個剪輯點在聲音內部,0 個意外詞彙。
使用者的品味
- 節奏明快。字詞間隙的跳躍剪輯是可以的;持續交替的推近放大效果則不行。
- 保留髒話、玩笑和有趣的片段。絕不要清除個性。
- 這個階段不要加入嗖嗖音效,也不要進行調色。
- 當使用者要求「只要好的部分,最多 X 分鐘」時,要剪掉整個時刻,而不僅僅是暫停。