Музыка по ходу игры: смерть, зелья, меч, конец уровня, катсцены

Звуки 24..43 в наборе оцифровки пустые — в оригинале это Adlib-музыка, и
в digisnd её нет. На этом и построено подключение: pop_sfx_play для звука
с нулевой длиной кладёт номер в pop_mus_req, а разбирает заявку
pop_music_service() — один вызов на кадр из любого цикла (игра, интро,
катсцена). Всё чтение с диска живёт там.

Ждать полной загрузки джингла нельзя — это фриз посреди игры. Поэтому
pop_music_stream читает первую страницу (33 мс) и сразу пускает трек: она
звучит 1,5 с, а следующая читается те же 33 мс. Остальные доливаются по
одной за кадр.

Расставлено по местам оригинала: смерть (24/28/32), вступление первого
уровня и тень шестого (25), сцены перед уровнями (27/35/40), встреча с
Джафаром (29), зелья (30/33/39), время вышло (36), меч и смерть стража
(37), смерть Джафара (43), конец уровня (41/32), встреча с принцессой
(26). Темы «раз за уровень» сбрасывает pop_music_level_start.

Упакован 21 трек (2,4 МБ). Не озвучен только финал: won — 115 с и 78
страниц EMM, ему нужен кольцевой стриминг (задача MUS-WON на доске).

Проверено в MAME: вступительная тема первого уровня отыгрывается на
старте (курсор дошёл до конца, id 25). Host-тесты: 15 наборов.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 21:52:37 +03:00
parent 65797af44c
commit 7e6b38cca6
33 changed files with 300 additions and 35 deletions
+43
View File
@@ -845,3 +845,46 @@ EMM: `pop_music_load*` всегда пишет в НЕ играющий, `pop_mu
курсор `pop_mus_id` меняется ровно на своих кадрах, интро доходит до
демо-режима. Слуховая проверка (нет ли хрипа от диска при играющей
музыке) — за пользователем.
## 7. МУЗЫКА ПО ХОДУ ИГРЫ (2026-08-26)
Звуки 24..43 в наборе оцифровки ПУСТЫЕ — в оригинале это Adlib-музыка, и
в digisnd её нет вовсе. На этом и построено подключение: `pop_sfx_play`
для звука с нулевой длиной не пытается его играть, а кладёт НОМЕР в
`pop_mus_req` (один байт). Заявку разбирает `pop_music_service()` — один
вызов на кадр из любого цикла (игрового, интро, катсцены); всё чтение с
диска живёт там.
**Стриминг вместо загрузки.** Ждать полной загрузки джингла нельзя — это
фриз на треть секунды посреди игры. `pop_music_stream` читает ПЕРВУЮ
страницу (33 мс) и сразу пускает трек: она звучит 1,5 с, а следующая
читается те же 33 мс — запас сорокакратный. Остальные доливаются по
одной за кадр, пока `pop_music_loading()`. Номера страниц известны сразу
после `mem_alloc_pages`, поэтому таблица для насоса заполняется целиком —
данные появятся раньше, чем насос до них дойдёт.
**Что и где играет** (номера и места — из SDLPoP):
| трек | событие | место у нас |
|------|---------|-------------|
| 24 / 28 / 32 | смерть: обычная / в бою / от руки тени | `ctrl_kid_death` |
| 25 | вступление 1-го уровня (Кид сидит), тень 6-го | `control_crouched`, `guards.c` |
| 27 / 35 / 40 | сцены перед 2/4/6/12, 8/9, «времени мало» | `pop_pre_cutscene_show` |
| 29 | встреча с Джафаром | `pop_meet_jaffar` |
| 30 / 33 | большая склянка / малая | `pop_proc_get_object` |
| 36 | время вышло | `pop_time_expired_show` |
| 37 / 43 | меч найден, страж убит / смерть Джафара | `pop_proc_get_object`, `on_guard_killed` |
| 39 | перо (медленное падение) | `pop_proc_get_object` |
| 41 / 32 | конец уровня / конец 4-го (тень) | опкод SND_LEVEL в `play_seq` |
| 26 | встреча с принцессой | `cut_ending` |
Темы, которые звучат один раз за заход на уровень (вступление 1-го, тень
6-го), сбрасывает `pop_music_level_start()` из `pop_start_level`. Оригинал
для этого портит переменную двери (`leveldoor_open = 0x4D`) — у нас на это
есть свои два байта.
**Чего пока нет.** Финальный `won` (56): 115 с, 1,2 МБ, 78 страниц EMM —
в `POP_MUS_PAGES` (20) он не помещается даже теоретически. Ему нужен
КОЛЬЦЕВОЙ стриминг: держать в памяти несколько страниц и дочитывать в те,
что насос уже прошёл. Это отдельная задача — курсор насоса придётся
научить заворачиваться, а загрузчик — держать дистанцию от него.