;;; $Id: sound.asm,v 1.7 2008/06/20 09:35:53 fvecoven Exp $ ;;; ;;; PACMAN/MSPACMAN SOUND CODE ;;; ;;; ;;; The copyright holders for the core program ;;; included within this file are: ;;; (c) 1980 NAMCO ;;; (c) 1980 Bally/Midway ;;; (c) 1981 General Computer Corporation (GCC) ;;; ;;; ;;; The goal of this project is to reproduce the pacman sound in a single ;;; microcontroller. This goal has been achieved using a PIC18, running at 10MHz ;;; (40MHz internally). For more information, check http://www.vecoven.com ;;; ;;; After looking on the net, I found the dissassembled file of Ms Pacman, where ;;; the contributors are below. This file was a great start, but it didn't contain ;;; much about the sound routines. After spending some time reading the Z80 code, ;;; and monitor it using MAME and its debugger (great tool!), the code is now fully ;;; understood. I've commented the sound portion in this file; others may find this ;;; interesting. ;;; ;;; F. Vecoven (frederic@vecoven.com) 6/15/2008 ;;; ;;; ;;; Research and compilation of the documentation by ;;; Scott 'Jerry' Lawrence ;;; pacman@umlautllama.com ;;; ;;; Documentation and Hack Contributors: ;;; David Caldwell http://www.porkrind.org ;;; Fred K "Juice" ;;; Marcel "The Sil" Silvius http://home.kabelfoon.nl/~msilvius/ ;;; Mark Spaeth http://rgvac.978.org/asm ;;; Dave Widel http://www.widel.com/ ;;; M.A.B. from Vigasoco ;;; ;;; ;;; This file contains the Z80 sound code of pacman and mspacman. ;;; ;;; The pacman hardware has basically a 3-voices. Each voice requires a frequency ;;; (20 bits for voice 1, 16 bits for voices 2 and 3), a wave number (3 bits) and a ;;; volume (4 bits). ;;; ;;; The software refreshes these value every 1/60 sec, during the vblank interrupt. ;;; ;;; Each voice can play an effect or a wave (for song). ;;; ;;; Effects are encoded with 8 bytes : ;;; ;;; 0 : upper 3 bits = frequency shift, lower 3 bits = wave select ;;; 1 : initial base frequency ;;; 2 : frequency increment (added to base freq) ;;; 3 : upper bit = reverse lower 7 bits = duration ;;; 4 : frequency increment (added to initial base frequency). Used when repeat > 1 ;;; 5 : repeat ;;; 6 : upper 4 bits = volume adjust type lower 4 bits = volume ;;; 7 : volume increment ;;; ;;; Songs are coded using a combination of special bytes and tone information. ;;; Special bytes allow selection of wave, volume, etc... ;;; ;;; Special bytes : ;;; F0 : followed by 2 bytes : address where song continues (allows loop or jump in rom) ;;; F1 : followed by 1 byte : wave select ;;; F2 : followed by 1 byte : frequency increment ;;; F3 : followed by 1 byte : volume ;;; F4 : followed by 1 byte : type ;;; FF : mark end of song ;;; ;;; Regular byte : ;;; - upper 3 bits = duration (power of 2 of these bits = duration) ;;; - lower 4 bits = base frequency (using a lookup table) ;;; - lower 5 bits are also assigned to W_DIR, where the 5th bit has a signification ;;; ;;; Songs are played on voices 1 and 2 simultaneously. Neither Pacman nor MsPacman play ;;; song on channel 3. Effects are played on any channel. ;;; ;;; Note that you cannot play songs or effects designed for channel 1 on channel 2 or 3, ;;; and vice-versa. This is due to the fact that channel 1 has a 20 bits adder, and therefore ;;; frequency range is different. ;;; ;;; ;; these 16 values are copied to the hardware every vblank interrupt. CH1_FREQ0 EQU 4e8c ; 20 bits CH1_FREQ1 EQU 4e8d CH1_FREQ2 EQU 4e8e CH1_FREQ3 EQU 4e8f CH1_FREQ4 EQU 4e90 CH1_VOL EQU 4e91 CH2_FREQ1 EQU 4e92 ; 16 bits CH2_FREQ2 EQU 4e93 CH2_FREQ3 EQU 4e94 CH2_FREQ4 EQU 4e95 CH2_VOL EQU 4e96 CH3_FREQ1 EQU 4e97 ; 16 bits CH3_FREQ2 EQU 4e98 CH3_FREQ3 EQU 4e99 CH3_FREQ4 EQU 4e9a CH3_VOL EQU 4e9b SOUND_COUNTER EQU 4c84 ; counter, incremented each VBLANK ; (used to adjust sound volume) EFFECT_TABLE_1 EQU 3b30 ; channel 1 effects. 8 bytes per effect EFFECT_TABLE_2 EQU 3b40 ; channel 2 effects. 8 bytes per effect EFFECT_TABLE_3 EQU 3b80 ; channel 3 effects. 8 bytes per effect #if MSPACMAN SONG_TABLE_1 EQU 9685 ; channel 1 song table SONG_TABLE_2 EQU 967d ; channel 2 song table SONG_TABLE_3 EQU 968d ; channel 3 song table #else SONG_TABLE_1 EQU 3bc8 SONG_TABLE_2 EQU 3bcc SONG_TABLE_3 EQU 3bd0 #endif CH1_E_NUM EQU 4e9c ; effects to play sequentially (bitmask) CH1_E_1 EQU 4e9d ; unused CH1_E_CUR_BIT EQU 4e9e ; current effect CH1_E_TABLE0 EQU 4e9f ; table of parameters, initially copied from ROM CH1_E_TABLE1 EQU 4ea0 CH1_E_TABLE2 EQU 4ea1 CH1_E_TABLE3 EQU 4ea2 CH1_E_TABLE4 EQU 4ea3 CH1_E_TABLE5 EQU 4ea4 CH1_E_TABLE6 EQU 4ea5 CH1_E_TABLE7 EQU 4ea6 CH1_E_TYPE EQU 4ea7 CH1_E_DURATION EQU 4ea8 CH1_E_DIR EQU 4ea9 CH1_E_BASE_FREQ EQU 4eaa CH1_E_VOL EQU 4eab CH1_W_NUM EQU 4ecc ; wave to play (bitmask) CH1_W_1 EQU 4ecd ; unused CH1_W_CUR_BIT EQU 4ece ; current wave CH1_W_SEL EQU 4ecf CH1_W_4 EQU 4ed0 CH1_W_5 EQU 4ed1 CH1_W_OFFSET1 EQU 4ed2 ; address in ROM to find the next byte CH1_W_OFFSET2 EQU 4ed3 ; (16 bits) CH1_W_8 EQU 4ed4 CH1_W_9 EQU 4ed5 CH1_W_A EQU 4ed6 CH1_W_TYPE EQU 4ed7 CH1_W_DURATION EQU 4ed8 CH1_W_DIR EQU 4ed9 CH1_W_BASE_FREQ EQU 4eda CH1_W_VOL EQU 4edb ;; ;; VBLANK - 1 ;; ;; load the sound into the hardware ;; 009d ld hl,#CH1_FREQ0 ; pointer to frequencies and volumes of the 3 voices 00a0 ld de,#5050 ; hardware address 00a3 ld bc,#0010 ; 16 bytes 00a6 ldir ; copy ! ;; voice 1 wave select 00a8 ld a,(#CH1_W_NUM) ; if we play a wave 00ab and a 00ac ld a,(#CH1_W_SEL) ; then WaveSelect = CH1_W_SEL 00af jr nz,#00b4 00b1 ld a,(#CH1_E_TABLE0) ; else WaveSelect = CH1_E_TABLE0 00b4 ld (#5045),a ; write WaveSelect to hardware ;; voice 2 wave select 00b7 ld a,(#CH2_W_NUM) 00ba and a 00bb ld a,(#CH2_W_SEL) 00be jr nz,#00c3 00c0 ld a,(#CH2_E_TABLE0) 00c3 ld (#504a),a ;; voice 3 wave select 00c6 ld a,(#CH3_W_NUM) 00c9 and a 00ca ld a,(#CH3_W_SEL) 00cd jr nz,#00d2 00cf ld a,(#CH3_E_TABLE0) 00d2 ld (#504f),a ;; ;; VBLANK - 2 ;; ;; Process sound 01b9 call #2d0c ; process effects 01bc call #2cc1 ; process waves ;; ;; PROCESS WAVE (all voices) ;; #if MSPACMAN 2cc1 jp #9797 ; sprite/cocktail stuff. we don't care for sound. ; The routine ends with "ld hl,#9685", "jp #2cc4" ; so this is a Ms Pacman patch #else 2cc1 ld hl,#SONG_TABLE_1 #endif ;; channel 1 song 2cc4 ld ix,#CH1_W_NUM ; ix = Pointer to Song number 2cc8 ld iy,#CH1_FREQ0 ; iy = Pointer to Freq/Vol parameters 2ccc call #2d44 ; call process_wave 2ccf ld b,a ; A is the returned volume (save it in B) 2cd0 ld a,(#CH1_W_NUM) ; if we are playing a song 2cd3 and a 2cd4 jr z,#2cda 2cd6 ld a,b ; then 2cd7 ld (#CH1_VOL),a ; save volume ;; channel 2 song 2cda ld hl,#SONG_TABLE_2 2cdd ld ix,#CH2_W_NUM 2ce1 ld iy,#CH2_FREQ1 2ce5 call #2d44 2ce8 ld b,a 2ce9 ld a,(#CH2_W_NUM) 2cec and a 2ced jr z,#2cf3 2cef ld a,b 2cf0 ld (#CH2_VOL),a ;; channel 3 song 2cf3 ld hl,#SONG_TABLE_3 2cf6 ld ix,#CH3_W_NUM 2cfa ld iy,#CH3_FREQ1 2cfe call #2d44 2d01 ld b,a 2d02 ld a,(#CH3_W_NUM) 2d05 and a 2d06 ret z 2d07 ld a,b 2d08 ld (#CH3_VOL),a 2d0b ret ;; ;; Process wave (one voice) ;; 2d44 ld a,(ix+#00) ; if (W_NUM == 0) 2d47 and a 2d48 jp z,#2df4 ; then goto init_param 2d4b ld c,a ; c = W_NUM 2d4c ld b,#08 ; b = 0x08 2d4e ld e,#80 ; e = 0x80 2d50 ld a,e ; find which bit is set in W_NUM 2d51 and c 2d52 jr nz,#2d59 ; found one, goto process wave bis 2d54 srl e 2d56 djnz #2d50 2d58 ret ; return ;; ;; Process wave bis : process one wave, represented by 1 bit (in E) ;; 2d59 ld a,(ix+#02) ; A = CUR_BIT 2d5c and e 2d5d jr nz,#2d66 ; if (CUR_BIT & E != 0) then goto #ed66 2d5f ld (ix+#02),e ; else save E in CUR_BIT 2d62 jp #364e ; and goto #36e4 2d65 inc c ; junk 2d66 dec (ix+#0c) ; decrement W_DURATION 2d69 jp nz,#2dd7 ; if W_DURATION == 0 2d6c ld l,(ix+#06) ; then HL = pointer store in W_OFFSET 2d6f ld h,(ix+#07) ;; process byte 2d72 ld a,(hl) ; A = (HL) 2d73 inc hl 2d74 ld (ix+#06),l ; W_OFFSET = ++HL 2d77 ld (ix+#07),h 2d7a cp #f0 ; if (A < 0xF) 2d7c jr c,#2da5 ; then process A (regular byte) 2d7e ld hl,#2d6c ; else process special byte using a jump table 2d81 push hl ; 2d82 and #0f ; take lowest nibble of special byte 2d84 rst #20 ; and jump (return in HL = 2d6c) ;; jump table 2d85 55 2f ; byte is F0 2d87 65 2f ; byte is F1 2d89 77 2f ; byte is F2 2d8b 89 2f ; byte is F3 2d8d 9b 2f ; byte is F4 2d8f 0c 00 ; 2d91 0c 00 ; 2d93 0c 00 ; 2d95 0c 00 ; 2d97 0c 00 ; 2d99 0c 00 ; 2d9b 0c 00 ; 2d9d 0c 00 ; 2d9f 0c 00 ; 2da1 0c 00 ; 2da3 ad 2f ; byte is FF ;; ;; Special byte F0 : this is followed by 2 bytes, the new offset (to allow loops) ;; 2f55 ld l,(ix+#06) 2f58 ld h,(ix+#07) ; HL = (W_OFFSET) 2f5b ld a,(hl) 2f5c ld (ix+#06),a 2f5f inc hl 2f60 ld a,(hl) 2f61 ld (ix+#07),a ; HL = (HL) 2f64 ret ;; ;; Special byte F1 : followed by one byte (wave select) ;; 2f65 ld l,(ix+#06) 2f68 ld h,(ix+#07) 2f6b ld a,(hl) ; A = (++HL) 2f6c inc hl 2f6d ld (ix+#06),l 2f70 ld (ix+#07),h 2f73 ld (ix+#03),a ; save A in W_WAVE_SEL 2f76 ret ;; ;; Special byte F2 : followed by one byte (Frequency increment) ;; 2f77 ld l,(ix+#06) 2f7a ld h,(ix+#07) 2f7d ld a,(hl) ; A = (++HL) 2f7e inc hl 2f7f ld (ix+#06),l 2f82 ld (ix+#07),h 2f85 ld (ix+#04),a ; save A in W_A 2f88 ret ;; ;; Special byte F3 : followed by one byte (Volume) ;; 2f89 ld l,(ix+#06) 2f8c ld h,(ix+#07) 2f8f ld a,(hl) ; A = (++HL) 2f90 inc hl 2f91 ld (ix+#06),l 2f94 ld (ix+#07),h 2f97 ld (ix+#09),a ; save A in W_VOL 2f9a ret ;; ;; Special byte F4 : followed by one byte (Type) 2f9b ld l,(ix+#06) 2f9e ld h,(ix+#07) 2fa1 ld a,(hl) ; A = (++HL) 2fa2 inc hl 2fa3 ld (ix+#06),l 2fa6 ld (ix+#07),h 2fa9 ld (ix+#0b),a ; save A in W_TYPE 2fac ret ;; ;; Special byte FF : mark the end of the song ;; 2fad ld a,(ix+#02) 2fb0 cpl 2fb1 and (ix+#00) 2fb4 ld (ix+#00),a ; W_NUM &= ~W_CUR_BIT 2fb7 jp #2df4 ;; select song 364e dec b ; B = current bit of song being played (from loop in 2d50) 364f push bc ; adapt B to the current level to find out the song number 3650 ld a,b 3651 cp #01 3653 jr z,#3659 3655 ld b,#00 3657 jr #366a 3659 ld a,(#4e13) 365c ld b,#01 365e cp #01 3660 jr z,#366a 3662 ld b,#02 3664 cp #04 3666 jr z,#366a 3668 ld b,#03 ; now B is adapted, and hold the song number 366a rst #18 ; HL = (HL+2B) [read from table in HL, i.e. SONG_TABLE_x] 366b pop bc 366c jp #2d72 ; jump to "process byte" routine ;; process regular byte (A=byte to process, it's not a special byte) 2da5 ld b,a ; copy A in B 2da6 and #1f 2da8 jr z,#2dad ; if (A & 0x1f == 0) 2daa ld (ix+#0d),b ; then W_DIR = B 2dad ld c,(ix+#09) ; C = W_9 2db0 ld a,(ix+#0b) 2db3 and #08 2db5 jr z,#2db9 ; if (W_8 & 0x8 == 0) 2db7 ld c,#00 ; then VOL = 0 2db9 ld (ix+#0f),c ; else VOL = W_9 2dbc ld a,b ; restore A 2dbd rlca 2dbe rlca 2dbf rlca 2dc0 and #07 ; A = (A & 0xE0) >> 5 2dc2 ld hl,#3bb0 2dc5 rst #10 ; A = ROM[0x3bb0 + A] ; Note: this is just A = 2**A 2dc6 ld (ix+#0c),a ; W_DURATION = A 2dc9 ld a,b ; restore A 2dca and #1f 2dcc jr z,#2dd7 ; if (A & 0x1f == 0) then goto compute_wave_freq 2dce and #0f ; A = A & 0x0F 2dd0 ld hl,#3bb8 ; lookup table, contains a table a frequencies 2dd3 rst #10 2dd4 ld (ix+#0e),a ; W_BASE_FREQ = ROM[3bb8 + A] ;; compute wave frequency 2dd7 ld l,(ix+#0e) 2dda ld h,#00 ; HL = W_BASE_FREQ (on 16 bits) 2ddc ld a,(ix+#0d) ; A = W_DIR 2ddf and #10 2de1 jr z,#2de5 ; if (W_DIR & 0x10 != 0) then 2de3 ld a,#01 ; A = 1 2de5 add a,(ix+#04) ; A += W_4 2de8 jp z,#2ee8 ; compute new frequency FREQ = BASE_FREQ * (1 << A) 2deb jp #2ee4 ;; ;; PROCESS EFFECT (all voices) ;; 2d0c ld hl,#EFFECT_TABLE_1 ; pointer to sound table 2d0f ld ix,#CH1_E_NUM ; effect number (voice 1) 2d13 ld iy,#CH1_FREQ0 2d17 call #2dee ; call process effect, returns volume in A 2d1a ld (#CH1_VOL),a ; store volume 2d1d ld hl,#EFFECT_TABLE_2 ; same for voice 2 2d20 ld ix,#CH2_E_NUM 2d24 ld iy,#CH2_FREQ1 2d28 call #2dee 2d2b ld (#CH2_VOL),a 2d2e ld hl,#EFFECT_TABLE_3 ; same for voice 3 2d31 ld ix,#CH3_E_NUM 2d35 ld iy,#CH3_FREQ1 2d39 call #2dee 2d3c ld (#CH3_VOL),a 2d3f xor a ; A = 0 2d40 ld (#CH1_FREQ4),a ; freq 4 channel 1 = 0 2d43 ret ;; ;; Process effect (one voice) ;; 2dee ld a,(ix+#00) ; if (E_NUM != 0) 2df1 and a ; 2df2 jr nz,#2e1b ; then goto find effect ;; ;; Init Param ;; 2df4 ld a,(ix+#02) ; if (CUR_BIT == 0) 2df7 and a 2df8 ret z ; then return 2df9 ld (ix+#02),#00 ; CUR_BIT = 0 2dfd ld (ix+#0d),#00 ; DIR = 0 2e01 ld (ix+#0e),#00 ; BASE_FREQ = 0 2e05 ld (ix+#0f),#00 ; VOL = 0 2e09 ld (iy+#00),#00 ; FREQ0 or 1 (5 freq for channel 1) 2e0d ld (iy+#01),#00 ; FREQ1 or 2 2e11 ld (iy+#02),#00 ; FREQ2 or 3 2e15 ld (iy+#03),#00 ; FREQ3 or 4 2e19 xor a ; 2e1a ret ; return 0 ;; ;; find effect. Effect num is not zero, find which bits are set ;; 2e1b ld c,a ; c = E_NUM 2e1c ld b,#08 ; b = 0x08 2e1e ld e,#80 ; e = 0x80 2e20 ld a,e ; find which bit is set in E_NUM 2e21 and c 2e22 jr nz,#2e29 ; found one, goto proces effect bis 2e24 srl e 2e26 djnz #2e20 2e28 ret ;; ;; Process effect bis : process one effect, represented by 1 bit (in E) ;; 2e29 ld a,(ix+#02) ; A = CUR_BIT 2e2c and e 2e2d jr nz,#2e6e ; if (CUR_BIT & E != 0) then goto 2e6e 2e2f ld (ix+#02),e ; else save E in CUR_BIT ; locate the 8 bytes for this effect in the rom tables 2e32 dec b ; the address is at HL + (B-1) * 8 2e33 ld a,b 2e34 rlca 2e35 rlca 2e36 rlca 2e37 ld c,a ; C = (B-1)*8 2e38 ld b,#00 ; B = 0 2e3a push hl ; save HL (pointer to EFFECT_TABLE) 2e3b add hl,bc ; HL = HL + (B-1)*8 2e3c push ix 2e3e pop de ; DE = E_NUM 2e3f inc de 2e40 inc de 2e41 inc de ; DE = E_TABLE0 2e42 ld bc,#0008 2e45 ldir ; copy 8 bytes from rom 2e47 pop hl ; restore HL (pointer to EFFECT_TABLE) 2e48 ld a,(ix+#06) 2e4b and #7f 2e4d ld (ix+#0c),a ; E_DURATION = E_TABLE3 & 0x7F 2e50 ld a,(ix+#04) 2e53 ld (ix+#0e),a ; E_BASE_FREQ = E_TABLE1 2e56 ld a,(ix+#09) 2e59 ld b,a ; B = E_TABLE6 2e5a rrca 2e5b rrca 2e5c rrca 2e5d rrca 2e5e and #0f 2e60 ld (ix+#0b),a ; E_TYPE = (E_TABLE6 >> 4) & 0xF 2e63 and #08 2e65 jr nz,#2e6e ; if (E_TYPE & 0x8 == 0) then 2e67 ld (ix+#0f),b ; E_VOL = E_TABLE6 2e6a ld (ix+#0d),#00 ; E_DIR = 0 ;; compute effect 2e6e dec (ix+#0c) ; E_DURATION-- 2e71 jr nz,#2ecd ; if (E_DURATION == 0) then 2e73 ld a,(ix+#08) 2e76 and a 2e77 jr z,#2e89 ; if (E_TABLE5 != 0) then 2e79 dec (ix+#08) ; E_TABLE5-- 2e7c jr nz,#2e89 ; if (E_TABLE5 == 0) then 2e7e ld a,e 2e7f cpl 2e80 and (ix+#00) 2e83 ld (ix+#00),a ; E_NUM &= ~E_CUR_BIT 2e86 jp #2dee ; goto process effect (one voice) 2e89 ld a,(ix+#06) 2e8c and #7f 2e8e ld (ix+#0c),a ; E_DURATION = E_TABLE3 & 0x7F 2e91 bit 7,(ix+#06) 2e95 jr z,#2ead ; if (E_TABLE3 & 0x80 != 0) then 2e97 ld a,(ix+#05) 2e9a neg 2e9c ld (ix+#05),a ; E_TABLE2 = - E_TABLE2 2e9f bit 0,(ix+#0d) ; if (E_DIR & 0x1 == 0) then 2ea3 set 0,(ix+#0d) ; E_DIR |= 0x1 2ea7 jr z,#2ecd ; goto update_freq 2ea9 res 0,(ix+#0d) ; E_DIR &= ~0x1 2ead ld a,(ix+#04) 2eb0 add a,(ix+#07) 2eb3 ld (ix+#04),a ; E_TABLE1 += E_TABLE4 2eb6 ld (ix+#0e),a ; E_BASE_FREQ = E_TABLE1 2eb9 ld a,(ix+#09) 2ebc add a,(ix+#0a) 2ebf ld (ix+#09),a ; E_TABLE6 += E_TABLE7 2ec2 ld b,a 2ec3 ld a,(ix+#0b) 2ec6 and #08 2ec8 jr nz,#2ecd ; if (E_TYPE & 0x8 == 0) then 2eca ld (ix+#0f),b ; E_VOL = E_TABLE6 ;; update freq 2ecd ld a,(ix+#0e) 2ed0 add a,(ix+#05) 2ed3 ld (ix+#0e),a ; E_BASE_FREQ += E_TABLE2 2ed6 ld l,a 2ed7 ld h,#00 ; HL = E_BASE_FREQ (on 16 bits) 2ed9 ld a,(ix+#03) ; compute new frequency 2edc and #70 ; FREQ = E_BASE_FREQ * ((1 << E_TABLE0 & 0x70) >> 4) 2ede jr z,#2ee8 2ee0 rrca 2ee1 rrca 2ee2 rrca 2ee3 rrca ;; compute new frequency 2ee4 ld b,a ; B = counter 2ee5 add hl,hl ; HL = 2 * HL 2ee6 djnz #2ee5 ; HL = HL * 2**B ; now extract the nibbles from HL 2ee8 ld (iy+#00),l ; 1st nibble 2eeb ld a,l 2eec rrca 2eed rrca 2eee rrca 2eef rrca 2ef0 ld (iy+#01),a ; 2nd nibble 2ef3 ld (iy+#02),h ; 3rd nibble 2ef6 ld a,h 2ef7 rrca 2ef8 rrca 2ef9 rrca 2efa rrca 2efb ld (iy+#03),a ; 4th nibble 2efe ld a,(ix+#0b) ; A = W_TYPE 2f01 rst #20 ; jump table to volume adjust routine ; jump table to adjust volume 2f02 22 2f 26 2f 2b 2f 3c 2f 43 2f 4a 2f 4b 2f 4c 2f 2f12 4d 2f 4e 2f 4f 2f 50 2f 51 2f 52 2f 53 2f 54 2f ;; type 0 2f22 ld a,(ix+#0f) ; constant volume 2f25 ret ;; type 1 2f26 ld a,(ix+#0f) ; decreasing volume 2f29 jr #2f34 ;; type 2 2f2b ld a,(#4c84) ; decreasing volume (1/2 rate) 2f2e and #01 2f30 ld a,(ix+#0f) ; (skip decrease if sound_counter (4c84) is odd) 2f33 ret nz 2f34 and #0f ; decrease routine 2f36 ret z 2f37 dec a 2f38 ld (ix+#0f),a 2f3b ret ;; type 3 2f3c ld a,(#4c84) ; decreasing volume (1/4 rate) 2f3f and #03 2f41 jr #2f30 ;; type 4 2f43 ld a,(#4c84) ; decreasing volume (1/8 rate) 2f46 and #07 2f48 jr #2f30 ;; type 5-15 2f4a ret 2f4b ret 2f4c ret 2f4d ret 2f4e ret 2f4f ret 2f50 ret 2f51 ret 2f52 ret 2f53 ret 2f54 ret ;; ;; PACMAN sound tables ;; ;; channel 1 effects 3B30 73 20 00 0C 00 0A 1F 00 72 20 FB 87 00 02 0F 00 ;; channel 2 effects 3B40 36 20 04 8C 00 00 06 00 36 28 05 8B 00 00 06 00 3B50 36 30 06 8A 00 00 06 00 36 3C 07 89 00 00 06 00 3B60 36 48 08 88 00 00 06 00 24 00 06 08 00 00 0A 00 3B70 40 70 FA 10 00 00 0A 00 70 04 00 00 00 00 08 00 ;; channel 3 effects 3B80 42 18 FD 06 00 01 0C 00 42 04 03 06 00 01 0C 00 3B90 56 0C FF 8C 00 02 0F 00 05 00 02 20 00 01 0C 00 3BA0 41 20 FF 86 FE 1C 0F FF 70 00 01 0C 00 01 08 00 ;; lookup tables 3BB0 01 02 04 08 10 20 40 80 3BB8 00 57 5C 61 67 6D 74 7B 82 8A 92 9A A3 AD B8 C3 ;; channel 1 : jump table to song data 3BC8 D4 3B F3 3B ;; channel 2 : jump table to song data 3BCC 58 3C 95 3C ;; channel 3 : jump table to song data 3BD0 DE 3C DF 3C ;; song data 3BD4 F1 02 F2 03 F3 0F F4 01 82 70 69 82 70 69 83 70 3BE4 6A 83 70 6A 82 70 69 82 70 69 89 8B 8D 8E FF 3BF3 F1 02 F2 03 F3 0F F4 01 67 50 30 47 30 67 50 30 3C03 47 30 67 50 30 47 30 4B 10 4C 10 4D 10 4E 10 67 3C13 50 30 47 30 67 50 30 47 30 67 50 30 47 30 4B 10 3C23 4C 10 4D 10 4E 10 67 50 30 47 30 67 50 30 47 30 3C33 67 50 30 47 30 4B 10 4C 10 4D 10 4E 10 77 20 4E 3C43 10 4D 10 4C 10 4A 10 47 10 46 10 65 30 66 30 67 3C53 40 70 F0 FB 3B 3C58 F1 00 F2 02 F3 0F F4 00 42 50 4E 50 49 50 46 50 3C68 4E 49 70 66 70 43 50 4F 50 4A 50 47 50 4F 4A 70 3C78 67 70 42 50 4E 50 49 50 46 50 4E 49 70 66 70 45 3C88 46 47 50 47 48 49 50 49 4A 4B 50 6E FF 3C95 F1 01 F2 01 F3 0F F4 00 26 67 26 67 26 67 23 44 3CA4 42 47 30 67 2A 8B 70 26 67 26 67 26 67 23 44 42 3CB4 47 30 67 23 84 70 26 67 26 67 26 67 23 44 42 47 3CC4 30 67 29 6A 2B 6C 30 2C 6D 40 2B 6C 29 6A 67 20 3CD4 29 6A 40 26 87 70 F0 9D 3C 3CDD 00 00 00 ;; ;; MSPACMAN sound tables ;; ;; 2 effects for channel 1 3b30 73 20 00 0c 00 0a 1f 00 72 20 fb 87 00 02 0f 00 ;; 8 effects for channel 2 3b40 59 01 06 08 00 00 02 00 59 01 06 09 00 00 02 00 3b50 59 02 06 0a 00 00 02 00 59 03 06 0b 00 00 02 00 3b60 59 04 06 0c 00 06 02 00 24 00 06 08 02 00 0a 00 3b70 36 07 87 6f 00 00 04 00 70 04 00 00 00 00 08 00 ;; 6 effects for channel 3 3b80 1c 70 8b 08 00 01 06 00 1c 70 8b 08 00 01 06 00 3b90 56 0c ff 8c 00 02 08 00 56 00 02 0a 07 03 0c 00 3ba0 36 38 fe 12 f8 04 0f fc 22 01 01 06 00 01 07 00 ;; lookup tables 3bb0 01 02 04 08 10 20 40 80 3bb8 00 57 5c 61 67 6d 74 7b 82 8a 92 9a a3 ad b8 c3 ;; junk left from pacman 3bc8 d4 3b f3 3b 58 3c 95 3c de 3c df 3c ;; song data 3bd4 f1 03 f2 03 f3 0a f4 02 90 7c 7b 7a 79 79 78 97 3be4 76 75 74 73 73 72 91 a8 88 60 4a 4c 91 95 88 95 3bf4 91 95 88 95 91 95 88 95 95 98 94 97 93 96 88 96 3c04 93 96 88 96 93 96 88 96 b6 b3 75 76 77 78 78 75 3c14 73 68 91 95 88 95 91 95 88 95 86 96 95 92 93 8c 3c24 8a 88 86 90 90 96 95 90 90 86 90 96 90 96 91 88 3c34 81 ff 3c36 47 30 4b 10 4c 10 4d 10 4e 10 77 20 4e 10 4d 10 3c46 4c 10 4a 10 47 10 46 10 65 30 66 30 67 40 70 f0 3c56 fb 3b ;; song data 3c58 f1 00 f2 02 f3 0a f4 00 88 6c 71 72 73 73 71 93 3c68 6c 73 75 76 76 75 96 7c 7a 78 76 75 96 6c 91 a0 3c78 88 75 76 77 78 71 73 74 75 71 75 71 68 68 65 66 3d78 67 a8 ab ac 8c 86 76 75 6c 71 75 73 6b 6c 73 76 3d88 7a 78 78 76 73 6c aa a8 71 73 74 75 6a 6b 6c 73 3d98 75 76 77 78 71 73 74 75 71 75 71 68 48 40 68 67 3da8 68 aa a9 aa 6a 60 8a 76 75 73 71 71 73 95 75 73 3db8 71 68 68 61 63 6a a8 6c 76 6a 6c 91 90 91 ff 3dc7 40 26 87 70 f0 9d 3c 00 00 ;; ;; Song pointers. When selecting one song, ;; use channels 1 and 2. ;; ;; song 0x01 : start ;; song 0x02 : act 1 ;; song 0x04 : act 2 ;; song 0x08 : act 3 ;; ;; channel 2 : jump table to song data 967d 95 96 d6 96 58 3c 4f 97 ;; channel 1 : jump table to song data 9685 b6 96 19 97 d4 3b 72 97 ;; channel 3 : jump table to song data (nothing here, 9796 = 0xff) 968d 96 97 96 97 96 97 96 97 ;; songs data 9695 f1 00 f2 02 f3 0a f4 00 41 43 45 86 8a 88 8b 6a 96a5 6b 71 6a 88 8b 6a 6b 71 6a 6b 71 73 75 96 95 96 96b5 ff 96b6 f1 02 f2 03 f3 0a f4 02 50 70 86 90 81 90 86 90 96c6 68 6a 6b 68 6a 68 66 6a 68 66 65 68 86 81 86 ff 96d6 f1 00 f2 02 f3 0a f4 00 69 6b 69 86 61 64 65 86 96e6 86 64 66 64 61 69 6b 69 86 61 64 64 a1 70 71 74 96f6 75 35 76 30 50 35 76 30 50 54 56 54 51 6b 69 6b 9706 69 6b 91 6b 69 66 f2 01 74 76 74 71 74 71 6b 69 9716 a6 a6 ff 9719 f1 03 f2 03 f3 0a f4 02 70 66 70 46 50 86 90 70 9729 66 70 46 50 86 90 70 66 70 46 50 86 90 70 61 70 9739 41 50 81 90 f4 00 a6 a4 a2 a1 f4 01 86 89 8b 81 9749 74 71 6b 69 a6 ff 974f f1 00 f2 02 f3 0a f4 00 65 64 65 88 67 88 61 63 975f 64 85 64 85 6a 69 6a 8c 75 93 90 91 90 91 70 8a 976f 68 71 ff 9772 f1 02 f2 03 f3 0a f4 02 65 90 68 70 68 67 66 65 9782 90 61 70 61 65 68 66 90 63 90 86 90 85 90 85 70 9792 86 68 65 ff 9796 ff ;; rst 20 (jump table) ;; ;; jump to (HL+2*A) 0020 pop hl ; get HL from stack 0021 add a,a 0022 rst #10 ; HL += 2A A = (HL) 0023 ld e,a ; E = A = (HL) 0024 inc hl ; 0025 ld d,(hl) ; D = (HL+1) so DE = 16-bits at HL+2A 0026 ex de,hl ; DE <-> HL 0027 jp (hl) ; goto HL ;; rst 10 (for dereferencing pointers to bytes) ;; hl = hl + a, (hl) -> a ;; HL = base address of table ;; A = index ;; after the call, A gets the data in HL+A 0010 add a,l 0011 ld l,a 0012 ld a,#00 0014 adc a,h 0015 ld h,a 0016 ld a,(hl) 0017 ret ;; rst 18 (for dereferencing pointers to words) ;; hl = hl + 2*b, (hl) -> e, (++hl) -> d, de -> hl ;; HL = base address of table ;; B = index ;; after the call, DE gets the data in HL+(2*B) 0018 78 ld a,b 0019 87 add a,a 001a d7 rst #10 001b 5f ld e,a ; E = (HL+2B) 001c 23 inc hl 001d 56 ld d,(hl) ; D = (HL+2B+1) 001e eb ex de,hl ; HL = (HL+2B) 001f c9 ret