; ; stephen ruddy music player ; with music demo version 1 song data by tim follin ; initial commented disassembly 14apr23bsi ; assembled md5sum: c1dd3f3b1d8bef79fa2864f9c2d99df3 ; assemble with tmpx or similar (no macros are used) ; * = $1000 ; 80 AD PL PH = set pulse width incdec and start value (ZP_PULSE_WIDTH_INCDEC_V1 / ZP_PULSE_WIDTH_SET_LO_V1 / ZP_PULSE_WIDTH_SET_HI_V1) ; 81 = next part of 82 command for loop (uses ZP_LOOP_CNT_CUR_V1 / ZP_LOOP_TOP_CKPT_LO_V1 / ZP_LOOP_TOP_CKPT_HI_V1) ; 82 IT = set top of loop plus iteration count (single nesting only, stores IT to ZP_LOOP_CNT_CUR_V1 checkpoints fetch to ZP_LOOP_TOP_CKPT_LO_V1 / ZP_LOOP_TOP_CKPT_HI_V1) ; 83 DR = set note dur + go into gate on (note) mode (store DR to ZP_DUR_V1, ZP_NOTE_REST_MODE_V1 = 1) ; 84 RM = set rest mode (ZP_NOTE_REST_MODE_V1 = RM) ; 85 OF VL ... = direct SID write write to $D400 + offset OF the value VL continuing until OF=$FF and not fetching VL byte after it (NOTE: OF can access all SID regs from any voice) ; 86 = "eighty-six" command to halt voice fetching (INC ZP_HALT_FETCH_V1) ; 87 = enter direct frequency mode (freq on voice is LLHH) (uses DEC ZP_DIRECT_FREQ_MODE_V1, ZP_TEMP_FREQ_LO, ZP_TEMP_FREQ_HI) then eventually use 00 00 to exit ; 88 AA BB .. HH = set filter sweep and freq parameters ; AA = ZP_FILT_FREQ_INCDEC_LO, BB = L_SMC_FILT_SWEEP_DIR_ORIG_V1+1, CC = ZP_FILT_FREQ_SET_LO, DD = ZP_FILT_FREQ_SET_HI ; EE = L_SMC_FILTER_FREQ_CMP_LO+1, FF = L_SMC_FILTER_FREQ_CMP_HI+1, GG = L_SMC_FILTER_FREQ_CMP_2_LO+1, HH = L_SMC_FILTER_FREQ_CMP_2_HI+1 ; 89 = voice 1: ZP_FILTER_FUNC_EN = 0, voice 2 = 1, voice 3 = 2 (NOTE: functions asymmetric across voices) ; 8A LL HH = jsr (acts as jmp if unpaired) to song at absolute address $HHLL, store return address at ZP_RTN_ADDR_V1_LO / ZP_RTN_ADDR_V1_HI ; 8B = return, get fetch address from appropriate voice return address (ZP_RTN_ADDR_V1_LO / ZP_RTN_ADDR_V1_HI) ; 8C TR = transpose subsequent notes by TR half steps (ZP_TRANSPOSE_V1) ; 8D WV = set wave for voice (ZP_WAVE_V1) ; 8E EN AD AA DI = vibrato/glide func (EN = ZP_FREQ_FUNC_EN_V1 = decr reload counter if nonzero; AD = ZP_FREQ_FUNC_ADCSBC_V1 = freq depth; AA = ZP_FREQ_FUNC_ADCSBC_MAX_V1 = iter count; DI = start dir = ZP_FREQ_FUNC_START_DIR_V1, 00 = sbc, FF = adc) ; vibrato/glide func remains enabled until explicitly disabled (8E 00 00 00 00) ; 8F DR DW FL FH = wave freq func (DR = dur ZP_DIRECT_FREQ_DUR_V1, DW = ZP_DIRECT_WAVE_V1, FL = L_CMD_8F_V1_FREQ, FH = L_CMD_8F_V1_FREQ+1) (for percussion+note effects) ; 90 GO = gate off matching time (counting down duration to zero, GO = ZP_WAVE_GATE_OFF_TIME_V1) ; 91 AT AS = arpeggio function (AT = ZP_AUTO_TRANSPOSE_NOTE_CNT_ORIG_V1, AS = ZP_AUTO_TRANSPOSE_NOTE_ADDSUB_V1) (91 02 0C for octave arp, 91 00 00 to disable) ; 92 GL = note to note glide function (GL = ZP_AUTO_TRANSPOSE_ADCSBC_V1) ; 93 TD = transpose disable (TD = L_SMC_TRANSPOSE_DISABLE_V1) (on next note only?) ; ; otherwise ; NN DR = note, dur (note NN = 0 is C-0 at 268/$010c using the C64 manual's frequency for NTSC)
BTW, may be help, but in JC64DIS, there is a commented disassembly of Ruddys GnG Player, which is way more easy to read i think.
I've fixed the asm-code and uploaded a better version to DeepSID.