Communitygithub.com

라펠 싱크

별도 녹음기(Tascam DR-10L 등)의 오디오 트랙과 카메라 영상을 동기화하고, DaVinci Resolve에서 싱크된 타임라인을 구축합니다.

라펠 싱크란 무엇인가요?

이 스킬은 라이브 강연, 이벤트, 워크숍 등에서 카메라에 내장된 마이크와 분리된 라펠 마이크(또는 필드 레코더) 오디오를 정밀하게 동기화합니다. 녹음기의 분할 파일을 이어 붙이고, 각 클립에 대한 라펠 오디오 조각을 추출하며, 모든 후속 작업(페이퍼 에딧, 비디오 릴스)이 수정 없이 동작할 수 있도록 준비합니다. 주요 기능으로는 단어 및 파형 기반 정렬, 클리핑 감지, DaVinci Resolve 프로젝트 생성 등이 포함됩니다. `ffmpeg`, `whisper.cpp`, Python, 그리고 DaVinci Resolve MCP 서버를 필요로 하며, 초기 20ms 이내의 정밀도로 동기화가 가능합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/beachyphotoandfilm-arch/video-skills/tree/HEAD/skills/lapel-sync

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

라펠 싱크은(는) 무엇을 하나요?

카메라 클립과 분리된 녹음기 트랙을 입력받아, 클립당 하나의 라펠 오디오 조각과 싱크된 Resolve 타임라인을 출력합니다. 라이브 강연에서 처음 테스트되었습니다: 5개의 카메라 클립을 59분 분량의 녹음기 트랙과 동기화했으며, 모든 클립이 20ms 이내(1프레임 미만)로 정확히 정렬되었습니다.

중요한 이유: 라이브 이벤트에서 카메라 마이크는 방 건너편에 있습니다. 그 오디오는 사용할 수 없으며, 라펠 마이크가 유일한 깨끗한 사운드입니다. 이 스킬을 적용하면 <work>/<clip>.wav와 <clip>.json이 라펠 오디오를 가리키므로, 페이퍼 에딧과 비디오 릴스는 아무것도 변경된 것을 모르고 깨끗한 오디오와 깨끗한 트랜스크립트를 읽을 수 있습니다.

설정: 다음을 입력하세요

항목설명예시
<FOOTAGE_DRIVE>원본 영상이 있는 드라이브, 비디오당 하나의 폴더, 녹음기 파일은 audio/ 하위 폴더에 있음/Volumes/MyWorkDrive
<SYNC_OUT>고품질 라펠 오디오 조각이 저장될 위치~/Movies/<video>-sync
<LUT_PATH>선택 사항인 LUT, Resolve의 LUT 폴더 기준 상대 경로MyLuts/SLog3-to-709.cube
WHISPER_MODEL (환경 변수)whisper.cpp 모델 파일기본값 ~/.cache/whisper-models/ggml-small.en.bin

필요 사항: ffmpeg, ffprobe, whisper-cli (whisper.cpp), Python 3 (numpy와 scipy는 ~/.cache/lapel-sync-venv에 자동 설치됨), execute_resolve_code를 노출하는 DaVinci Resolve MCP 서버, 그리고 paper-edit 스킬 (ensure_resolve.sh를 위해).

실행

작업 디렉토리: 세션 스크래치패드, 예: <scratchpad>/<video>. 아래 스킬 디렉토리는 .claude/skills/lapel-sync입니다. 고품질 오디오 조각은 <SYNC_OUT>으로 이동합니다.

zsh 주의: 인라인 셸에서 $ss:end_sample는 :e를 수식어로 해석하여 조용히 텍스트를 먹어버립니다. 항상 ${ss}로 쓰세요.

1. 영상과 오디오 찾기

<FOOTAGE_DRIVE>에 비디오당 하나의 폴더가 있습니다. 녹음기 파일은 audio/ 하위 폴더에 있습니다:

find "<FOOTAGE_DRIVE>" -maxdepth 4 -iname "*<keyword>*" -not -path "*/.*"
ls "<folder>" "<folder>/audio"

예를 들어 Tascam DR-10L은 000_YYMMDD.wav, 001_...와 같이 15분마다 분할된 파일과 _D 쌍을 기록합니다. _D 파일은 이중 녹음 안전 트랙으로, 약 20dB 낮습니다. 기본 파일을 사용하고 클리핑된 부분을 패치하기 위해 _D를 보관하십시오.

2. 녹음기 파일 이어 붙이기

bash <skill>/scripts/stitch.sh "<folder>/audio" "<SYNC_OUT>/lav-master.wav"

각 파일의 BWF time_reference(자정 이후 샘플 수)를 읽고 모든 파일이 마지막 파일이 끝난 정확한 지점에서 시작하는지 확인합니다. 샘플이 연속적이면 무손실 스트림 복사가 이루어집니다. 갭이 있으면 해당 시간만큼 무음을 삽입하여 마스터가 실제 시간에 맞도록 유지하고 경고를 표시합니다.

3. 양쪽 트랜스크립션

bash <skill>/scripts/transcribe_sources.sh "<folder>" "<SYNC_OUT>/lav-master.wav" "<work>"

모든 것은 <work>/sync/로 이동하며, 페이퍼 에딧의 sentences.py가 읽지 못하도록 <work> 자체에는 보관되지 않습니다. 카메라 오디오는 먼저 강력하게 증폭됩니다(highpass=f=120,volume=40dB,alimiter, 16k 모노). 카메라 오디오는 종종 약 -65dB이기 때문입니다. 이미 완료된 작업은 건너뛰므로 자유롭게 다시 실행할 수 있습니다.

라펠 오디오는 오디오 1시간당 약 8분이 소요됩니다. 백그라운드에서 실행하세요. Whisper는 단어 타임스탬프를 <work>/sync/lav.log로 스트리밍하고, align.py는 lav.json이 아직 작성되지 않은 경우 해당 로그를 읽어 라펠 오디오가 완료되기 전에 정렬을 시작할 수 있습니다. 트랜스크립션 지점을 지난 클립은 "N개의 단어 일치만 있음"이라고 보고합니다. 완료되면 다시 실행하세요.

4. 정렬

python3 <skill>/scripts/align.py "<work>"

<work>/sync/sync.json을 작성합니다. 첫 번째 실행은 ~/.cache/lapel-sync-venv를 생성하여 numpy와 scipy를 설치합니다(시스템 python3에는 종종 둘 다 없음). 그 후에는 내부에서 자체적으로 다시 실행됩니다.

작동 방식(출력을 신뢰하거나 의문을 가질 수 있도록):

  • 단어 우선. 두 트랜스크립트에 모두 나타나는 고유한 4단어 실행을 찾습니다. 오프셋 = 라펠 시간 - 카메라 시간. 클립당 수백 개의 일치 항목; 가장 밀집된 클러스터를 유지하고, 0.5초 이내, 중앙값을 사용합니다. 약 0.1초 정확도.
  • 파형 미세 조정. 카메라 오디오의 각 20초 청크(40초 미만 클립의 경우 6초 청크)를 300-3000 Hz, 8kHz로 대역 통과 필터링한 후, 단어 오프셋의 +-0.6초 이내에서 라펠 오디오와 교차 상관 관계를 계산합니다. 중앙값의 6배를 초과하는 피크를 찾습니다. 20ms 이내의 청크는 서로 일치합니다. 5분 이상의 클립에서는 선형 피팅(linear fit)으로 오프셋과 드리프트를 제공합니다.

출력되는 모든 줄을 읽으십시오: 오프셋, 일치하는 청크 수, 분산, 드리프트. CHECK BY EAR로 표시된 클립(일치하는 청크가 3개 미만)은 최대 0.1초 정도 어긋날 수 있습니다. 신뢰하기 전에 Resolve에서 스크러빙하여 확인하십시오. 클립 전체에서 한 프레임 이상의 드리프트가 있는 경우에도 플래그가 표시됩니다.

5. 클립별로 라펠 오디오 자르기

python3 <skill>/scripts/slice.py "<work>" "<SYNC_OUT>/lav-master.wav" "<SYNC_OUT>"

각 클립에 대해 다음을 작성합니다:

  • <SYNC_OUT>/<clip>_lav.wav: 24비트, 원본 샘플레이트, 클립 길이에 샘플 정확하게 일치하여 라펠 시간이 클립 시간과 같음
  • <work>/<clip>.wav (16k 모노) 및 <work>/<clip>.json (슬라이스의 whisper): 페이퍼 에딧과 비디오 릴스가 읽는 파일
  • "audio" 필드가 슬라이스를 가리키는 <work>/clips.ndjson

녹음기가 클립에 대해 늦게 시작했거나 일찍 중지된 경우, 해당 부분은 무음으로 채워지고 경고가 표시됩니다. 슬라이스에 대한 Whisper 작업은 몇 분이 소요됩니다. 이후에 페이퍼 에딧의 transcribe.sh를 실행하지 마십시오(json이 이미 존재하므로 어차피 건너뛸 것입니다).

6. 클리핑 확인

slice.py는 슬라이스당 0.99 풀 스케일 이상의 샘플 수를 계산하고 가장 긴 실행을 출력합니다. 수백 개의 짧은 실행(수십 개의 샘플)은 일반적으로 녹음기의 리미터가 피크를 잡는 것이며, 왜곡이 아닙니다. 1ms 이상의 실행이 나열된 경우나 사용자가 소리가 깨진다고 말하는 경우에만 _D 쌍에서 해당 순간을 패치하십시오(동일한 타이밍, 약 20dB 증폭).

7. Resolve에서 구축

bash .claude/skills/paper-edit/scripts/ensure_resolve.sh

<work>/sync/params.json을 작성합니다:

{"project":"<Video> - YYYY-MM-DD","work":"<work>","name":"Synced - Full Talk",
 "lut":"<LUT_PATH>"}

lut은 선택 사항입니다. 사용하지 않으면 생략하십시오. 그런 다음 execute_resolve_code 호출 한 번:

PARAMS = "<work>/sync/params.json"
exec(open("<skill>/scripts/resolve_sync_timeline.py").read())

프로젝트를 생성하거나(이름이 이미 존재하면 열기), 카메라 클립과 라펠 오디오 슬라이스를 가져오고, Synced - Full Talk 타임라인을 구축합니다: 각 클립은 V1에 그림 전용(mediaType: 1), 해당 슬라이스는 A1에 사운드 전용(mediaType: 2), 동일한 in/out 프레임을 가집니다. recordFrame = 타임라인 시작 + round((오프셋 - 가장 이른 오프셋) * 24000/1001)이므로 클립 간의 실제 간격이 유지됩니다. LUT는 노드 1에 적용됩니다. 카메라 스크래치 오디오는 비활성화됩니다. 클립이 세로인 경우 타임라인은 1080x1920, 그렇지 않으면 1920x1080입니다(width/height로 재정의 가능). 타임라인 이름이 이미 사용 중이면 기존 타임라인을 건드리지 않고 v2를 추가합니다.

사용자가 각 클립에서 명확한 자음("p" 또는 "t")이 있는 몇 군데를 스크러빙하여 확인하도록 하십시오. 이것이 실제 확인입니다.

8. 인계

사용자에게 타임라인이 존재하고, 4단계의 클립별 숫자가 각각 한 줄씩, 플래그가 지정된 사항, 클리핑 판정을 알려줍니다. 그런 다음 페이퍼 에딧(트랜스크립션 단계는 건너뛰기; <work>가 이미 설정됨) 또는 비디오 릴스로 이동합니다.

알아둘 가치가 있는 사실

  • 파형 상관 관계만으로는 실패했습니다. 카메라 마이크가 잔향이 있는 방에서 평균 약 -65dB일 때, 넓은 창에 걸친 전체 클립 및 20초 청크 상관 관계는 일관성 없는 쓰레기를 생성했습니다. 단어를 먼저 찾은 다음 좁은 파형 검색을 하는 것이 효과적입니다.
  • 카메라 시계는 종종 잘못되었습니다. 테스트에서 카메라는 녹음기보다 약 149초 느렸습니다. 일부 카메라(예: Sony)는 creation_time을 UTC(끝에 Z)로 기록하는 반면, 녹음기의 BWF time_reference는 로컬 시간입니다. creation_time은 대략적인 힌트로만 취급하십시오. 단어 일치에는 필요하지 않습니다.
  • 드리프트는 테스트된 장비에서 무시할 만합니다. 약 0.5ms/분, 21분 클립에서 11ms입니다. 시간 스트레칭이 필요하지 않습니다. 짧은 클립은 몇 초에 걸친 피팅이 단순히 노이즈이기 때문에 0으로 보고합니다.
  • 스크립트를 다시 실행하면 수동으로 만든 슬라이스와 6ms 이내로 재현되었습니다.
  • 세로 영상: 예를 들어, 세로로 촬영하는 Sony는 rotation=90 디스플레이 매트릭스로 4K 23.976을 기록합니다. Resolve는 회전 수정 없이 2160x3840으로 읽습니다.
  • 예시 녹음기, Tascam DR-10L: 48k 24비트 모노 BWF, 15분마다 새 파일, _D 안전 쌍은 약 20dB 낮음.
  • 페이퍼 에딧의 resolve_build.py는 여전히 카메라 파일에서 사운드를 가져옵니다. 라펠 촬영의 경우, "audio" 필드를 읽도록 업데이트될 때까지 해당 타임라인은 카메라의 스크래치 오디오를 전달합니다. 그때까지는 사용자에게 알리거나 A1을 _lav.wav 슬라이스로 다시 연결하십시오. 슬라이스 시간이 클립 시간과 같기 때문에 컷 포인트는 동일합니다.
  • Whisper는 단어 타임스탬프를 위해 -oj -ml 1 -sow와 함께 실행됩니다.

관련 스킬

  • paper-edit: 러프 컷, 이 스킬 후에 실행
  • video-reels: clips.ndjson을 읽습니다. "audio" 필드는 슬라이스에서 사운드를 가져오도록 지시합니다(설치된 경우)

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

beachyphotoandfilm-arch/video-skills

Turn raw talking-head footage into an assembled rough cut inside DaVinci Resolve. Pulls the clips off your footage drive, transcribes them locally, removes failed takes, restarts, asides and dead air, then creates a new Resolve project with two paper-edit timelines ready for your fine trim. Trigger on "paper edit", "cut my raw footage", "make a rough cut", "clean up this video", or when the user points at a folder of raw camera files for a YouTube video.

beachyphotoandfilm-arch/video-skills

Design a unique Instagram cover for each reel in your house style. Reads what the reel is about, writes a short hook headline, picks one of your own photos from a tagged photo library, lays it out like your existing covers, and proofs it in grid view at phone size. Renders locally, never with AI image generation. Can be called by a scheduling skill before reels are scheduled. Trigger on "make covers", "reel covers", "cover photo for this reel", "design the IG covers".

beachyphotoandfilm-arch/video-skills

Render finished reels out of DaVinci Resolve, write captions in the creator's voice, attach a custom Instagram cover from reel-covers, and schedule them to Instagram, TikTok and YouTube Shorts through Metricool. Handles the Drive upload hop, collision checks against the existing calendar, and cleanup. Trigger on "schedule the reels", "post these", "put these on the calendar", or after reels are approved.

beachyphotoandfilm-arch/video-skills

Build animated brand overlays (motion graphics) for a talking-head video, timed to the speaker's exact words, plus a DaVinci Resolve import file. House style is in-scene type (text beside and behind the speaker's head) plus diagrams. Transcribes the rough cut locally, picks the moments, renders transparent .mov clips, and writes an FCPXML that drops every clip onto the timeline already in position. Trigger on "make animations for this video", "add overlays/motion graphics", "animate this", "b-roll graphics for my YouTube video", or when the user shares a rough cut and asks for graphics.

beachyphotoandfilm-arch/video-skills

Cut vertical Instagram reels out of a long-form talking-head video, hook first. Picks the strongest standalone moments from the transcript, opens each reel on its punchiest line, builds vertical timelines in DaVinci Resolve framed on the speaker's face with the LUT applied, and finishes them: a hook (a held text card, or a word-by-word "build" hook with punch-in) and burned-look captions on V3; this-or-that reels get product graphics and a comment-keyword CTA card. You trim and render, nothing to import. Trigger on "make reels", "clip this for Instagram", "cut some verticals", or after a YouTube video is cut.

beachyphotoandfilm-arch/video-skills

Design YouTube thumbnails and titles for a talking-head video. Pulls graded full-res frames out of the raw footage, renders brand-styled variants in two proven layouts, and proofs them at phone size where the click actually gets decided. Trigger on "make thumbnails", "thumbnail for this video", "title and thumbnail", or after a video is cut.

beachyphotoandfilm-arch/video-skills

Run the whole YouTube video pipeline end to end, one stage at a time, stopping for the creator's approval at every gate. Paper edit, punch-ins, reels, reel covers, scheduling the reels, overlays, thumbnail and title, then scheduling the long-form video, all through Metricool. Keeps state per video so you can stop anywhere and pick up later. Trigger on "/youtube", "let's do the whole video", "run the video pipeline", "continue the <name> video", or when handed raw footage for a YouTube video.

관련 스킬