Две системы звука. Один таймлайн.
Камера пишет черновой звук, петличка или рекордер — чистый. Их кварцевые часы расходятся: за час набегает до секунды ползучего, порой нелинейного дрейфа. WhisperSync находит точное совпадение вдоль всей записи — по словам, а не по волне — и отдаёт готовый FCPXML для Final Cut Pro или DaVinci Resolve.
- Python 3.10–3.14
- faster-whisper / CTranslate2
- Windows · macOS · Linux
- GUI + CLI
- CI: black · ruff · mypy
- 11.8 msостаточная ошибка на реальной съёмке
- 412словесных якорей на клип
- 3+1стратегии + акустический fallback
- 24-bitбит-перфект: каналы и битность сохраняются
// как это работает
Слова вместо волны: шесть шагов
Волновые синхронизаторы цепляются за начало и теряют хвост. WhisperSync транскрибирует обе дорожки пословно, общие слова становятся якорями времени — и работает там, где волна сдаётся: эхо, дальний микрофон, шумный зал.
- TranscribeWhisper: обе дорожки → слова с таймкодами (кэш SHA-256)
- Anchorsобщие слова двух транскриптов — якоря; грубый поиск по редким словам, потом точный
- RANSACробастная оценка K (отношение часов) и offset, выбросы отсеиваются в два прохода
- Strategyплан кусков: где резать, что растягивать, что впитают паузы
- Renderбит-перфект сборка: прозрачный ресемпл вместо time-stretch
- FCPXMLпроект со всеми дорожками — импорт в FCP / Resolve
// интерактив
Симулятор: как стратегия пересобирает звук
Синие блоки — фразы на видео камеры. Зелёные — куски звука рекордера, как их уложит выбранная стратегия. Потяните дрейф и переключите стратегию: красным подсвечиваются куски, разъехавшиеся с картинкой. Это упрощённая версия симулятора, встроенного в GUI программы.
// стратегии
Три честных способа и один запасной
После каждого прогона WhisperSync сверяет характер измеренного дрейфа с выбранной стратегией — и прямо говорит, если другая подошла бы лучше. Перепрогон дешёвый: транскрипты в кэше.
- Стратегия 1Global Linear
Один конформ-коэффициент на весь файл. Для честного линейного дрейфа — самый частый случай. Быстро, минимум обработки.
- Стратегия 2Local Time-Stretch
Каждому сегменту между якорями — свой коэффициент. Для нелинейного дрейфа; границы кусков прищёлкиваются к паузам между словами.
- Стратегия 3Hybrid
Рекордер режется только в настоящих паузах между фразами. Фразы конформятся прозрачным ресемплом, а весь остаток дрейфа впитывают паузы — растянутый room tone не слышен.
…а если совпадений по тексту нет вовсе — музыка, шум, язык, который Whisper коверкает, — включается «стратегия 0»: акустический fallback через GCC-PHAT кросс-корреляцию. Грубее якорей, но превращает жёсткий отказ в рабочую укладку.
// интерфейс
PyQt6: тёмная тема, живой таймлайн
Перетащили папку с видео и файл(ы) рекордера, нажали SYNC — мультитрек-таймлайн показывает каждый клип на реальной позиции, применённое изменение скорости (например, +0.10%) и статус: ждёт, в работе, готово.



// звук и не только
Бит-перфект до последнего сэмпла
- 🎚️Родное качество насквозь
24-битный стерео-рекордер выйдет 24-битным стерео: без принудительного моно, без даунмикса. Куски режутся из lossless PCM-мастера.
- 🌀Ресемпл вместо стретча
Реальный дрейф — доли процента. Прозрачный «varispeed» сдвигает питч на неслышимые центы; WSOLA с его фазовыми артефактами — только когда правка действительно велика.
- ✂️Швы — только в тишине
Границы кусков прищёлкиваются к паузам между словами, а Boundary Flex акустически доводит каждый стык с субкадровой точностью (GCC-PHAT).
- 🎥Мультикам и мультирекордер
Папка на камеру — дорожка на камеру. Несколько петличек: режим best (сильнейший рекордер на клип) или all (каждый на своей дорожке).
- 🌫️Ambience-дорожка
AI-разделение источников убирает из камеры её эхо-голос, оставляя атмосферу зала — отдельной дорожкой рядом с чистым голосом.
- 🧪Проверяемый результат
--verifyизмеряет реальный лип-синк после рендера (медиана/p90/max);--dry-runи--json— для автоматизации.
// cli
Одна команда — и в монтажку
$ python main.py --cli --video-dir ./videos --audio-file recorder.wav === Sync Complete === Anchors: 412 K: 1.000237 # отношение часов камеры и рекордера Offset: 12.8470 s Residual: 11.8 ms # меньше кадра — идеальный лип-синк Output: output/sync_output.fcpxml
Часы ручной синхронизации — в один клик