SprPoP: музыка без перелинковки — длины и длительности уехали на диск
Часть I плана music_runtime_index_plan.md (MI0..MI5). gen/pop_music_tbl.h и gen/pop_music_ticks.h УДАЛЕНЫ: длины треков и длительности реплик читаются из MUS/mus.idx (формат PMI1, tools/pop_idx.py, тесты в make test-tools). Один и тот же sprpop.exe работает с любым из четырёх наборов записей — sha256 бинарника при смене MUSIC_FMT не меняется. ГДЕ ЖИВЁТ ИНДЕКС. 228 байт таблицы в W2 не положить (свободной кучи там порядка двух сотен), поэтому индекс лежит в одной странице EMM, а в резиденте от него два байта. Данные в странице — со смещения 0x100: gfx_w0_page_prepare пишет в неё стабы прерываний (0x38 и 0x66), и с нуля они попали бы прямо в записи id 10 и 21. Со смещением работает штатная защита, а не запрет прерываний (тот же приём, что CFG_BASE в pop_config.c). Число страниц в индексе не хранится — считается из blocks, чтобы не разъехалось. ПАУЗА КОНЦА УРОВНЯ — СОСТОЯНИЕМ, А НЕ СЧЁТЧИКОМ. pop_endmus_left и POP_MUS_TICKS_32/41 удалены; главный цикл ждёт pop_music_active() — «заявка лежит, идёт загрузка или трек звучит». Одного busy мало: между заявкой и первой нотой 190-230 мс (замер в sound_plan §9). Прежний счётчик закрывал эту щель ценой зависимости EXE от набора и жёсткого делителя /4, который врал в режимах FAST/FASTEST (там логический кадр 3 кадра луча, а не 4). Побочно исправилось расхождение с SDLPoP: при выключенном звуке заявка не кладётся, и уровень меняется сразу, как в оригинале (seg006:651 + seg003:387) — раньше игра держала пройденный уровень лишние 12 секунд в тишине. PV-СЦЕНА — на четырёх якорях (8 байт статики), которые считаются из индекса при входе в сцену; прежние выражения шкалы не изменились. План предлагал протащить структуру времён через пять функций — для сцены, которая идёт раз за запуск, это того не стоит. ПАМЯТЬ. За обе фазы резидент не вырос, а освободился: _CODE 23865 -> 23544, куча 239 -> 256 Б. Банк 9 похудел на 118 Б (ушла pop_mus_tbl из rodata), банк 11 — на длительности реплик. ПРОВЕРЕНО В MAME: exe побайтово одинаков для flac и mt32; все 22 трека в индексах различаются, и контрольные значения совпали с предсказанными планом (m41 732->685, m50 831->867, m53 985->1044, m56 9865->10462 блоков, 78->82 страницы); на mt32 PV-сцена проходит целиком по его длительностям; без mus.idx музыки нет, эффекты работают, игра проходима. НЕ ПРОВЕРЕНО: потоковый m56 на 82 страницах — до финала надо дойти в игре. Единственный оставшийся пункт приёмки, отмечен в sound_plan §11.5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY
This commit is contained in:
@@ -366,7 +366,6 @@ int main(void)
|
||||
* девелоперская сборка может до title держать дворец LEVEL=11. */
|
||||
if (pop_app_state == POP_APP_DEMO) {
|
||||
pop_next_level = 0;
|
||||
pop_endmus_left = 0;
|
||||
pop_seamless = 0;
|
||||
pop_checkpoint = 0;
|
||||
if (pop_level_switch() != 0) {
|
||||
@@ -787,14 +786,22 @@ int main(void)
|
||||
* сколько звучит трек конца уровня; мы же уходили на смену
|
||||
* уровня сразу и обрывали мелодию на первых нотах.
|
||||
*
|
||||
* «Звучит» проверяем двумя способами: pop_music_busy() пока
|
||||
* трек играет и счётчик pop_endmus_left по длине записи (его
|
||||
* взводит play_seq вместе с самим треком) — иначе с
|
||||
* ВЫКЛЮЧЕННОЙ музыкой паузы не было бы вовсе, а оригинал
|
||||
* выдерживает её и молча. */
|
||||
if (pop_endmus_left) pop_endmus_left--;
|
||||
if (!pop_endmus_left && !pop_music_busy() &&
|
||||
pop_level_change(back) != 0) {
|
||||
* «Звучит» — это pop_music_active(), а не busy: между заявкой
|
||||
* на трек и первой нотой проходит 190-230 мс на открытие
|
||||
* файла и чтение первой полустраницы, и в этой щели busy ещё
|
||||
* ложен (замер — docs/sound_plan.md §9). Раньше щель
|
||||
* закрывал счётчик по длине записи, но он же тянул за собой
|
||||
* зависимость EXE от набора музыки и жёсткий делитель `/4`,
|
||||
* враньё которого вылезало в быстрых режимах (там кадр 3
|
||||
* луча, а не 4). Состояние «заявка/загрузка/звучание»
|
||||
* закрывает щель без единой константы.
|
||||
*
|
||||
* ЗВУК ВЫКЛЮЧЕН — ПАУЗЫ НЕТ, и это тоже верно: pop_sfx_play
|
||||
* не кладёт заявку при !pop_snd_ok, все три признака ложны, и
|
||||
* уровень меняется сразу. Ровно так в оригинале, где трек
|
||||
* ставится под `if (is_sound_on)` (seg006:651), а ожидание —
|
||||
* `check_sound_playing()` (seg003:387). */
|
||||
if (!pop_music_active() && pop_level_change(back) != 0) {
|
||||
failed = 1; quit = 1; break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user