Commit graph

14 commits

Author SHA1 Message Date
chaiman
e09e61103d Вид звукового клипа сохраняется, вставки тишины заказываются
Вид клипа «звук» не умел записываться: в файле проекта он превращался в
«видео». После открытия такой клип терял форму звука, получал ненужную
кнопку кадрирования, а ползунок начинал править прозрачность вместо
громкости. Найдено прямо в файле проекта пользователя.

Уже записанные проекты чинятся при чтении: клип на звуковой дорожке
обязан быть звуковым.

Вторая правка: списки кусков звуковых дорожек ссылаются на вставки
тишины, но о недостающих никто не сообщал, и они не создавались. Список
тогда указывает на несуществующий файл, плеер его не открывает, и
дорожка молчит целиком. Теперь недостающие собираются вместе с
остальными.

Третья: громкости дорожек и сами дорожки собирались разными проходами и
могли разъехаться — тогда дорожка с нулевой громкостью заглушила бы
чужую. Теперь громкости берутся ровно по тому списку, из которого
построены списки кусков.

Проверено на проекте пользователя: виды клипов после чтения верные,
список звуковой дорожки A2 играет сам по себе (-16 dB), и вся связка с
смешиванием тоже (-8.8 dB).
2026-08-20 19:30:30 +03:00
chaiman
f9e50632aa Кадрирование: поворот после обрезки, рамка не расходится с настройкой
Поворот и отражение применялись к исходному кадру, а обрезка шла после
них. Из-за этого рамка показывала одно место, а вырезалось другое.
Теперь наоборот: сначала выбирается кусок, потом он поворачивается и
отражается. Если после поворота кусок лёг поперёк кадра проекта, он
вписывается целиком с полями.

Проверено: с отражением левый и правый края вырезанного куска меняются
местами, то есть отражается именно он, а не оригинал.

Вторая причина расхождения — предел ползунков смещения. Рамку можно было
утащить туда, куда ползунок не дотягивается: рамка рисовалась от
неограниченного значения, а фильтр считался от обрезанного. Предел
расширен вчетверо, а рамка теперь пересчитывается обратно из настройки —
если та упёрлась, это сразу видно.

Отдельно: разбор звука больше не держит главный поток. Перезапуск ждал
окончания текущего файла, а это чтение гигабайтов — окно всё это время не
отвечало, и меню не открывалось вовсе. Теперь проход доигрывает сам и
запускается заново, а идёт он с наинизшим приоритетом.
2026-08-20 19:23:54 +03:00
chaiman
40a0e2041f Цепочка смешивания снимается до загрузки
Чёрное окно и полная тишина оказались следствием того, что цепочка
смешивания звуковых дорожек оставалась от прошлой загрузки. Она
ссылается на дорожки по номерам, а в новом файле таких номеров нет.

Проверено на живом mpv через канал управления: с оставшейся цепочкой
следующая загрузка даёт ноль дорожек, размер кадра недоступен, не играет
ничего. После снятия — кадр 320, звук выбран.

Снимать после загрузки поздно: ломается сама загрузка. Теперь снимается
перед ней.

Проверена вся последовательность: две звуковые дорожки, затем одна, затем
без внешнего звука. Кадр на месте во всех трёх случаях.
2026-08-20 13:17:27 +03:00
chaiman
3583f74864 Звуковые дорожки смешиваются, а не побеждают друг друга
Правило «верхний побеждает» я перенёс на звук механически, и это была
ошибка: оно придумано для картинки, где и делает возможной сборку
копированием. Для звука оно бессмысленно — под голос нельзя было положить
фоновую музыку. И стоит смешивание ничего: звук всё равно перекодируется.

В сборке куски со звуком нескольких дорожек сводятся тем же путём, что
переходы: слоями, каждый со своей громкостью.

В предпросмотре сложнее: плеер играет одну звуковую дорожку за раз.
Поэтому каждая дорожка монтажа подаётся своим списком кусков, а смесь
собирается цепочкой фильтров плеера. Громкость клипов подставляется в ту
же цепочку — иначе предпросмотр врал бы про баланс.

Проверено: два тона на разных дорожках, второй с громкостью 50%. В
готовом ролике -21.2 и -27.1 dB, в предпросмотре -21.2 и -27.2. Совпало.

Найдена по дороге ошибка в собственном условии: я считал слои без
победителя и потому обнулял список, когда звучали ровно две дорожки.
2026-08-20 12:10:57 +03:00
chaiman
79fe091fbb Звуковая дорожка подключается командой, а не свойством
Найдена настоящая причина обеих жалоб на звук. Свойство audio-files,
заданное перед загрузкой, не подключает внешний список кусков вовсе:
проверено на живом mpv через его канал управления — после установки
свойства дорожек по-прежнему две, обе не внешние. Играл звук, встроенный
в саму картинку.

Отсюда обе стороны: звук был слышен там, где на монтаже его нет (шёл из
видеофайла), и не был слышен там, где есть (в этом месте картинкой была
чёрная вставка, а она молчит).

Правильный способ — команда audio-add с признаком select после загрузки.
Проверено: дорожек становится четыре, внешняя звуковая выбрана,
внутренняя снята с выбора.

Если подключить не удалось, в журнал пишется предупреждение. Глушить звук
на этот случай нельзя — прошлая попытка так сделать оставила без звука
весь монтаж.
2026-08-20 11:58:29 +03:00
chaiman
d0dc22630e Убрана заглушка звука, из-за которой пропал звук вообще
Вчерашняя правка глушила звук, когда перебор дорожек не находил внешнюю.
Задумывалось как защита: играть звук из картинки вместо отдельной дорожки
монтажа нельзя. Вышло наоборот — звука не стало нигде.

Перебор может не сработать по причинам, до которых из программы не
дознаться, а mpv и сам предпочитает внешний список, когда тот открылся.
Поэтому выбор оставлен ему, а в журнал пишется, что произошло: если звук
окажется не тот, будет с чего начинать.

Проверено на точном списке кусков, который строит предпросмотр: картинка
2..8 с, звук сдвинут на 4..10 с. Воспроизведение дало тишину до четвёртой
секунды и тон после — ровно то, что на монтаже.
2026-08-20 11:27:55 +03:00
chaiman
cf20a0164e Две ошибки раздельного звука
Первая: при выключенных дорожках картинки не играло вообще ничего. Поток
картинки опустевал, уплощение возвращало неудачу, и предпросмотр
останавливался вместе со звуком, которого выключение не касалось.

Теперь длина берётся по обоим видам дорожек сразу, и недостающее
заполняется чёрным и тишиной. Оба потока всегда одной длины.

Вторая: звук был слышен там, где на монтаже его нет. mpv добавляет
внешний список кусков ещё одной дорожкой, а какую играть, решает сам, и
мог взять звук, встроенный в саму картинку.

Теперь после загрузки внешняя дорожка выбирается явно. Если её не
оказалось, звук выключается совсем: играть вместо него звук из картинки
нельзя — на монтаже его там нет.

Проверено: при выключенных дорожках картинки получается чёрный кадр и
сохранившийся звук (-21 dB); внешний список кусков выбирается верно и в
ту, и в другую сторону.
2026-08-20 11:00:41 +03:00
chaiman
3acf79d174 Этап 5: прозрачность, переходы и затухания
Ползунок на клипе картинки теперь задаёт непрозрачность, на звуковом —
громкость. Уплощение выдаёт для таких мест не одного победителя, а слои.

Слои появляются в трёх случаях: клип полупрозрачен и сквозь него виден
нижний; два клипа на одной дорожке наползли друг на друга и должны
перетечь один в другой; у клипа задано плавное появление или уход.

Перекрытие на разных дорожках переходом не считается — там по-прежнему
побеждает верхний. Иначе в проекте, где дорожки перекрываются постоянно,
каждое такое место пришлось бы пересобирать.

Картинка собирается фильтрами ffmpeg: постоянная доля через overlay,
переход через xfade, затухание через fade. Звук сводится прямо в
отсчётах — доля каждого слоя считается на каждый отсчёт, и длина
результата получается ровно такой, какая нужна.

Перед сборкой программа сообщает, сколько секунд из скольких придётся
пересобрать, и даёт отказаться.

Проверено замерами:
- красный с непрозрачностью 50% поверх синего дал (127, 0, 126);
- переход на одной дорожке: синий плавно перешёл в красный за секунду;
- звуковой переход: -24 dB, -27.5, -35, -51, тишина;
- появление за 2 секунды: пересобрано 2 секунды из 6, остальное
  скопировано.

Найдено по дороге: участок с наложением склеивался с соседним куском и
терял слои — в условии склейки они не учитывались.
2026-08-20 10:11:20 +03:00
chaiman
b6e215a03f Связки клипов и порядок дорожек
Ctrl+G связывает выделенные клипы и развязывает их, если они уже в одной
связке. Связка двигается, режется и удаляется целиком: половина связки —
это разъехавшийся звук, который потом не найти.

Форма звука переехала на звуковые клипы: на клипе картинки ей не место,
звук у него теперь свой и живёт на своей дорожке. Кнопка кадрирования, наоборот,
осталась только у картинки.

Новая дорожка картинки встаёт перед первой звуковой, а не в конец списка:
порядок дорожек задаёт, кто побеждает при перекрытии.

Найдена и исправлена настоящая ошибка: при резе новый кусок терял
громкость и кадрирование — они просто не переносились на хвост.
2026-08-20 09:58:16 +03:00
chaiman
a06ecfd720 Этапы 3 и 4: звук отдельно от картинки
У дорожки появился вид — картинка или звук, у клипа принадлежность к
связке. Проект заводит две дорожки картинки и две звука; при добавлении
файла со звуком клип кладётся парой, связанной общим номером.

Уплощение теперь делается двумя проходами: отдельно для картинки,
отдельно для звука. Одним проходом такое не выразить — в один и тот же
момент картинка берётся с одной дорожки, а звук с другой.

Сборка соответственно тоже раздваивается. Картинка собирается прежним
способом, копированием. Звук собирается в сырой поток и сжимается одним
проходом: куски дописываются друг за другом байтами, и длина каждого
считается из длительности, а не берётся у ffmpeg. Поэтому стык получается
с точностью до отсчёта, а не до звукового кадра, и звук не уезжает от
картинки. Тишина в дырах пишется нулями, без запуска ffmpeg вовсе.

Готовые потоки сшиваются копированием.

Предпросмотр получает второй список кусков как внешнюю звуковую дорожку.

Проекты, записанные раньше, переносятся при чтении: звук там шёл вместе с
клипом картинки и без пары просто пропал бы.

Проверено сборкой:
- картинка из молчащего синего файла 0..6 с, звук из другого файла с 2 по
  6 с. В результате тишина первые две секунды и тон дальше — звук встал
  туда, куда положен, а не туда, где картинка;
- обычный парный случай: клип с 2 по 6 с, тишина до него и тон в нём;
- проверки уплощения пройдены.
2026-08-20 09:50:03 +03:00
chaiman
b7b41f7cf0 Этап 2: кадрирование на клипе с перетаскиваемой рамкой
Настройка кадрирования переехала с файла на клип: два куска одного файла
бывает нужно кадрировать по-разному. У файла осталась такая же, но лишь
как заготовка — её берёт новый клип при добавлении. Проекты, записанные
раньше, читаются: клип без своей настройки берёт её у файла.

Открывается кнопкой в правом нижнем видимом углу клипа. Именно видимом:
у клипа длиной в час настоящий угол почти всегда за краем экрана — та же
задача, что уже решена для ручки громкости.

В окне слева появился кадр источника с рамкой, которую тянут мышью за
середину и за правый нижний угол. Рамка держит пропорции кадра проекта и
пересчитывается в увеличение и смещение; ползунки и рамка следуют друг за
другом.

Кусок пересобирается теперь не только когда файл не совпадает с проектом,
но и когда у клипа своё кадрирование.

Проверено сборкой: первый кусок без кадрирования скопирован, второй с
увеличением вдвое пересобран через scale=1280:720,crop=640:360:384:180.
154 пакета вошло, 154 вышло, декодирование без ошибок.

Заодно: правый щелчок по списку файлов теперь выделяет файл под курсором.
Без этого меню без выделения отключалось целиком и выглядело так, будто
его нет. Цвет формы звука сменён на пастельно-жёлтый.
2026-08-19 23:10:08 +03:00
chaiman
f1ef6e624a Этап 1: форма звука на клипах
Для каждого файла один раз строится список пиков: сто значений в секунду,
каждое есть наибольший модуль отсчёта за свои десять миллисекунд. Рисовать
по настоящим отсчётам нельзя — в секунде их 48 тысяч, а в клипе на экране
сотни пикселей.

Разбор идёт в отдельном потоке и запоминается в кэше проекта. Через
временный файл, а не по трубе: запуск внешних программ режет вывод на
строки, а тут поток байтов, где перевод строки — такой же отсчёт.

Shift со стрелками вверх и вниз растягивает форму по высоте. Звук бывает
тихим, и угадывать за человека нужное усиление неправильно. Меняется
только рисунок, значение сохраняется между запусками.

Проверено: файл «4 с тона, 4 с тишины, 4 с тона» даёт форму в первой и
последней трети и пустоту посередине. Полная амплитуда даёт 254 из 255.
Разбор записи на 892 с занимает 12.7 с — это чтение 6.3 ГБ с диска,
быстрее не выйдет. Первоначальный критерий «меньше двух секунд» в плане
был занижен и исправлен по замеру.

Заодно снят риск четвёртого этапа: mpv принимает edl:// как внешнюю
звуковую дорожку и берёт звук именно из неё. Проверено встречными
списками — картинке «тишина, потом тон», звуку «тон, потом тишина».
2026-08-19 21:23:24 +03:00
chaiman
f7fc7a0503 Свои полосы прокрутки у таблиц и три исправления к ним
Полосы прокрутки рисует система, и цвет им задать нечем. Единственный
способ получить их в своих цветах — не пользоваться системными вовсе.
Таблица при этом остаётся обычной: у неё выключаются свои полосы, а
прокрутка задаётся свойствами TopRow и LeftCol.

По дороге найдены и исправлены три ошибки, две из них — от раскраски окон:

- контекстное меню библиотеки перестало открываться: раскраска
  принудительно создавала системный дескриптор всплывающего меню
  задолго до показа. Теперь дескриптор только читается;
- окно кадрирования падало при открытии: смена режима отрисовки
  выпадающего списка вызывает его обработчик изменения, а тот обращался
  к таймеру, который создавался ниже по коду;
- полосы не появлялись вовсе: размер содержимого таблицы брался из
  GridWidth и GridHeight, а с выключенными полосами те возвращают не
  полный размер. Теперь считается сложением ширин столбцов и высот строк.

Многострочные поля в сведениях о проекте и в перепаковке заменены своим
журналом: у них оставались системные полосы. Заодно ответ ffprobe стало
можно выделить и скопировать.

Удалён неиспользуемый uScrollAid: горизонтальная прокрутка колесом теперь
внутри журнала и одинакова на обеих системах. Список юнитов в файле
проекта приведён в соответствие с тем, что лежит на диске.
2026-08-19 19:16:50 +03:00
chaiman
b59cdb1352 Нелинейный видеоредактор без перекодирования
Куски видео вырезаются и склеиваются копированием потока: сборка ролика
занимает время копирования файла, а не время рендера. Композитинга нет
принципиально — при перекрытии побеждает клип с верхней дорожки целиком,
и картинкой, и звуком. Именно это ограничение и делает сборку копированием
возможной.

Что внутри:

- монтажный стол со своей отрисовкой: дорожки, масштаб, прилипание,
  схлопывание, громкость на клипе;
- предпросмотр прямо с монтажа через libmpv и виртуальный список кусков,
  без промежуточных файлов;
- сборка через ffmpeg с точными резами: перекодируется только огрызок от
  реза до ближайшего опорного кадра, остальное копируется;
- разбор заголовка MP4 для поиска опорных кадров — в 500 раз быстрее
  опроса ffprobe;
- перепаковка контейнеров, кадрирование и поворот, сведения о проекте;
- свои цвета всего окна: системные элементы под Windows цвет не берут,
  поэтому кнопки, полоса меню, журнал и полосы прокрутки нарисованы сами;
- окно зависимостей: недостающие ffmpeg, ffprobe и libmpv скачиваются с
  официальных источников;
- кросс-сборка под Windows и работа под Wine.

Первый коммит: до этого история не велась.
2026-08-19 18:36:16 +03:00