Архивы ресурсов 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
+15 -3
View File
@@ -48,6 +48,9 @@ uint8_t pop_snd_want;
volatile uint8_t pop_mus_pg;
volatile uint16_t pop_mus_ptr;
volatile uint16_t pop_mus_left;
/* Номер играющего трека в нумерации ОРИГИНАЛА: музыка участвует в тех же
* таблицах приоритета и перебиваемости, что и эффекты (см. pop_sfx_tick). */
uint8_t pop_mus_id;
static volatile uint8_t sfx_pg; /* индекс в pop_snd_page[] */
static volatile uint16_t sfx_ptr; /* адрес в окне W0: 0x0000..0x3FFF */
@@ -210,9 +213,18 @@ void pop_sfx_tick(void)
if (!snd_next1) return;
id = (uint8_t)(snd_next1 - 1);
snd_next1 = 0; /* номинант живёт ровно кадр */
if (sfx_left != 0 && /* что-то играет... */
(!snd_interruptible(snd_curr) || snd_prio[id] > snd_prio[snd_curr]))
return; /* ...и уступать не обязано */
/* ЧТО СЕЙЧАС ЗВУЧИТ — эффект либо музыка. У оригинала это один и тот
* же вопрос: check_sound_playing() отвечает «играет хоть что-то», без
* различия типа, а музыкальные id лежат в тех же таблицах приоритета и
* перебиваемости (seg000:1672 + data.h:433). Почти вся музыка помечена
* НЕперебиваемой, поэтому пока она играет, эффект просто не стартует —
* ровно это слышно в оригинале. Исключение одно: 29 meet_Jaffar. */
{
uint8_t cur = sfx_left ? snd_curr : pop_mus_id;
if ((sfx_left != 0 || pop_mus_left != 0) &&
(!snd_interruptible(cur) || snd_prio[id] > snd_prio[cur]))
return; /* ...и уступать не обязано */
}
snd_curr = id;
pg = pop_snd_tbl[id].page;
off = pop_snd_tbl[id].off;