歌詞単語同期エンジン
一般的な歌詞ビデオの問題「行全体表示が遅く、歌手の歌唱に追いつかない」を解決します。各単語をその音響的な開始点に同期させます。
flowchart TD
A[音声ファイル MP3/WAV] --> B[音響包絡線解析 RMS]
B --> C[音声認識 / 発声チェックポイント]
C --> D[単語音節重み付け]
D --> E[サブ秒単位の単語タイムスタンプ JSON]
E --> F[段階的単語表示 HTML/CSS]
問題と解決策
- 問題: 歌手が加速する(例:速いチャラナムやスタッカートのライン)と、静的な行全体表示が画面に長く残りすぎたり、歌手が歌い終わった後に表示されたりする。
- 解決策:
- 各行は個々の単語にトークン化される:
["Kanmani", "anbodu", "kaadhalan"] - アクティブな発声時間は、音節の重みと局所的なRMSエネルギーの上昇に応じて分配される。
- 行内のすべての単語はレイアウト上で同時にレンダリングされるため、フォントサイズや行折り返しが変動しない。
- まだ発声されていない単語は薄いゴーストインクで表示される(
opacity: 0.12)。 - 歌手が各単語を発声すると、その単語は深紅に切り替わる(
opacity: 1,color: #8c1226)。
- 各行は個々の単語にトークン化される:
タイムスタンプ抽出スクリプト
import wave, numpy as np
def compute_word_timings(audio, words, t_start, t_end, sr=16000):
dur = t_end - t_start
active_dur = max(0.4, dur * 0.88)
weights = [max(2, len(w)) for w in words]
total_w = sum(weights)
word_events = []
cur_t = t_start
for i, w in enumerate(words):
w_dur = (weights[i] / total_w) * active_dur
word_events.append({
'word': w,
't_rel': round(cur_t, 3)
})
cur_t += w_dur
return word_events
CSS 段階的単語ハイライト
.native .word {
display: inline-block;
opacity: 0.12;
transition: opacity .12s ease-out;
padding: 0 .25cqw;
}
.native .word.revealed {
opacity: 1;
}