ba3aca07bf
ЗАМЕР, из которого всё выросло (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>
62 lines
4.1 KiB
C
62 lines
4.1 KiB
C
/*
|
|
* pop_music.h — музыкальный трек через тот же CBL, что и эффекты.
|
|
*
|
|
* ПОЧЕМУ PCM, А НЕ AY. Оцифровки музыки в игре нет вовсе: digisnd*.dat
|
|
* содержит только эффекты, музыка лежит MIDI под Adlib. Зато есть готовые
|
|
* записи DOS-версии, и путь «запись -> сырой поток CBL» не требует ни
|
|
* синтезатора на хосте, ни аранжировки под три канала AY (разбор вариантов
|
|
* — ../docs/sound_plan.md §1). Плата известна: CBL один, поэтому пока
|
|
* играет музыка, эффектов нет. Оригинал ведёт себя так же — play_sound
|
|
* там глушит предыдущий звук.
|
|
*
|
|
* ГДЕ УМЕСТНО. Заставки и титры: эффектов там не бывает, картинка
|
|
* статична, и загрузка сотни-другой килобайт с диска никому не мешает.
|
|
* Музыка ПО ХОДУ игры (джинглы смерти, зелья) — отдельный вопрос, её
|
|
* придётся либо гасить эффектами, либо уводить на AY.
|
|
*
|
|
* ФОРМАТ на диске — пачка кусков m<id>_<nn>.bin по 16 КБ (bank_load_file
|
|
* читает файл только целиком и только в одну страницу). Каталог с
|
|
* длинами генерирует toolchain/pop_pack_music.py в pop_music_tbl.h.
|
|
*/
|
|
#ifndef POP_MUSIC_H
|
|
#define POP_MUSIC_H
|
|
|
|
#include <stdint.h>
|
|
|
|
/* Сколько страниц EMM держим под трек. Двадцать = 320 КБ, это все
|
|
* заставочные треки, кроме финального «won» (115 с, 1,2 МБ): тот придётся
|
|
* либо резать, либо стримить, и это отдельная задача. */
|
|
#define POP_MUS_PAGES 20
|
|
|
|
/* Номера треков — нумерация оригинала (SDLPoP data/music/names.txt). */
|
|
#define POP_MUS_STORY_1 55 /* «In the absence of the Sultan...» */
|
|
|
|
/* Курсор проигрывания — читает НАСОС (pop_sfx.c, резидент), пишет
|
|
* загрузчик. Отдельный от эффектов: они звучат поверх музыки, а не
|
|
* вместо неё, и у каждого свой источник. */
|
|
extern uint8_t pop_mus_page[POP_MUS_PAGES]; /* физические страницы EMM */
|
|
extern volatile uint8_t pop_mus_pg; /* индекс текущей страницы */
|
|
extern volatile uint16_t pop_mus_ptr; /* адрес в окне W0 */
|
|
extern volatile uint16_t pop_mus_left; /* порций до конца, 0 — молчим */
|
|
/* Номер играющего трека (нумерация оригинала). Нужен менеджеру звука:
|
|
* музыка участвует в таблицах приоритета наравне с эффектами. */
|
|
extern uint8_t pop_mus_id;
|
|
|
|
/* Загрузить трек в EMM (НЕ запускает). Звать там, где допустима пауза на
|
|
* диск: CBL в это время обязан быть закрыт, иначе насос не успевает долить
|
|
* блок и железо повторяет старый — на слух скрежет (pop_sfx.h).
|
|
* 0 — готово, -1 — нет трека/памяти/файла. */
|
|
int8_t pop_music_load(uint8_t id) __banked;
|
|
|
|
/* Отпустить страницы. Останавливает проигрывание, если оно шло. */
|
|
void pop_music_free(void) __banked;
|
|
|
|
/* Пустить загруженный трек с начала / оборвать. */
|
|
void pop_music_play(void) __banked;
|
|
void pop_music_stop(void) __banked;
|
|
|
|
/* Трек ещё звучит? 0 — доиграл или не запускался. */
|
|
uint8_t pop_music_busy(void) __banked;
|
|
|
|
#endif /* POP_MUSIC_H */
|