; let's also convert from S98 to VGM... ; sectionbss cmdptr.d: resd s98loop.d: resd fname1: resb 128 fname2: resb 128 vgmbuf.b: resb 512 s98buf.b: resb 512 s98header.b: resb 96 sectiondata chipcmd.b: db $56,$57,$A6,$A7 ; this row is for 'none' so shouldn't matter db $A0,$A0,$A0,$A0 ; how are dual AY-8910 supposed to work??? db $55,$55,$A5,$A5 ; YM2203 db $52,$53,$A2,$A3 ; YM2612 db $56,$57,$A6,$A7 ; YM2608 db $54,$54,$A4,$A4 ; YM2151 usage: db 13,10 db "USAGE:",13,10,13,10 db "S98toVGM inputfile outputfile",13,10 crlf: db 13,10,0 alignd devclk.d: dd 7987200,0 devtype.d: dd 4,0 alignd vgmheader: dd "Vgm ",0,$160,0 dd 0,0,0,0 dd 0,0,0,0 dd 0,$4C,0,0 dd 0,0,0,0 dd 0,0,0,0 dd 0,0,0,0 dd 0,0,0,0 sectioncode start! callex cmdptr,initplatform beginfunc localvar w.d,x.d,y.d,z.d,xx.d,ff1.d,ff2.d,filep.d,outp.d,tick.d,port.d,chip.d,time.d ; check command line callex w,readcmdstr,fname1 ifunequal w,0,cv01 cv02: callex ,printnt,usage goto endprogram cv01: callex w,readcmdstr,fname2 ifequal w,0,cv02 ; open files callex ff1,fileopen,fname1 ifequal ff1.sd,-1,abortmsg callex ff2,filecreate,fname2 ifequal ff2.sd,-1,abortmsg callex ,fileread,ff1,s98header.a,96 ifunequal s98header.w,"S9".w,abortmsg ifequal s98header.d(12),0,cv03 callex ,printnt,"data is compressed (unsupported!)"r.a end cv03: ; setup timer x=s98header.d(4) ifunequal x,0,cv04 > x=10 cv04: y=s98header.d(8) ifunequal y,0,cv05 > y=1000 cv05: whilegreater x,$17C60 ; ensure that the multiply won't overflow on 32-bit CPU x=_ shr 1 > y=_ shr 1 wend ; whilegreater x,$FFFF ; ensure that the multiply won't overflow on 16-bit CPU ; x=_ shr 1 > y=_ shr 1 ; wend ; whilegreater y,$FFFF ; ensure that the divide won't overflow on 16-bit CPU ; x=_ shr 1 > y=_ shr 1 ; wend tick=44100*x/y ; number of 44.1KHz ticks per S98 timer tick x=s98header.d($20) ifequal x,0,cv07 ; is there device data? ; 0 = none 1 = PSG (YM2149?) ; 2 = YM2203 3 = YM2612 ; 4 = YM2608 5 = YM2151 devtype=x devclk=s98header.d($24) x=s98header.d($30) ifequal x,0,cv07 ; is there a 2nd device? devtype(4)=x devclk(4)=s98header.d($34) ifunequal devtype(4),devtype,cv22 devclk(4)=_ or $40000000 ; flag for dual chips cv22: cv07: y=0 > gosub setdevice y=4 > gosub setdevice goto cv06 setdevice: x=devtype(y) ifequal x,0,cv08 z=devclk(y) ifunequal x,1,cv09 > vgmheader.d($74)=z cv09: ifunequal x,2,cv10 > vgmheader.d($44)=z cv10: ifunequal x,3,cv11 > vgmheader.d($2C)=z cv11: ifunequal x,4,cv12 > vgmheader.d($48)=z cv12: ifunequal x,5,cv13 > vgmheader.d($30)=z cv13: cv08: return cv06: callex ,filewrite,ff2,vgmheader.a,$80 ; write VGM header, even though it needs ; to be updated again later outp=0 callex ,fileskread,ff1,s98header.d($14),s98buf.a,512 ; begin reading S98 data stream filep=0 s98loop=s98header.d($18)-s98header.d($14) time=0 cv15: ifunequal s98loop,filep,cv19 ; did I hit the loop point (if any) ? vgmheader.d($1C)=outp+$64 ; +$80 -$1C cv19: gosub getbyte ifequal w,0,cv24 ; EOF? y=1 ifequal xx,$FF,cv17 ifunequal xx,$FE,cv16 ; time delays gosub getbyte > y=xx and $7F ifequal y,xx,cv25 gosub getbyte > y=xx and $7F shl 7+_ ifequal xx and $80,0,cv25 gosub getbyte > y=xx and $7F shl 14+_ ifequal xx and $80,0,cv25 gosub getbyte > y=xx and $7F shl 21+_ cv25: y=_+2 cv17: y=_*tick time=_+y whilegreater y,$FFFF xx=$61 > gosub putbyte xx=$FF > gosub putbyte xx=$FF > gosub putbyte y=_-$FFFF wend xx=$61 > gosub putbyte xx=y and $FF > gosub putbyte xx=y shr 8 > gosub putbyte goto cv15 cv16: ifunequal xx,$FD,cv18 ; end or loop xx=$66 > gosub putbyte cv24: callex ,printnt,"stream end"r.a goto streamdone cv18: z=xx gosub getbyte > x=xx ; address byte gosub getbyte > y=xx ; data byte port=0 > chip=0 ifequal z,$00,cv20 ; 1st chip, out1 ifequal z,$01,cv21 ; 1st chip, out2 chip=1 ifequal z,$02,cv20 ; 2nd chip, out1 ifequal z,$03,cv21 ; 2nd chip, out2 callex ,printnt,"S98 parsing error"r.a goto streamdone cv21: port=1 cv20: xx=chipcmd(devtype(chip shl 2) shl 1+chip shl 1+port) gosub putbyte xx=x > gosub putbyte xx=y > gosub putbyte goto cv15 streamdone: ; flush output data buffer ifequal outp and 511,0,cv23 callex ,filewrite,ff2,vgmbuf.a,outp and 511 cv23: ; finish VGM header vgmheader.d(4)=outp+$7C vgmheader.d($18)=time callex ,fileskwrite,ff2,0,vgmheader.a,$80 callex ,fileclose,ff1 callex ,fileclose,ff2 end getbyte: w=1 xx=s98buf.b(filep and 511) > filep=_+1 ifunequal filep and 511,0,cv14 callex w,fileread,ff1,s98buf.a,512 cv14: return putbyte: vgmbuf.b(outp and 511)=xx > outp=_+1 ifunequal outp and 511,0,cv14 callex ,filewrite,ff2,vgmbuf.a,512 return abortmsg: callex ,printnt,"some type of error :("r.a programend: endfunc end ; function that copies a string from [cmdptr] ; skips leading spaces, ends at space or null ; returns length, terminates output with 0 readcmdstr: beginfunc straddr.d localvar w.d,x.d,quoted.d w=0 > quoted=0 ; skip any extraneous spaces (and other weird characters?) whileless [cmdptr].b,33 ifequal [cmdptr].b,0,a354 cmdptr=_+1 wend ; then copy the name ; allow spaces between quotes, but remove the quotes (for Windows LFNs) whileless w,127 a357: x=[cmdptr].b > cmdptr=_+1 ifequal x,0,a354 ifunequal quoted,0,a355 ifless x,33,a354 a355: ifunequal x,34,a356 ifunequal quoted,0,a354 quoted=1 > goto a357 a356: [straddr].b=x > straddr=_+1 w=_+1 wend a354: [straddr].b=0 endfunc w returnex 4