?login_element?

Subversion Repositories NedoOS

Rev

Rev 2019 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ; ProTracker modules player for AY8910/TurboSound
  2. ; Player for MIDI UART connected to AY port A.2 (e.g. ZX MultiSound)
  3.  
  4.         DEVICE ZXSPECTRUM128
  5.         include "../_sdk/sys_h.asm"
  6.         include "playerdefs.asm"
  7.  
  8. MDLADDR = 0x8000
  9. TITLELENGTH = 64
  10. MEMORYSTREAMMAXPAGES = 210
  11. MEMORYSTREAMERRORMASK = 255
  12. MIDMAXTRACKS = 64
  13. MIDCHANNELS = 16
  14.  
  15.         struct MIDTRACK
  16. lastcommand ds 1
  17. nexteventtick ds 4
  18. streamoffset ds 4
  19.         ends
  20.  
  21.         struct MIDPLAYER
  22. filetype ds 1
  23. trackcount ds 1
  24. tickcounter ds 4
  25. ticksperupdate ds 4
  26. ticksperqnoteXupdatelen ds 4
  27. tracks ds MIDTRACK*MIDMAXTRACKS
  28.         ends
  29.  
  30.         org PLAYERSTART
  31.  
  32. begin   PLAYERHEADER
  33.  
  34. isfilesupported
  35. ;cde = file extension
  36. ;out: zf=1 if this player can handle the file and the sound hardware is available, zf=0 otherwise
  37.         call ismidfile
  38.         jr nz,.checkpt
  39.         ld hl,0
  40.         ld (MUSICTITLEADDR),hl
  41.         ld hl,musicprogress+1
  42.         ld (MUSICPROGRESSADDR),hl
  43.         jp initprogress
  44. .checkpt
  45.         ld a,c
  46.         cp 'p'
  47.         ret nz
  48.         ld a,d
  49.         cp 't'
  50.         ret nz
  51.         ld a,e
  52.         cp '2'
  53.         jr nz,.checkpt3
  54. ;prepare local variables
  55.         ld hl,0
  56.         ld (MUSICTITLEADDR),hl
  57.         ld (MUSICPROGRESSADDR),hl
  58.         ret
  59. .checkpt3
  60.         cp '3'
  61.         ret nz
  62. ;prepare local variables
  63.         ld hl,0
  64.         ld (MUSICTITLEADDR),hl
  65.         ld hl,musicprogress+1
  66.         ld (MUSICPROGRESSADDR),hl
  67.         jp initprogress
  68.  
  69. ismidfile
  70. ;cde = file extension
  71. ;out: zf=1 if .mod, zf=0 otherwise
  72.         ld a,'m'
  73.         cp c
  74.         ret nz
  75.         ld a,'i'
  76.         cp d
  77.         ret nz
  78.         ld a,'d'
  79.         cp e
  80.         ret
  81.  
  82. playerinit
  83. ;hl,ix = GPSETTINGS
  84. ;a = player page
  85. ;out: zf=1 if init is successful, hl=init message
  86.         ld (playerpage),a
  87.         ld a,(hl)
  88.         ld (page8000),a
  89.         inc hl
  90.         ld a,(hl)
  91.         ld (pageC000),a
  92.         call setuartdelay
  93.         ld a,(waitspincount)
  94.         or a
  95.         call z,initwaitspincount
  96.         ld hl,initokstr
  97.         xor a
  98.         ret
  99.  
  100. setuartdelay
  101. ;ix = GPSETTINGS
  102.         ld de,(ix+GPSETTINGS.midiuartdelayoverride)
  103.         ld a,d
  104.         or e
  105.         ret z
  106.         ld bc,3*256
  107. .loop   ld a,(de)
  108.         sub '0'
  109.         jr c,.done
  110.         cp 10
  111.         jr nc,.done
  112.         ld h,a
  113.         ld a,c
  114.         add a,a
  115.         ld c,a
  116.         add a,a
  117.         add a,a
  118.         add a,c
  119.         add a,h
  120.         ld c,a
  121.         inc de
  122.         djnz .loop
  123. .done   ld a,c
  124.         ld (waitspincount),a
  125.         ret
  126.  
  127. playerdeinit
  128.         ret
  129.  
  130. musicload
  131. ;cde = file extension
  132. ;hl = input file name
  133. ;out: zf=1 if the file is ready for playing, zf=0 otherwise
  134.         call ismidfile
  135.         jr nz,.ptfile
  136.         call midloadfile
  137.         ret nz
  138.         ld a,255
  139.         ld (isplayingmidfile),a
  140.         xor a
  141.         ret
  142. .ptfile ex de,hl
  143.         call openstream_file
  144.         or a
  145.         ret nz
  146. page8000=$+1
  147.         ld a,0
  148.         SETPG8000
  149. pageC000=$+1
  150.         ld a,0
  151.         SETPGC000
  152.         ld de,MDLADDR
  153.         ld hl,de
  154.         call readstream_file
  155.         push hl
  156.         call closestream_file
  157.         pop ix
  158.         call getconfig
  159.         ld (SETUP),a
  160.         ld de,MDLADDR
  161.         add hl,de
  162.         ex hl,de
  163.         call INIT
  164. playerpage=$+1
  165.         ld a,0
  166.         ld hl,PLAY
  167.         OS_SETMUSIC
  168.         xor a
  169.         ld (isplayingmidfile),a
  170.         ret
  171.  
  172. musicunload
  173.         ld a,(isplayingmidfile)
  174.         or a
  175.         jp nz,midunload
  176.         ld a,(playerpage)
  177.         ld hl,play_reter
  178.         OS_SETMUSIC
  179.         jp MUTE
  180.  
  181. play_reter
  182.         ret
  183.  
  184. musicplay
  185. ;out: zf=0 if still playing, zf=1 otherwise
  186.         ld a,(isplayingmidfile)
  187.         or a
  188.         jp nz,midplay
  189.         YIELD
  190.         YIELD
  191.         YIELD
  192.         YIELD
  193.         YIELD
  194.         ld a,(SETUP)
  195.         and 2
  196.         ld a,(VARS1+VRS.CurPos)
  197.         call z,updateprogress
  198.         ld a,(SETUP)
  199.         cpl
  200.         and 128
  201.         ret
  202.  
  203. findts
  204. ;ix = file size
  205. ;out: zf = 1 if TS data is found, hl = offset to the second module if available
  206.         ld de,MDLADDR
  207.         add ix,de ;past-the-end address of the data buffer
  208.         ld a,'0'
  209.         cp (ix-4)
  210.         ret nz
  211.         ld a,'2'
  212.         cp (ix-3)
  213.         ret nz
  214.         ld a,'T'
  215.         cp (ix-2)
  216.         ret nz
  217.         ld a,'S'
  218.         cp (ix-1)
  219.         ret nz
  220.         ld hl,(ix-12)
  221.         ret
  222.  
  223. getconfig
  224. ;ix = file size
  225. ;out: a = player config bits, hl = offset to the second module if available
  226.         ld a,(MDLADDR)
  227.         cp 'V'
  228.         jr z,.ispt3
  229.         cp 'P'
  230.         jr z,.ispt3
  231.         ld a,%00000011 ;PT2
  232.         ret
  233. .ispt3
  234.         ld a,(MDLADDR+101)
  235.         call setprogressdelta
  236. ;set title
  237.         ld hl,titlestr
  238.         ld (MUSICTITLEADDR),hl
  239.         ld de,titlestr+1
  240.         ld bc,TITLELENGTH-1
  241.         ld (hl),' '
  242.         ldir
  243.         xor a
  244.         ld (de),a
  245.         ld hl,titlestr-1
  246.         ld de,MDLADDR+30
  247.         ld bc,68*256+TITLELENGTH
  248. .copytitleloop
  249.         ld a,(de)
  250.         inc de
  251.         cp ' '
  252.         jr nz,$+5
  253.         cp (hl)
  254.         jr z,$+7
  255.         inc hl
  256.         ld (hl),a
  257.         dec c
  258.         jr z,$+4
  259.         djnz .copytitleloop
  260.         call findts
  261.         ld a,%00010001 ;2xPT3
  262.         ret z
  263.         ld a,%00100001 ;PT3
  264.         ret
  265.  
  266.         include "../_sdk/file.asm"
  267.         include "ptsplay/ptsplay.asm"
  268.         include "common/memorystream.asm"
  269.         include "common/muldiv.asm"
  270.         include "progress.asm"
  271.  
  272. VSYNC_FREQ = 49
  273. BAUD_RATE = 31250
  274. WAIT_LOOP_TSTATES = 14
  275. BENCHMARK_LOOP_TSTATES = 42
  276. DEFAULT_QNOTE_DURATION_MCS = 500000
  277.  
  278. VSYNC_MCS = 1000000/VSYNC_FREQ
  279. CC1 = WAIT_LOOP_TSTATES*BAUD_RATE
  280. CC2 = (VSYNC_FREQ*BENCHMARK_LOOP_TSTATES*65536+CC1/2)/CC1
  281.  
  282. SSG_REG = 0xfffd
  283. SSG_DAT = 0xbffd
  284.  
  285.         macro wait_32us reducebytstates
  286.         ld a,(waitspincount)
  287.         add a,-(20+reducebytstates+7)/14
  288. .loop   dec a
  289.         jp z,.done
  290.         dec a
  291.         jp z,.done
  292.         dec a
  293.         jp z,.done
  294.         dec a
  295.         jp nz,.loop
  296. .done   ;that's all, folks
  297.         endm
  298.  
  299. midinitport
  300.         ld bc,SSG_REG
  301.         ld a,0xff
  302.         out (c),a
  303.         ld a,7
  304.         out (c),a
  305.         ld bc,SSG_DAT
  306.         ld a,0xfc
  307.         out (c),a
  308.         ret
  309.  
  310. midsend3
  311. ;dhl = data
  312.         call midsendbyte
  313. midsend2
  314. ;hl = data
  315.         ld d,h
  316.         call midsendbyte
  317.         ld d,l
  318. midsendbyte
  319. ;d = data
  320.         di
  321.         ld bc,SSG_REG
  322.         ld a,14
  323.         out (c),a
  324.         ld bc,SSG_DAT
  325.         ld a,%11111010
  326.         out (c),a
  327.         wait_32us 42
  328.         scf
  329.         rr d
  330. .loop   sbc a,a
  331.         and %00000100
  332.         add a,%11111010
  333.         out (c),a
  334.         wait_32us 48
  335.         srl d
  336.         jp nz,.loop
  337.         nop
  338.         nop
  339.         nop
  340.         ld a,%11111110
  341.         out (c),a
  342.         wait_32us 0
  343.         ei
  344.         ret
  345.  
  346. initwaitspincount
  347.         call swapinterrupthandler ;avoid OS while benchmarking
  348.         halt
  349.         ld hl,0
  350.         ld e,0
  351.         xor a
  352.         ld (.spincount),a
  353.         ld a,32
  354.         halt
  355. ;--> 42 t-states loop start
  356. .loop   inc e
  357.         jp nz,$+4
  358.         inc hl
  359.         nop
  360. .spincount=$+1
  361.         ld bc,0
  362.         cp c
  363.         jp nc,.loop
  364. ;<-- loop end
  365.         push de
  366.         push hl
  367.         call swapinterrupthandler ;restore OS handler
  368.         pop hl
  369.         pop de
  370. ;hl = hle / 32
  371.         sla e : adc hl,hl
  372.         sla e : adc hl,hl
  373.         sla e : adc hl,hl
  374.         ld (framelength),hl
  375.         ex de,hl
  376.         ld bc,CC2
  377.         call uintmul16
  378.         xor a
  379.         rl h
  380.         adc a,e
  381.         ld (waitspincount),a
  382.         ret
  383.  
  384. swapinterrupthandler
  385.         di
  386.         ld hl,.store
  387.         ld de,0x38
  388.         ld b,3
  389. .loop   ld a,(de)
  390.         ld c,(hl)
  391.         ld (hl),a
  392.         ld a,c
  393.         ld (de),a
  394.         inc hl
  395.         inc de
  396.         djnz .loop
  397.         ei
  398.         ret
  399. .store  jp lightweightinterrupthandler
  400.  
  401. lightweightinterrupthandler
  402.         push af
  403.         push hl
  404.         ld hl,initwaitspincount.spincount
  405.         inc (hl)
  406.         pop hl
  407.         pop af
  408.         ei
  409.         ret
  410.  
  411. midloadfile
  412. ;hl = input file name
  413. ;out: zf=1 if loaded, zf=0 otherwise
  414.         call midinitport
  415. ;reset the reciever
  416.         ld d,255
  417.         call midsendbyte
  418. ;load and parse the file
  419.         ex de,hl
  420.         call memorystreamloadfile
  421.         ret nz
  422.         ld hl,midplayer
  423.         ld de,midplayer+1
  424.         ld bc,MIDPLAYER-1
  425.         ld (hl),0
  426.         ldir
  427.         call memorystreamstart
  428.         ld b,midheadersigsize
  429.         ld de,midheadersig
  430.         call midchecksignature
  431.         jp nz,memorystreamfree ;sets zf=0
  432.         memory_stream_read_2 c,a
  433.         ld (midplayer.filetype),a
  434.         memory_stream_read_2 c,a
  435.         ld (midplayer.trackcount),a
  436.         add a,-MIDMAXTRACKS-1
  437.         sbc a,a
  438.         ret nz
  439.         memory_stream_read_2 b,c
  440.         ld de,VSYNC_MCS
  441.         call uintmul16
  442.         add hl,hl : rl de
  443.         add hl,hl : rl de
  444.         ld (midplayer.ticksperqnoteXupdatelen+0),hl
  445.         ld (midplayer.ticksperqnoteXupdatelen+2),de
  446.         call midloadtracks
  447.         jp nz,memorystreamfree ;sets zf=0
  448.         call midsetprogressdelta
  449.         ld de,0
  450.         ld hl,14
  451.         call memorystreamseek
  452.         call midloadtracks
  453.         jp nz,memorystreamfree ;sets zf=0
  454.         ld hl,DEFAULT_QNOTE_DURATION_MCS%65536
  455.         ld de,DEFAULT_QNOTE_DURATION_MCS/65536
  456.         call setticksperupdate
  457.         xor a
  458.         ret
  459.  
  460. midchecksignature
  461. ;b = byte count
  462. ;de = signature
  463. ;out: zf=1 if ok, zf=0 otherwise
  464.         ld hl,(memorystreamcurrentaddr)
  465. .loop   memory_stream_read_byte c
  466.         ld a,(de)
  467.         cp c
  468.         ret nz
  469.         inc de
  470.         djnz .loop
  471.         ld (memorystreamcurrentaddr),hl
  472.         ret
  473.  
  474. midloadtracks
  475.         ld ix,midplayer.tracks
  476.         ld iy,(midplayer.trackcount)
  477. .loop   ld b,midtracksigsize
  478.         ld de,midtracksig
  479.         call midchecksignature
  480.         ret nz
  481.         call memorystreamread4
  482.         ld l,b
  483.         ld h,c
  484.         push hl
  485.         ld e,a
  486.         push de
  487.         call memorystreamgetpos
  488.         push de
  489.         push hl
  490.         ld hl,(memorystreamcurrentaddr)
  491.         call midreadvarint
  492.         ld (memorystreamcurrentaddr),hl
  493.         ld (ix+MIDTRACK.nexteventtick+0),de
  494.         ld (ix+MIDTRACK.nexteventtick+2),c
  495.         call memorystreamgetpos
  496.         ld (ix+MIDTRACK.streamoffset+0),hl
  497.         ld (ix+MIDTRACK.streamoffset+2),de
  498.         pop hl
  499.         pop de
  500.         pop bc
  501.         add hl,bc
  502.         ex de,hl
  503.         pop bc
  504.         adc hl,bc
  505.         ex de,hl
  506.         call memorystreamseek
  507.         ld bc,MIDTRACK
  508.         add ix,bc
  509.         dec iyl
  510.         jp nz,.loop
  511.         ret
  512.  
  513. midmute
  514.         ld e,0xb0
  515.         ld b,MIDCHANNELS
  516. .loop   push bc
  517.         ld d,e
  518.         ld hl,123*256
  519.         call midsend3 ;notes off
  520.         ld d,e
  521.         ld hl,120*256
  522.         call midsend3 ;sounds off
  523.         ld d,e
  524.         ld hl,121*256
  525.         call midsend3 ;controllers off
  526.         pop bc
  527.         inc e
  528.         djnz .loop
  529.         ret
  530.  
  531. midunload
  532.         call midmute
  533.         jp memorystreamfree
  534.  
  535. midplay
  536.         YIELD
  537. ;advance tick counter
  538.         ld hl,(midplayer.tickcounter+0)
  539.         ld de,(midplayer.ticksperupdate+0)
  540.         add hl,de
  541.         ld (midplayer.tickcounter+0),hl
  542.         ex de,hl
  543.         ld hl,(midplayer.tickcounter+2)
  544.         ld bc,(midplayer.ticksperupdate+2)
  545.         adc hl,bc
  546.         ld (midplayer.tickcounter+2),hl
  547.         ex de,hl
  548.         call midgetprogress
  549.         call updateprogress
  550. ;iterate through the tracks
  551.         ld ix,midplayer.tracks
  552.         ld a,(midplayer.trackcount)
  553.         ld b,a
  554.         ld c,0
  555. .trackloop
  556.         bit 7,(ix+MIDTRACK.streamoffset+3)
  557.         jr nz,.skiptrack
  558.         ld c,255
  559.         ld hl,(midplayer.tickcounter+0)
  560.         ld de,(ix+MIDTRACK.nexteventtick+0)
  561.         sub hl,de
  562.         ld hl,(midplayer.tickcounter+2)
  563.         ld de,(ix+MIDTRACK.nexteventtick+2)
  564.         sbc hl,de
  565.         jr c,.skiptrack
  566.         push bc
  567.         call midhandletrackevent
  568.         pop bc
  569.         jr .trackloop
  570. .skiptrack
  571.         ld de,MIDTRACK
  572.         add ix,de
  573.         djnz .trackloop
  574.         ld a,c
  575.         or a
  576.         ret
  577.  
  578. midreadvarint
  579. ;hl = memory stream addr
  580. ;out: cde = number, hl = memory stream addr
  581.         ld de,0
  582.         ld c,0
  583. .loop   memory_stream_read_byte b
  584.         ld a,e
  585.         rrca
  586.         xor b
  587.         and 0x80
  588.         xor b
  589.         rr c
  590.         rr de
  591.         ld c,d
  592.         ld d,e
  593.         ld e,a
  594.         bit 7,b
  595.         jr nz,.loop
  596.         ret
  597.  
  598.         macro process_midi_event call_send_byte,call_send_2,call_send_3
  599. ;ix = track
  600. ;hl = memory stream address
  601.         memory_stream_read_byte b
  602.         bit 7,b
  603.         jr z,.gotdatabyte
  604.         ld (ix+MIDTRACK.lastcommand),b
  605.         memory_stream_read_byte d
  606.         jr .handlecommand
  607. .gotdatabyte
  608.         ld d,b
  609.         ld b,(ix+MIDTRACK.lastcommand)
  610. .handlecommand
  611.         ld a,b
  612.         rrca
  613.         rrca
  614.         rrca
  615.         rrca
  616.         and 7
  617.         ld c,a
  618.         add a,a
  619.         add a,c
  620.         ld (.commandtable),a
  621. .commandtable=$+1
  622.         jr $
  623.         jp .send3 ; 8 Note Off
  624.         jp .send3 ; 9 Note On
  625.         jp .send3 ; A Polyphonic Pressure
  626.         jp .send3 ; B Control Change   
  627.         jp .send2 ; C Program Change
  628.         jp .send2 ; D Channel Pressure
  629.         jp .send3 ; E Pitch Bend
  630. ;;;;;;;;;;;;;;;;;;; F System
  631.         ld a,b
  632.         cp 0xff
  633.         jp z,.handlemeta
  634.         cp 0xf0
  635.         jp nz,.finalize
  636.         call midreadvarint
  637.         ld d,0xf0
  638.         call_send_byte
  639. .sendloop
  640.         memory_stream_read_byte e
  641.         ld d,e
  642.         call_send_byte
  643.         ld a,e
  644.         cp 0xf7
  645.         jr nz,.sendloop
  646.         ld (memorystreamcurrentaddr),hl
  647.         jr .finalize
  648. .handlemeta
  649.         ld a,d
  650.         cp 0x2f
  651.         jr z,.markdone
  652.         cp 0x51
  653.         jr z,.setduration
  654.         call midreadvarint
  655.         ld a,e
  656.         or d
  657.         jr z,.finalize
  658.         ld a,e
  659.         dec de
  660.         inc d
  661.         ld c,d
  662.         ld b,a
  663. .skiploop
  664.         bit 6,h
  665.         call nz,memorystreamnextpage
  666.         inc hl
  667.         djnz .skiploop
  668.         dec c
  669.         jr nz,.skiploop
  670.         ld (memorystreamcurrentaddr),hl
  671.         jr .finalize
  672. .markdone
  673.         set 7,(ix+MIDTRACK.streamoffset+3)
  674.         ret
  675. .setduration
  676.         call midreadvarint
  677.         memory_stream_read_byte a
  678.         memory_stream_read_byte d
  679.         memory_stream_read_byte e
  680.         ld (memorystreamcurrentaddr),hl
  681.         ex de,hl
  682.         ld e,a
  683.         ld d,0
  684.         push ix
  685.         call setticksperupdate
  686.         pop ix
  687.         jr .finalize
  688. .send2  ld (memorystreamcurrentaddr),hl
  689.         ld l,d
  690.         ld h,b
  691.         call_send_2
  692.         jr .finalize
  693. .send3  memory_stream_read_byte e
  694.         ld (memorystreamcurrentaddr),hl
  695.         ex de,hl
  696.         ld d,b
  697.         call_send_3
  698. .finalize
  699.         ld hl,(memorystreamcurrentaddr)
  700.         call midreadvarint
  701.         ld (memorystreamcurrentaddr),hl
  702.         ld b,0
  703.         sla de : rl bc
  704.         sla de : rl bc
  705.         ld hl,(ix+MIDTRACK.nexteventtick+0)
  706.         add hl,de
  707.         ld (ix+MIDTRACK.nexteventtick+0),hl
  708.         ld hl,(ix+MIDTRACK.nexteventtick+2)
  709.         adc hl,bc
  710.         ld (ix+MIDTRACK.nexteventtick+2),hl
  711.         endm
  712.  
  713. midhandletrackevent
  714. ;ix = track
  715.         ld hl,(ix+MIDTRACK.streamoffset+0)
  716.         ld de,(ix+MIDTRACK.streamoffset+2)
  717.         call memorystreamseek
  718.         process_midi_event <call midsendbyte>,<call midsend2>,<call midsend3>
  719.         call memorystreamgetpos
  720.         ld (ix+MIDTRACK.streamoffset+0),hl
  721.         ld (ix+MIDTRACK.streamoffset+2),de
  722.         ret
  723.  
  724. midgetprogress
  725. ;dehl = ticks
  726. ;out: a = progress
  727.         ld a,e
  728.         add hl,hl : rla
  729.         add hl,hl : rla
  730.         add hl,hl : rla
  731.         add hl,hl : rla
  732.         ret
  733.  
  734. midsetprogressdelta
  735.         ld ix,midplayer.tracks
  736.         ld a,(midplayer.trackcount)
  737.         ld b,a
  738.         ld c,0
  739. .trackloop
  740.         push bc
  741.         ld hl,(ix+MIDTRACK.streamoffset+0)
  742.         ld de,(ix+MIDTRACK.streamoffset+2)
  743.         call memorystreamseek
  744. .eventloop
  745.         call midadvancetrack
  746.         bit 7,(ix+MIDTRACK.streamoffset+3)
  747.         jr z,.eventloop
  748.         ld hl,(ix+MIDTRACK.nexteventtick+0)
  749.         ld de,(ix+MIDTRACK.nexteventtick+2)
  750.         call midgetprogress
  751.         pop bc
  752.         cp c
  753.         jr c,$+3
  754.         ld c,a
  755.         ld de,MIDTRACK
  756.         add ix,de
  757.         djnz .trackloop
  758.         ld a,c
  759.         jp setprogressdelta
  760.  
  761. midadvancetrack
  762. ;ix = track
  763.         ld hl,(memorystreamcurrentaddr)
  764.         process_midi_event < >,< >,< >
  765.         ret
  766.  
  767. setticksperupdate
  768. ;dehl = qnote duration in mcs
  769.         exx
  770.         ld hl,(midplayer.ticksperqnoteXupdatelen+0)
  771.         ld de,(midplayer.ticksperqnoteXupdatelen+2)
  772.         call uintdiv32
  773.         ld (midplayer.ticksperupdate+0),hl
  774.         ld (midplayer.ticksperupdate+2),de
  775.         ret
  776.  
  777. midheadersig
  778.         db "MThd",0,0,0,6
  779. midheadersigsize = $-midheadersig
  780. midtracksig
  781.         db "MTrk"
  782. midtracksigsize = $-midtracksig
  783. initokstr
  784.         db "OK\r\n",0
  785. playernamestr
  786.         db "ProTracker and MIDI UART player",0
  787. end
  788.  
  789. titlestr ds TITLELENGTH+1
  790. isplayingmidfile ds 1
  791. framelength ds 2
  792. waitspincount ds 1
  793. midplayer MIDPLAYER
  794.  
  795.         assert $ <= PLAYEREND ;ensure everything is within the player page
  796.  
  797.         savebin "pt3.bin",begin,end-begin
  798.