Архивы ресурсов PBA1: звук одним файлом, музыка потоком; ALLOCS 6000

ЗАМЕР, из которого всё выросло (MAME, 2026-08-25): `open` стоит 51,4 мс,
а чтение 16 КБ из уже открытого файла — 32,6 мс.  То есть 61 % времени
загрузки уходит на ОТКРЫТИЕ, а не на данные, и чистая скорость чтения —
491 КБ/с, а не 260.  На диске игры 343 файла; одна только стартовая пачка
(kid+shadow+bg+sound+guard, ~142 файла) — это 7,3 секунды чистого open.

* toolchain/pop_pack_arc.py + pop_arc.c/h (банк 8) — формат PBA1:
  заголовок 512 Б, магия, count, записи по 4 байта (offset в СЕКТОРАХ —
  архив бывает больше 64 КБ; size в байтах — ресурс всегда <= 16 КБ,
  он обязан лезть в EMM-страницу).  Таблицу держит вызывающий на своём
  стеке: в W2 её класть нельзя, а стека в точке загрузки израсходовано
  75 байт из 1279 (замер там же).
* libc: bank_read_page — чтение из УЖЕ ОТКРЫТОГО файла в EMM-страницу.
  bank_load_file переписана через неё, поэтому дублирования работы с W3
  не осталось и резидент почти не вырос.
* Набор эффектов: 10 файлов -> SND\snd.arc, один open вместо десяти.
* Музыка: трек лежит ОДНИМ файлом и читается порциями по странице —
  нарезка на куски больше не нужна.  Этот же путь понадобится финалу
  `won` (1,2 МБ), который в память целиком не влезает.
* Менеджер звука приведён к оригиналу: играющая музыка участвует в
  таблицах приоритета наравне с эффектами (seg000:1672 + data.h:433).
  Почти вся музыка НЕперебиваема, поэтому поверх неё эффект не стартует —
  ровно как в SDLPoP; раньше эффект её перебивал.
* ALLOCS 3000 -> 6000 (решение пользователя): сборка +20 с, резидент
  -161 байт.  Куча 87 -> 248 Б.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 17:13:25 +03:00
parent 34ba5f71d5
commit ba3aca07bf
25 changed files with 357 additions and 67 deletions
+10 -8
View File
@@ -12,11 +12,15 @@
берём не 11 000, а частоту железа: тогда CBL открывается ОДИН раз за
запуск и не переключается ни между эффектами, ни при переходе на музыку.
РЕЖЕМ НА СТРАНИЦЫ EMM по 16 КБ. bank_load_file умеет читать файл только
целиком и только в одну страницу, поэтому трек на диске лежит пачкой
кусков M<id>_<nn>.BIN — ровно как набор эффектов лежит s0..s9.bin.
Последний кусок дополняется тишиной (0x80) до кратности 128: насос отдаёт
CBL блоками по 128 байт, и остаток «не полного блока» ему пришлось бы
ОДИН ФАЙЛ НА ТРЕК. Резать его на куски не нужно: читаем порциями по
16 КБ из ОДНОГО открытого файла (`bank_read_page` + `lseek`), и «дорогой»
open платится раз на трек, а не на каждую страницу — замер 2026-08-25:
open 51,4 мс против 32,6 мс на чтение 16 КБ. Этот же путь работает для
финального `won` (1,2 МБ), который в память целиком не помещается и
обязан подгружаться по ходу.
Хвост дополняется тишиной (0x80) до кратности 128: насос отдаёт CBL
блоками по 128 байт, и остаток «не полного блока» ему пришлось бы
досчитывать в прерывании.
Длина трека уходит в pop_music_tbl.h блоками по 128 байт, а не байтами:
@@ -90,9 +94,7 @@ def pack(track_id: int, name: str) -> tuple[int, int]:
chunks = (len(data) + PAGE - 1) // PAGE
OUT_DIR.mkdir(parents=True, exist_ok=True)
for i in range(chunks):
part = data[i * PAGE:(i + 1) * PAGE]
(OUT_DIR / f"m{track_id:02d}_{i:02d}.bin").write_bytes(part)
(OUT_DIR / f"m{track_id:02d}.bin").write_bytes(bytes(data))
return chunks, len(data) // BLOCK