Communitygithub.com

CatsMansion/mv-jp-lyrics-subtitle

建立符合日本人閱讀習慣的日文歌詞字幕:在文節邊界斷句、以實測起唱時間點(非平均分配)顯示每個短語、使用漢字假名混合表記而非全假名,並驗證每一行文字都出現在背景排版中。

mv-jp-lyrics-subtitle 是什麼?

這個技能(Skill)專門處理日文歌詞字幕製作中常見的四大問題:按字數平均分配時間、斷句在詞中間、全用平假名、以及將句末音符誤當作下一句起點。它提供了一套完整的製作流程,包含兩套核心腳本:一個是「實測起唱時間提取器」(measure_lyric_onsets.py),使用 PyTorch 的 pyin 演算法加上能量閘控(energy gating)與「短語結束假陽性修正」(phrase-end false-positive fix),確保每個文節的顯示時間點對應到實際唱出的那一刻,而不是靠平均計算;另一個是「覆蓋率檢查器」(check_lyric_coverage.py),用於比對背景大字與螢幕字幕的每個字元是否完全一致,避免遺漏任何文字。 該技能支援橫排與直排排版,並提供了從商業 MV 量化反向工程得出的排版參數(如字體大小、基線位置、最大行寬等),以及基於實測的多項對齊工具比較表(MMS_FA、WhisperX、aeneas 等),明確指出只有 MMS_FA 能達到日文歌詞所需的 ≤0.15 秒誤差。此外,還包含關於字體授權的詳細風險評估,提示使用 Windows 系統字體(如游ゴシック)可能面臨的商用風險,並推薦更安全的 OFL 開源字體選項。 總體而言,這個技能是為需要高精度、文化上正確的日文歌詞字幕的開發者、影片創作者、或本地化團隊所設計,可應用於 Claude Code、Cursor、Codex 等 AI 代理工具中,以自動化生成或審查字幕檔案。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add CatsMansion/mv-jp-lyrics-subtitle

在你喜歡的 AI 中提問

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

說明文件

日文歌詞字幕:斷句、出字時刻、表記、排版

0. 這個 skill 解決什麼

日文歌詞字幕最常見的四種錯,全都是"看著還行、日本人一眼就錯":

  1. 按字數均分時間 —— 一句 5.7 秒 16 個音節,平均每音 0.36 秒。實際唱起來長短差 3 倍。
  2. 斷在詞中間 —— 君 / を見るたび。助詞不能單獨起頭。
  3. 全平假名 —— 歌詞表為了給 TTS/生成模型用而寫成全假名,直接貼上屏日本人讀起來像兒童讀物。
  4. 出字時刻吸附到"音高變化點" —— 會把句末收音符當成下一句的起點,整句提前半秒。

1. 八條硬規則

#規則反例
R1斷點只落在文節邊界。名詞+助詞、動詞+助動詞不得拆開✗ 君/を見るたび ✗ 見/てるのに
R2每段出字時刻=該段首音節實測起唱。⛔ 禁止按字數均分✗ (end-start)/n × k
R3一句最多 3 個出字段,優先 2 段✗ 君を/見る/たび
R4不顯示標點;段間用全形空格  ✗ 君を、見るたび
R5禁則(JIS X 4051):小假名 ゃゅょっ、長音 ー、促音、閉括號不得起行✗ 行首出現 っ
R6單行 ≤ 16 字(Netflix 日文字幕口徑)—
R7出字後不消失(累積顯示),否則觀眾失去上下文✗ 出第二段時抹掉第一段
R8背景大字必須包含該句全部字,逐字比對 missing 必須為空✗ 背景只有後半句

R1 為什麼是文節而不是"詞":日文沒有空格,機器斷行只會在框寬處斷。 人讀的時候是按文節呼吸的 —— 君を/見るたび 正好是兩次呼吸。 判斷方法:把這段單獨念出來,如果像一次換氣,它就是對的。


2. 實測出字時刻(核心,別用估的)

2.1 前置

需要人聲分離軌(Demucs / htdemucs 的 vocals.wav)。混音軌上有鼓和貝斯,能量峰值全是鼓點。

python scripts/measure_lyric_onsets.py --vocal vocals.wav --lines lines.json --out timing.json

lines.json 長這樣(kana 用於算音節數定預期位置,disp 是上屏表記):

[{"id": 9, "start": 42.26, "end": 48.00,
  "kana": ["きみを", "みるたび", "しんぞうがとまるの"],
  "disp": ["君を", "見るたび", "心臓が止まるの"]}]

2.2 演算法(三段,缺一段就會錯)

  1. 取 F0:librosa.pyin(fmin=150, fmax=900, hop_length=128),再對 F0 做中值濾波去掉顫音。
  2. 取候選邊界:音高跳變 ≥0.8 半音 ∪ librosa.onset.onset_detect(delta=0.30, wait=3)。
  3. ⛔ 門檻過濾(最關鍵的一步):候選點必須同時滿足
    • 之後 40ms 能量不低於之前 40ms 的 55%(不是驟降)
    • 之後 180ms 內 F0 非 NaN 的幀佔比 ≥60%(還有人在唱)

然後:把每個文節按"累計音節數 / 總音節數"算出預期相對位置,吸附到最近的合法邊界。

2.3 為什麼第 3 步不能省(實測反例)

「君を見るたび 心臓が止まるの」的 び 在 44.87 秒收尾降調(F2# → 收),靜音 0.33 秒後 しんぞう 才在 45.24 起。

  • 只做第 2 步 → 邊界抓到 44.81(び 的降調),把「心臓が止まるの」提前 0.43 秒。
  • 只做第 3 步的第一條(40ms 能量比) → 仍然錯。44.81 處能量還沒掉下來,40ms 視窗太短。
  • 加上「之後 180ms 仍有發聲」 → 45.17,與手工核對差 0.07 秒。✅

⇒ "之後還有沒有人在唱"比"這一刻能量高不高"更能區分換字與收句。

2.4 什麼時候這條也會失效

  • 英文句:沒有音高平台,pyin 測不出音節邊界。只能按時長比例分,並在交付裡明確標註"估的"。
  • 一字多音的連唱(melisma):音高平台數 > 音節數,吸附會偏。需要人工聽。
  • 吸附偏差 > 0.45 秒的句子:一律標 UNSURE 交給人工,不要當成測準了。

2.5 ⛔⛔ 先驗證"每句的時間窗"本身,再談句內斷句

這是比 §2.3 更上游的坑,也是最容易被忽略的。

絕大多數歌詞時間軸檔案(lyrics.ts / SRT / LRC)的 start/end 是按行數線性切分或手工估的, 不是逐句聽出來的。帶這種檔案做字幕,句內測得再準,整句也是錯位的。

症狀:字幕整體比人聲早或晚 1–4 秒,而且越往後漂得越多(因為是線性拉伸)。 用戶在副歌聽不出來(副歌視窗通常是對的),一聽主歌前幾句就發現不同步。

修法:用換氣間隔重新錨定每一句

人聲分軌上,句與句之間一定有靜音。這是最硬的分界,不需要任何模型:

rms = librosa.feature.rms(y=vocal, frame_length=1024, hop_length=128)[0]
e = rms / rms.max()
quiet = e < 0.055                      # 相對閾值,實測夠用
# 連續 quiet >= 0.16s 記為一個換氣間隔

然後:相鄰兩個間隔之間的有聲段,就是一個樂句。

實測例子(同一首歌):

間隔 0.00-12.12(前奏無演唱)
有聲 12.12-13.73  ← ドアのとこで
間隔 13.73-14.67
有聲 14.67-16.59  ← 立ち止まってる
間隔 16.59-17.07
有聲 17.07-17.98  ← 本当は

而歌詞表寫的是「第 1 句 12.00–15.75」「第 3 句 19.50 起」——第 3 句實際 23.63 起,早了 4.1 秒。

⭐ 判據:把檢測出的有聲段數,和這一段歌詞的文節數比。

  • 數量相等 ⇒ 這個歌手是"一文節一換氣",直接 1:1 對應,精度到毫秒級,不用猜。
  • 數量偏少 ⇒ 有連唱,再用 §2.2 的音高法找句內邊界。
  • 數量偏多 ⇒ 閾值太鬆,調高 0.055 或加長 0.16。

⛔ 不要用"能量峰計數"代替換氣檢測:一個長音裡的顫音會產生多個峰。 實測 16 個音節的一句子被數出 33 個能量峰,完全沒法用。

⛔ 也不要用"滾動中位數歸一 + 淺閾值"去找弱換氣:主歌裡會冒出 23 個假間隔(真值 19), 雜訊和真換氣分不開。寧可只錨定有硬靜音的那些句,剩下的明確標"重映射/估"。


3. 表記:漢字假名交じり

歌詞表(尤其是 AI 生成歌曲的歌詞稿)常寫全假名。上屏必須轉常用漢字表記。

全假名(歌詞稿)上屏表記
きみをみるたび君を見るたび
ほんとは / きみのほう本当は / 君のほう
なかに中に
においだけで匂いだけで
いちばんとおい一番遠い
こわれちゃいそう / ちかづくと壊れちゃいそう / 近づくと
たちどまってる立ち止まってる
わたしのあかし私の証

⛔ 不要過度漢字化:すきだよって 不要寫成 好きだよって…其實要寫(好き)。 但 なっちゃう、ずるいよね、なんてかな 這類口語副詞/終助詞保持假名 —— 全改漢字反而生硬。 判據:這個詞在日本人的小説/歌詞排版裡通常寫漢字嗎? 不確定就保持假名。


4. 排版參數(有出處,別自己發明)

以下數值來自對四支商業二次元 MV 的量化反向工程(1280×720 基準換算到 1080p):

項1080p 值
主歌詞字高97~108px
旁白小字53px
副歌強調句124px
巨型背景字270~670px
底部基線y ≈ 950~1004
單行最寬≤1747px(≤91% 畫寬)

⭐ 最重要的發現:商業 MV 的主歌詞普遍"無底板",白字 + 2~3px 深描邊。 只在強調句才用通欄白帶 + 黑字。給每一句都加圓角底板是業餘感的主要來源。

配色不要中途換調:一支片只有一個主色相,副歌只加飽和不換色相。

4.1 直排多列 = 斷句視覺化

橫排用全形空格分隔,觀感上等於"沒斷句"。直排時把每個文節排成一列,從右往左, 斷句就變成版面本身:

君を | 見るたび | 息が止まるの
右列    中列        左列

列位固定按文節序號算(第 k 段永遠在第 k 列),新段出現時已有列不位移 —— 否則每次出字整塊文字會橫跳。

4.2 直排的物理上限(先算再定字號)

一行 n 字、行距比 1.46:所需高度 = n × 字號 × 1.46。 1080 畫高、可用 940px ⇒ 字號上限 = 940 / (n × 1.46)。

  • 8 字(心臓が止まるの)→ 79px,達不到 97px 下限
  • 6 字 → 107px ✅

⇒ 超過 7 字的長句,直排放不進主歌詞字號區間,要改橫排兩行。 先算,別排完才發現。


5. 自檢(每次都要印,不看就交付必翻車)

python scripts/check_lyric_coverage.py --timing timing.json --disp disp.json

輸出必須同時滿足:

COVER line='君を見るたび' missing=[] OK=True
ORDER sub_a='君を' sub_b='見るたび' concat_equals_full=True

missing 不為空 ⇒ 這一版不許交付。ORDER 檢查拼接後是否等於整句(防漏字/重字)。


6. 開工前必做的一件事

先在專案文件裡 grep 一遍字幕規格。 本專案已經裁定過的字號、色板、有無底板, 通常躺在 02_文檔/ 或 docs/ 的某份拆解/裁定裡:

grep -rn -E "字幕|字體|排版|幾何|字高|描邊|底板" docs/ 02_文檔/ | head -40

⛔ 不要"我覺得這樣更好看"就自己定一套 —— 那一定會和已裁定的規格衝突, 而且返工成本是整個片子重渲。這個 skill 的第 4 節就是被這條教訓逼出來的。


7. 實測記錄(供校準預期)

一支 163.994 BPM 的日文歌,副歌首句:

音節きみをみるたび
起唱(s)42.3142.7643.0943.4143.6143.9844.18
音高B3E4F#4G#4F#4F4F#4

7 音節 ↔ 7 個音高平台一一對應 ⇒ 這首歌副歌是一字一音。 換一首連唱多的歌,平台數會少於音節數,吸附就要標 UNSURE。


8. ⛔ BPM 不是網格(實測漂移)

一首歌的 bpm 字段只能當標籤,不能拿來算切點。 實測:某曲 128.28 → 132.39 BPM(beat 468ms → 453ms),固定網格到第 30 小節就整整差一拍。

  • 用 beats[](已吸附到 onset)+ bars[].start 取真實時間
  • beats 用於打擊點(切鏡/閃/砸字);beats_smooth 用於連續運動(相機速度/循環)
  • ⛔ 永遠不要寫 t0 + n * 60 / bpm
  • 小節號 ≠ 陣列下標:有 pickup 小節時 bars[].index 與位置不同,按 index 查

9. ⛔ ASR 的單詞時間戳偏早,不能當出字時刻

實測偏差 0.04–2.0 秒,中位 0.62 秒;長音之後最差。 ⇒ 用 ASR 只能取每句的近似起點(±1s),精確出字必須用強制對齊(MMS CTC / torchaudio)。 判據:每句起唱誤差 ≤ 0.15 秒才算測準。

10. ⛔ Whisper 幻覺清單(出現即刪)

在靜音、氣口、vocalise 處會生成:

  • 「ご視聴ありがとうございました」(曾覆蓋 0.6–103 秒)
  • 「チャンネル登録…」
  • 「作詞・作曲・編曲 初音ミク」
  • 重複短詞、ラララ…

⇒ 規則:官方歌詞為準;無官方歌詞才用轉寫,且逐句與官方稿對照(差異法看不見"整句缺失")。 ⇒ VAD 要關掉(Silero 誤判歌唱母音);分離出的人聲軌 > 任何 DSP 增強。

11. LRC 標記(歌詞動畫的 mini 語言)

標記作用
詞組A/詞組B強制切行,兩半成為不同 beat
*詞*強調:更大 + 衝擊部件 + 強調色
行尾 !キメ行(最強處理,可帶閃/震)——副歌每段 1–2 行
[間奏]器樂行:阻止上一句佔著空隙不消失

⛔ 不要重複抵消提前量:歌詞引擎通常已內建「比人聲早 0.2 秒」; 若你的時間軸已經減過 0.2,這裡再加一次就會早 0.4 秒。

12. 副歌收尾的 stop 小節

副歌末尾樂隊撤空、近乎 a cappella 的那幾個小節,是全片最重要的畫面該放的位置, 不是切走的時機。別把它當"這裡沒鼓所以隨便放點什麼"。


13. ⭐ 五個強制對齊工具在日文歌詞上的實測對比

出處:第三方 benchmark(20 段,含中/英/日),下表取日文列。

工具起點誤差(中位)終點誤差(中位)覆蓋率判
MMS_FA(torchaudio)0.08 s0.11 s8/8✅ 唯一達標
whisper-timestamped—0.16 s8/8⚠️ 次選
WhisperX—1.67 s(p90 2.81)8/8❌ 覆蓋全但邊界飄
NeMo NFA——0/8❌ 無日文 pretrained CTC
aeneas2.70 s3.66 s8/8❌ 崩盤

⛔ aeneas 不適合唱歌:它自己的文件就寫著「Audio is assumed to be spoken: not suitable for song captioning」。 實測日文 2.7–3.7 秒誤差,比按字數均分還差。

⇒ 要 ≤0.15 秒,只有 MMS_FA 這條路。 其餘都不達標。

⚠️⚠️ 但 MMS_FA 的 License 是 CC-BY-NC(非商用)。我們若上 Steam 商業化,必須另做許可安排, 或只用它做內部對齊、不隨產品分發模型權重。這條在商業化前必須確認。

⚠️ MMS_FA 對非拉丁語種靠 uroman 羅馬化;日文漢字混排時,長段 p90 會飄到 2.53 s ⇒ 必須逐句核對。

14. 提前量的兩個數值不是一回事

數值目的出處
0.15–0.25 s讓人讀得完(閱讀提前量)歌詞引擎預設「文字は聲より 0.2 秒先」
0.03–0.05 s讓人跟得上唱(卡拉OK對齊感)另一來源的歌詞影片實踐

⇒ 選哪個取決於這支片子是"讀的字"還是"跟唱的字"。 我們做的是讀的字 ⇒ 用 0.15–0.2 s。⛔ 不要兩者疊加。


15. 直排組版的實際規則(不是"把字豎著排")

規則做法
句読點佔一格,寫在格子的右上方(橫排是左下方)
小假名(っ ゃ ゅ ょ)佔一格,寫在格內右上方
拗音(きゃ)看作兩個假名,各佔一格
長音符「ー」佔一格
段首空一格
⛔ 禁則句読點不能出現在一行的開頭
行末標點如果句末標點落在行末沒格子,寫在格外或與末字同格
數字豎寫用漢字數字;橫寫可用阿拉伯數字(每格 1–2 個)

⇒ 我們現在的直排是"每個字一行堆下來",沒有處理句読點的位置、小假名的偏移、段首空一格。 這三樣加上去,日文讀者一眼就會覺得"對了"。

16. 閱讀速度判據:4 cps 是廣播字幕標準,不是歌詞標準(含本專案實測)

⚠️ 可信度分佈:數字 B 級(日本字幕認證 AVTpro 的 JA 風格指南、兩家字幕公司的公開規格,三源交叉一致); "歌詞該怎麼用"是我自己的推論,D 級 —— 已明確標註,不許當證據用。

16.1 三個源給出的硬數字(互相一致的部分)

項AVTpro JA(認證標準)GoLocaliseDMPJ取用
最大讀速4.0 cps12 字/秒(≈上限口徑不同)~4 字/秒4.0–5.0 cps
每行字數(橫)15 字16 字13–16 字≤15
每行字數(豎)11 字——≤11
同屏行數2222
最短顯示20 幀(0.8 s @25fps)1 s1.5 s≥0.8 s
最長顯示6 s(歌詞可 7 s)7 s—6 s(歌詞 7 s)
標點處理。→ 全形空格;、→ 半形空格——同 AVTpro
字體ゴシック—Gothic 優先(可讀性)ゴシック

⭐ 兩條驗證了我們已有的裁定:

  1. 「⛔ 不用標點」是對的 —— AVTpro 的正式做法就是把標點換成空格(。→全形、、→半形)。 我們直接不加標點,效果等價且更乾淨 ⇒ R7 不需要改。
  2. 「ゴシック體」是對的 —— 我們用的 Yu Gothic Bold 屬於ゴシック,方向沒錯(但字體授權有問題,見 §17)。

16.2 ⛔ 但 4 cps 不能直接套在歌詞上(我的推論,D 級)

4 cps 的存在理由是:對白聽不懂就得重看,字幕是唯一資訊通道。 而歌詞是同時被唱出來的 —— 觀眾在聽到那個詞的同一秒看到它,不需要"讀完再理解"。

⇒ 歌詞的字幕不該按"讀完"設計,該按"跟著唱"設計。 (AVTpro 自己也給歌詞開了口子:最長顯示時長從 6 s 放寬到 7 s,說明行業承認歌詞是另一類。)

⚠️ 但這不等於"歌詞可以隨便快"。超過 ~6 cps 連"跟著唱"都跟不上,因為眼睛找不到當前那個字。 ⇒ 實踐判據:峰值 cps ≤ 5.0 可接受,5.0–6.0 要提高,>6.0 必須改排版(拆行 / 兩行並出 / 縮短文節)。

16.3 本專案實測(lyric_timing_v2.json,22 行 / 52 文節)

口徑結果
按整行(v7 現行 WHOLE_LINE)22 行裡 5 行 >4.0 cps,最差 L5 = 5.30 cps(16 字 / 3.02 s)
按文節(若改回逐文節顯現)52 個裡 11 個 >4.0 cps(21%),最差 L3「ポケットのなかに」6.90 cps
直排每列字數最長 16 字 → 分兩列每列 8 字,未超 11,OK

⇒ 結論分兩層,別混:

  • 按 4.0 cps 嚴格判:5 行不合格,但按 §16.2 的歌詞口徑(≤5.0)只有 L5 的 5.30 需要處理。
  • ⛔ 若改回逐文節顯現,21% 的文節會超速到 5–7 cps ⇒ 這是"整行一起出"這個決定的量化依據 (當初改 WHOLE_LINE 只憑"逐文節會誘發跟著核對同步"的直覺,現在有數字了)。

16.4 ⭐ 順手查出的真缺陷:L3–L7 的時間軸是等分推算的

症狀L3–L7 連續五行時長全部恰好 3.02 s,且首尾嚴絲合縫(23.63→38.72 = 15.09 s ÷ 5)
根因換氣間隔檢測在這段(legato 連唱,字與字之間不換氣)找不到 gap,REMAP 退化為等分,且沒報警
實測反證在 22–44 s 內掃 4 檔閾值 × 2 檔最短長度,真實靜音只有 7 處(22.63 / 23.01 / 24.24 / 25.60 / 28.29 / 31.43 / 41.55),沒有一處落在 26.65 / 29.67 / 32.69 / 35.70 / 38.72 上 ⇒ 這五個邊界不是測出來的
為什麼難發現source 字段只寫 REMAP,不區分"有依據的重映射"和"等分兜底"
修法(未做,屬程式端)①REMAP 拆成 REMAP_ANCHORED / EQUAL_DIVIDE,後者必須印出警告 ②等分兜底時同時輸出 cps,超 5.0 直接判紅 ③legato 段改用 pyin 音高連續性定邊界,不用靜音

⛔ 這條是"判據看著全綠、實際是假的"的又一例:missing=[] 只說明"每行都有時間",不說明"時間是量出來的"。

17. ⛔ 字體授權:我們現在用的是 Windows 系統字體,商用有風險(B 級)

⚠️ 可信度 B(各家字體廠商的正式許可頁 / FAQ 原文,逐條讀到,不是二手轉述)

17.1 四類授權,天差地別

字體影片裡燒字幕商用備註
SIL OFL 1.1(Noto/Source Han、M PLUS、Zen Maru、Kosugi、Shippori、侵食明朝…)✅✅ 免標註唯一要遵守:⛔ 不許單獨賣字體檔案;改作須同協議
IPA Font License 1.0(IPAex、こころ明朝…)✅ 明寫"映像內容"可用✅⛔ 衍生字體名不得含「IPA」;再分發須附協議
ヒラギノ(macOS 自帶)✅ 產物可販賣/頒布✅⛔ 但明禁"デジタルコンテンツにおいてフォントとして機能する形態でデータを制作する行為";且綁 macOS,我們在 Windows 上用它 = 越界
日本書技研究所 等商業字庫⚠️ 要買需商用授權映像テロップ按資本金 ¥22,000–55,000
ことり文字ふぉんと Pro✅(含 YouTube 收益化)✅⛔ 但"埋め込み/Webフォント"原則禁止 ⇒ 燒進影片 ≠ 嵌入字體,這兩件事在不同條款裡

⭐ 關鍵區分(最容易搞錯的一條): 「把字燒進畫面」和「把字體檔案嵌進文件/網頁」是兩種行為,適用不同條款。 前者產物是像素,一般按"輸出物"處理;後者是把字體本體交出去。⛔ 別把 ことり 的"禁止嵌入"讀成"禁止做影片"——它自己的 FAQ 裡"動画への使用"是明確 OK 的。

17.2 我們現在的實際狀態

項值
當前字體C:\Windows\Fonts\YuGothB.ttc(游ゴシック Bold,Windows 自帶)
字形方向ゴシック ✅(與 §16.1 的可讀性建議一致)
授權狀態⚠️ 未核。Windows 自帶字體綁 OS 授權,燒進商用成品(Steam DLC)屬於灰區,不是明確許可

⇒ 建議換 OFL 字體(零成本、明確可商用、免標註),候選按氣質排:

候選許可氣質適配
Zen Maru GothicOFL圓潤、柔和⭐ 最貼我們的粉紫/可愛調
Shippori MinchoOFL情緒濃的明朝適合抒情句,但與"可愛"有張力
M PLUS 1pOFL幾何、現代中性安全
Noto Sans JPOFL最中性兜底,不會錯

⚠️ 換字體 = 改觀感,必須 Ronny 目檢後定,⛔ 不許我單方面換(這是"畫面層"改動,按用戶級鐵律必須他看)。

相關技能