From 3bf28da8ee3af1ee0b0bfffd063a1f10fc103bbc Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Fri, 28 Aug 2026 18:53:44 +0300 Subject: [PATCH] =?UTF-8?q?SprPoP:=20=D1=82=D1=80=D0=B5=D0=BA=20=D0=B7?= =?UTF-8?q?=D0=B0=D1=81=D1=82=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B6=D0=B8=D0=B2=D0=B0=D0=B5=D1=82=20=D0=B7=D0=B0=D0=B3?= =?UTF-8?q?=D1=80=D1=83=D0=B7=D0=BA=D1=83=20=D1=83=D1=80=D0=BE=D0=B2=D0=BD?= =?UTF-8?q?=D1=8F=20=E2=80=94=20=D0=BF=D0=BE=D1=80=D1=8F=D0=B4=D0=BE=D0=BA?= =?UTF-8?q?=20=D0=BA=D0=B0=D0=BA=20=D0=B2=20=D0=BE=D1=80=D0=B8=D0=B3=D0=B8?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ЗАМЕР (MAME, 2026-08-28). Брейк на pop_sfx_fill с печатью totalcycles, 500 подряд вызовов насоса через всю загрузку уровня 1->2 под звучащий трек 27: медиана интервала 245 760 тактов, максимум 245 832 при дедлайне 251 000 (11,7 мс) — НИ ОДНОЙ пропущенной порции. Загрузка уровня насос не морит. Поэтому снята двойная заплатка: * pop_level_switch больше не глушит насос перед pop_level_load_num; * pre_cut_finish больше не досиживает трек на чёрном экране (это делалось только чтобы глушение не обрубило его на полуслове; ценой были ~8 секунд пустого экрана — трек 27 длиннее сцены: 10,7 с против 2,6 с). Взамен восстановлен порядок оригинала (seg003:68-108, play_level): катсцена возвращает управление сразу -> уровень грузится ПОД музыку -> ожидание конца трека на чёрном экране (порт `while (check_sound_playing())` + stop_sounds) -> показ уровня. Общая чернота теперь max(трек, загрузка), а не их сумма, и трек не обрывается. Ожидание со страховкой на ~20 с, чтобы потоковый трек не подвесил переход. Пропуск сцены по-прежнему обрывает музыку — как и было. Co-Authored-By: Claude Opus 5 --- applications/SprPoP/src/pop_intro.c | 22 ++++++++++------- applications/SprPoP/src/sprpop_cold.c | 34 ++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/applications/SprPoP/src/pop_intro.c b/applications/SprPoP/src/pop_intro.c index 451a4af..6dae5f1 100644 --- a/applications/SprPoP/src/pop_intro.c +++ b/applications/SprPoP/src/pop_intro.c @@ -1765,15 +1765,21 @@ uint8_t pop_intro_show(void) __banked * дальше, а не чтобы досидеть до конца трека. */ static void pre_cut_finish(uint8_t aborted) { - if (!aborted) { - intro_skip_t tail; - - intro_skip_begin(&tail); - while (pop_music_busy() && !intro_skip_requested(&tail)) - pop_wait_edge(); + /* ТРЕК ПЕРЕЖИВАЕТ СЦЕНУ — как в оригинале. load_intro (seg001:690) + * ничего не ждёт: гасит экран и возвращает управление, а звук играет + * дальше поверх загрузки уровня и первых секунд игры. Мы вместо этого + * ДОСИЖИВАЛИ трек на чёрном экране (27 — 10,7 с против 2,6 с картинки), + * то есть дарили игроку восемь секунд пустого экрана, и только потом + * глушили. ЗАМЕР 2026-08-28: снято вместе с глушением на загрузке + * уровня; если загрузка не укладывается в дедлайн насоса (251 000 + * тактов), вернуть оба места разом. + * + * Пропуск сцены по-прежнему обрывает и музыку: игрок нажал клавишу, + * чтобы идти дальше, а не чтобы дослушать. */ + if (aborted) { + pop_music_free(); + pop_sfx_pause(); } - pop_music_free(); - pop_sfx_pause(); intro_restore_game_palette(); } diff --git a/applications/SprPoP/src/sprpop_cold.c b/applications/SprPoP/src/sprpop_cold.c index 6561429..dc2033b 100644 --- a/applications/SprPoP/src/sprpop_cold.c +++ b/applications/SprPoP/src/sprpop_cold.c @@ -25,6 +25,7 @@ #include "pop_ctrl.h" /* pop_ctrl_init/close — ввод поднимает и закрывает boot */ #include "pop_shadow.h" /* запечённый набор Тени */ #include "pop_sfx.h" /* звуковые эффекты через CBL */ +#include "pop_music.h" /* pop_music_busy/free — ждём трек заставки */ #include "pop_vflip.h" /* сброс зеркальных страниц на смене уровня */ #include "pop_cheat.h" /* pop_cheats — режим разработки включает pop_boot */ #include "pop_pace.h" /* pop_speed_mode — режим скорости в отладочной метке */ @@ -1227,7 +1228,10 @@ int pop_level_switch(void) __banked * дальше, а урон — нет (do_startpos дольёт до потолка). */ hitp_beg_lev = hitp_max; pop_checkpoint = 0; /* уровень пройден (seg003:413) */ - pop_sfx_pause(); /* загрузка уровня — ESTEX надолго, звук глушим */ + /* ЗАМЕР 2026-08-28: глушение снято ВРЕМЕННО, чтобы измерить + * зазоры насоса на загрузке уровня (дедлайн 251 000 тактов). + * Если зазоры укладываются — снятие остаётся, и трек заставки + * доигрывает поверх загрузки, как в оригинале (seg001:690). */ if (pop_level_load_num(pop_next_level) != 0) { pop_next_level = pop_current_level; /* файла нет — остаёмся */ } else { @@ -1294,6 +1298,34 @@ int pop_level_switch(void) __banked /* Атомарный commit на границе растра: впервые показать * готовую комнату уже с окончательной палитрой уровня. * Вторую страницу синхронизировать аппаратной копией. */ + /* ЖДЁМ КОНЦА ТРЕКА ЗАСТАВКИ НА ЧЁРНОМ ЭКРАНЕ — порт + * seg003:107: + * while (check_sound_playing() && !do_paused()) idle(); + * stop_sounds(); + * draw_level_first(); + * Порядок оригинала важен: загрузка уровня идёт ПОД + * звучащий трек, и только потом чернота до его конца. Тогда + * общее время черноты = max(трек, загрузка), а не их сумма, + * и трек не обрывается на полуслове. Раньше у нас было + * наоборот: pre_cut_finish досиживал трек, потом глушил + * насос и грузил уровень. + * + * ЗАМЕР 2026-08-28: 500 подряд вызовов насоса через всю + * загрузку — максимальный зазор 245 832 такта при дедлайне + * 251 000, ни одной пропущенной порции. Поэтому глушение на + * загрузке снято и музыка её переживает. + * + * Счётчик — страховка от вечного ожидания (потоковый трек, + * который никогда не кончится): ~20 с и идём дальше. */ + { + uint16_t mus_guard = 1000; + + while (pop_music_busy() && mus_guard) { + mus_guard--; + pop_wait_edge(); + } + pop_music_free(); /* порт stop_sounds() */ + } pop_wait_edge(); gfx_set_visible_page(level_prepared_page); gfx_set_draw_page(old_page);