Sincronização de Lapela
Entrada: clipes de câmera mais uma faixa de gravador separada. Saída: um segmento de lapela por clipe e uma timeline sincronizada no Resolve. Testado pela primeira vez em uma palestra ao vivo: 5 clipes de câmera contra uma faixa de gravador de 59 minutos. Cada clipe caiu dentro de 20 ms, bem abaixo de um quadro.
Por que é importante: em um evento ao vivo, o microfone da câmera está do outro lado da sala. Seu áudio é inutilizável, e a lapela é o único som limpo. Após esta skill, <trabalho>/<clipe>.wav e <clipe>.json são a lapela, então paper-edit e video-reels leem áudio limpo e transcrições limpas sem saber que algo mudou.
Configuração: preencha estes campos
| Placeholder | O que é | Exemplo |
|---|---|---|
<DRIVE_DE_MIDIA> | Onde o material bruto reside, uma pasta por vídeo, arquivos do gravador em uma subpasta audio/ | /Volumes/MyWorkDrive |
<SAIDA_SYNC> | Onde os segmentos de lapela em qualidade total vão | ~/Movies/<vídeo>-sync |
<CAMINHO_LUT> | LUT opcional, relativo à pasta de LUT do Resolve | MyLuts/SLog3-to-709.cube |
WHISPER_MODEL (env) | Arquivo de modelo whisper.cpp | padrão ~/.cache/whisper-models/ggml-small.en.bin |
Requisitos: ffmpeg, ffprobe, whisper-cli (whisper.cpp), Python 3 (numpy e scipy são instalados automaticamente em ~/.cache/lapel-sync-venv), DaVinci Resolve com um servidor MCP Resolve expondo execute_resolve_code, e a skill paper-edit (para ensure_resolve.sh).
Executar
Diretório de trabalho: o scratchpad da sessão, ex.: <scratchpad>/<vídeo>. O diretório da skill abaixo é .claude/skills/lapel-sync. Os segmentos em qualidade total vão para <SAIDA_SYNC>.
Armadilha do zsh: em shell inline, $ss:end_sample interpreta :e como um modificador e silenciosamente come o texto. Sempre escreva ${ss}.
1. Encontre o material e o áudio
Uma pasta por vídeo em <DRIVE_DE_MIDIA>. Os arquivos do gravador estão em uma subpasta audio/:
find "<DRIVE_DE_MIDIA>" -maxdepth 4 -iname "*<palavra-chave>*" -not -path "*/.*"
ls "<pasta>" "<pasta>/audio"
Um Tascam DR-10L, por exemplo, escreve 000_YYMMDD.wav, 001_..., dividido a cada 15 minutos, mais gêmeos _D. Os arquivos _D são a faixa de segurança de gravação dupla, cerca de 20 dB mais silenciosos. Use os arquivos principais; mantenha _D para corrigir pontos cortados.
2. Una os arquivos do gravador
bash <skill>/scripts/stitch.sh "<pasta>/audio" "<SAIDA_SYNC>/lav-master.wav"
Ele lê o time_reference BWF (amostras desde a meia-noite) de cada arquivo e verifica se cada arquivo começa exatamente onde o último terminou. Quando são contíguos em amostras, é uma cópia de stream sem perdas. Se houver uma lacuna, ele insere esse tanto de silêncio, para que o master permaneça no tempo de parede, e avisa com o tamanho.
3. Transcreva ambos os lados
bash <skill>/scripts/transcribe_sources.sh "<pasta>" "<SAIDA_SYNC>/lav-master.wav" "<trabalho>"
Tudo cai em <trabalho>/sync/, mantido fora de <trabalho> para que o sentences.py do paper-edit nunca o leia. O áudio da câmera é primeiro amplificado fortemente (highpass=f=120,volume=40dB,alimiter, 16k mono), porque geralmente está em torno de -65 dB. Pula qualquer coisa já feita, então execute novamente à vontade.
A lapela leva cerca de 8 minutos por hora de áudio. Execute em segundo plano. O Whisper transmite temporizações de palavras para <trabalho>/sync/lav.log, e align.py lê esse log quando lav.json ainda não foi escrito, para que o alinhamento possa começar antes da lapela terminar. Clipes além do ponto transcrito apenas relatam "apenas N correspondências de palavras"; execute novamente quando terminar.
4. Alinhe
python3 <skill>/scripts/align.py "<trabalho>"
Escreve <trabalho>/sync/sync.json. A primeira execução cria ~/.cache/lapel-sync-venv com numpy e scipy (o python3 do sistema geralmente não tem nenhum); depois disso, ele apenas se executa novamente dentro dele.
Como funciona, para que você possa confiar ou questionar a saída:
- Palavras primeiro. Sequências únicas de 4 palavras que aparecem em ambas as transcrições. Deslocamento = tempo da lapela menos tempo da câmera. Centenas de correspondências por clipe; aglomerado mais denso, mantenha dentro de 0,5s, mediana. Bom para cerca de 0,1s.
- Refinamento de forma de onda. Cada bloco de 20s do áudio da câmera (blocos de 6s em clipes com menos de 40s), passa-banda 300-3000 Hz a 8 kHz, é correlacionado cruzadamente com a lapela dentro de +-0,6s do deslocamento de palavras. Picos acima de 6x a mediana contam. Blocos dentro de 20 ms um do outro concordam; em clipes com mais de 5 minutos, um ajuste de linha fornece deslocamento mais deriva.
Leia cada linha que ele imprime: deslocamento, blocos concordantes, dispersão, deriva. Qualquer clipe marcado VERIFICAR DE OUVIDO (menos de 3 blocos concordantes) pode estar até 0,1s errado; verifique-o no Resolve antes de confiar. Deriva acima de um quadro em um clipe também é sinalizada.
5. Corte a lapela por clipe
python3 <skill>/scripts/slice.py "<trabalho>" "<SAIDA_SYNC>/lav-master.wav" "<SAIDA_SYNC>"
Para cada clipe, ele escreve:
<SAIDA_SYNC>/<clipe>_lav.wav: 24 bits, taxa de origem, amostra exata ao comprimento do clipe, para que o tempo da lapela seja igual ao tempo do clipe<trabalho>/<clipe>.wav(16k mono) e<trabalho>/<clipe>.json(whisper do corte): o que paper-edit e video-reels leem<trabalho>/clips.ndjsoncom um campo"audio"apontando para o corte
Se o gravador começou atrasado ou parou cedo para um clipe, essa parte é preenchida com silêncio e ele avisa. O Whisper nos cortes leva alguns minutos; não execute também o transcribe.sh do paper-edit depois (ele pularia de qualquer maneira, já que os jsons existem).
6. Verifique cortes
slice.py conta amostras em ou acima de 0,99 de escala completa por corte e imprime a sequência mais longa. Centenas de sequências curtas (dezenas de amostras) são geralmente o limitador do gravador capturando picos, não distorção. Somente quando lista pontos para ouvir (sequências de 1 ms ou mais), ou o usuário diz que soa estalado, corrija esses momentos a partir do gêmeo _D (mesma temporização, aumente cerca de 20 dB).
7. Construa no Resolve
bash .claude/skills/paper-edit/scripts/ensure_resolve.sh
Escreva <trabalho>/sync/params.json:
{"project":"<Vídeo> - YYYY-MM-DD","work":"<trabalho>","name":"Sincronizado - Palestra Completa",
"lut":"<CAMINHO_LUT>"}
lut é opcional; remova-o se não usar um. Então uma chamada execute_resolve_code:
PARAMS = "<trabalho>/sync/params.json"
exec(open("<skill>/scripts/resolve_sync_timeline.py").read())
Ele cria o projeto (ou abre se o nome existir), importa os clipes da câmera e os cortes de lapela, e constrói Sincronizado - Palestra Completa: cada clipe na V1 como apenas imagem (mediaType: 1), seu corte na A1 como apenas som (mediaType: 2), mesmos quadros de entrada e saída. recordFrame = início da timeline + arredondar((deslocamento - deslocamento mais antigo) * 24000/1001), para que as lacunas reais entre clipes permaneçam. LUT no nó 1. O áudio bruto da câmera é deixado de fora. A timeline é 1080x1920 quando os clipes são verticais, 1920x1080 caso contrário (substitua com width/height). Se o nome da timeline já existir, ele adiciona v2 em vez de tocar na existente.
Peça ao usuário para verificar alguns pontos com consoantes claras (um "p" ou "t") em cada clipe. Essa é a verificação real.
8. Passe adiante
Informe ao usuário que a timeline existe, os números por clipe da etapa 4 em uma linha cada, qualquer coisa sinalizada e o veredito de corte. Depois prossiga: paper-edit (pule a etapa de transcrição; <trabalho> já está configurado) ou video-reels.
Fatos que valem a pena manter
- A correlação de forma de onda sozinha falhou. A correlação de clipe inteiro e bloco de 20s em uma janela ampla deu lixo inconsistente quando o microfone da câmera estava com média de cerca de -65 dB em uma sala reverberante. Palavras primeiro, depois uma busca estreita de forma de onda, é o que funciona.
- O relógio da câmera geralmente está errado. Nos testes, a câmera estava cerca de 149s atrás do gravador. Algumas câmeras (ex.: Sony) escrevem
creation_timeem UTC (termina emZ), enquanto otime_referenceBWF de um gravador é local. Trate creation_time como uma dica aproximada na melhor das hipóteses. A correspondência de palavras não precisa disso. - A deriva é insignificante no equipamento testado: cerca de 0,5 ms/min, 11 ms em um clipe de 21 minutos. Nenhum alongamento de tempo necessário. Clipes curtos relatam 0 porque um ajuste em alguns segundos é apenas ruído.
- Re-executar os scripts reproduziu cortes feitos à mão com precisão de 6 ms.
- Imagem vertical: ex.: uma Sony gravando vertical grava 4K 23.976 com uma matriz de exibição rotation=90. O Resolve lê como 2160x3840 sem necessidade de correção de rotação.
- Exemplo de gravador, Tascam DR-10L: 48k 24-bit mono BWF, novo arquivo a cada 15 minutos, gêmeo de segurança
_Dcerca de 20 dB abaixo. - O
resolve_build.pydo paper-edit ainda capta som do arquivo da câmera. Em uma gravação de lapela, suas timelines carregam o áudio bruto da câmera até que aprenda a ler o campo"audio". Até lá, informe o usuário, ou religue A1 aos cortes_lav.wav; os pontos de corte são os mesmos porque o tempo do corte é igual ao tempo do clipe. - Whisper executa com
-oj -ml 1 -sowpara temporizações de palavras.
Relacionados
paper-edit: o corte bruto, execute após estevideo-reels: lêclips.ndjson; o campo"audio"diz a ele para captar som do corte (se instalado)