Музыка: PCM-трек через CBL, первый экран истории озвучен
Путь C из sound_plan.md вместо ранее выбранного A (ноты спикера на AY). Причина смены: появились готовые записи DOS-версии, и строка «нужен синтезатор на хосте», из-за которой C считался дорогим, отпала — осталось `ffmpeg -ac 1 -ar 10937 -f u8`. Оцифровки музыки в самой игре нет вовсе: digisnd*.dat содержит только эффекты, музыка лежит MIDI под Adlib, так что конвертировать ресурс игры всё равно было не из чего. * toolchain/pop_pack_music.py — запись flac -> сырой u8 на 10 937,5 Гц (частота CBL, чтобы её не переключать никогда), нарезка на куски MUS\m<id>_<nn>.bin по 16 КБ: bank_load_file читает файл только целиком и только в одну страницу. Каталог -> pop_music_tbl.h; длина трека хранится ПОРЦИЯМИ по 128 байт — 169 КБ в uint16 не влезает, 1350 блоков влезает (32-бит арифметики на Z80 избегаем). * pop_music.c (банк 9) — загрузка трека в EMM и курсор; pop_sfx_fill (резидент) получил третий источник: эффект важнее музыки, музыка важнее тишины. Эффект музыку не сбрасывает — её курсор стоит, пока тот доигрывает, и она продолжается с места. * story_1_absence звучит на первом экране истории, где была тишина. Грузим ПОСЛЕ сборки картинки: чтение идёт через ESTEX, и при открытом CBL насос не успел бы долить блок. Проверено записью звука из MAME: корреляция огибающих с эталоном 0,836 при сдвиге 1,8 с, RMS 22,6 против 18,3 (разница — 8-битное квантование). Эффекты двери в PV-сцене после трека звучат по-прежнему. Бюджет: резидент +83 Б кода и +25 Б данных, запас W2 151 Б (кучи в приложении нет, malloc не слинкован); банк 9 занят на 88 %. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <cbl.h>
|
||||
#include <irq.h> /* IRQ_DISABLE/IRQ_ENABLE вокруг курсора */
|
||||
#include "pop_sfx.h"
|
||||
#include "pop_music.h"
|
||||
#include "_pop_sfx.h"
|
||||
|
||||
/* Физические страницы набора; заполняет холодная половина. */
|
||||
@@ -42,6 +43,12 @@ uint8_t pop_snd_want;
|
||||
* Всё в 8/16 бит — 32-битной арифметики на Z80 избегаем (см. memory
|
||||
* avoid_32bit_arith_z80); поэтому и в таблице смещение уже разобрано на
|
||||
* страницу и адрес в окне. */
|
||||
/* Курсор МУЗЫКИ. Лежит здесь, а не в pop_music.c, по той же причине, что
|
||||
* и курсор эффектов: его читает насос из прерывания, то есть резидент. */
|
||||
volatile uint8_t pop_mus_pg;
|
||||
volatile uint16_t pop_mus_ptr;
|
||||
volatile uint16_t pop_mus_left;
|
||||
|
||||
static volatile uint8_t sfx_pg; /* индекс в pop_snd_page[] */
|
||||
static volatile uint16_t sfx_ptr; /* адрес в окне W0: 0x0000..0x3FFF */
|
||||
static volatile uint16_t sfx_left; /* сколько байт осталось (кратно 128) */
|
||||
@@ -66,15 +73,39 @@ static volatile uint16_t sfx_left; /* сколько байт осталось
|
||||
* тесном резиденте W2 отказала бы и уронила весь звук. */
|
||||
int pop_sfx_fill(uint16_t n)
|
||||
{
|
||||
uint8_t saved, pg;
|
||||
uint8_t saved, phys;
|
||||
uint16_t ptr;
|
||||
if (sfx_left) { pg = sfx_pg; ptr = sfx_ptr; }
|
||||
else { pg = POP_SND_SILENCE_PAGE; ptr = POP_SND_SILENCE_OFF; }
|
||||
|
||||
/* Три источника по убыванию важности: эффект, музыка, тишина. Эффект
|
||||
* перебивает музыку — как у оригинала, где play_sound глушит всё, что
|
||||
* звучало; голос-то один. Музыка при этом НЕ теряет позицию: её
|
||||
* курсор стоит, пока эффект доигрывает, и она продолжается с места. */
|
||||
if (sfx_left) {
|
||||
phys = pop_snd_page[sfx_pg]; ptr = sfx_ptr;
|
||||
} else if (pop_mus_left) {
|
||||
phys = pop_mus_page[pop_mus_pg]; ptr = pop_mus_ptr;
|
||||
} else {
|
||||
phys = pop_snd_page[POP_SND_SILENCE_PAGE];
|
||||
ptr = POP_SND_SILENCE_OFF;
|
||||
}
|
||||
saved = _io_page_w0;
|
||||
_io_page_w0 = pop_snd_page[pg];
|
||||
_io_page_w0 = phys;
|
||||
cbl_push_otir((const void *)ptr, n);
|
||||
_io_page_w0 = saved;
|
||||
if (!sfx_left) return 1; /* играли тишину — курсор не двигаем */
|
||||
if (!sfx_left) {
|
||||
if (!pop_mus_left) return 1; /* тишина — курсор не двигаем */
|
||||
/* Длину трека считаем ПОРЦИЯМИ насоса, а не байтами: 169 КБ в
|
||||
* uint16 не влезает, а 1350 блоков — легко (32-бит арифметики на
|
||||
* Z80 избегаем, тем более в прерывании). */
|
||||
pop_mus_left--;
|
||||
pop_mus_ptr += n;
|
||||
if (pop_mus_ptr >= 0x4000) {
|
||||
pop_mus_ptr = 0;
|
||||
if ((uint8_t)(pop_mus_pg + 1) < POP_MUS_PAGES) pop_mus_pg++;
|
||||
else pop_mus_left = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sfx_ptr += n;
|
||||
if (sfx_ptr >= 0x4000) { /* граница страницы — ровно по блоку */
|
||||
|
||||
Reference in New Issue
Block a user