Login

Subversion Repositories NedoOS

Rev

Rev 1797 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

; Player for NeoGS decoder chip (also GS/NeoGS .mod player)
; Supports a range of VLSI decoders: VS1001, VS1011, VS1003, VS1033, VS1053

        DEVICE ZXSPECTRUM128
        include "../_sdk/sys_h.asm"
        include "ngsdec/gscodedefs.asm"
        include "ngsdec/gsports.asm"
        include "ngsdec/vs10xx.asm"
        include "playerdefs.asm"

BUFADDR = 0x8000
BUFSIZE = 0x8000

        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
isgsdisabled=$+1
        jr nosupportedfiles
        call ismodfile
        jr nz,checkmid
        ld hl,0
        ld (MUSICTITLEADDR),hl
        ld hl,musicprogress+1
        ld (MUSICPROGRESSADDR),hl
        jp initprogress
nosupportedfiles
        or 1
        ret
checkmid
vsversion=$+1
        ld a,255
        ld l,'m'
        ld h,b
        sub hl,bc
        jr nz,checkogg
        ld hl,'id'
        sbc hl,de
        jr nz,checkogg
        cp SS_VER_VS1003
        jr z,initmidvars
        cp SS_VER_VS1033
        jr z,initmidvars
        cp SS_VER_VS1053
        jr z,initmidvars
        cp SS_VER_VS1103
        ret nz
initmidvars
        ld (filechunkcounter),hl
        ld (MUSICTITLEADDR),hl
        ld (MUSICPROGRESSADDR),hl
        jp initprogress
checkogg
        ld l,'o'
        ld h,b
        sub hl,bc
        jr nz,checkaac
        ld hl,'gg'
        sbc hl,de
        jr nz,checkaac
        cp SS_VER_VS1053
        jr z,initmp3vars
        cp SS_VER_VS1063
        jr z,initmp3vars
        ret    
checkaac
        ld l,'a'
        ld h,b
        sub hl,bc
        jr nz,checkmp3
        ld hl,'ac'
        sbc hl,de
        jr nz,checkmp3
        cp SS_VER_VS1033
        jr z,initmp3vars
        cp SS_VER_VS1053
        jr z,initmp3vars
        cp SS_VER_VS1063
        jr z,initmp3vars
        ret
checkmp3
        ld l,'m'
        ld h,b
        sub hl,bc
        ret nz
        ld hl,'p3'
        sbc hl,de
        ret nz
        and ~SS_VER_MASK
        ret nz
initmp3vars
        ld (filechunkcounter),hl
        ld (MUSICTITLEADDR),hl
        ld hl,musicprogress+1
        ld (MUSICPROGRESSADDR),hl
        jp initprogress

ismodfile
;cde = file extension
;out: zf=1 if .mod, zf=0 otherwise
        ld a,'m'
        cp c
        ret nz
        ld a,'o'
        cp d
        ret nz
        ld a,'d'
        cp e
        ret

playerinit
;hl = 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

;       call gssoftreset
;b==0 if no reply from GS
;       dec b
;       inc b
;       call z,gshardreset
        call gshardreset
;b==0 if no reply from GS
        ld a,b
        cp 1
        ld hl,nodevicestr
        ret c

;get chip id
        call gsstartcode
        SC CMDGETCHIPID
        WC
        WN
        GD
        ld (vsversion),a
        call gscodereset

        ld a,(vsversion)
        cp SS_VER_VS1103+1
        ld hl,gsinitok
        jr nc,.gsonly
        rrca
        rrca
        add a,idtostr%256
        ld l,a
        adc a,idtostr/256
        sub l
        ld h,a
        ld de,chipidstr
        ld bc,4
        ldir
        ld hl,ngsinitokstr
.gsonly
        xor a
        ld (isgsdisabled),a
        ret

playerdeinit
        ret

musicload
;cde = file extension
;hl = input file name
;out: zf=1 if the file is ready for playing, zf=0 otherwise
        call ismodfile
        ld a,1
        jr z,$+3
        dec a
        ld (isplayingmodfile),a

        ex de,hl
        call openstream_file
        or a
        ret nz

page8000=$+1
        ld a,0
        SETPG8000
pageC000=$+1
        ld a,0
        SETPGC000

        ld a,(isplayingmodfile)
        or a
        jr nz,loadmod

        ld a,(filehandle)
        ld b,a
        OS_GETFILESIZE
        ld a,e
        call setprogressdelta

        call gsstartcode

        ld hl,firstpaddingframedata
        ld (paddingframedataptr),hl
        ld hl,0
        ld (paddingframecount),hl
        ld (bufferdataleft),hl

        xor a
        ret

TITLELENGTH = 64
MODHEADERSIZE = 1084

loadmod
        ld hl,MODHEADERSIZE
        ld de,BUFADDR
        call readstream_file
;init progress
        call getmodtype
        ld a,(BUFADDR+950)
        jr z,$+5
        ld a,(BUFADDR+470)
        call setprogressdelta
;set title
        ld hl,titlestr
        ld (MUSICTITLEADDR),hl
        ld de,BUFADDR
        ld b,TITLELENGTH+1
.copytitleloop
        ld a,(de)
        ld (hl),a
        inc de
        inc hl
        dec b
        or a
        jr nz,.copytitleloop
        dec hl
.filltitleloop
        ld (hl),' '
        inc hl
        djnz .filltitleloop
        ld (hl),0
;load module
        SC 0x30
        WC
;open stream
        SC 0xD1
        WC
;upload file
        ld hl,BUFADDR
        ld bc,MODHEADERSIZE
.uploadloop
        ld a,(hl)
        out (GSDAT),a
        WD
        inc hl
        dec bc
        ld a,b
        or c
        jr nz,.uploadloop
        ld hl,BUFSIZE
        ld de,BUFADDR
        push de
        call readstream_file
        ex (sp),hl
        pop bc
        ld a,b
        or c
        jr nz,.uploadloop
        call closestream_file
;close stream
        SC 0xD2
        WC
;play module
        ld a,1
        out (GSDAT),a
        SC 0x31
        WC
        xor a
        ld (currentposition),a
        ret

musicunload
        ld a,(isplayingmodfile)
        or a
        jr nz,unloadmod

        call closestream_file
        jp gscodereset

unloadmod
        SC 0xf3
        WC
        ret

musicplay
;out: zf=0 if still playing, zf=1 otherwise
isplayingmodfile=$+1
        ld a,0
        or a
        jr nz,playmod

bufferreadptr=$+1
        ld hl,0
bufferdataleft=$+1
        ld bc,0
        ld a,c
        or b
        jr nz,checkifcanupload
readfilechunk
        ld hl,(paddingframecount)
        ld de,150
        sub hl,de
        sbc a
        ret z
        call readdata
        ld hl,BUFADDR
        ex de,hl
        sub hl,de
        ld b,l
        dec hl
        inc h
        ld c,h
        ex de,hl
        jr checkifcanupload

uploaddataloop
        ld a,(hl)
        out (GSDAT),a
        WD
        inc hl
        djnz uploaddataloop
        dec c
        jr z,readfilechunk          ;done uploading current chunk
        bit 0,c
        jr z,uploaddataloop         ;poll GS once per 512 bytes
checkifcanupload
        SC CMDGETFREEBUFFERSPACE
        WC
        WN
        GD
        cp 6
        jr nc,uploaddataloop        ;keep uploading until we have less than 1024 free buffer space

        ld (bufferreadptr),hl
        ld (bufferdataleft),bc

        YIELD

        or 1
        ret

playmod
        YIELD
        YIELD
        YIELD
        YIELD
;update progress
        SC 0x60
        WC
        WN
        GD
        push af
        call updateprogress
        pop af
;check if the position is increasing monotonically
        ld hl,currentposition
        cp (hl)
        ld (hl),a
        ccf
        sbc a
        ret

readdata
;out: de = past-the-end data pointer
        ld hl,(paddingframecount)
        ld a,l
        or h
        ld hl,BUFSIZE
        ld de,BUFADDR
        jr nz,writepadding
        call readstream_file
        ld bc,hl
        ld hl,BUFADDR
        add hl,bc
        ex de,hl
        ld hl,BUFSIZE
        sub hl,bc
        jr nz,writepadding
;update progress
        ld hl,(filechunkcounter)
        ld de,BUFSIZE>>8 ;256 bytes chunks
        add hl,de
        ld (filechunkcounter),hl
        ld a,h
        call updateprogress
        ld de,(BUFADDR+BUFSIZE)%65536
        ret

writepadding
        ld bc,paddingframedata_end-paddingframedata
        sub hl,bc
        ret c
        push hl
paddingframedataptr=$+1
        ld hl,0
        ldir
        ld hl,paddingframedata
        ld (paddingframedataptr),hl
paddingframecount=$+1
        ld hl,0
        inc hl
        ld (paddingframecount),hl
        pop hl
        jr writepadding

gshardreset
;out: b!=0 if got reply from GS, b==0 otherwise
        ld a,C_GRST
        out (GSCTR),a               ;hw reset
        YIELD
        YIELD
        YIELD
gssoftreset
        SC 0xf3                     ;GS reset
        ld b,50                     ;max spins
wcloop
        push bc
        YIELD
        pop bc
        dec b
        ret z
        in a,(GSCOM)
        rrca
        jr c,wcloop
        ret

gsstartcode
        ld bc,GSDAT
        ld de,gscode_end-gscode
        ld hl,GSPROGSTART
        out (c),e
        SC 0x14
        WC
        out (c),d
        WD
        out (c),l
        WD
        out (c),h
        WD
;start upload
        ld hl,gscode
.uploadloop
        outi
        WD
        dec de
        ld a,d
        or e
        jr nz,.uploadloop
;launch the code
        ld hl,GSPROGSTART
        out (c),l
        SC 0x13
        WC
        out (c),h
        WD
;the code is starting
        YIELD
        YIELD
        YIELD
        ret

getmodtype
;https://github.com/psbhlw/gs-firmware/blob/6c783a56147511b43d197e4079e993c2b94b4f12/firmware/src/PLAY.a80#L27
;out: zf=0 for SoundTracker 4/15 file, zf=1 otherwise
        LD A,(BUFADDR+1080)
        CP "M"
        JR Z,TTY1
        CP "4"
        JR Z,TTY1
        CP "F"
        JR Z,TTY1
        ret
TTY1    LD A,(BUFADDR+1081)
        CP "."
        JR Z,TTY2
        CP "L"
        JR Z,TTY2
        CP "!"
        JR Z,TTY2
        CP "C"
        JR Z,TTY2
        ret
TTY2    LD A,(BUFADDR+1082)
        CP "K"
        ret z
        CP "T"
        ret z
        CP "H"
        ret

gscodereset
        SC CMDRESET
        WC
        ret

firstpaddingframedata
        db 0xFF,0xFB,0x90,0x64,0x00,0x0F,0xF0,0x00,0x00
        db 0x69,0x00,0x00,0x00,0x08,0x00,0x00,0x0D,0x20
        db 0x00,0x00,0x01,0x00,0x00,0x01,0xA4,0x00,0x00
        db 0x00,0x20,0x00,0x00,0x34,0x80,0x00,0x00,0x04
        ds 381,0x55
firstpaddingframedata_end

paddingframedata
        db 0xFF,0xFB,0x90,0x64,0x40,0x8F,0xF0,0x00,0x00
        db 0x69,0x00,0x00,0x00,0x08,0x00,0x00,0x0D,0x20
        db 0x00,0x00,0x01,0x00,0x00,0x01,0xA4,0x00,0x00
        db 0x00,0x20,0x00,0x00,0x34,0x80,0x00,0x00,0x04
        ds 381,0x55
paddingframedata_end

gscode
        incbin "gscode.bin"
gscode_end

        include "../_sdk/file.asm"
        include "progress.asm"

SS_VER_VS1001 = 0x00
SS_VER_VS1011 = 0x10
SS_VER_VS1002 = 0x20
SS_VER_VS1003 = 0x30
SS_VER_VS1053 = 0x40
SS_VER_VS8053 = 0x40
SS_VER_VS1033 = 0x50
SS_VER_VS1063 = 0x60
SS_VER_VS1103 = 0x70

idtostr
        db "1001"
        db "1011"
        db "1002"
        db "1003"
        db "1053"
        db "1033"
        db "1063"
ngsinitokstr
        db "NeoGS with VS"
chipidstr
        db "????\r\n",0
gsinitok
        db "GS\r\n",0
nodevicestr
        db "no device!\r\n",0
playernamestr
        db "GS/NeoGS",0
end

currentposition
        ds 1
filechunkcounter
        ds 2
titlestr
        ds TITLELENGTH+1

        savebin "mp3.bin",begin,end-begin