; Video Game Music player
; Supports AY8910, YM3812, YMF262, YMF278B, YM2203.
DEVICE ZXSPECTRUM128
include "../_sdk/sys_h.asm"
include "playerdefs.asm"
HEADER_DATA_OFFSET = 0x8034
HEADER_LOOP_SAMPLES_COUNT = 0x8020
HEADER_GD3_OFFSET = 0x8014
HEADER_SAMPLES_COUNT = 0x8018
HEADER_LOOP_OFFSET = 0x801c
HEADER_SIZE_MAX = 256
TITLELENGTH = 64
MEMORYSTREAMMAXPAGES = 210
MEMORYSTREAMERRORMASK = 255 ; TODO: do we need to enforce loading the entire file?
ENABLE_FM = 1
org PLAYERSTART
begin PLAYERHEADER
isfilesupported
;cde = file extension
;out: zf=1 if this player can handle the file and the sound hardware is available, zf=0 otherwise
ld a,c
cp 'v'
ret nz
ld a,d
cp 'g'
ret nz
ld a,e
cp 'm'
jr z,$+5
cp 'z'
ret nz
;prepare local variables
ld hl,0
ld (MUSICTITLEADDR),hl
ld hl,musicprogress+1
ld (MUSICPROGRESSADDR),hl
jp initprogress
playerinit
;hl,ix = GPSETTINGS
;a = player page
;out: zf=1 if init is successful, hl=init message
ld a,(hl)
ld (page8000),a
inc hl
ld a,(hl)
ld (pageC000),a
inc hl
ld a,(hl)
ld (filedatapage),a
ld a,(ix+GPSETTINGS.moonsoundstatus)
ld (moonsoundstatus),a
ld a,(ix+GPSETTINGS.tfmstatus)
ld (tfmstatus),a
;hardware detection is done when loading VGM
ld hl,initokstr
xor a
ret
macro a_or_dw addr
ld hl,(addr+0)
or h
or l
ld de,(addr+2)
or d
or e
endm
macro set_timer wait,ticks
ld hl,wait
ld (waittimercallback),hl
ld hl,ticks
ld (waittimerstep),hl
endm
musicload
;cde = file extension
;hl = input file name
;out: a = device mask, zf=1 if the file is ready for playing, zf=0 otherwise
ld a,e
cp 'z'
ex de,hl
jr z,.loadcompressed
call memorystreamloadfile
jr z,.doneloading
ret
.loadcompressed
call decompressfiletomemorystream
ret nz
.doneloading
set_timer waittimer50hz,882
ld hl,0
ld (waitcounter),hl
ld (samplecounterlo),hl
xor a
ld (samplecounterhi),a
ld (devicemask),a
;map header to 0x8000
ld a,(memorystreampages)
SETPG8000
;copy header
ld bc,HEADER_SIZE_MAX
ld hl,vgmheadercopy
ld de,vgmheadercopy+1
ld (hl),0
ldir
ld hl,(HEADER_DATA_OFFSET)
ld a,h
or l
ld bc,0x40
jr z,$+4
ld c,0x34
add hl,bc
ld (.dataoffset),hl
ld bc,hl
ld hl,-HEADER_SIZE_MAX-1
add hl,bc
jr nc,$+5
ld bc,HEADER_SIZE_MAX
ld hl,0x8000
ld de,vgmheadercopy
ldir
;init progress
ld hl,(HEADER_SAMPLES_COUNT+2)
ld bc,(HEADER_LOOP_SAMPLES_COUNT+2)
add hl,bc
inc hl ;+1 as if low-word addition sets cf
ld a,l
inc h
dec h
jr z,$+4
ld a,255
call setprogressdelta
;check for GD3
xor a
a_or_dw HEADER_GD3_OFFSET
call nz,parsegd3
;setup loop
xor a
a_or_dw HEADER_LOOP_OFFSET
ld (loopoffsetlo),hl
ld (loopoffsethi),de
jr z,$+4
ld a,1
inc a
ld (loopcounter),a
;init AY before TFM in case of weird chip combos
xor a
a_or_dw HEADER_CLOCK_AY8910
call nz,initAY8910
;init TFM
xor a
a_or_dw HEADER_CLOCK_YM2203
a_or_dw HEADER_CLOCK_YM2608
call nz,initYM2203
jp nz,memorystreamfree ;sets zf=0
;init Moonsound
xor a
a_or_dw HEADER_CLOCK_YM3812
ld (useYM3812),a
a_or_dw HEADER_CLOCK_YMF262
jr nz,.opl4notneeded
a_or_dw HEADER_CLOCK_YMF278B
jr z,.opl4notneeded
ld a,(moonsoundstatus)
cp 2
jp nz,memorystreamfree ;sets zf=0
or a
.opl4notneeded
call nz,initYMF278B
jp nz,memorystreamfree ;sets zf=0
.dataoffset=$+1
ld hl,0
ld de,0
call memorystreamseek
devicemask=$+1
ld a,0
;zf=0 if there isn't any supported device
dec a
ret m
inc a
cp a
ret
playerdeinit
ret
include "../_sdk/file.asm"
include "common/memorystream.asm"
include "common/opl4.asm"
include "vgm/opl4.asm"
include "common/opn.asm"
include "vgm/opn.asm"
include "vgm/ssg.asm"
include "progress.asm"
waittimer50hz
YIELD
ret
musicplay
;out: zf=0 if still playing, zf=1 otherwise
waittimercallback=$+1
call 0
playloop
waitcounter=$+1
ld hl,0
waittimerstep=$+1
ld bc,0
sub hl,bc
jr nc,exitplayloop
;read command
memory_stream_read_1 a
ld l,a
ld h,cmdtable/256
ld e,(hl)
inc h
ld d,(hl)
ld hl,playloop
push hl
ex hl,de
jp (hl)
exitplayloop
ld (waitcounter),hl
;update progress
samplecounterlo=$+1
ld hl,0
samplecounterhi=$+1
ld a,0
add hl,bc
adc a,0
jr nc,$+4
ld a,255
ld (samplecounterlo),hl
ld (samplecounterhi),a
call updateprogress
;continue playing
or 1
ret
wait1 ld hl,(waitcounter)
inc hl
ld (waitcounter),hl
ret
waitn memory_stream_read_2 e,d
ld hl,(waitcounter)
add hl,de
ld (waitcounter),hl
ret
macro wait_n n
ld hl,(waitcounter)
ld de,n
add hl,de
ld (waitcounter),hl
ret
endm
wait2 wait_n 2
wait3 wait_n 3
wait4 wait_n 4
wait5 wait_n 5
wait6 wait_n 6
wait7 wait_n 7
wait8 wait_n 8
wait9 wait_n 9
wait10 wait_n 10
wait11 wait_n 11
wait12 wait_n 12
wait13 wait_n 13
wait14 wait_n 14
wait15 wait_n 15
wait16 wait_n 16
wait735 wait_n 735
wait882 wait_n 882
macro skip_n n
ld b,n
jp memorystreamskip
endm
skip1 ret
skip2 skip_n 1
skip3 skip_n 2
skip4 skip_n 3
skip5 skip_n 4
skip6 skip_n 5
skip11 skip_n 10
skip12 skip_n 11
endofsounddata
loopcounter=$+1
ld a,0
dec a
ld (loopcounter),a
jp nz,seektoloop
cmdunsupported
;stop playing
pop af
xor a
ret
cmdYM2203
memory_stream_read_2 e,d
jp opnwritemusiconlyfm1
cmdYM2203dp
memory_stream_read_2 e,d
jp opnwritemusiconlyfm2
cmdYMF262p0
memory_stream_read_2 e,d
jp opl4writemusiconlyfm1
cmdYMF262p1
memory_stream_read_2 e,d
jp opl4writemusiconlyfm2
cmdYMF278B
memory_stream_read_3 c,e,d
dec c
jp z,opl4writemusiconlyfm2
jp p,opl4writewavemusiconly
jp opl4writemusiconlyfm1
cmdYM3812
memory_stream_read_2 e,d
jp opl4writemusiconlyfm1
cmdYM3812dp
memory_stream_read_2 e,d
jp opl4writemusiconlyfm2
cmdAY8910
memory_stream_read_2 e,d
bit 7,e
jp z,ssgwritemusiconlychip0
res 7,e
jp ssgwritemusiconlychip1
cmdYMF262dp0 equ memorystreamread2
cmdYMF262dp1 equ memorystreamread2
processdatablock
memory_stream_read_2 a,e ;a = 0x66 guard, e = type
cp 0x66
jp nz,cmdunsupported
call memorystreamread4 ;adbc = data size
ld a,e
ld hl,bc
cp 0x84
jp z,opl4loadromdatablock
cp 0x87
jp z,opl4loadramdatablock
call setup24bitscounterloop
.loop call memorystreamskip
dec de
ld a,e
or d
jr nz,.loop
ret
seektoloop
ld bc,0x1c
loopoffsethi=$+1
ld de,0
loopoffsetlo=$+1
ld hl,0
seektopos
;dehl + bc = position
;out: hl = read address
add hl,bc
jp nc,memorystreamseek
inc de
jp memorystreamseek
parsegd3
;dehl = GD3 offset
ld bc,32
call seektopos
ld b,TITLELENGTH
ld de,titlestr
ld a,' '
.fillloop
ld (de),a
inc de
djnz .fillloop
xor a
ld (de),a
ld b,TITLELENGTH
ld de,titlestr
call gd3stringcopy ;track name
call z,gd3stringskip ;track name in Japanese
push hl
ld hl,fromstr
call z,stringcopy
pop hl
call z,gd3stringcopy ;game name
call z,gd3stringskip ;game name in Japanese
call z,gd3stringskip ;system name
call z,gd3stringskip ;system name in Japanese
push hl
ld hl,bystr
call z,stringcopy
pop hl
call z,gd3stringcopy ;author
ld hl,titlestr
ld (MUSICTITLEADDR),hl
ld a,(memorystreampages)
SETPG8000
ret
gd3stringcopy
;hl = memorystreamcurrentaddr
;de = dest
;b = bytes remaining
;out: zf=1 if encountered zero terminator, zf=0 if out of space
memory_stream_read_byte a
memory_stream_read_byte c
or a
ret z
ld (de),a
inc de
djnz gd3stringcopy
ret
gd3stringskip
;hl = memorystreamcurrentaddr
;out: zf=1
memory_stream_read_byte a
memory_stream_read_byte c
or c
jr nz,gd3stringskip
ret
stringcopy
;hl = source
;de = dest
;b = bytes remaining
;out: zf=1 if encountered zero terminator, zf=0 if out of space
ld a,(hl)
or a
ret z
ld (de),a
inc hl
inc de
djnz stringcopy
ret
align 256
cmdtable
db skip1 %256 ; 00
db skip1 %256 ; 01
db skip1 %256 ; 02
db skip1 %256 ; 03
db skip1 %256 ; 04
db skip1 %256 ; 05
db skip1 %256 ; 06
db skip1 %256 ; 07
db skip1 %256 ; 08
db skip1 %256 ; 09
db skip1 %256 ; 0A
db skip1 %256 ; 0B
db skip1 %256 ; 0C
db skip1 %256 ; 0D
db skip1 %256 ; 0E
db skip1 %256 ; 0F
db skip1 %256 ; 10
db skip1 %256 ; 11
db skip1 %256 ; 12
db skip1 %256 ; 13
db skip1 %256 ; 14
db skip1 %256 ; 15
db skip1 %256 ; 16
db skip1 %256 ; 17
db skip1 %256 ; 18
db skip1 %256 ; 19
db skip1 %256 ; 1A
db skip1 %256 ; 1B
db skip1 %256 ; 1C
db skip1 %256 ; 1D
db skip1 %256 ; 1E
db skip1 %256 ; 1F
db skip1 %256 ; 20
db skip1 %256 ; 21
db skip1 %256 ; 22
db skip1 %256 ; 23
db skip1 %256 ; 24
db skip1 %256 ; 25
db skip1 %256 ; 26
db skip1 %256 ; 27
db skip1 %256 ; 28
db skip1 %256 ; 29
db skip1 %256 ; 2A
db skip1 %256 ; 2B
db skip1 %256 ; 2C
db skip1 %256 ; 2D
db skip1 %256 ; 2E
db skip1 %256 ; 2F
db cmdunsupported %256 ; 30
db skip2 %256 ; 31
db skip2 %256 ; 32
db skip2 %256 ; 33
db skip2 %256 ; 34
db skip2 %256 ; 35
db skip2 %256 ; 36
db skip2 %256 ; 37
db skip2 %256 ; 38
db skip2 %256 ; 39
db skip2 %256 ; 3A
db skip2 %256 ; 3B
db skip2 %256 ; 3C
db skip2 %256 ; 3D
db skip2 %256 ; 3E
db skip2 %256 ; 3F
db skip3 %256 ; 40
db skip3 %256 ; 41
db skip3 %256 ; 42
db skip3 %256 ; 43
db skip3 %256 ; 44
db skip3 %256 ; 45
db skip3 %256 ; 46
db skip3 %256 ; 47
db skip3 %256 ; 48
db skip3 %256 ; 49
db skip3 %256 ; 4A
db skip3 %256 ; 4B
db skip3 %256 ; 4C
db skip3 %256 ; 4D
db skip3 %256 ; 4E
db skip2 %256 ; 4F
db cmdunsupported %256 ; 50
db cmdunsupported %256 ; 51
db cmdunsupported %256 ; 52
db cmdunsupported %256 ; 53
db cmdunsupported %256 ; 54
db cmdYM2203 %256 ; 55
db cmdYM2608p0 %256 ; 56
db cmdYM2608p1 %256 ; 57
db cmdunsupported %256 ; 58
db cmdunsupported %256 ; 59
db cmdYM3812 %256 ; 5A
db cmdunsupported %256 ; 5B
db cmdunsupported %256 ; 5C
db skip3 %256 ; 5D
db cmdYMF262p0 %256 ; 5E
db cmdYMF262p1 %256 ; 5F
db cmdunsupported %256 ; 60
db waitn %256 ; 61
db wait735 %256 ; 62
db wait882 %256 ; 63
db cmdunsupported %256 ; 64
db cmdunsupported %256 ; 65
db endofsounddata %256 ; 66
db processdatablock%256 ; 67
db skip12 %256 ; 68
db cmdunsupported %256 ; 69
db cmdunsupported %256 ; 6A
db cmdunsupported %256 ; 6B
db cmdunsupported %256 ; 6C
db cmdunsupported %256 ; 6D
db cmdunsupported %256 ; 6E
db cmdunsupported %256 ; 6F
db wait1 %256 ; 70
db wait2 %256 ; 71
db wait3 %256 ; 72
db wait4 %256 ; 73
db wait5 %256 ; 74
db wait6 %256 ; 75
db wait7 %256 ; 76
db wait8 %256 ; 77
db wait9 %256 ; 78
db wait10 %256 ; 79
db wait11 %256 ; 7A
db wait12 %256 ; 7B
db wait13 %256 ; 7C
db wait14 %256 ; 7D
db wait15 %256 ; 7E
db wait16 %256 ; 7F
db skip1 %256 ; 80
db wait1 %256 ; 81
db wait2 %256 ; 82
db wait3 %256 ; 83
db wait4 %256 ; 84
db wait5 %256 ; 85
db wait6 %256 ; 86
db wait7 %256 ; 87
db wait8 %256 ; 88
db wait9 %256 ; 89
db wait10 %256 ; 8A
db wait11 %256 ; 8B
db wait12 %256 ; 8C
db wait13 %256 ; 8D
db wait14 %256 ; 8E
db wait15 %256 ; 8F
db skip5 %256 ; 90
db skip5 %256 ; 91
db skip6 %256 ; 92
db skip11 %256 ; 93
db skip2 %256 ; 94
db skip5 %256 ; 95
db cmdunsupported %256 ; 96
db cmdunsupported %256 ; 97
db cmdunsupported %256 ; 98
db cmdunsupported %256 ; 99
db cmdunsupported %256 ; 9A
db cmdunsupported %256 ; 9B
db cmdunsupported %256 ; 9C
db cmdunsupported %256 ; 9D
db cmdunsupported %256 ; 9E
db cmdunsupported %256 ; 9F
db cmdAY8910 %256 ; A0
db skip3 %256 ; A1
db cmdunsupported %256 ; A2
db cmdunsupported %256 ; A3
db cmdunsupported %256 ; A4
db cmdYM2203dp %256 ; A5
db skip3 %256 ; A6
db skip3 %256 ; A7
db skip3 %256 ; A8
db skip3 %256 ; A9
db cmdYM3812dp %256 ; AA
db cmdunsupported %256 ; AB
db cmdunsupported %256 ; AC
db skip3 %256 ; AD
db cmdYMF262dp0 %256 ; AE
db cmdYMF262dp0 %256 ; AF
db skip3 %256 ; B0
db skip3 %256 ; B1
db skip3 %256 ; B2
db skip3 %256 ; B3
db skip3 %256 ; B4
db skip3 %256 ; B5
db skip3 %256 ; B6
db skip3 %256 ; B7
db skip3 %256 ; B8
db skip3 %256 ; B9
db skip3 %256 ; BA
db skip3 %256 ; BB
db skip3 %256 ; BC
db skip3 %256 ; BD
db skip3 %256 ; BE
db skip3 %256 ; BF
db skip4 %256 ; C0
db skip4 %256 ; C1
db skip4 %256 ; C2
db skip4 %256 ; C3
db skip4 %256 ; C4
db skip4 %256 ; C5
db skip4 %256 ; C6
db skip4 %256 ; C7
db skip4 %256 ; C8
db skip4 %256 ; C9
db skip4 %256 ; CA
db skip4 %256 ; CB
db skip4 %256 ; CC
db skip4 %256 ; CD
db skip4 %256 ; CE
db skip4 %256 ; CF
db cmdYMF278B %256 ; D0
db skip4 %256 ; D1
db cmdunsupported %256 ; D2
db skip4 %256 ; D3
db skip4 %256 ; D4
db skip4 %256 ; D5
db skip4 %256 ; D6
db skip4 %256 ; D7
db skip4 %256 ; D8
db skip4 %256 ; D9
db skip4 %256 ; DA
db skip4 %256 ; DB
db skip4 %256 ; DC
db skip4 %256 ; DD
db skip4 %256 ; DE
db skip4 %256 ; DF
db cmdunsupported %256 ; E0
db skip5 %256 ; E1
db skip5 %256 ; E2
db skip5 %256 ; E3
db skip5 %256 ; E4
db skip5 %256 ; E5
db skip5 %256 ; E6
db skip5 %256 ; E7
db skip5 %256 ; E8
db skip5 %256 ; E9
db skip5 %256 ; EA
db skip5 %256 ; EB
db skip5 %256 ; EC
db skip5 %256 ; ED
db skip5 %256 ; EE
db skip5 %256 ; EF
db skip5 %256 ; F0
db skip5 %256 ; F1
db skip5 %256 ; F2
db skip5 %256 ; F3
db skip5 %256 ; F4
db skip5 %256 ; F5
db skip5 %256 ; F6
db skip5 %256 ; F7
db skip5 %256 ; F8
db skip5 %256 ; F9
db skip5 %256 ; FA
db skip5 %256 ; FB
db skip5 %256 ; FC
db skip5 %256 ; FD
db skip5 %256 ; FE
db skip5 %256 ; FF
db skip1 /256 ; 00
db skip1 /256 ; 01
db skip1 /256 ; 02
db skip1 /256 ; 03
db skip1 /256 ; 04
db skip1 /256 ; 05
db skip1 /256 ; 06
db skip1 /256 ; 07
db skip1 /256 ; 08
db skip1 /256 ; 09
db skip1 /256 ; 0A
db skip1 /256 ; 0B
db skip1 /256 ; 0C
db skip1 /256 ; 0D
db skip1 /256 ; 0E
db skip1 /256 ; 0F
db skip1 /256 ; 10
db skip1 /256 ; 11
db skip1 /256 ; 12
db skip1 /256 ; 13
db skip1 /256 ; 14
db skip1 /256 ; 15
db skip1 /256 ; 16
db skip1 /256 ; 17
db skip1 /256 ; 18
db skip1 /256 ; 19
db skip1 /256 ; 1A
db skip1 /256 ; 1B
db skip1 /256 ; 1C
db skip1 /256 ; 1D
db skip1 /256 ; 1E
db skip1 /256 ; 1F
db skip1 /256 ; 20
db skip1 /256 ; 21
db skip1 /256 ; 22
db skip1 /256 ; 23
db skip1 /256 ; 24
db skip1 /256 ; 25
db skip1 /256 ; 26
db skip1 /256 ; 27
db skip1 /256 ; 28
db skip1 /256 ; 29
db skip1 /256 ; 2A
db skip1 /256 ; 2B
db skip1 /256 ; 2C
db skip1 /256 ; 2D
db skip1 /256 ; 2E
db skip1 /256 ; 2F
db cmdunsupported /256 ; 30
db skip2 /256 ; 31
db skip2 /256 ; 32
db skip2 /256 ; 33
db skip2 /256 ; 34
db skip2 /256 ; 35
db skip2 /256 ; 36
db skip2 /256 ; 37
db skip2 /256 ; 38
db skip2 /256 ; 39
db skip2 /256 ; 3A
db skip2 /256 ; 3B
db skip2 /256 ; 3C
db skip2 /256 ; 3D
db skip2 /256 ; 3E
db skip2 /256 ; 3F
db skip3 /256 ; 40
db skip3 /256 ; 41
db skip3 /256 ; 42
db skip3 /256 ; 43
db skip3 /256 ; 44
db skip3 /256 ; 45
db skip3 /256 ; 46
db skip3 /256 ; 47
db skip3 /256 ; 48
db skip3 /256 ; 49
db skip3 /256 ; 4A
db skip3 /256 ; 4B
db skip3 /256 ; 4C
db skip3 /256 ; 4D
db skip3 /256 ; 4E
db skip2 /256 ; 4F
db cmdunsupported /256 ; 50
db cmdunsupported /256 ; 51
db cmdunsupported /256 ; 52
db cmdunsupported /256 ; 53
db cmdunsupported /256 ; 54
db cmdYM2203 /256 ; 55
db cmdYM2608p0 /256 ; 56
db cmdYM2608p1 /256 ; 57
db cmdunsupported /256 ; 58
db cmdunsupported /256 ; 59
db cmdYM3812 /256 ; 5A
db cmdunsupported /256 ; 5B
db cmdunsupported /256 ; 5C
db skip3 /256 ; 5D
db cmdYMF262p0 /256 ; 5E
db cmdYMF262p1 /256 ; 5F
db cmdunsupported /256 ; 60
db waitn /256 ; 61
db wait735 /256 ; 62
db wait882 /256 ; 63
db cmdunsupported /256 ; 64
db cmdunsupported /256 ; 65
db endofsounddata /256 ; 66
db processdatablock/256 ; 67
db skip12 /256 ; 68
db cmdunsupported /256 ; 69
db cmdunsupported /256 ; 6A
db cmdunsupported /256 ; 6B
db cmdunsupported /256 ; 6C
db cmdunsupported /256 ; 6D
db cmdunsupported /256 ; 6E
db cmdunsupported /256 ; 6F
db wait1 /256 ; 70
db wait2 /256 ; 71
db wait3 /256 ; 72
db wait4 /256 ; 73
db wait5 /256 ; 74
db wait6 /256 ; 75
db wait7 /256 ; 76
db wait8 /256 ; 77
db wait9 /256 ; 78
db wait10 /256 ; 79
db wait11 /256 ; 7A
db wait12 /256 ; 7B
db wait13 /256 ; 7C
db wait14 /256 ; 7D
db wait15 /256 ; 7E
db wait16 /256 ; 7F
db skip1 /256 ; 80
db wait1 /256 ; 81
db wait2 /256 ; 82
db wait3 /256 ; 83
db wait4 /256 ; 84
db wait5 /256 ; 85
db wait6 /256 ; 86
db wait7 /256 ; 87
db wait8 /256 ; 88
db wait9 /256 ; 89
db wait10 /256 ; 8A
db wait11 /256 ; 8B
db wait12 /256 ; 8C
db wait13 /256 ; 8D
db wait14 /256 ; 8E
db wait15 /256 ; 8F
db skip5 /256 ; 90
db skip5 /256 ; 91
db skip6 /256 ; 92
db skip11 /256 ; 93
db skip2 /256 ; 94
db skip5 /256 ; 95
db cmdunsupported /256 ; 96
db cmdunsupported /256 ; 97
db cmdunsupported /256 ; 98
db cmdunsupported /256 ; 99
db cmdunsupported /256 ; 9A
db cmdunsupported /256 ; 9B
db cmdunsupported /256 ; 9C
db cmdunsupported /256 ; 9D
db cmdunsupported /256 ; 9E
db cmdunsupported /256 ; 9F
db cmdAY8910 /256 ; A0
db skip3 /256 ; A1
db cmdunsupported /256 ; A2
db cmdunsupported /256 ; A3
db cmdunsupported /256 ; A4
db cmdYM2203dp /256 ; A5
db skip3 /256 ; A6
db skip3 /256 ; A7
db skip3 /256 ; A8
db skip3 /256 ; A9
db cmdYM3812dp /256 ; AA
db cmdunsupported /256 ; AB
db cmdunsupported /256 ; AC
db skip3 /256 ; AD
db cmdYMF262dp0 /256 ; AE
db cmdYMF262dp0 /256 ; AF
db skip3 /256 ; B0
db skip3 /256 ; B1
db skip3 /256 ; B2
db skip3 /256 ; B3
db skip3 /256 ; B4
db skip3 /256 ; B5
db skip3 /256 ; B6
db skip3 /256 ; B7
db skip3 /256 ; B8
db skip3 /256 ; B9
db skip3 /256 ; BA
db skip3 /256 ; BB
db skip3 /256 ; BC
db skip3 /256 ; BD
db skip3 /256 ; BE
db skip3 /256 ; BF
db skip4 /256 ; C0
db skip4 /256 ; C1
db skip4 /256 ; C2
db skip4 /256 ; C3
db skip4 /256 ; C4
db skip4 /256 ; C5
db skip4 /256 ; C6
db skip4 /256 ; C7
db skip4 /256 ; C8
db skip4 /256 ; C9
db skip4 /256 ; CA
db skip4 /256 ; CB
db skip4 /256 ; CC
db skip4 /256 ; CD
db skip4 /256 ; CE
db skip4 /256 ; CF
db cmdYMF278B /256 ; D0
db skip4 /256 ; D1
db cmdunsupported /256 ; D2
db skip4 /256 ; D3
db skip4 /256 ; D4
db skip4 /256 ; D5
db skip4 /256 ; D6
db skip4 /256 ; D7
db skip4 /256 ; D8
db skip4 /256 ; D9
db skip4 /256 ; DA
db skip4 /256 ; DB
db skip4 /256 ; DC
db skip4 /256 ; DD
db skip4 /256 ; DE
db skip4 /256 ; DF
db cmdunsupported /256 ; E0
db skip5 /256 ; E1
db skip5 /256 ; E2
db skip5 /256 ; E3
db skip5 /256 ; E4
db skip5 /256 ; E5
db skip5 /256 ; E6
db skip5 /256 ; E7
db skip5 /256 ; E8
db skip5 /256 ; E9
db skip5 /256 ; EA
db skip5 /256 ; EB
db skip5 /256 ; EC
db skip5 /256 ; ED
db skip5 /256 ; EE
db skip5 /256 ; EF
db skip5 /256 ; F0
db skip5 /256 ; F1
db skip5 /256 ; F2
db skip5 /256 ; F3
db skip5 /256 ; F4
db skip5 /256 ; F5
db skip5 /256 ; F6
db skip5 /256 ; F7
db skip5 /256 ; F8
db skip5 /256 ; F9
db skip5 /256 ; FA
db skip5 /256 ; FB
db skip5 /256 ; FC
db skip5 /256 ; FD
db skip5 /256 ; FE
db skip5 /256 ; FF
decompressfiletomemorystream
;de = input file name
;out: zf=1 is successful, zf=0 otherwise
call openstream_file
or a
ret nz
;read the last 4 bytes containing decompressed file size
ld a,(filehandle)
ld b,a
OS_GETFILESIZE
ld bc,4
sub hl,bc
jr nc,$+3
dec de
ld a,(filehandle)
ld b,a
OS_SEEKHANDLE
ld de,memorystreamsize
ld hl,4
call readstream_file
ld a,(filehandle)
ld b,a
ld hl,0
ld de,hl
OS_SEEKHANDLE
;allocate memory
ld hl,(memorystreamsize+0)
ld de,(memorystreamsize+2)
call memorystreamallocate
jr nz,closefilewitherror
call memorystreamstart
;decompress
call setsharedpages
ld hl,0xffff
ld (filedatasourceaddr),hl
ld (savedSP),sp
call GzipExtract
call closestream_file
xor a
ret
GzipThrowException
savedSP=$+1
ld sp,0
GzipExitWithError
call memorystreamfree
closefilewitherror
call closestream_file
or 1
ret
setsharedpages
page8000=$+1
ld a,0
SETPG8000
pageC000=$+1
ld a,0
SETPGC000
ret
GzipReadInputBuffer
;de = InputBuffer
;hl = InputBufSize
filedatapage=$+1
ld a,0
SETPG8000
filedatasourceaddr=$+1
ld hl,0
bit 6,h
call nz,loadfiledata
ld bc,InputBufSize
ldir
ld (filedatasourceaddr),hl
ld a,(page8000)
SETPG8000
ret
loadfiledata
exx
ex af,af'
push af,bc,de,hl,ix,iy
ld de,0x8000
ld hl,0x4000
call readstream_file
pop iy,ix,hl,de,bc,af
exx
ex af,af'
ld hl,0x8000
ld de,InputBuffer
ret
GzipWriteOutputBuffer
;de = OutputBuffer
;hl = size
ld a,(memorystreamcurrentpage)
SETPG8000
ld bc,hl
add hl,de
bit 7,h
jr z,.below8000
push hl
ld bc,0x8000-OutputBuffer
call memorystreamwrite
pop hl
res 7,h
push hl
ld de,0x4000
sub hl,de
ld a,(page8000)
jr c,.write8000
jr z,.write8000
ex (sp),hl
SETPGC000
ld de,0xc000
ld bc,0x4000
call memorystreamwrite
ld a,(pageC000)
.write8000
SETPGC000
ld de,0xc000
pop bc
.below8000
call memorystreamwrite
jp setsharedpages
include "common/gunzip.asm"
initAY8910
call ssginit
ld hl,devicemask
ld a,(HEADER_CLOCK_AY8910+3)
and 0x40
jr nz,.dualchip
set DEVICE_AY_BIT,(hl)
ret
.dualchip
set DEVICE_TURBOSOUND_BIT,(hl)
ret
initYM2203
tfmstatus=$+1
ld a,0
dec a
ret m
call opninit
set_timer opnwaittimer60hz,735
call opninittimer60hz
ld hl,devicemask
set DEVICE_TFM_BIT,(hl)
xor a
ret
initYMF278B
moonsoundstatus=$+1
ld a,0
dec a
ret m
call vgmopl4init
ld a,(HEADER_CLOCK_YM3812+3)
and 0x40
jr nz,notOPL2
useYM3812=$+1
or 0
ld de,0x0005
call nz,opl4writefm2
notOPL2 set_timer opl4waittimer60hz,735
call opl4inittimer60hz
ld hl,devicemask
set DEVICE_MOONSOUND_BIT,(hl)
xor a
ret
musicunload
ld a,(devicemask)
and DEVICE_MOONSOUND_MASK
call nz,opl4mute
ld a,(devicemask)
and DEVICE_TFM_MASK
call nz,opnmute
ld a,(devicemask)
and DEVICE_AY_MASK|DEVICE_TURBOSOUND_MASK
call nz,ssgmute
jp memorystreamfree
cmdYM2608p0 equ cmdYM2203
cmdYM2608p1
memory_stream_read_2 e,d
ld a,e
cp 0x30
ret c
jp opnwritefm2
initokstr
db "OK\r\n",0
playernamestr
db "VGM Player",0
fromstr
db " [",0
bystr
db "] by ",0
end
GzipBuffersStart = $
waveheaderbuffer = $
waveheaderbufferend = waveheaderbuffer+WAVEHEADERBUFFERSIZE
titlestr = waveheaderbufferend
titlestrend = titlestr+TITLELENGTH
vgmheadercopy = titlestrend
vgmheadercopyend = vgmheadercopy+HEADER_SIZE_MAX
HEADER_CLOCK_YM2203 = vgmheadercopy+0x44
HEADER_CLOCK_YM2608 = vgmheadercopy+0x48
HEADER_CLOCK_YM3812 = vgmheadercopy+0x50
HEADER_CLOCK_YMF262 = vgmheadercopy+0x5c
HEADER_CLOCK_YMF278B = vgmheadercopy+0x60
HEADER_CLOCK_AY8910 = vgmheadercopy+0x74
assert vgmheadercopyend <= PLAYEREND ;ensure everything is within the player page
assert GzipBuffersEnd <= 0x10000
savebin "vgm.bin",begin,end-begin