Community程式設計與開發github.com

ethan-podcast-post

處理使用者錄製的播客或口播錄音:降噪、修剪首尾靜音、人聲均衡與壓縮、響度標準化至約 -16 LUFS 並匯出 MP3;可選片頭片尾配樂與分段配樂,並提供剪輯建議。

ethan-podcast-post 是什麼?

這是一個專為播客創作者設計的 AI 技能,能將使用者本機的錄音檔案處理成可發佈的成品。它整合了完整的音訊後製流程:從降噪(支援 RNNoise 模型或 ffmpeg 內建 afftdn)、修剪首尾靜音、人聲均衡與壓縮,到響度標準化至約 -16 LUFS 並匯出 MP3。此外,它還提供可選的片頭片尾配樂、分段配樂(使用 cue 表)、以及長停頓收緊與重錄段剪輯建議,使用者確認後再進行剪切。此技能支援 macOS 和 Linux 系統,需要本機安裝 ffmpeg 和 Python 3.9 以上,全程離線處理,不上傳錄音或收費。它不產生或克隆人聲、不配音、不轉寫、不發佈。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Ethanyang9512/ai-creator-studio/tree/main/skills/ethan-podcast-post

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

播客剪輯與母帶處理

把使用者自己錄的播客、口播錄音處理成可以發佈的成片:降噪,修掉首尾靜音,人聲均衡和壓縮,把響度標準化到約 -16 LUFS,匯出 MP3。需要時再加片頭片尾配樂和分段配樂,並給出剪輯建議(哪些長停頓可以收緊、哪裡是重錄段),由使用者確認後再剪。

下文的 scripts/、references/ 都在本技能目錄裡,執行時寫成完整路徑,例如 bash <本技能目錄>/scripts/edit_podcast.sh。

一、開始前先跟使用者講清楚

  • 要在本機裝好 ffmpeg(免費開源的音訊工具)。沒有的話請使用者自己安裝:macOS 用 brew install ffmpeg,Linux 用系統的套件管理器(如 apt install ffmpeg)。腳本按這個順序找:環境變數 FFMPEG → 系統 PATH 裡的 ffmpeg → 常見安裝位置 /opt/homebrew/bin、/usr/local/bin。實測過 6.0 和 8.1 兩個版本。
  • 要用 bash 和 Python 3.9 以上,只用標準庫,不用另裝 Python 套件。
  • 只支援 macOS 和 Linux:在 macOS 上實測過;Linux 應可用;Windows 需要 WSL,沒有測過。
  • 首次降噪會聯網下載一個約 300KB 的公開降噪模型(RNNoise),存到 ~/.cache/ethan-podcast-post/,下載後按 SHA-256 校驗。下載不了或校驗不對,自動改用 ffmpeg 自帶的 afftdn 降噪,腳本會列印用的是哪一種,你要把這一點告訴使用者。模型出處見 references/third-party.md。
  • 全程在本機處理:不上傳錄音,不收費。
  • 不做的事:不產生或克隆人聲,不配音,不轉寫(需要字幕時請使用者提供 SRT 字幕檔案),不發佈到任何平台,不提供音樂(背景音樂由使用者自備,並確認有使用授權)。

二、檔案安全(必須遵守)

  1. 原始錄音唯讀:腳本只讀取,不改、不移動、不刪。
  2. 輸出一律寫到新目錄:在錄音旁邊新建一個目錄(例如 第3期_後期/),不要和錄音、背景音樂放在同一個目錄。腳本發現輸出目錄和輸入檔案在同一目錄時會停下。
  3. 不擅自覆蓋:輸出目錄裡已有成片、audio_raw.wav、voice_master.wav 時,腳本停下不覆蓋。要覆蓋,先告訴使用者哪幾個檔案會被覆蓋、覆蓋後舊檔案找不回來,使用者同意後再加 OVERWRITE=1 重跑。剪輯建議、剪切和人聲處理的腳本同理:已有同名輸出時停下,使用者同意後才加 --overwrite。
  4. 刪除前先確認:任何刪除(包括清理 audio_raw.wav 這類大檔案)都先向使用者說明刪哪個檔案、為什麼,取得同意後再刪。腳本的中間檔案都放在輸出目錄下本次執行專用的臨時子目錄裡,結束時只清理這個子目錄。
  5. 剪什麼由使用者定:剪輯建議只是候選清單,使用者確認之前不剪。

三、處理流程

先跑一次環境檢查,把結果告訴使用者:

bash <本技能目錄>/scripts/edit_podcast.sh --check

它會列出找到的 ffmpeg、版本、250Hz 動態均衡是否啟用(見第六節),以及降噪模型是否已就緒。找不到 ffmpeg 時會提示怎麼安裝,先裝好再繼續。

第 1 步:第一遍處理,出人聲母帶和試聽版

KEEP_MASTER=1 bash <本技能目錄>/scripts/edit_podcast.sh <錄音檔案> <輸出目錄>/pass1 <名稱>
  • 錄音可以是 wav、m4a、mp3、mp4 等 ffmpeg 能讀的格式。雙人或多人對談加 INTERVIEW_MODE=1(壓縮更強,並自動拉平幾個人的音量差)。
  • 處理順序:提取成 48kHz WAV → 品質檢查 → 修剪首尾靜音(中間的停頓一處不動)→ 去唇齒咔噠 → 80Hz 高通 → 降噪 → 250Hz 動態均衡 → 去齒音 → 壓縮 → 5kHz 提亮 → 線性增益到 -16 LUFS → 限幅 → 匯出 MP3 → 復測響度。
  • 產出:
    • <名稱>_final.mp3:沒有配樂的成片(也是試聽版);
    • voice_master.wav:人聲母帶(已修剪首尾),後面的轉寫、剪輯建議和剪切都以它為準;
    • audio_raw.wav:原始錄音轉成的 WAV 副本(處理全部成功後才寫進輸出目錄),以後重做可以用,檔案較大。
  • 看輸出裡的這幾項,告訴使用者:
    • 尾部音量低於 -80dB:錄音可能中途斷了,先和使用者確認;
    • 降噪方式:RNNoise 還是 afftdn;
    • 成片響度應在 -16 LUFS ±1 以內,真峰值不高於 -1.5 dBTP。超出時腳本會提示,照實告訴使用者。
  • 錄音太輕或者是空錄音時,腳本會報錯停下,不會出空成片。報錯裡會按錄音峰值給出建議值:先和使用者確認錄音裡確實有說話,再按提示加 INPUT_GAIN=<建議值>(單位 dB,已經算上當前設的 INPUT_GAIN)把整段抬到正常電平後重跑;報錯時輸出目錄裡不會留下檔案,可以直接用同一個目錄重跑。同時建議使用者以後錄音時把輸入音量調高。

第 2 步:剪輯建議(只列候選,不動音訊)

字幕要從第 1 步的 voice_master.wav 轉寫(或者轉寫第 1 步沒加配樂的成片 MP3,兩者時間軸一致)。不要用原始錄音的轉寫:原始錄音首尾沒修剪,時間對不上,找出來的位置會偏。

找可以收緊的長停頓:

python3 <本技能目錄>/scripts/edit_cuts.py suggest <輸出目錄>/pass1/voice_master.wav \
    [--srt 字幕.srt] [--protect 15:00.0-15:03.0 ...]
  • 預設把長於 1.5 秒的停頓列為候選,建議收緊到 1.2 秒(停頓兩頭各留一半,保住房間底噪)。
  • 使用者特意留的停頓(比如一句重要的話之後的沉默),用 --protect 開始-結束 標出來,前後各留 0.5 秒緩衝,不會被建議剪掉。
  • 明顯的長停頓沒被找到,說明底噪偏高,把 --noise 從預設的 -45 調到 -40 再跑。
  • 每 40 分鐘的候選超過 15 處或累計超過 60 秒,腳本會提醒參數太緊:調大 --min-pause,不要照單全剪。

找重錄口令標出的重錄段(需要字幕):

python3 <本技能目錄>/scripts/edit_cuts.py retakes <輸出目錄>/pass1/voice_master.wav --srt 字幕.srt [--phrase 你的口令]
  • 錄音時的約定:說錯了 → 停 1 秒以上 → 平靜地說一句重錄口令 → 停 1 秒以上 → 從整句開頭重說。
  • 預設口令是「重來重來」。換成你自己的口令就用 --phrase;轉寫軟體常把口令寫成同音字時,可以寫多次 --phrase,把幾種寫法都加上。口令選一個正文裡不會出現的短語,連說兩遍更不容易誤判。
  • 腳本在字幕裡找口令,用重說那句的開頭去前面匹配說錯的那句,給出剪切區間和把握程度(high / mid / low)。low 的一定要讓使用者試聽確認。

兩個命令分別寫出 voice_master_suggested_cuts.tsv 和 voice_master_retake_cuts.tsv(已存在時不覆蓋,使用者同意後加 --overwrite)。把候選逐條講給使用者(時間、前後文、能省幾秒),使用者確認要剪哪些之後,把這些行抄進一個新的 cuts.tsv(tab 分隔:開始、結束、備註;時間寫 MM:SS.s)。

第 3 步:剪切

python3 <本技能目錄>/scripts/edit_cuts.py apply <輸出目錄>/pass1/voice_master.wav --cuts cuts.tsv [--srt 字幕.srt]
  • 按取樣剪切,接縫做 15 毫秒等功率交叉淡化,輸出 24-bit 的 voice_master_edited.wav 和剪切圖 voice_master_edited.edit_map.json(記錄每段保留音訊的來源和位置)。
  • 給了 --srt 時,完整保留的字幕會跟著平移;有字幕被剪掉一半時腳本拒絕執行——去掉 --srt 重跑,剪完請使用者對剪後母帶重新轉寫。
  • 剪完請使用者試聽每個接縫前後幾秒:沒有咔噠聲、沒有兩次吸氣、音色不跳。

第 4 步(可選):給引文、回憶等片段換一種聲音質感

python3 <本技能目錄>/scripts/voice_fx.py <剪後母帶.wav> --fx fx.tsv
python3 <本技能目錄>/scripts/voice_fx.py --list     # 看五個預設
  • 預設:quote(唸信件、他人文字)、archive(舊報紙、舊公文)、telephone(轉述電話)、memory(回憶、夢境)、radio(舊廣播,一期最多一次)。
  • fx.tsv 每行:預設、開始、結束、淡入、淡出、備註(tab 分隔,淡入淡出寫 - 用預設)。
  • 處理後時長按取樣不變、響度不變;輸出 <原名>_fx.wav。

第 5 步(可選):配樂和 cue 表

只有使用者提供了背景音樂時才做。先寫 cue 表,再預檢。cue 表放在第二遍的輸出目錄裡,檔案名必須是 <名稱>_cues.tsv。

cue 表:tab 分隔 7 列,# 開頭的行忽略,某列寫 - 表示用預設值。time 寫 MM:SS.s,相對人聲母帶的時間軸。下面的時間都是範例:

# 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	-	-	-	-
類型作用dur預設音量
stinger一小段音樂記號,疊在人聲上預設 6 秒0.12
bed / post在人聲下面鋪一段音樂,人聲出現時自動壓低必填0.12
break在這點把人聲切開,插一段純音樂,放完再接回人聲;成片變長 dur 秒必填0.5
ending結尾音樂:說話時壓低,說完升上來,最後淡出寫 -0.22
  • src 寫 - 表示用這次傳入的背景音樂;-@20 表示從背景音樂第 20 秒開始取;也可以寫另一個音樂檔案的完整路徑,同樣可以加 @秒(不加就從頭取)。
  • stinger 的 src 寫 - 而不帶 @ 時,預設從背景音樂第 60 秒取段;其他類型不帶 @ 時從頭取。
  • 寫完先預檢,有 ❌ 先改:
python3 <本技能目錄>/scripts/cues_lint.py <名稱>_cues.tsv --master <剪後母帶.wav> --bg <背景音樂>

它會檢查格式、越界、素材是否存在、視窗重疊、音樂總佔比(建議不超過 15%),並給出「母帶 → 成片」時間戳換算表,寫節目時間線時直接用。

第 6 步:第二遍出成片

MASTER_WAV=<剪後母帶.wav> bash <本技能目錄>/scripts/edit_podcast.sh - [背景音樂] <輸出目錄>/final <名稱>
  • 第一個參數寫 -。有 MASTER_WAV 時跳過提取、降噪和標準化,直接疊 cue、混配樂、匯出。
  • 有背景音樂且音訊長於 80 秒時,自動加片頭片尾配樂:片頭音樂先響 3 秒再進人聲,人聲結束後音樂留約 7 秒淡出,人聲出現時音樂自動壓低。
  • 沒有剪輯、沒有配樂時,第 1 步的成片就是最終成片,不用跑這一步。

第 7 步:驗收

腳本最後已經復測過一次。要再獨立量一遍(ffmpeg 用 --check 顯示的那個路徑):

"<ffmpeg 路徑>" -hide_banner -nostats -i <成片.mp3> -filter_complex ebur128=peak=true -f null - 2>&1 | tail -12
  • 達標:Integrated 在 -16 LUFS ±1 以內,True peak 不高於 -1.5 dBFS(即 dBTP)。
  • 請使用者戴耳機聽:音樂沒蓋過人聲;停頓時音樂沒有突然跳回來;每個剪切點自然;結尾沒有被切斷;特意留的停頓還在。
  • 交付時告訴使用者:成片位置、降噪方式、響度和真峰值的實測數字、剪了哪幾處。沒達標就照實說,不要說成通過。

四、剪輯原則

  • 只剪事故,不剪呼吸:口誤、看稿走神、重錄的廢段要剪;呼吸、思考時的「嗯」、句間遲疑、特意留的沉默不剪。拿不準的,留下。
  • 0.8 秒以內的停頓不動;0.8–1.5 秒的句間停頓預設全留;更長的停頓要有卡頓或走神的證據才收緊。
  • 剪口選在自然氣口,不切傷字頭、尾音;呼吸要嘛整留要嘛整刪。
  • 背景音樂低於人聲,避開有人聲的曲子和中頻(1–3kHz)很滿的曲子;有旋律的音樂優先放在段落之間(break),不壓在人聲下面;音樂總時長一般不超過成片的 15%。
  • 詳細做法見 references/editing-style-guide.md(風格和包裝)、references/editing-essentials.md(剪輯執行要點和驗收),術語見 references/audio-glossary.md。

五、環境變數(都可以不設)

變數預設作用
FFMPEG自動尋找指定 ffmpeg 路徑
DENOISErnnoisernnoise / afftdn / off
RNNOISE_MODEL~/.cache/ethan-podcast-post/bd.rnnn降噪模型位置;已有模型可直接指向它
RNNOISE_URLGitHub 上的公開模型網路不通時可換成鏡像地址(下載後仍校驗 SHA-256)
INPUT_GAIN0處理前把錄音整體抬高(或降低)多少 dB;錄音太輕時按報錯裡的建議值設
TRIM_THRESHOLD-50修剪首尾靜音的閾值(dB);只是開頭結尾的輕聲被切掉時調低,如 -60
INTERVIEW_MODE01 = 雙人或多人對談
KEEP_MASTER01 = 保留人聲母帶 voice_master.wav
MASTER_WAV空第二遍用的人聲母帶
MUSIC_VOLUME0.12背景音樂音量比例
INTRO_DURATION40片頭、片尾配樂視窗秒數;音訊短於它的 2 倍時不加
PREROLL / TAIL3 / 7片頭音樂先行秒數 / 人聲結束後音樂留的秒數
OUTRO_SEEK空片尾音樂從曲子第幾秒取
MP3_BITRATE160k成片碼率
OVERWRITE01 = 允許覆蓋已有成品(先徵得使用者同意)

六、常見問題

  • 找不到 ffmpeg:請使用者先安裝(macOS brew install ffmpeg,Linux 用套件管理器),或用 FFMPEG=/完整路徑/ffmpeg 指定。
  • ffmpeg 版本:腳本會讀版本號。250Hz 動態均衡這一級的參數含義在 ffmpeg 6 和 8 之間變了,兩種寫法都用正弦訊號標定過,效果一致;遇到 7.x 等沒驗證過的版本會跳過這一級並提示,其餘處理照常。修剪首尾靜音的參數也按新版行為調過,6.x 和 8.x 切得一樣。
  • 報錯「修剪首尾靜音後幾乎什麼都不剩」或「處理後測不到響度」:錄音太輕或是空的。確認有說話後,按報錯裡給的 INPUT_GAIN 建議值重跑(響度低於 -70 LUFS 時無法測量,只調修剪閾值不夠);錄音裡真的沒有聲音時會一直報錯,不會輸出空成片。
  • 降噪用了 afftdn:說明模型沒下載成功。可以設 RNNOISE_URL 換鏡像,或用 RNNOISE_MODEL 指向已有的模型檔案,再重跑(覆蓋已有成品前先問使用者)。
  • 尾部音量低於 -80dB:錄音很可能中途斷了,先和使用者確認,不要當成剪輯問題。
  • 重錄段一個都沒找到:確認字幕是從 voice_master.wav 轉寫的,再看轉寫裡口令被寫成了什麼字,用 --phrase 補上這種寫法。
  • 想看每一步的命令:bash -x <本技能目錄>/scripts/edit_podcast.sh ...。
  • 在 zsh 裡自己拼 ffmpeg 濾鏡參數:變數後面緊跟冒號時寫成 ${VAR}:...,否則 zsh 會把 $VAR:a、$VAR:r 當成修飾符,參數被悄悄改掉。

許可:程式碼 MIT,文件 CC BY 4.0。

相關技能