◂ База знанийRYA.AEMulticam Word-Sync — синхрон дорожек после съёмки по транскриптамобновлено 12 июл 2026
После мультикам-съёмки клипы нескольких камер и рекордеров надо положить на один таймлайн в синхроне. Часам устройств верить нельзя: они сбиты на минуты и часы, а имена файлов рекордеров врут после рестарта. Единственное, что у всех дорожек общее — сама речь. Раз мы всегда транскрибируем всё с пословной точностью (.words.json, тайминги до миллисекунд), эти транскрипты и становятся якорем синхрона.
📌 Когда применять. Любой съёмочный день с 2+ источниками (камеры, петличка, рекордер), который надо собрать в мультикам-секвенцию: студия на 4 камеры + петля, интервью на 2 камеры без петли, подкаст с внешним рекордером. Требования: пословные транскрипты всех источников + живой creation_time в контейнерах. Не нужно: для одной камеры (линейная сборка) и когда есть общий таймкод (jam-sync).
🎙 .words.json 🧩 n-грамм голоса 🕸 граф часов проверки 📦 v2.0 ingest 🖥 UXP Build

Почему не creation_time и не имена файлов

На одном реальном дне (YTUVI, 4 камеры + DJI-петля) часы четырёх камер были сбиты на разные величины — от +5м49с до +22м00с чистой ошибки кварца (Sony пишет UTC честно, но сам кварц никто не выставлял). Время в именах DJI-файлов после рестарта рекордера врало на ~9.5 минут. На соседнем дне у камеры стоял 2027 год. Wall-clock-сборка по метаданным промахивается на минуты; аудио-кросскорреляция без опоры тонет в дублях и шуме. Речь же одна на всех — и у неё есть точные пословные тайминги.
кварц врёт по-разномуимена файлов врут после рестартаречь = общий якорь

Модель: граф часов

Неизвестных мало, измерений много — решаем как систему.

· У каждой камеры один устойчивый (но сбитый) кварц: истина = creation_time + Δ_cam. Одно Δ на камеру на день — за смену дрейф кварца незаметен (<1с).
· Каждый кусок петли/рекордера k стартует в неизвестный момент T_k (имя файла — только начальное приближение).
· Речевое выравнивание клипа i по куску k даёт измерение r_ik — позицию начала клипа на таймлайне куска: creation_time_i + Δ_cam(i) ≈ T_k + r_ik.

Все Δ и T решаются итерированными медианами (робастно к выбросам), затем trimmed refit: рёбра с резидуалом >5с выкидываются, граф перерешивается. Рамка привязывается к большинству имён файлов — лжецы всплывают как поправки-меньшинство. Клипы без речи (макро, паузы петли) размещаются по часовой модели ct + Δ_cam — она уже откалибрована остальными клипами.

Выравнивание пары и защита от дублей

N-грамм голосование (Hough-стиль). Слова нормализуются (lower, без пунктуации, ё→е), триграммы клипа ищутся в куске; каждое совпадение голосует оффсетом t_chunk − t_clip. Плотный кластер голосов = кандидат-совпадение; медиана кластера = измерение. ASR-ошибки не мешают: голосуют только совпавшие триграммы, а их тысячи.
Дубли — главный враг. В сценарном шоу один текст звучит несколько раз за день; «уверенный» матч цепляется за чужой дубль, и без защиты граф разъезжается на минуты. Защита: кластеры-кандидаты конкурируют по клип-локальным спанам слов. Перекрываются спаны = альтернативные гипотезы одних и тех же слов (эхо дубля) → выживает сильнейший. Спаны раздельны = клип реально пересекает два куска → оба ребра валидны. На один кусок клип даёт максимум одно ребро (линейный клип имеет один оффсет). Уцелевшие эхо добивает trimmed refit.
перекрытие спанов = эхораздельные спаны = два куска1 кусок = максимум 1 ребро

Два режима: с петлёй и без

A
Lav-referenced — есть петля/рекордер
Куски петли = опора (их имена дают начальные T_k, решение их поправляет). Камеры выравниваются против кусков. Так собрана студия YTUVI: 4 камеры × 45 клипов + 9 DJI-кусков → V1–V4 + A1–A4 + петля на A5.
B
Ref-cam — петли нет (2+ камеры пишут звук сами)
Одна камера назначается опорной (--ref-cam): её клипы становятся якорным пулом, рамка = её часы, T фиксированы. Остальные камеры пришиваются рёбрами. Важно: в якорный пул идут все транскрипты опорной камеры (даже клипы, не попавшие в выборку) — больше рёбер, точнее Δ. Так собрано интервью YTUVI-706: ZVE1 пришит к FX3A (кварц ZVE1 спешил на +3м15с).

Система проверок — 5 уровней

Синхрон, который нельзя проверить, не существует. Каждый уровень ловит свой класс ошибок; все пять зелёные → можно строить таймлайн.

1
Selftest на синтетике
wordsync.py --selftest — сгенерированный «день» с врущим именем куска и настоящим эхом дубля. Проверяет и решатель, и защиту от эха (echo_rejections ≥ 1). Гоняется после любого изменения кода.
2
Резидуалы речь ↔ часовая модель
Для каждого клипа: разница речевого размещения и ct + Δ_cam. Норма < 1с (тип. 0.2–0.6с). Большой резидуал = клип пришит к чужому дублю или у камеры нестабильные часы — смотреть руками.
3
Непрерывность сплитов рекордера — контроль истиной
Рекордер режет длинную запись на куски встык (сэмпл-точно). Решение обязано выставить эти пары в ноль: gap ≈ 0. На YTUVI-704 сплит-пары сошлись в +0.006с / −0.054с / +0.014с — независимое подтверждение всей системы. Зазор в секунды = решение неверно.
4
Gauge-инвариантность
Смена рамки (поправка имён, таймзона) не должна двигать клипы друг относительно друга: wall_offset до/после — идентичны до мс. Проверяется diff'ом двух прогонов.
5
Контракт билдера + QC-витрина
validate_ingest.py — все требования UXP-билдера, включая ТИХИЕ отказы (fallback в linear, выпадение петли, «unknown_cam», коллизии имён — билдер резолвит клипы по имени глобально). qc_html.py — тёмная витрина: таймлайн дня, часы камер, поправки имён, рёбра/эхо/резидуалы каждого клипа, первые слова матча.

Инструменты

Репо ~/YTAI/scripts/999_extra/wordsync_multicam/ — README там = полный контракт билдера и грабли. Подробный ранбук для пошагового исполнения (в т.ч. слабыми моделями): scripts/05_editing/0500_uxp/docs/wordsync/WORDSYNC_RUNBOOK.md.
# 1. решить день (петля)
python3 wordsync.py --day /Volumes/DISK/DAY --cam-map "CAM1=CAM1_Name,..."
# 1'. решить день (без петли)
python3 wordsync.py --day /Volumes/DISK/DAY --ref-cam CAM1-FX3A --only-file selected.txt
# 2. ingest + симлинк-раскладка (мультикам-сцена; --add = merge в общий ingest)
python3 make_ingest.py --project PROJ --scene 05_Interview --add \
    --result .../_wordsync/wordsync_result.json --cam-order CAM1,CAM2
# 2'. линейная сцена (selects/b-roll, одна дорожка)
python3 make_ingest.py --project PROJ --scene 04_Stones --add \
    --linear --files-from stones.txt --folder STONES
# 3. проверки + витрина
python3 validate_ingest.py PROJ/00_Setup/01_Ingest/CODE_ingest.json
python3 qc_html.py --result .../wordsync_result.json --tr .../Transcription --out qc.html
# 4. Premiere → UXP «YTAI Assembly» → Ingest → Build Ingest

В Premiere: Build Ingest и точная раскладка дорожек

Ingest готов и провалидирован → дальше всё делает UXP-панель «YTAI Assembly». Дорожки раскладывает не Premiere и не ты — их на 100% задаёт ingest. Ниже — как загрузить, собрать и убедиться, что легло ровно.

1
Загрузить панель
Premiere ≥ 25.6 → открыть {PROJECT}.prproj. Панель грузится через Adobe UXP Developer Tool: Add Plugin → выбрать ~/YTAI/scripts/05_editing/0500_uxp/manifest.jsonLoad. В Premiere появится панель «YTAI Assembly» (id com.ytai.assembly.panel). Если панель уже грузилась раньше — в UDT просто Load/Reload.
2
Вкладка Ingest — автодетект
Панель сама ищет {PROJECT}/00_Setup/01_Ingest/{CODE}_ingest.json (код проекта берётся из имени папки по ^(YT[A-Z]{2,4}\d+)_). Кнопка Build Ingest должна стать активной.

Капкан 1: статус завис на «Detecting files…», Build неактивна → ingest не распарсился. Чаще всего это отсутствие top-level files:{} или битый JSON. Прогони validate_ingest.py — он назовёт точную причину.
Капкан 2: Build прошёл, но секвенция получилась «встык, без петли» → билдер ТИХО ушёл в linear-режим (нет layout_mode:"wallclock" или хоть у одного клипа нет числового wall_offset). Наш генератор это исключает, но если ingest правили руками — validate_ingest поймает.
3
Build Ingest — что построится
По секвенции на каждую сцену, имя = {CODE}_{scene} (напр. YTUVI01_04_Studio). Клипы каждой камеры лягут на свою V-дорожку на позиции wall_offset; недостающие дорожки создаются автоматически, лимита нет.
4
Чем задаётся порядок дорожек (единственный источник правды)
Порядок V1..VN = массив cam_layers[scene] в ingest, слева направо: первый элемент → V1, второй → V2… Задаётся флагом --cam-order у make_ingest.py. Имена в массиве обязаны байт-в-байт совпадать с именами папок-родителей клипов (симлинк-папки камер) — иначе клипы камеры молча выпадут (warning unknown_cam в логе панели).

Звук: аудио каждой камеры автоматически ложится на A-дорожку с номером её V-дорожки (V1→A1, V2→A2…). Петличка — на дорожку A(N+1), где N = число камер (4 камеры → петля на A5), нарезанной полосами строго под видео (там, где видео нет — петли не будет, это норма).

Канон YTUVI: --cam-order "CAM1_VostorgB,CAM2_VostorgA,CAM3_VostorgC,CAM4_FX3" → V1 = B (основная), V2 = A (верхняя, руки), V3 = C (детали), V4 = FX3 (лайв) · A1–A4 звук камер · A5 петля DJI.
5
Проверить, что легло ровно
· Открой секвенцию: число V-дорожек = числу камер, петля на A(N+1) полосами.
· V1 = основная камера (для YTUVI — Vostorg B): включи Solo V1 и убедись по картинке.
· Синхрон ушами: в 3 случайных точках включи A-дорожки двух камер одновременно — не должно быть эха/даблинга; хлопок или стук в кадре совпадает на всех углах; петля A5 совпадает со звуком камер.
· Клип красный «Media Offline» → панель Doctor → Find & Relink local (симлинки живы, это кэш путей Premiere).
6
Если порядок дорожек не тот — НЕ перетаскивай руками
Ручное перетаскивание умрёт при следующем ребилде. Правильный цикл: перегенерировать ingest с нужным --cam-order (wall_offset'ы не изменятся — проверено diff'ом) → в панели снова Build Ingest → панель построит НОВУЮ секвенцию с правильным порядком → старую удалить или переименовать в *_old, чтобы не путаться. Финальная докрутка синхрона (если нужна): панель Offset / Sync Audio / Export Audio Map.

Боевые случаи

YTUVI-704 (студия, 4 кам + DJI). 48 рёбер, ~293 эха дублей отсечено, резидуалы <0.63с. Найдено решением: имена DJI_23/24 врали на +573…576с; все камеры реально стартовали в одну минуту. YTUVI-706 (интервью, 2 кам без петли). ZVE1 пришит к FX3A по 5 рёбрам, кварц ZVE1 +3м15с, резидуалы ≤0.58с. Грабли: мастер-конкат сессии склеен встык — session-время кусочно к wall, решать по кускам, не по мастеру; короткий чисто-сценарный клип может пришиться к чужому дублю — ловится резидуалом; кадровая точность (40мс @ 25p) при необходимости добивается аудио-кросскорреляцией в окне ±2с вокруг речевого оффсета или панельным Offset/Sync Audio.