; 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_chip0 dw 0 ch3_ofs_chip1 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 2, music_p0_ch4 channel_struct_t 2, music_p0_ch5 channel_struct_t 2, music_p0_ch6 channel_struct_t 2, music_p0_ch7 channel_struct_t 0, 0 channel_struct_t 0, 0 channel_struct_t 0, 0 channel_struct_t 0, 0 channel_struct_t 2, music_p0_ch12 channel_struct_t 2, music_p0_ch13 channel_struct_t 2, music_p0_ch14 channel_struct_t 2, music_p0_ch15 player_struct player_struct_t player_channels+(channel_struct_t*(3+0)+channel_struct_t.reg_extch3_fhi), player_channels+(channel_struct_t*(3+8)+channel_struct_t.reg_extch3_fhi) .i = 0 dup 16 display "channel ", /h, .i, " struct ofs: ", /h, player_channels+(channel_struct_t*.i) .i = .i + 1 edup ; ----------------------------- ; ----------------------------- ; OPN register dump output ; in: HL - registers in (reg:data) byte pairs, reg==0xFF - return reg_out: ld bc, 0xFFFD ld de, 0x00C0 ; 0xFFBF compensated for outi ; select 1st chip ld a, 0b11111000 out (c), a .loop: ld b, d ld a, [hl] inc a ; test for 0xFF terminator ret z outi ld b, e outi 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: ldi a, [hl] : and 0x0F : ld d, a ldi e, [hl] ret .short: ldi 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 z, 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 z, 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 z, 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 z, 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] : exa ; a = ctx->ssg_r7[chip_index] &= ~(((1 << 3) | (1 << 0)) << ch); sla e : sla e ld a, b : and 3 : add e : ld e, a ld hl, .mask_lookup add hl, de exa : or [hl] : ld [ix], a ; ctx->ssg_r7[chip_index] |= (mask_lookup[mask & 3] << ch); pop ix, hl, de ; if (mask & OPM_AYTONE_MASK_EOF) endOfFrame = true; bit OPM_AYTONE_MASK_EOF_BIT, b jp z, 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 envelope/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 z, 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 z, 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 z, 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 z, 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 z, 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 z, 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 z, 1f ld a, b : ld [player_struct.end_of_frame], a 1: scf ret .not_period: and a ; clear carry ret ; parse FM control stream ; HL - stream data, IX- channel context, IY - register buffer, CF - do next op parse_fm_control_stream: ld b, [hl] ; if ((*(data) & 0xE0) == OPM_CTRL_TIMER_CSM) { ld a, b : and 0xE0 : cp OPM_CTRL_TIMER_CSM jp nz, .not_timer_csm inc hl ;if (mask & OPM_CTRL_CMD80_REG25) opn_write_reg(chip_index, 0x25, *data++); bit OPM_CTRL_CMD80_REG25_BIT, b jp z, 1f ldi [iy], 0x25 : ldi a, [hl] : ldi [iy], a 1: ;if (mask & OPM_CTRL_CMD80_REG24) opn_write_reg(chip_index, 0x24, *data++); bit OPM_CTRL_CMD80_REG24_BIT, b jp z, 1f ldi [iy], 0x24 : ldi a, [hl] : ldi [iy], a 1: ;if (mask & OPM_CTRL_CMD80_REG27) opn_write_reg(chip_index, 0x27, *data++); bit OPM_CTRL_CMD80_REG27_BIT, b jp z, 1f ldi [iy], 0x27 : ldi a, [hl] : ldi [iy], a 1: ;if (mask & OPM_CTRL_CMD80_REG22) opn_write_reg(chip_index, 0x22, *data++); bit OPM_CTRL_CMD80_REG25_BIT, b jp z, 1f ldi [iy], 0x22 : ldi a, [hl] : ldi [iy], a 1: ;if (mask & OPM_CTRL_CMD80_EOF) endOfFrame = true; bit OPM_CTRL_CMD80_EOF_BIT, b jp z, 1f ld a, b : ld [player_struct.end_of_frame], a 1: scf ret .not_timer_csm: ; if ((*(data) & 0x80) == OPM_CTRL_EXTCH3) { ld a, b : and 0x80 : cp OPM_CTRL_EXTCH3 jp nz, .not_extch3 inc hl ; extract extch3 offset push hl ld a, [player_struct.chip_idx] : add a : ld e, a : ld d, 0 ld hl, player_struct.ch3_ofs_chip0 : add hl, de ld e, [hl] : inc hl : ld d, [hl] ; de - channel 3 extch3 block pop hl ; if (mask & OPM_CTRL_EXTCH3_OP1_HIGH) ctx->extch3_block[chip_index][0] = *data++; ; if (mask & OPM_CTRL_EXTCH3_OP1_LOW) { ; opn_write_reg(chip_index, 0xAD, ctx->extch3_block[chip_index][0]); ; opn_write_reg(chip_index, 0xA9, *data++); ; } bit OPM_CTRL_EXTCH3_OP1_HIGH_BIT, b jp z, 1f ld a, [hl] : ld [de], a : inc hl 1: bit OPM_CTRL_EXTCH3_OP1_LOW_BIT, b jp z, 1f ldi [iy], 0xAD : ld a, [de] : ldi [iy], a ldi [iy], 0xA9 : ldi a, [hl] : ldi [iy], a 1: inc e ; if (mask & OPM_CTRL_EXTCH3_OP2_HIGH) ctx->extch3_block[chip_index][1] = *data++; ; if (mask & OPM_CTRL_EXTCH3_OP2_LOW) { ; opn_write_reg(chip_index, 0xAC, ctx->extch3_block[chip_index][1]); ; opn_write_reg(chip_index, 0xA8, *data++); ; } bit OPM_CTRL_EXTCH3_OP2_HIGH_BIT, b jp z, 1f ld a, [hl] : ld [de], a : inc hl 1: bit OPM_CTRL_EXTCH3_OP2_LOW_BIT, b jp z, 1f ldi [iy], 0xAC : ld a, [de] : ldi [iy], a ldi [iy], 0xA8 : ldi a, [hl] : ldi [iy], a 1: inc e ; if (mask & OPM_CTRL_EXTCH3_OP3_HIGH) ctx->extch3_block[chip_index][2] = *data++; ; if (mask & OPM_CTRL_EXTCH3_OP3_LOW) { ; opn_write_reg(chip_index, 0xAE, ctx->extch3_block[chip_index][2]); ; opn_write_reg(chip_index, 0xAA, *data++); ; } bit OPM_CTRL_EXTCH3_OP3_HIGH_BIT, b jp z, 1f ld a, [hl] : ld [de], a : inc hl 1: bit OPM_CTRL_EXTCH3_OP3_LOW_BIT, b jp z, 1f ldi [iy], 0xAE : ld a, [de] : ldi [iy], a ldi [iy], 0xAA : ldi a, [hl] : ldi [iy], a 1: ; if (mask & OPM_CTRL_EXTCH3_EOF) endOfFrame = true; bit OPM_CTRL_EXTCH3_EOF_BIT, b jp z, 1f ld a, b : ld [player_struct.end_of_frame], a 1: scf ret .not_extch3: and a ; clear carry ret ; parse FM channel stream ; HL - stream data, IX- channel context, IY - register buffer, CF - do next op parse_fm_channel_stream: ld b, [hl] ; if ((*(data) & 0xC0) == OPM_FM_ADSR) { ld a, b : and 0xC0 : cp OPM_FM_ADSR jp nz, .not_adsr inc hl ; int regbase = (ch & 3) + ((mask & OPM_FM_CMD00_OP_MASK) >> 2); ld a, [player_struct.channel_idx] : ld c, a ld a, b : and OPM_FM_CMD00_OP_MASK : rrca : rrca or c : ld c, a ;if (mask & OPM_FM_CMD00_REG50) opn_write_reg(chip_index, 0x50 + regbase, *data++); bit OPM_FM_CMD00_REG50_BIT, b jp z, 1f ld a, 0x50 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ;if (mask & OPM_FM_CMD00_REG60) opn_write_reg(chip_index, 0x60 + regbase, *data++); bit OPM_FM_CMD00_REG60_BIT, b jp z, 1f ld a, 0x60 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ;if (mask & OPM_FM_CMD00_REG70) opn_write_reg(chip_index, 0x70 + regbase, *data++); bit OPM_FM_CMD00_REG70_BIT, b jp z, 1f ld a, 0x70 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ;if (mask & OPM_FM_CMD00_REG80) opn_write_reg(chip_index, 0x80 + regbase, *data++); bit OPM_FM_CMD00_REG80_BIT, b jp z, 1f ld a, 0x80 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: scf ret .not_adsr: ; if ((*(data) & 0xC0) == OPM_FM_MUL_TL_EG) { ld a, b : and 0xC0 : cp OPM_FM_MUL_TL_EG jp nz, .not_mul_tl_eg ; multplier\TL\SSG-EG inc hl ; int regbase = (ch & 3) + ((mask & OPM_FM_CMD40_OP_MASK) >> 2); ld a, [player_struct.channel_idx] : ld c, a ld a, b : and OPM_FM_CMD40_OP_MASK : rrca : rrca or c : ld c, a ;if (mask & OPM_FM_CMD40_REG30) opn_write_reg(chip_index, 0x30 + regbase, *data++); bit OPM_FM_CMD40_REG30_BIT, b jp z, 1f ld a, 0x30 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ;if (mask & OPM_FM_CMD40_REG40) opn_write_reg(chip_index, 0x40 + regbase, *data++); bit OPM_FM_CMD40_REG40_BIT, b jp z, 1f ld a, 0x40 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ;if (mask & OPM_FM_CMD40_REG90) opn_write_reg(chip_index, 0x90 + regbase, *data++); bit OPM_FM_CMD40_REG90_BIT, b jp z, 1f ld a, 0x90 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ;if (mask & OPM_FM_CMD40_EOF) endOfFrame = true; bit OPM_FM_CMD40_EOF_BIT, b jp z, 1f ld a, b : ld [player_struct.end_of_frame], a 1: scf ret .not_mul_tl_eg: ; if ((*(data) & 0xE0) == OPM_FM_FREQ_FB_PAN) { ld a, b : and 0xE0 : cp OPM_FM_FREQ_FB_PAN jp nz, .not_freq_fb_pan inc hl ld a, [player_struct.channel_idx] : ld c, a ; if (mask & OPM_FM_CMD80_REGA4) chctx->block = *data++; bit OPM_FM_CMD80_REGA4_BIT, b jp z, 1f ldi a, [hl] : ld [ix + channel_struct_t.reg_fhi], a 1: ; if (mask & OPM_FM_CMD80_REGA0) { ; opn_write_reg(chip_index, 0xA4 + ch, chctx->block); ; opn_write_reg(chip_index, 0xA0 + ch, *data++); ; } bit OPM_FM_CMD80_REGA0_BIT, b jp z, 1f ld a, 0xA4 : add c : ldi [iy], a ld a, [ix + channel_struct_t.reg_fhi] : ldi [iy], a ld a, 0xA0 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ; if (mask & OPM_FM_CMD80_REGB0) opn_write_reg(chip_index, 0xB0 + ch, *data++); bit OPM_FM_CMD80_REGB0_BIT, b jp z, 1f ld a, 0xb0 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ; if (mask & OPM_FM_CMD80_REGB4) opn_write_reg(chip_index, 0xB4 + ch, *data++); bit OPM_FM_CMD80_REGB4_BIT, b jp z, 1f ld a, 0xb4 : add c : ldi [iy], a ldi a, [hl] : ld [iy], a 1: ; if (mask & OPM_FM_CMD80_EOF) endOfFrame = true; bit OPM_FM_CMD80_EOF_BIT, b jp z, 1f ld a, b : ld [player_struct.end_of_frame], a 1: scf ret .not_freq_fb_pan: ; if ((*(data) & 0xE0) == OPM_FM_KEY) { ld a, b : and 0xE0 : cp OPM_FM_KEY jp nz, .not_key ; opn_write_reg(chip_index, 0x28, ((mask & OPM_FM_CMDA0_OP_MASK) << 4) + ch); ld a, [player_struct.channel_idx] : ld c, a ld a, b : and OPM_FM_CMDA0_OP_MASK add a, a : add a, a : add a, a : add a, a : add a, c ldi [iy], 0x28 : ldi [iy], a 1: ; if (mask & OPM_FM_CMDA0_EOF) endOfFrame = true; bit OPM_FM_CMDA0_EOF_BIT, b jp z, 1f ld a, b : ld [player_struct.end_of_frame], a 1: scf ret .not_key: and a ; clear carry 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.delay] dec de ld [ix+channel_struct_t.delay], de ld a, d or e ret nz ; save proc ptr ld [.proc], bc ; 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 equ $-2 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 ; 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 ld [ix + channel_struct_t.ptr], hl ; 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.reload], 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.reload] ld [ix + channel_struct_t.delay], 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 ; select 2nd chip ldi [iy], 0b11111000 ldi [iy], 0xFF ; chip_index = 1; ld a, 1 : 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 + 1] ldi [iy], a ; terminate list ldi [iy], -1 ret endmodule