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_play_seconds
|
||||||
.globl _isr_read_ptr
|
.globl _isr_read_ptr
|
||||||
.globl _isr_done
|
.globl _isr_done
|
||||||
|
.globl _isr_final_pending
|
||||||
.globl _cmd_buf_a
|
.globl _cmd_buf_a
|
||||||
.globl _cmd_buf_b
|
.globl _cmd_buf_b
|
||||||
.globl _isr_init
|
.globl _isr_init
|
||||||
@@ -56,7 +57,7 @@ WC_IM2_VEC = 0x5BFF
|
|||||||
CMD_WRITE_AY = 0x00
|
CMD_WRITE_AY = 0x00
|
||||||
CMD_INC_SEC = 0x10
|
CMD_INC_SEC = 0x10
|
||||||
CMD_WRITE_AY2 = 0x20
|
CMD_WRITE_AY2 = 0x20
|
||||||
CMD_CALL_WC = 0x30
|
CMD_FINALIZE = 0x30
|
||||||
CMD_WRITE_B0 = 0x40
|
CMD_WRITE_B0 = 0x40
|
||||||
CMD_SKIP_TICKS= 0x50
|
CMD_SKIP_TICKS= 0x50
|
||||||
CMD_WRITE_SAA = 0x60
|
CMD_WRITE_SAA = 0x60
|
||||||
@@ -301,8 +302,8 @@ _isr_cmd_loop:
|
|||||||
jp z, _isr_cmd_done
|
jp z, _isr_cmd_done
|
||||||
cp #CMD_INC_SEC
|
cp #CMD_INC_SEC
|
||||||
jp z, _isr_inc_sec
|
jp z, _isr_inc_sec
|
||||||
cp #CMD_CALL_WC
|
cp #CMD_FINALIZE
|
||||||
jp z, _isr_call_wc
|
jp z, _isr_cmd_finalize
|
||||||
; Unknown command: skip 3 bytes, continue
|
; Unknown command: skip 3 bytes, continue
|
||||||
inc de
|
inc de
|
||||||
inc de
|
inc de
|
||||||
@@ -589,29 +590,23 @@ _skip_spec_next:
|
|||||||
; ISR зацикливается на этой команде, не переключает буферы.
|
; ISR зацикливается на этой команде, не переключает буферы.
|
||||||
; Main loop ждёт isr_done == 1 перед завершением.
|
; Main loop ждёт isr_done == 1 перед завершением.
|
||||||
_isr_cmd_done:
|
_isr_cmd_done:
|
||||||
inc de
|
|
||||||
inc de
|
|
||||||
inc de ; пропустить 3 байта параметров
|
|
||||||
; Выставить флаг готовности к завершению
|
|
||||||
ld a, #1
|
ld a, #1
|
||||||
ld (_isr_done), a
|
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
|
ex de, hl
|
||||||
dec hl
|
dec hl
|
||||||
dec hl
|
|
||||||
dec hl
|
|
||||||
dec hl
|
|
||||||
ld (_isr_read_ptr), hl
|
ld (_isr_read_ptr), hl
|
||||||
jp _isr_exit
|
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)
|
; 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_read_ptr:: .dw 0
|
||||||
_isr_wait_ctr:: .dw 0
|
_isr_wait_ctr:: .dw 0
|
||||||
_isr_done:: .db 0 ; 1 = ISR замер на CMD_ISR_DONE, готов к завершению
|
_isr_done:: .db 0 ; 1 = ISR замер на CMD_ISR_DONE, готов к завершению
|
||||||
|
_isr_final_pending:: .db 0 ; 1 = последний VGM 0x66 уже исполнен
|
||||||
_pos_ptr: .dw 0 ; инициализируется в isr_init()
|
_pos_ptr: .dw 0 ; инициализируется в isr_init()
|
||||||
_isr_saved_vec: .dw 0 ; сохранённый вектор WC (#5BFF)
|
_isr_saved_vec: .dw 0 ; сохранённый вектор WC (#5BFF)
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -34,7 +34,7 @@
|
|||||||
* CMD_WRITE_AY │ reg │ val │ 0 │ OUT AY8910 chip 1
|
* CMD_WRITE_AY │ reg │ val │ 0 │ OUT AY8910 chip 1
|
||||||
* CMD_INC_SEC │ 0 │ 0 │ 0 │ Инкр. isr_play_seconds
|
* CMD_INC_SEC │ 0 │ 0 │ 0 │ Инкр. isr_play_seconds
|
||||||
* CMD_WRITE_AY2 │ reg │ val │ 0 │ OUT AY8910 chip 2 (TS)
|
* 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_WRITE_B0 │ reg │ val │ 0 │ OUT OPL3 Bank 0
|
||||||
* CMD_SKIP_TICKS│ N │ smsk_lo│ smsk_hi│ Пропустить N позиций pos_table
|
* CMD_SKIP_TICKS│ N │ smsk_lo│ smsk_hi│ Пропустить N позиций pos_table
|
||||||
* CMD_WRITE_SAA │ reg │ val │ 0 │ OUT SAA1099 chip 0
|
* 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_WRITE_AY 0x00 /* AY8910 chip 1: [reg, val, 0] */
|
||||||
#define CMD_INC_SEC 0x10 /* Инкрементировать счётчик секунд: [0,0,0] */
|
#define CMD_INC_SEC 0x10 /* Инкрементировать счётчик секунд: [0,0,0] */
|
||||||
#define CMD_WRITE_AY2 0x20 /* AY8910 chip 2 (TurboSound): [reg,val,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_WRITE_B0 0x40 /* OPL3 Bank 0 write: [reg, val, 0] */
|
||||||
#define CMD_SKIP_TICKS 0x50 /* Пропустить N pos_table: [N,sml,smh] */
|
#define CMD_SKIP_TICKS 0x50 /* Пропустить N pos_table: [N,sml,smh] */
|
||||||
#define CMD_WRITE_SAA 0x60 /* SAA1099 write: [reg, val, 0] bit7=chip */
|
#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 очищает при старте воспроизведения. */
|
* Main loop очищает при старте воспроизведения. */
|
||||||
extern volatile uint8_t isr_done;
|
extern volatile uint8_t isr_done;
|
||||||
|
|
||||||
|
/** ISR дошёл до последнего 0x66; main должен запустить shutdown. */
|
||||||
|
extern volatile uint8_t isr_final_pending;
|
||||||
|
|
||||||
/** Командные буферы A и B. Заполняются main loop, читаются ISR. */
|
/** Командные буферы A и B. Заполняются main loop, читаются ISR. */
|
||||||
extern uint8_t cmd_buf_a[CMD_BUF_SIZE];
|
extern uint8_t cmd_buf_a[CMD_BUF_SIZE];
|
||||||
extern uint8_t cmd_buf_b[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_wait_accum = fb_wacc;
|
||||||
}
|
}
|
||||||
vgm_hl_pos++;
|
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;
|
goto next_hl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-12
@@ -675,6 +675,7 @@ void start_playback(void)
|
|||||||
isr_active_buf = 0;
|
isr_active_buf = 0;
|
||||||
isr_wait_ctr = 0;
|
isr_wait_ctr = 0;
|
||||||
isr_done = 0;
|
isr_done = 0;
|
||||||
|
isr_final_pending = 0;
|
||||||
|
|
||||||
/* MultiSound ctrl: включить FM/SAA только для присутствующих чипов.
|
/* MultiSound ctrl: включить FM/SAA только для присутствующих чипов.
|
||||||
* 0xF2 = FM ON + SAA ON + normal read + chip1 (base).
|
* 0xF2 = FM ON + SAA ON + normal read + chip1 (base).
|
||||||
@@ -763,6 +764,7 @@ void stop_playback(void)
|
|||||||
s_buf_ready[1] = 0;
|
s_buf_ready[1] = 0;
|
||||||
s_last_active_buf = 0;
|
s_last_active_buf = 0;
|
||||||
isr_done = 0;
|
isr_done = 0;
|
||||||
|
isr_final_pending = 0;
|
||||||
|
|
||||||
ints_enable();
|
ints_enable();
|
||||||
}
|
}
|
||||||
@@ -865,18 +867,6 @@ void update_playback_info(void)
|
|||||||
|
|
||||||
sec = isr_play_seconds;
|
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);
|
sec_changed = (sec != s_last_displayed_sec);
|
||||||
loop_changed = (vgm_loop_count != s_last_loop_count);
|
loop_changed = (vgm_loop_count != s_last_loop_count);
|
||||||
|
|
||||||
@@ -1130,6 +1120,15 @@ void main(void)
|
|||||||
/* ── 1. Буфер: максимальный приоритет ──────────────── */
|
/* ── 1. Буфер: максимальный приоритет ──────────────── */
|
||||||
update_buffer();
|
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 → чистый выход */
|
/* ISR замер на CMD_ISR_DONE → чистый выход */
|
||||||
if (isr_done)
|
if (isr_done)
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user