# Цвет и звук: пресеты, порядок операций, проверка

> **Истинный пик.** `alimiter` меряет *отсчётные* пики: сигнал может лежать под
> потолком на каждом отсчёте, пока восстановленная волна между ними уходит выше.
> Именно это меряет `validate_delivery.py` в dBTP и именно это клиппит
> транскодер платформы. Поэтому `audio_fx.py` лимитирует на четырёхкратной
> частоте (`aresample=192000` → `alimiter` → `aresample=48000`) и берёт 0.3 дБ
> запаса на то, чего четырёхкратная передискретизация всё ещё не видит.
> `resampler=soxr` не просить — он собран не во всех сборках ffmpeg и валит весь
> граф вместо отката на стандартный.
>
> **Плёночные грейды.** `kodak_2383_print`, `fuji_eterna_soft`,
> `kodak_portra_skin`, `bleach_bypass` собраны методом колориста, а не
> подстановкой LUT: носок и плечо тональной кривой → перекрёстное влияние
> каналов (оттенок обязан меняться вместе с яркостью — это и отличает эмуляцию
> от «S-кривой с подкраской») → расщепление тона → лепка насыщенности. Метод
> описан в `assets/grades/grade_presets.json`, ключ `method`.

## Цветокоррекция

12 грейдов в `assets/grades/grade_presets.json`, плюс 5 добавок (виньетка, зерно,
резкость, свечение).

```bash
python scripts/apply_grade.py --list
python scripts/apply_grade.py base.mp4 graded.mp4 --grade teal_orange \
  --extras grain_light --contact-sheet grade_cmp.jpg
```

### Порядок операций — не рекомендация, а условие

1. Приведение к канвасу (`scale`/`crop`) — иначе грейд считается по лишним пикселям.
2. Грейд.
3. Зерно и виньетка, если нужны.
4. **Прожиг субтитров — поверх готовой картинки.**

Грейд поверх уже прожжённого текста сдвигает цвет титров от того значения, под которое
пресет рисовался. Грейд, применённый дважды (в базовом рендере и на мастере),
удваивает контраст и хоронит тени — это самая частая ошибка на этом шаге.

### Проверка измерением, а не на глаз

`apply_grade.py` считает по кадру до и после: средняя яркость, контраст (СКО яркости),
средняя насыщенность, доля пикселей, выбитых в чистый чёрный и чистый белый,
5-й и 95-й процентили.

Предупреждения приходят автоматически:

* больше 1.5% кадра в чистом чёрном — тени потеряны;
* больше 1% в чистом белом — света срезаны;
* насыщенность выросла больше чем в 1.6 раза — проверь кожу.

`--strength 0.6` подмешивает грейд обратно к оригиналу — так пресет приглушается без
переписывания кривых.

### Что где применять

| Грейд | Когда |
|---|---|
| `neutral_clean` | База, честная картинка |
| `teal_orange` | Универсальный «дорогой» вид, контраст кожи и фона |
| `warm_film` | Интервью, история, воспоминание |
| `cold_tech` | Техника, IT, ночной город |
| `moto_punch` | Скорость, дорога, спорт |
| `soft_pastel` | Лайфстайл, красота, еда |
| `high_key_clean` | Продукт, презентация |
| `noir_contrast` | Драма, серьёзная тема |
| `vhs_camcorder` | Ретро — но титры прожигай ПОСЛЕ, шум съедает читаемость |
| `night_city` | Огни, вечер |
| `documentary_flat` | Максимум информации в тенях |
| `print_editorial` | Как журнальная страница |

## Звук речи

9 обработок голоса и 6 акцентов в `scripts/audio_fx.py`. Видео всегда копируется —
перекодировать картинку, чтобы изменить звук, значит потерять поколение качества
даром.

```bash
python scripts/audio_fx.py --list
python scripts/audio_fx.py cut.mp4 out.mp4 --plan audio_plan.json \
  --accents accents.json --loudness reels
```

### Обработки применяются к интервалам и сшиваются кроссфейдом

Цепочка, которая переключается мгновенно, слышна как глитч, а не как эффект.
Кроссфейд по умолчанию 120 мс.

| Обработка | Для чего |
|---|---|
| `clean` | База для любой речи |
| `podcast_tight` | Плотный разговорный звук |
| `warm_radio` | Тёплый эфирный тон |
| `telephone` | Телефон, голосовое сообщение |
| `megaphone` | Объявление, крик в толпу |
| `whisper_intimate` | Интимный шёпот |
| `vinyl_lofi` | Ретро-подача |
| `robot` | Механический голос |
| `underwater` | За стеной, «выключенное» состояние |

Акценты подмешиваются **поверх** голоса, а не заменяют его: `pitch_drop`,
`pitch_rise`, `reverse_tail`, `stutter`, `hall_hit`, `radio_squelch`.

### Замер подтверждает, что цепочки делают заявленное

На реальной записи (телефонный микрофон, полоса до ~7 кГц) относительный порядок
верен: `telephone` даёт самую узкую полосу (234–5049 Гц), `whisper_intimate` — больше
всего верха (до 6907 Гц), `warm_radio` — самый мягкий верх и самый тихий уровень.
На исходнике с широкой полосой разница будет заметнее.

## Громкость

| Цель | I (LUFS) | TP (dBTP) | LRA |
|---|---|---|---|
| `reels` | −14 | −1.0 | 9 |
| `youtube` | −14 | −1.0 | 11 |
| `broadcast` | −23 | −2.0 | 7 |
| `loud` | −12 | −1.0 | 7 |

Отдавать громче цели бессмысленно: платформа всё равно приглушит, и микс потеряет
динамику. Итоговая громкость измеряется через `ebur128` и сравнивается с целью;
`on_target` означает расхождение не больше 1 LU.

## Порядок звуковых шагов

1. Обработка речи (`audio_fx.py`) — до сведения с чем-либо ещё.
2. Шина SFX (`mix_sfx_track.py`), задакированная под речь.
3. Музыкальный бэд там же, тоже задакированный.
4. Финальная нормализация громкости — **один раз**, в последнем шаге.

Два `loudnorm` в цепочке дают непредсказуемый результат: второй считает статистику по
уже обработанному сигналу.
