Files
Sprinter-SDCC/applications/SprPoP/src/pop_snd_tbl.h
T
snark13 2349481b86 SprPoP: звуковые эффекты без перелинковки — раскладка уехала на диск
Часть II плана music_runtime_index_plan.md (SI0..SI4).  gen/pop_sound_tbl.h
БОЛЬШЕ НЕ ГЕНЕРИРУЕТСЯ: раскладка набора читается из SND/snd.idx (формат
PSI1, писатель и разборщик — tools/pop_idx.py, 22 теста в make test-tools).
Один и тот же sprpop.exe работает с набором SDLPoP (9 страниц) и MSDOS
(10) — sha256 бинарника при смене набора не меняется.

Заодно умолчание источника эффектов переведено на SDLPoP (SND_SRC=sdlpop):
сборка обязана работать без оригинального дистрибутива DOS.  У кого он
есть, включает лучший набор явно — make SND_SRC=msdos (там полнее
оцифровка: в SDLPoP звук 48 spiked пустой).

Устройство: pop_snd_tbl/pop_snd_page/pop_snd_pages — резидентные данные
(pop_snd_data.c), тип и инварианты — рукописный pop_snd_tbl.h.  Записи
читаются ОДНИМ read прямо в таблицу, поэтому sizeof(pop_snd_ent_t) == 5
стало частью дискового контракта: проверяется статически и полем размера
записи в заголовке.  POP_SND_PAGES как compile-time размер набора исчез —
вместо него POP_SND_MAX_PAGES (вместимость, 16) и runtime pop_snd_pages.

Цена: таблица переехала из _CODE в _DATA, суммарный резидент почти не
изменился (куча 239 -> 229 Б); банк 8 +601 Б на чтение и валидацию.

Валидация не доверяет файлу: заголовок целиком плюс каждая запись
(страница, смещение, кратность блоку, непересечение с блоком тишины,
выход за последнюю страницу).  Последнее считается В БЛОКАХ — байтовый
адрес конца не влезает в uint16, а 32-битная арифметика на Z80 дорога.

НЕТ ИНДЕКСА — ЭФФЕКТОВ НЕТ, НО МУЗЫКА ИГРАЕТ.  Первая версия просто
возвращала ошибку, и игра становилась непроходимой: тишину льёт первый
блок набора, без набора CBL не открывался, а с ним вставала музыка (её
блоки считает тот же насос) — заставка ждала конца трека вечно.  Теперь
поднимается пустой набор с блоком тишины.  Заливается ровно 128 байт и
под DI: gfx_w0_page_prepare ставит в страницу IRQ-стабы, и заливка всей
страницы затирала их — первое же прерывание давало чёрный экран.

Грабли сборки: смена SND_SRC тихо давала неверный результат
(sdlpop -> msdos -> sdlpop оставлял чужой набор в assets/packed).  Причина
не в логике, а в секундной гранулярности mtime.  Лечение убирает время из
решения: смена варианта сносит stamp'ы своего семейства, а упаковка,
сборка архива и копия индекса делаются одним рецептом.  То же получила и
музыка (MUSIC_FMT).

Проверено в MAME: таблица в памяти совпадает с файлом из образа побайтово;
один EXE поднимает оба набора; отладочный --order reverse (30 из 31
записей отличаются от штатных) звучит правильно; битый индекс выключает
эффекты, не роняя игру; без индекса PV-сцена проходит с музыкой; Ctrl+S
работает в обоих режимах.  Разбор — docs/sound_plan.md §10.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY
2026-08-31 16:14:53 +03:00

51 lines
3.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pop_snd_tbl.h — РАСКЛАДКА ОЦИФРОВАННЫХ ЭФФЕКТОВ: тип и инварианты.
*
* Раньше этот файл ПЕЧАТАЛ упаковщик (gen/pop_sound_tbl.h), и конкретные
* page/off/len становились частью EXE — из-за чего замена звукового набора
* (SDLPoP <-> MSDOS) требовала перекомпиляции игры. Теперь значения
* приезжают с диска (SND/snd.idx, формат PSI1 — tools/pop_idx.py), а
* здесь остаётся только то, что от набора НЕ зависит: устройство записи и
* пределы, на которые рассчитан загрузчик.
*
* ЗАПИСЬ ЧИТАЕТСЯ С ДИСКА ПОБАЙТОВО, прямо в pop_snd_tbl[]. Значит
* раскладка структуры в ABI SDCC z80 (uint8 + uint16 + uint16 подряд, без
* выравнивания = 5 байт) — часть дискового контракта, а не деталь
* компилятора. Расхождение молча разъехало бы весь набор, поэтому оно
* ловится статически (pop_snd_data.c) и проверяется загрузчиком по полю
* размера записи в заголовке индекса.
*/
#ifndef POP_SND_TBL_H
#define POP_SND_TBL_H
#include <stdint.h>
/* Пространство id оригинала: 0..56. От набора не зависит. */
#define POP_SND_COUNT 57
/* Блок запроса CBL при 8 бит; страница EMM кратна ему, поэтому ни один
* блок не пересекает границу страницы (см. docs/sound_plan.md). */
#define POP_SND_BLOCK 128
/* СКОЛЬКО СТРАНИЦ ГОТОВ ПРИНЯТЬ ЗАГРУЗЧИК — вместимость, а НЕ размер
* конкретного набора: тот приходит в индексе (pop_snd_pages). Запас
* ради будущих наборов без перекомпиляции; цена — 16 байт таблицы
* страниц вместо 9-10. */
#define POP_SND_MAX_PAGES 16
/* ПЕРВЫЙ БЛОК СТРАНИЦЫ 0 — ТИШИНА. Насос льёт её, когда играть нечего:
* без этого железо доигрывает по кругу хвост своего буфера (жужжание).
* Это инвариант ПРОГРАММЫ — упаковщик обязан оставить блок свободным, а
* загрузчик проверяет, что ни одна запись в него не залезла. */
#define POP_SND_SILENCE_PAGE 0
#define POP_SND_SILENCE_OFF 0x0000
/* page — индекс в pop_snd_page[] (физические страницы EMM), off — начало
* внутри страницы, len — длина PCM. Оба кратны POP_SND_BLOCK; len == 0
* значит «у этого id нет оцифровки» (это музыка, см. sound_plan.md). */
typedef struct {
uint8_t page;
uint16_t off;
uint16_t len;
} pop_snd_ent_t;
#endif /* POP_SND_TBL_H */