Synchronize OPL4 track finalization
This commit is contained in:
Binary file not shown.
BIN
Binary file not shown.
+15
-19
@@ -29,6 +29,7 @@
|
||||
.globl _isr_play_seconds
|
||||
.globl _isr_read_ptr
|
||||
.globl _isr_done
|
||||
.globl _isr_final_pending
|
||||
.globl _cmd_buf_a
|
||||
.globl _cmd_buf_b
|
||||
.globl _isr_init
|
||||
@@ -56,7 +57,7 @@ WC_IM2_VEC = 0x5BFF
|
||||
CMD_WRITE_AY = 0x00
|
||||
CMD_INC_SEC = 0x10
|
||||
CMD_WRITE_AY2 = 0x20
|
||||
CMD_CALL_WC = 0x30
|
||||
CMD_FINALIZE = 0x30
|
||||
CMD_WRITE_B0 = 0x40
|
||||
CMD_SKIP_TICKS= 0x50
|
||||
CMD_WRITE_SAA = 0x60
|
||||
@@ -301,8 +302,8 @@ _isr_cmd_loop:
|
||||
jp z, _isr_cmd_done
|
||||
cp #CMD_INC_SEC
|
||||
jp z, _isr_inc_sec
|
||||
cp #CMD_CALL_WC
|
||||
jp z, _isr_call_wc
|
||||
cp #CMD_FINALIZE
|
||||
jp z, _isr_cmd_finalize
|
||||
; Unknown command: skip 3 bytes, continue
|
||||
inc de
|
||||
inc de
|
||||
@@ -589,29 +590,23 @@ _skip_spec_next:
|
||||
; ISR зацикливается на этой команде, не переключает буферы.
|
||||
; Main loop ждёт isr_done == 1 перед завершением.
|
||||
_isr_cmd_done:
|
||||
inc de
|
||||
inc de
|
||||
inc de ; пропустить 3 байта параметров
|
||||
; Выставить флаг готовности к завершению
|
||||
ld a, #1
|
||||
ld (_isr_done), a
|
||||
; Перемотать read_ptr на начало CMD_ISR_DONE (DE - 4)
|
||||
jr _isr_cmd_freeze
|
||||
|
||||
;--- CMD_FINALIZE: музыкальный поток полностью исполнен -----------------
|
||||
; Замереть на маркере и попросить main собрать shutdown как при ESC.
|
||||
_isr_cmd_finalize:
|
||||
ld a, #1
|
||||
ld (_isr_final_pending), a
|
||||
|
||||
_isr_cmd_freeze:
|
||||
; DE уже указывает на первый параметр: вернуть read_ptr на opcode.
|
||||
ex de, hl
|
||||
dec hl
|
||||
dec hl
|
||||
dec hl
|
||||
dec hl
|
||||
ld (_isr_read_ptr), hl
|
||||
jp _isr_exit
|
||||
|
||||
;--- CMD_CALL_WC: вызов оригинального WC handler [0,0,0] ------------------
|
||||
; Внутренняя команда ISR (не используется buffer filler, зарезервировано)
|
||||
_isr_call_wc:
|
||||
inc de
|
||||
inc de
|
||||
inc de ; пропустить 3 байта параметров
|
||||
jp _isr_cmd_loop ; просто пропустить
|
||||
|
||||
;==============================================================================
|
||||
; call_wc_handler() — Вызов WC ISR из main loop (C-callable)
|
||||
;
|
||||
@@ -641,6 +636,7 @@ _isr_play_seconds:: .dw 0 ; инкрементируется CMD_INC_SE
|
||||
_isr_read_ptr:: .dw 0
|
||||
_isr_wait_ctr:: .dw 0
|
||||
_isr_done:: .db 0 ; 1 = ISR замер на CMD_ISR_DONE, готов к завершению
|
||||
_isr_final_pending:: .db 0 ; 1 = последний VGM 0x66 уже исполнен
|
||||
_pos_ptr: .dw 0 ; инициализируется в isr_init()
|
||||
_isr_saved_vec: .dw 0 ; сохранённый вектор WC (#5BFF)
|
||||
|
||||
|
||||
+5
-2
@@ -34,7 +34,7 @@
|
||||
* CMD_WRITE_AY │ reg │ val │ 0 │ OUT AY8910 chip 1
|
||||
* CMD_INC_SEC │ 0 │ 0 │ 0 │ Инкр. isr_play_seconds
|
||||
* CMD_WRITE_AY2 │ reg │ val │ 0 │ OUT AY8910 chip 2 (TS)
|
||||
* CMD_CALL_WC │ 0 │ 0 │ 0 │ Вызов WC ISR handler
|
||||
* CMD_FINALIZE │ 0 │ 0 │ 0 │ Конец VGM → shutdown в main
|
||||
* CMD_WRITE_B0 │ reg │ val │ 0 │ OUT OPL3 Bank 0
|
||||
* CMD_SKIP_TICKS│ N │ smsk_lo│ smsk_hi│ Пропустить N позиций pos_table
|
||||
* CMD_WRITE_SAA │ reg │ val │ 0 │ OUT SAA1099 chip 0
|
||||
@@ -81,7 +81,7 @@
|
||||
#define CMD_WRITE_AY 0x00 /* AY8910 chip 1: [reg, val, 0] */
|
||||
#define CMD_INC_SEC 0x10 /* Инкрементировать счётчик секунд: [0,0,0] */
|
||||
#define CMD_WRITE_AY2 0x20 /* AY8910 chip 2 (TurboSound): [reg,val,0]*/
|
||||
#define CMD_CALL_WC 0x30 /* Вызов WC ISR handler: [0,0,0] */
|
||||
#define CMD_FINALIZE 0x30 /* Конец VGM: остановить ISR и уведомить main */
|
||||
#define CMD_WRITE_B0 0x40 /* OPL3 Bank 0 write: [reg, val, 0] */
|
||||
#define CMD_SKIP_TICKS 0x50 /* Пропустить N pos_table: [N,sml,smh] */
|
||||
#define CMD_WRITE_SAA 0x60 /* SAA1099 write: [reg, val, 0] bit7=chip */
|
||||
@@ -136,6 +136,9 @@ extern volatile uint16_t isr_play_seconds;
|
||||
* Main loop очищает при старте воспроизведения. */
|
||||
extern volatile uint8_t isr_done;
|
||||
|
||||
/** ISR дошёл до последнего 0x66; main должен запустить shutdown. */
|
||||
extern volatile uint8_t isr_final_pending;
|
||||
|
||||
/** Командные буферы A и B. Заполняются main loop, читаются ISR. */
|
||||
extern uint8_t cmd_buf_a[CMD_BUF_SIZE];
|
||||
extern uint8_t cmd_buf_b[CMD_BUF_SIZE];
|
||||
|
||||
@@ -1755,6 +1755,16 @@ ym2_fm_passthru:;
|
||||
vgm_wait_accum = fb_wacc;
|
||||
}
|
||||
vgm_hl_pos++;
|
||||
/* Финальная silence-цепочка должна начинаться с пустого
|
||||
* ISR-буфера. Иначе большой cmdblock может быть разрезан
|
||||
* границей буфера и при следующем fill стартует сначала. */
|
||||
if (fb_is_vgm && vgm_hl_pos == vgm_hl_abort_pos) {
|
||||
/* ISR замрёт здесь после исполнения всего музыкального
|
||||
* хвоста. Main затем запустит shutdown как при ESC. */
|
||||
fb_wp[0] = CMD_FINALIZE;
|
||||
fb_wp += 4;
|
||||
goto finish;
|
||||
}
|
||||
goto next_hl;
|
||||
}
|
||||
|
||||
|
||||
+11
-12
@@ -675,6 +675,7 @@ void start_playback(void)
|
||||
isr_active_buf = 0;
|
||||
isr_wait_ctr = 0;
|
||||
isr_done = 0;
|
||||
isr_final_pending = 0;
|
||||
|
||||
/* MultiSound ctrl: включить FM/SAA только для присутствующих чипов.
|
||||
* 0xF2 = FM ON + SAA ON + normal read + chip1 (base).
|
||||
@@ -763,6 +764,7 @@ void stop_playback(void)
|
||||
s_buf_ready[1] = 0;
|
||||
s_last_active_buf = 0;
|
||||
isr_done = 0;
|
||||
isr_final_pending = 0;
|
||||
|
||||
ints_enable();
|
||||
}
|
||||
@@ -865,18 +867,6 @@ void update_playback_info(void)
|
||||
|
||||
sec = isr_play_seconds;
|
||||
|
||||
/* Страховка для VGM без разрешённого loop. Нормальный путь
|
||||
* заканчивается на opcode 0x66; если нестандартный хвост до него не
|
||||
* дошёл, не оставляем OPL4 удерживать последнюю ноту бесконечно.
|
||||
* Две секунды запаса покрывают округление total_samples и уже
|
||||
* поставленные в ISR команды. */
|
||||
if (!vgm_loop_enabled && vgm_total_seconds &&
|
||||
sec >= (uint16_t)(vgm_total_seconds + 2u))
|
||||
{
|
||||
vgm_hl_pos = vgm_hl_abort_pos;
|
||||
instant_abort();
|
||||
}
|
||||
|
||||
sec_changed = (sec != s_last_displayed_sec);
|
||||
loop_changed = (vgm_loop_count != s_last_loop_count);
|
||||
|
||||
@@ -1130,6 +1120,15 @@ void main(void)
|
||||
/* ── 1. Буфер: максимальный приоритет ──────────────── */
|
||||
update_buffer();
|
||||
|
||||
/* ISR исполнил весь музыкальный хвост и замер на FINALIZE.
|
||||
* Пересобрать shutdown с начала чистого буфера — тот же путь,
|
||||
* который используется для надёжного выхода по ESC. */
|
||||
if (isr_final_pending) {
|
||||
isr_final_pending = 0;
|
||||
vgm_hl_pos = vgm_hl_abort_pos;
|
||||
instant_abort();
|
||||
}
|
||||
|
||||
/* ISR замер на CMD_ISR_DONE → чистый выход */
|
||||
if (isr_done)
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user