Subversion Repositories NedoOS

Rev

Rev 2304 | Blame | Compare with Previous | Last modification | View Log | Download

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