From ea07a8d7b04a50303ff35ac29c61dd87f35a60ba Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Fri, 28 Aug 2026 17:29:04 +0300 Subject: [PATCH] =?UTF-8?q?SprPoP:=20=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=B1?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20=D0=BD=D0=B5=20=D0=B3=D0=BB?= =?UTF-8?q?=D1=83=D1=88=D0=B8=D1=82=20=D0=B7=D0=B2=D1=83=D0=BA=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=80=D0=B5=D0=BC=D1=8F=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ui_begin() звал pop_sfx_pause() перед полностраничной accel-копией, и это слышно: pause закрывает CBL целиком (cbl_close), курсор трека стоит, и короткая мелодия начала уровня замирала ровно на время перерисовки меню — а на перемещении по пунктам это повторялось на каждом кадре меню. Обоснование заплатки устарело. Лист, который зовёт gfx_copy_page (_bgi_scroll_rows_raw), режет DI бандами по 16 строк — ~1,6 мс против дедлайна насоса 11,7 мс (85,4 порции в секунду), между бандами есть окно прерываний. Тот же полностраничный копир каждый кадр делают игровой цикл и катсцены, и звук там не рвётся. Скрежет, под который заплатка ставилась, шёл от чтения насосом мусора и вылечен отдельно. Парный pop_sfx_start() в ui_end оставлен: он идемпотентен и чинит вход в меню при закрытом выводе (например сразу после загрузки уровня). Co-Authored-By: Claude Opus 5 --- applications/SprPoP/src/pop_menu.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/applications/SprPoP/src/pop_menu.c b/applications/SprPoP/src/pop_menu.c index 82fda82..18bcc6f 100644 --- a/applications/SprPoP/src/pop_menu.c +++ b/applications/SprPoP/src/pop_menu.c @@ -197,10 +197,21 @@ static uint8_t ui_begin(void) gfx_rect_t full; uint8_t back = (uint8_t)(gfx_get_visible_page() ^ 1); - /* Полностраничная accel-копия держит DI дольше половины CBL-буфера. - * Закрываем вывод, иначе железо повторяет старые 128 байт (скрежет). - * ui_end откроет его уже с заново заполненной тишиной. */ - pop_sfx_pause(); + /* ЗВУК ЗДЕСЬ БОЛЬШЕ НЕ ГЛУШИМ (снято 2026-08-28). + * + * Был вызов pop_sfx_pause() с обоснованием «полностраничная accel-копия + * держит DI дольше половины CBL-буфера, иначе железо повторяет старые + * 128 байт». Обоснование устарело: лист, который зовёт gfx_copy_page + * (_bgi_scroll_rows_raw), режет DI бандами по 16 строк — это ~1,6 мс + * против дедлайна насоса 11,7 мс, и окно прерываний между бандами есть. + * Тот же полностраничный копир каждый кадр делают игровой цикл и + * катсцены, и звук там не рвётся. + * + * А цена была слышимой: pause закрывает CBL целиком (cbl_close), курсор + * трека остаётся на месте, и короткая мелодия начала уровня замирала + * ровно на время перерисовки меню — «тормозится на кусочек» (жалоба + * пользователя 2026-08-28). У оригинала такого нет и быть не может: + * там нет насоса, который надо кормить руками. */ gfx_set_draw_page(back); full.x = 0; full.y = 0; full.w = GFX_WIDTH; full.h = GFX_HEIGHT; gfx_copy_page(&full, GFX_COPY_DIRECT); @@ -230,6 +241,10 @@ static void ui_end(uint8_t back) { ui_wait_frame(); /* готовый кадр показать только на фронте */ gfx_set_visible_page(back); + /* Парный к снятому pop_sfx_pause (см. ui_begin) вызов оставлен: он + * идемпотентен (открытый CBL возвращает 0 сразу) и чинит случай, когда + * в меню вошли при закрытом выводе — например сразу после загрузки + * уровня, которая глушит звук намеренно. */ (void)pop_sfx_start(); }