O que Motor de Sincronização de Palavras de Letra faz?
Resolve o problema comum em vídeos de letra onde a exibição de linhas inteiras parece lenta ou atrasada em relação à entrega do cantor, sincronizando cada palavra individual ao seu onset acústico.
flowchart TD
A[Arquivo de Áudio MP3/WAV] --> B[Análise de Envelope Acústico RMS]
B --> C[Reconhecimento de Fala / Pontos de Verificação Vocal]
C --> D[ Ponderação de Sílabas por Palavra]
D --> E[Timestamps de Palavra em Sub-segundos JSON]
E --> F[Revelação Progressiva de Palavra HTML/CSS]
Problema e Solução
- O Problema: Quando um cantor acelera (por exemplo, charanans rápidos ou linhas staccato), uma revelação estática de linha inteira permanece na tela por muito tempo ou aparece depois que o cantor já terminou.
- A Solução:
- Cada linha é tokenizada em palavras individuais:
["Kanmani", "anbodu", "kaadhalan"]. - A duração vocal ativa é distribuída de acordo com os pesos das sílabas e os aumentos localizados de energia RMS.
- Todas as palavras na linha são renderizadas simultaneamente no layout para que o tamanho da fonte e a quebra de linha nunca saltem.
- As palavras próximas são renderizadas em tinta fantasma fraca (
opacity: 0.12). - À medida que o cantor pronuncia cada palavra, essa palavra específica faz a transição para carmesim sólido (
opacity: 1,color: #8c1226).
- Cada linha é tokenizada em palavras individuais:
Script de Extração de Timestamps
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
Destaque Progressivo de Palavra em CSS
.native .word {
display: inline-block;
opacity: 0.12;
transition: opacity .12s ease-out;
padding: 0 .25cqw;
}
.native .word.revealed {
opacity: 1;
}