implement AY part of the player (untested :p)

This commit is contained in:
wbcbz7 2025-08-14 05:00:51 +07:00
parent 334e575752
commit 808dd7c045
3 changed files with 717 additions and 1 deletions

View file

@ -9,7 +9,7 @@ codestart equ 0x8080
reg_buffer equ 0x5B00 ; basic variables :meatjob:
EMPTYTAP "psgplay.tap"
EMPTYTAP "player.tap"
; IM2 vector table - all 257 values for floating bus condition
org ivt

View file

@ -0,0 +1,176 @@
; OPM v0 stream data, stream-independent commands
OPM_STREAM_END_FRAME equ 0xFF ; end of frame, next channel
OPM_STREAM_END equ 0xFE ; end of stream, stop here or loop to OPM_STREAM_LOOP stream point
OPM_STREAM_NOP equ 0xFD ; nop
OPM_STREAM_NEW_ORDER equ 0xFC ; nop, marks new order
OPM_STREAM_SET_FRAME_RATE equ 0xFB ; word rate (as in opm_header_t::frame_rate)
OPM_STREAM_LOOP equ 0xFA ; set loop point here
; delay commands
OPM_STREAM_DELAY_INT32 equ 0xF9 ; dword delay
OPM_STREAM_DELAY_INT16 equ 0xF8 ; word delay
OPM_STREAM_DELAY_INT12 equ 0xD0 ; D0..DF - 0..4095 frames delay (hibyte in low 4 bits of command)
OPM_STREAM_DELAY_SHORT equ 0xC0 ; C0..CF - 1..16 frames delay
; back reference
OPM_STREAM_BACKREF equ 0xE0 ; E0..EF - word backrefpos (12 bit), byte frames
; OPN control stream commands
OPM_CTRL_EXTCH3 equ 0x00 ; 00..7F - ext. CH3 op1-3 frequency
OPM_CTRL_TIMER_CSM equ 0x80 ; 80..9F - set timer/CSM/LFO frequency
OPM_CTRL_RHYTHM equ 0xA0 ; A0..BF - rhythm control
OPM_CTRL_CMD80_REG25 equ (1 << 0) ;
OPM_CTRL_CMD80_REG25_BIT equ 0 ; shift value for OPM_CTRL_CMD80_REG25
OPM_CTRL_CMD80_REG24 equ (1 << 1) ;
OPM_CTRL_CMD80_REG24_BIT equ 1 ; shift value for OPM_CTRL_CMD80_REG24
OPM_CTRL_CMD80_REG27 equ (1 << 2) ;
OPM_CTRL_CMD80_REG27_BIT equ 2 ; shift value for OPM_CTRL_CMD80_REG27
OPM_CTRL_CMD80_REG22 equ (1 << 3) ;
OPM_CTRL_CMD80_REG22_BIT equ 3 ; shift value for OPM_CTRL_CMD80_REG22
OPM_CTRL_CMD80_EOF equ (1 << 4) ;
OPM_CTRL_CMD80_EOF_BIT equ 4 ; shift value for OPM_CTRL_CMD80_EOF
OPM_CTRL_EXTCH3_OP1_HIGH equ (1 << 0) ;
OPM_CTRL_EXTCH3_OP1_HIGH_BIT equ 0 ; shift value for OPM_CTRL_EXTCH3_OP1_HIGH
OPM_CTRL_EXTCH3_OP1_LOW equ (1 << 1) ;
OPM_CTRL_EXTCH3_OP1_LOW_BIT equ 1 ; shift value for OPM_CTRL_EXTCH3_OP1_LOW
OPM_CTRL_EXTCH3_OP2_HIGH equ (1 << 2) ;
OPM_CTRL_EXTCH3_OP2_HIGH_BIT equ 2 ; shift value for OPM_CTRL_EXTCH3_OP2_HIGH
OPM_CTRL_EXTCH3_OP2_LOW equ (1 << 3) ;
OPM_CTRL_EXTCH3_OP2_LOW_BIT equ 3 ; shift value for OPM_CTRL_EXTCH3_OP2_LOW
OPM_CTRL_EXTCH3_OP3_HIGH equ (1 << 4) ;
OPM_CTRL_EXTCH3_OP3_HIGH_BIT equ 4 ; shift value for OPM_CTRL_EXTCH3_OP3_HIGH
OPM_CTRL_EXTCH3_OP3_LOW equ (1 << 5) ;
OPM_CTRL_EXTCH3_OP3_LOW_BIT equ 5 ; shift value for OPM_CTRL_EXTCH3_OP3_LOW
OPM_CTRL_EXTCH3_EOF equ (1 << 6) ;
OPM_CTRL_EXTCH3_EOF_BIT equ 6 ; shift value for OPM_CTRL_EXTCH3_EOF
OPM_CTRL_CMDA0_REG_MASK equ (0x0F << 0) ;
OPM_CTRL_CMDA0_REG_MASK_BIT equ 0 ; shift value for OPM_CTRL_CMDA0_REG_MASK
OPM_CTRL_CMDA0_EOF equ (1 << 4) ;
OPM_CTRL_CMDA0_EOF_BIT equ 4 ; shift value for OPM_CTRL_CMDA0_EOF
; OPN FM stream commands
OPM_FM_ADSR equ 0x00 ; 00..3F - set ADSR
OPM_FM_MUL_TL_EG equ 0x40 ; 40..7F - set MULT/TL/SSG-EG
OPM_FM_FREQ_FB_PAN equ 0x80 ; 80..9F - set frequency/feedback/panning
OPM_FM_KEY equ 0xA0 ; A0..BF - key on/off
OPM_FM_CMD00_REG50 equ (1 << 0) ;
OPM_FM_CMD00_REG50_BIT equ 0 ; shift value for OPM_FM_CMD00_REG50
OPM_FM_CMD00_REG60 equ (1 << 1) ;
OPM_FM_CMD00_REG60_BIT equ 1 ; shift value for OPM_FM_CMD00_REG60
OPM_FM_CMD00_REG70 equ (1 << 2) ;
OPM_FM_CMD00_REG70_BIT equ 2 ; shift value for OPM_FM_CMD00_REG70
OPM_FM_CMD00_REG80 equ (1 << 3) ;
OPM_FM_CMD00_REG80_BIT equ 3 ; shift value for OPM_FM_CMD00_REG80
OPM_FM_CMD00_OP_MASK equ (3 << 4) ;
OPM_FM_CMD00_OP_MASK_BIT equ 4 ; shift value for OPM_FM_CMD00_OP_MASK
OPM_FM_CMD40_REG30 equ (1 << 0) ;
OPM_FM_CMD40_REG30_BIT equ 0 ; shift value for OPM_FM_CMD40_REG30
OPM_FM_CMD40_REG40 equ (1 << 1) ;
OPM_FM_CMD40_REG40_BIT equ 1 ; shift value for OPM_FM_CMD40_REG40
OPM_FM_CMD40_REG90 equ (1 << 2) ;
OPM_FM_CMD40_REG90_BIT equ 2 ; shift value for OPM_FM_CMD40_REG90
OPM_FM_CMD40_EOF equ (1 << 3) ;
OPM_FM_CMD40_EOF_BIT equ 3 ; shift value for OPM_FM_CMD40_EOF
OPM_FM_CMD40_OP_SHIFT equ 4 ;
OPM_FM_CMD40_OP_MASK equ (3 << 4) ;
OPM_FM_CMD40_OP_MASK_BIT equ 4 ; shift value for OPM_FM_CMD40_OP_MASK
OPM_FM_CMD80_REGA4 equ (1 << 0) ;
OPM_FM_CMD80_REGA4_BIT equ 0 ; shift value for OPM_FM_CMD80_REGA4
OPM_FM_CMD80_REGA0 equ (1 << 1) ;
OPM_FM_CMD80_REGA0_BIT equ 1 ; shift value for OPM_FM_CMD80_REGA0
OPM_FM_CMD80_REGB0 equ (1 << 2) ;
OPM_FM_CMD80_REGB0_BIT equ 2 ; shift value for OPM_FM_CMD80_REGB0
OPM_FM_CMD80_REGB4 equ (1 << 3) ;
OPM_FM_CMD80_REGB4_BIT equ 3 ; shift value for OPM_FM_CMD80_REGB4
OPM_FM_CMD80_EOF equ (1 << 4) ;
OPM_FM_CMD80_EOF_BIT equ 4 ; shift value for OPM_FM_CMD80_EOF
OPM_FM_CMDA0_OP_SHIFT equ 0 ;
OPM_FM_CMDA0_OP_MASK equ (0x0F << 0) ;
OPM_FM_CMDA0_OP_MASK_BIT equ 0 ; shift value for OPM_FM_CMDA0_OP_MASK
OPM_FM_CMDA0_EOF equ (1 << 4) ;
OPM_FM_CMDA0_EOF_BIT equ 4 ; shift value for OPM_FM_CMDA0_EOF
; OPNA rhythm channel stream
OPN_RHYTHM_KEY equ 0x00 ; 00..7F - key on
OPN_RHYTHM_REGS1 equ 0x80 ; 80..9F - write reg set 1
OPN_RHYTHM_REGS2 equ 0xA0 ; A0..BF - write reg set 2
OPN_RHYTHM_KEY_EOF equ (1 << 6) ;
OPN_RHYTHM_KEY_EOF_BIT equ 6 ; shift value for OPN_RHYTHM_KEY_EOF
OPN_RHYTHM_CMD80_REG10 equ (1 << 0) ;
OPN_RHYTHM_CMD80_REG10_BIT equ 0 ; shift value for OPN_RHYTHM_CMD80_REG10
OPN_RHYTHM_CMD80_REG11 equ (1 << 1) ;
OPN_RHYTHM_CMD80_REG11_BIT equ 1 ; shift value for OPN_RHYTHM_CMD80_REG11
OPN_RHYTHM_CMD80_REG18 equ (1 << 2) ;
OPN_RHYTHM_CMD80_REG18_BIT equ 2 ; shift value for OPN_RHYTHM_CMD80_REG18
OPN_RHYTHM_CMD80_REG19 equ (1 << 3) ;
OPN_RHYTHM_CMD80_REG19_BIT equ 3 ; shift value for OPN_RHYTHM_CMD80_REG19
OPN_RHYTHM_CMDA0_REG1A equ (1 << 0) ;
OPN_RHYTHM_CMDA0_REG1A_BIT equ 0 ; shift value for OPN_RHYTHM_CMDA0_REG1A
OPN_RHYTHM_CMDA0_REG1B equ (1 << 1) ;
OPN_RHYTHM_CMDA0_REG1B_BIT equ 1 ; shift value for OPN_RHYTHM_CMDA0_REG1B
OPN_RHYTHM_CMDA0_REG1C equ (1 << 2) ;
OPN_RHYTHM_CMDA0_REG1C_BIT equ 2 ; shift value for OPN_RHYTHM_CMDA0_REG1C
OPN_RHYTHM_CMDA0_REG1D equ (1 << 3) ;
OPN_RHYTHM_CMDA0_REG1D_BIT equ 3 ; shift value for OPN_RHYTHM_CMDA0_REG1D
OPN_RHYTHM_REGS_EOF equ (1 << 4) ;
OPN_RHYTHM_REGS_EOF_BIT equ 4 ; shift value for OPN_RHYTHM_REGS_EOF
; OPN SSG tone stream commands (shared with AY chip type)
OPM_AYTONE_REGS equ 0x00 ; 00..7F - set volume and period low
OPM_AYTONE_PERIOD equ 0x80 ; 80..BF - set period
OPM_AYTONE_MASK equ 0xF0 ; F0..F7 - set tone/noise mask
OPM_AYTONE_CMD00_VOLUME_MASK equ (0x1F << 0) ;
OPM_AYTONE_CMD00_VOLUME_MASK_BIT equ 0 ; shift value for OPM_AYTONE_CMD00_VOLUME_MASK
OPM_AYTONE_CMD00_PERIOD_LOW equ (1 << 5) ;
OPM_AYTONE_CMD00_PERIOD_LOW_BIT equ 5 ; shift value for OPM_AYTONE_CMD00_PERIOD_LOW
OPM_AYTONE_CMD00_EOF equ (1 << 6) ;
OPM_AYTONE_CMD00_EOF_BIT equ 6 ; shift value for OPM_AYTONE_CMD00_EOF
OPM_AYTONE_CMD80_PERIOD_HIGH equ (0xF << 0) ;
OPM_AYTONE_CMD80_PERIOD_HIGH_BIT equ 0 ; shift value for OPM_AYTONE_CMD80_PERIOD_HIGH
OPM_AYTONE_CMD80_PERIOD_LOW equ (1 << 4) ;
OPM_AYTONE_CMD80_PERIOD_LOW_BIT equ 4 ; shift value for OPM_AYTONE_CMD80_PERIOD_LOW
OPM_AYTONE_CMD80_EOF equ (1 << 5) ;
OPM_AYTONE_CMD80_EOF_BIT equ 5 ; shift value for OPM_AYTONE_CMD80_EOF
OPM_AYTONE_MASK_TONE equ (1 << 0) ;
OPM_AYTONE_MASK_TONE_BIT equ 0 ; shift value for OPM_AYTONE_MASK_TONE
OPM_AYTONE_MASK_NOISE equ (1 << 1) ;
OPM_AYTONE_MASK_NOISE_BIT equ 1 ; shift value for OPM_AYTONE_MASK_NOISE
OPM_AYTONE_MASK_EOF equ (1 << 2) ;
OPM_AYTONE_MASK_EOF_BIT equ 2 ; shift value for OPM_AYTONE_MASK_EOF
; OPN SSG envelope/noise stream commands (shared with AY chip type)
OPM_AYENV_REGS equ 0x00 ; 00..7F - set noise and period low
OPM_AYENV_ENVTYPE equ 0x80 ; 80..BF - set env type and period low
OPM_AYENV_PERIOD_FULL equ 0xF0 ; F0..F7 - set full envelope period
OPM_AYENV_CMD00_NOISE_MASK equ (0x1F << 0) ;
OPM_AYENV_CMD00_NOISE_MASK_BIT equ 0 ; shift value for OPM_AYENV_CMD00_NOISE_MASK
OPM_AYENV_CMD00_PERIOD_LOW equ (1 << 5) ;
OPM_AYENV_CMD00_PERIOD_LOW_BIT equ 5 ; shift value for OPM_AYENV_CMD00_PERIOD_LOW
OPM_AYENV_CMD00_EOF equ (1 << 6) ;
OPM_AYENV_CMD00_EOF_BIT equ 6 ; shift value for OPM_AYENV_CMD00_EOF
OPM_AYENV_CMD80_ENV_TYPE equ (0xF << 0) ;
OPM_AYENV_CMD80_ENV_TYPE_BIT equ 0 ; shift value for OPM_AYENV_CMD80_ENV_TYPE
OPM_AYENV_CMD80_PERIOD_LOW equ (1 << 4) ;
OPM_AYENV_CMD80_PERIOD_LOW_BIT equ 4 ; shift value for OPM_AYENV_CMD80_PERIOD_LOW
OPM_AYENV_CMD80_EOF equ (1 << 5) ;
OPM_AYENV_CMD80_EOF_BIT equ 5 ; shift value for OPM_AYENV_CMD80_EOF
OPM_AYENV_CMDF0_PERIOD_LOW equ (1 << 0) ;
OPM_AYENV_CMDF0_PERIOD_LOW_BIT equ 0 ; shift value for OPM_AYENV_CMDF0_PERIOD_LOW
OPM_AYENV_CMDF0_PERIOD_HIGH equ (1 << 1) ;
OPM_AYENV_CMDF0_PERIOD_HIGH_BIT equ 1 ; shift value for OPM_AYENV_CMDF0_PERIOD_HIGH
OPM_AYENV_CMDF0_EOF equ (1 << 2) ;
OPM_AYENV_CMDF0_EOF_BIT equ 2 ; shift value for OPM_AYENV_CMDF0_EOF

View file

@ -1,5 +1,66 @@
; if this code looks like HLL vomit, you're pretty close
; i used index registers since speed is not critical, it's a music compo player after all ;)
include "opmfile.inc"
module player
MAX_CHANNELS equ 16
MAX_STACK_DEPTH equ 4
; channel structures format
struct channel_stack_t
ptr dw 0
frames_to_play dw 0
ends
struct channel_struct_t
page db 0 ; base page with stream data
ptr dw 0 ; current pointer
frames_to_play dw -1 ; used for stack popping
delay dw 1
reload dw 1
stack_pos db 0 ; stack offset
stack block channel_stack_t*MAX_STACK_DEPTH, 0 ; stack
; reg cache
reg_extch3_fhi block 3, 0 ; extch3 block/fnum-high reg
reg_fhi db 0 ; block/fnum-high reg
reserved block 2, 0
ends
struct player_struct_t
ch3_ofs_ch0 dw 0
ch3_ofs_ch1 dw 0
chip_idx db 0 ; current chip active
channel_idx db 0
end_of_frame db 0
do_next_op db 0
ssg_r7 block 2, 0
ends
; instantinate structures
align 256
player_channels:
channel_struct_t 0, 0 ; TODO: fill start offsets here
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
channel_struct_t 0, 0
player_struct player_struct_t player_channels+(channel_struct_t*(3+0)), player_channels+(channel_struct_t*(3+8))
; -----------------------------
; -----------------------------
; OPN register dump output
@ -22,5 +83,484 @@ reg_out:
dup 4: nop : edup ; delay
jp .loop
; ------------------------
; pop from stack
; in: IX - channel context
; trashes A, DE
pop_stack:
dec [ix + channel_struct_t.stack_pos] ; --chctx->stack_pos;
ld l, [ix + channel_struct_t.stack_pos] : ld h, 0 ; hl = chctx->stack_pos;
add hl, hl ; *= 2
add hl, hl ; *= 4
ld de, channel_struct_t.stack
add hl, de
ld de, ix
add hl, de ; hl = st = chctx->stack + chctx->stack_pos;
ld e, [hl] : inc l
ld d, [hl] : inc l ; de = st->ptr
ld [ix + channel_struct_t.ptr], de ; chctx->ptr = st->ptr
ld e, [hl] : inc l
ld d, [hl] ; de = st->frames_to_play
ld [ix + channel_struct_t.frames_to_play], de ; chctx->frames_to_play = st->frames_to_play
ret
; ------------------------
; push to stack
; in: IX - channel context
; trashes A, DE
push_stack:
ld l, [ix + channel_struct_t.stack_pos] : ld h, 0 ; hl = chctx->stack_pos;
add hl, hl ; *= 2
add hl, hl ; *= 4
ld de, channel_struct_t.stack
add hl, de
ld de, ix
add hl, de ; hl = st = chctx->stack + chctx->stack_pos;
ld de, [ix + channel_struct_t.ptr]
ld [hl], e : inc l
ld [hl], d : inc l ; st->ptr = chctx->ptr
ld de, [ix + channel_struct_t.frames_to_play]
ld [hl], e : inc l
ld [hl], d : inc l ; st->frames_to_play = chctx->frames_to_play
inc [ix + channel_struct_t.stack_pos]
ret
; ------------------------
; set delay
; in: HL - stream ptr
; out: DE - delay, trashes A
set_delay:
ld a, [hl]
cp OPM_STREAM_DELAY_INT16
jp z, .int16
and 0xF0
cp OPM_STREAM_DELAY_INT12
jp z, .int12
cp OPM_STREAM_DELAY_SHORT
jp z, .short
ret
.int16:
inc hl
ldi de, [hl]
ret
.int12:
ld a, [hl] : inc hl : and 0x0F : ld d, a
ld e, [hl] : inc hl
ret
.short:
ld a, [hl] : and 0x0F : inc a : ld e, a : ld d, 0
ret
; ------------------------------------------
; parse AY channel stream
; HL - stream data, IX- channel context, IY - register buffer, CF - do next op
parse_ay_channel_stream:
ld b, [hl]
; if ((*(data) & 0x80) == OPM_AYTONE_REGS) {
ld a, b : and 0x80 : cp OPM_AYTONE_REGS
jp nz, .not_regs
; volume and period low
; opn_write_reg(chip_index, 8 + ch, (mask & OPM_AYTONE_CMD00_VOLUME_MASK));
inc hl
ld a, [player_struct.channel_idx]
add 8
ldi [iy], a
ld a, b : and OPM_AYTONE_CMD00_VOLUME_MASK
ldi [iy], a
; if (mask & OPM_AYTONE_CMD00_PERIOD_LOW) opn_write_reg(chip_index, 0 + (ch<<1), *data++);
bit OPM_AYTONE_CMD00_PERIOD_LOW_BIT, b
jp nz, 1f
ld a, [player_struct.channel_idx]
add a
ldi [iy], a
ldi a, [hl]
ldi [iy], a
1:
; if (mask & OPM_AYTONE_CMD00_EOF) endOfFrame = true;
bit OPM_AYTONE_CMD00_EOF_BIT, b
jp nz, 1f
ld a, b : ld [player_struct.end_of_frame], a
1:
scf
ret
.not_regs:
; if ((*(data) & 0xC0) == OPM_AYTONE_PERIOD) {
ld a, b : and 0xC0 : cp OPM_AYTONE_PERIOD
jp nz, .not_period
; period low/high
; opn_write_reg(chip_index, 1 + (ch<<1), (mask & OPM_AYTONE_CMD80_PERIOD_HIGH));
inc hl
ld a, [player_struct.channel_idx]
add a
add 1
ldi [iy], a
exa
ld a, b : and OPM_AYTONE_CMD80_PERIOD_HIGH
ldi [iy], a
exa
; if (mask & OPM_AYTONE_CMD80_PERIOD_LOW) opn_write_reg(chip_index, 0 + (ch << 1), *data++);
bit OPM_AYTONE_CMD80_PERIOD_LOW_BIT, b
jp nz, 1f
dec a
ldi [iy], a
ldi a, [hl]
ldi [iy], a
1:
; if (mask & OPM_AYTONE_CMD00_EOF) endOfFrame = true;
bit OPM_AYTONE_CMD80_EOF_BIT, b
jp nz, 1f
ld a, b : ld [player_struct.end_of_frame], a
1:
scf
ret
.not_period:
; if ((*(data) & 0xF8) == OPM_AYTONE_MASK) {
ld a, b : and 0xF8 : cp OPM_AYTONE_MASK
jp nz, .not_mask
inc hl
push de, hl, ix
; ctx->ssg_r7[chip_index] &= ~(((1 << 3) | (1 << 0)) << ch);
ld a, [player_struct.chip_idx] : ld e, a
ld d, 0
ld ix, player_struct.ssg_r7
add ix, de ; ix = ctx->ssg_r7[chip_index]
ld a, [player_struct.channel_idx] : ld e, a
ld hl, .mask_channel
add hl, de
ld a, [ix] : and [hl] ; a = ctx->ssg_r7[chip_index] &= ~(((1 << 3) | (1 << 0)) << ch);
srl e : srl e
ld hl, .mask_lookup
add hl, de
or [hl] : ld [ix], a ; ctx->ssg_r7[chip_index] |= (mask_lookup[mask & 3] << ch);
pop hl, de, ix
; if (mask & OPM_AYTONE_MASK_EOF) endOfFrame = true;
bit OPM_AYTONE_MASK_EOF_BIT, b
jp nz, 1f
ld a, b : ld [player_struct.end_of_frame], a
1:
scf
ret
.mask_lookup:
.p = 0
dup 3
db ((0<<3)|(0<<0)) << .p, ((0<<3)|(1<<0)) << .p, ((1<<3)|(0<<0)) << .p, ((1<<3)|(1<<0)) << .p
.p = .p + 1
edup
.mask_channel:
.p = 0
dup 3
db ~(((1<<3)|(1<<0)) << .p)
.p = .p + 1
edup
.not_mask:
.done:
and a ; clear carry
ret
; parse AY envalope/noise stream
; HL - stream data, IX- channel context, IY - register buffer, CF - do next op
parse_ay_envnoise_stream:
ld b, [hl]
; if ((*(data) & 0x80) == OPM_AYENV_REGS) {
ld a, b : and 0x80 : cp OPM_AYENV_REGS
jp nz, .not_regs
; opn_write_reg(chip_index, 6, (mask & OPM_AYENV_CMD00_NOISE_MASK));
inc hl
ldi [iy], 6
ld a, b : and OPM_AYENV_CMD00_NOISE_MASK
ldi [iy], a
; if (mask & OPM_AYENV_CMD00_PERIOD_LOW) opn_write_reg(chip_index, 11, *data++);
bit OPM_AYENV_CMD00_PERIOD_LOW_BIT, b
jp nz, 1f
ldi [iy], 11
ldi a, [hl]
ldi [iy], a
1:
; if (mask & OPM_AYENV_CMD00_EOF) endOfFrame = true;
bit OPM_AYENV_CMD00_EOF_BIT, b
jp nz, 1f
ld a, b : ld [player_struct.end_of_frame], a
1:
scf
ret
.not_regs:
; if ((*(data) & 0xC0) == OPM_AYENV_ENVTYPE) {
ld a, b : and 0xC0 : cp OPM_AYENV_ENVTYPE
jp nz, .not_envtype
; opn_write_reg(chip_index, 13, (mask & OPM_AYENV_CMD80_ENV_TYPE));
inc hl
ldi [iy], 13
ld a, b : and OPM_AYENV_CMD80_ENV_TYPE
ldi [iy], a
; if (mask & OPM_AYENV_CMD80_PERIOD_LOW) opn_write_reg(chip_index, 11, *data++);
bit OPM_AYENV_CMD80_PERIOD_LOW_BIT, b
jp nz, 1f
ldi [iy], 11
ldi a, [hl]
ldi [iy], a
1:
; if (mask & OPM_AYENV_CMD80_EOF) endOfFrame = true;
bit OPM_AYENV_CMD80_EOF_BIT, b
jp nz, 1f
ld a, b : ld [player_struct.end_of_frame], a
1:
scf
ret
.not_envtype:
; if ((*(data) & 0xF8) == OPM_AYENV_PERIOD_FULL) {
ld a, b : and 0xF8 : cp OPM_AYENV_PERIOD_FULL
jp nz, .not_period
inc hl
; if (mask & OPM_AYENV_CMDF0_PERIOD_LOW) opn_write_reg(chip_index, 11, *data++);
bit OPM_AYENV_CMDF0_PERIOD_LOW_BIT, b
jp nz, 1f
ldi [iy], 11
ldi a, [hl]
ldi [iy], a
1:
; if (mask & OPM_AYENV_CMDF0_PERIOD_HIGH) opn_write_reg(chip_index, 12, *data++);
bit OPM_AYENV_CMDF0_PERIOD_HIGH_BIT, b
jp nz, 1f
ldi [iy], 12
ldi a, [hl]
ldi [iy], a
1:
; if (mask & OPM_AYENV_CMDF0_EOF) endOfFrame = true;
bit OPM_AYENV_CMDF0_EOF_BIT, b
jp nz, 1f
ld a, b : ld [player_struct.end_of_frame], a
1:
scf
ret
.not_period:
ret
; parse channel stream
; in: IX - stream struct, IY - register buffer, BC - stream parser procedure, A - channel index
parse_stream:
; endOfFrame = false;
xor a : ld [player_struct.end_of_frame], a
; if (--chctx->stream.delay == 0) {
ld de, [ix+channel_struct_t.frames_to_play]
dec de
ld [ix+channel_struct_t.frames_to_play], de
ld a, d
or e
ret z
; save proc ptr
ld bc, .proc
; load stream pointer
ld a, [ix+channel_struct_t.page]
ld bc, 0x7FFD
out (c), a
ld de, [ix+channel_struct_t.ptr]
exd ; hl = chctx->stream.ptr
.tok_loop:
ld a, [player_struct.end_of_frame] : and a : jp nz, .end_of_frame
; call stream parser proc
call 0 ; :grins:
.proc
jp c, .tok_loop ; token handled
; handle common tokens
ld b, [hl]
; if ((*data & 0xF0) == OPM_STREAM_BACKREF) {
ld a, b : and 0xF0 : cp OPM_STREAM_BACKREF
jp nz, .not_backref
; TODO
; back reference, nested call :)
; int distance = ((*(data + 0) & 0x0F) << 8) | (*(data + 1));
ld a, b : and 0x0F : ld d, a : inc hl
ldi e, [hl] ; de = distance
ldi a, [hl] ; int frames_to_play = *(data + 2); data += 3
exd : ld [ix + channel_struct_t.ptr], de ; chctx->stream.ptr = data + 3;
push af, de, hl
call push_stack
pop hl, de, af
and a : sbc hl, de ; data -= distance;
; chctx->stream.frames_to_play = frames_to_play; // hack?
ld e, a : ld d, 0 : ld [ix + channel_struct_t.frames_to_play], de
jp .tok_loop
.not_backref
ld a, b
cp OPM_STREAM_END
jp z, .tok_end_of_stream
cp OPM_STREAM_END_FRAME
jp z, .tok_end_of_frame
; then it's most likely an delay
call set_delay
ld [ix + channel_struct_t.delay], de
; fetch next token until it's end of frame
jp .tok_loop
.tok_end_of_stream:
ld de, -1
ld [ix + channel_struct_t.delay], de
jp .end_of_frame
.tok_end_of_frame:
inc hl
.end_of_frame:
; chctx->stream.delay = chctx->stream.reload;
ld de, [ix + channel_struct_t.delay]
ld [ix + channel_struct_t.reload], de
; // decrement samples to play counter
; if (--chctx->stream.samples_to_play == 0) {
push hl
ld hl, [ix + channel_struct_t.frames_to_play]
dec hl
ld [ix + channel_struct_t.frames_to_play], hl
ld a, h : or l
pop hl
jp nz, .not_pop
.pop_loop:
call pop_stack ; todo: kludge below, fixme
push hl
ld hl, [ix + channel_struct_t.frames_to_play]
dec hl
ld [ix + channel_struct_t.frames_to_play], hl
ld a, h : or l
pop hl
jp z, .pop_loop ; to parse nested backrefs
ret
.not_pop:
exd
ld [ix+channel_struct_t.ptr], de
ret
; -----------------------------
; -----------------------------
; play one tick!!!
; trashes all registers
play_tick:
ld iy, reg_buffer
; play AY only for now
; chip_index = 0;
xor a : ld [player_struct.chip_idx], a
; opmplay_parse_stream(ctx, ctx->channels + 4, 0, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 4)
ld bc, parse_ay_channel_stream
ld a, 0 : ld [player_struct.channel_idx], a
call parse_stream
; opmplay_parse_stream(ctx, ctx->channels + 5, 1, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 5)
ld bc, parse_ay_channel_stream
ld a, 1 : ld [player_struct.channel_idx], a
call parse_stream
; opmplay_parse_stream(ctx, ctx->channels + 6, 2, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 6)
ld bc, parse_ay_channel_stream
ld a, 2 : ld [player_struct.channel_idx], a
call parse_stream
; opmplay_parse_stream(ctx, ctx->channels + 7, 0, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 7)
ld bc, parse_ay_envnoise_stream
call parse_stream
ldi [iy], 7
ld a, [player_struct.ssg_r7 + 0]
ldi [iy], a
; chip_index = 1;
xor a : ld [player_struct.chip_idx], a
; opmplay_parse_stream(ctx, ctx->channels + 4, 0, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 4)
ld bc, parse_ay_channel_stream
ld a, 0 : ld [player_struct.channel_idx], a
call parse_stream
; opmplay_parse_stream(ctx, ctx->channels + 5, 1, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 5)
ld bc, parse_ay_channel_stream
ld a, 1 : ld [player_struct.channel_idx], a
call parse_stream
; opmplay_parse_stream(ctx, ctx->channels + 6, 2, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 6)
ld bc, parse_ay_channel_stream
ld a, 2 : ld [player_struct.channel_idx], a
call parse_stream
; opmplay_parse_stream(ctx, ctx->channels + 7, 0, opmplay_parse_ay_channel_stream);
ld ix, player_channels + (channel_struct_t * 7)
ld bc, parse_ay_envnoise_stream
call parse_stream
ldi [iy], 7
ld a, [player_struct.ssg_r7 + 0]
ldi [iy], a
; terminate list
ldi [iy], -1
ret
endmodule