Subversion Repositories NedoOS

Rev

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

  1. S3MMAXINSTRUMENTS = 128
  2. S3MWAVEHEADERBUFFERSIZE = S3MMAXINSTRUMENTS*MOONWAVEHEADERSIZE
  3. S3MSAMPLEDATASTART = MODSAMPLEDATASTART
  4. S3MMAXCHANNELS = 32
  5. S3MMAXPATTERNS = 100
  6. S3MPATTERNSTEPCOUNT = 64
  7. S3MMAXORDER = 256
  8. S3MHEADERADDR = 0xc000
  9. S3MMINPERIOD = 4
  10.  
  11.         struct S3MHEADER
  12. songname ds 28
  13. byte1a ds 1
  14. filetype ds 1
  15. unused1 ds 2
  16. ordernum ds 2
  17. instnum ds 2
  18. pattnum ds 2
  19. flags ds 2
  20. createdwith ds 2
  21. fileversion ds 2
  22. id ds 4
  23. globalvol ds 1
  24. initialspeed ds 1
  25. initialtempo ds 1
  26. mastermult ds 1
  27. ultraclicks ds 1
  28. panningmagic ds 1
  29. unused2 ds 8
  30. special ds 2
  31. chsettings ds S3MMAXCHANNELS
  32.         ends
  33.  
  34.         struct S3MINSTRUMENT
  35. type ds 1
  36. dosname ds 12
  37. paraptr ds 3
  38. length ds 4
  39. loopstart ds 4
  40. loopend ds 4
  41. volume ds 1
  42. disknum ds 1
  43. pack ds 1
  44. flags ds 1
  45. c2spd ds 4
  46. tunefactorcoeff ds 2
  47. tunefactorshift ds 1
  48. unused ds 9
  49. name ds 28
  50. id ds 4
  51.         ends
  52.  
  53.         struct S3MCHANNEL
  54. index ds 1
  55. instrument ds 1
  56. oldinstrument ds 1
  57. period ds 2
  58. note ds 1
  59. volume ds 1
  60. tempcommand ds 2
  61. vibratocommand ds 1
  62. vibratotableposition ds 1
  63. tremolocommand ds 1
  64. tremolotableposition ds 1
  65. wavecontrol ds 1
  66. patternloopstart ds 1
  67. patternloopcount ds 1
  68. pankeyon ds 1
  69. tunefactorcoeff ds 2
  70. tunefactorshift ds 1
  71. tunefactorcoeffoverride ds 2
  72. tunefactorshiftoverride ds 1
  73. portaspeed ds 1
  74. volumeslide ds 1
  75.         ends
  76.  
  77.         struct S3MSTEPDATA
  78. note ds 1
  79. instrument ds 1
  80. volume ds 1
  81. effectcommand ds 1
  82. effectdata ds 1
  83. extendedcommand ds 1
  84.         ends
  85.  
  86.         struct S3MINFO
  87. instparapointers ds 2
  88. pattparapointers ds 2
  89. choffset ds S3MMAXCHANNELS
  90. chpanning ds S3MMAXCHANNELS
  91. chnum ds 1
  92. chinitsize ds 2
  93. samplesizesinkb ds 2
  94. instnum ds 1
  95.         ends
  96.  
  97.         struct S3MPLAYER
  98. patterntableindex ds 1
  99. patternstepindex ds 1
  100. arpeggio ds 1
  101. patterndelay ds 1
  102. speed ds 1
  103. speedstep ds 1
  104. channels ds S3MCHANNEL*S3MMAXCHANNELS
  105. stepdatabuffer ds S3MSTEPDATA*(S3MMAXCHANNELS+1)
  106.         ends
  107.  
  108. s3mpatterntable equ s3mheader+S3MHEADER
  109.  
  110. s3mload
  111. ;de = input file name
  112. ;out: zf=1 if the file is ready for playing, zf=0 otherwise
  113.         ld (s3mloadsamples.filename),de
  114.         call memorystreamloadfile
  115.         ret nz
  116. ;map header to S3MHEADERADDR
  117.         ld a,(memorystreampages)
  118.         SETPGC000
  119.         call opl4init
  120.         call s3mloadpatterns
  121.         jp nz,memorystreamfree ;sets zf=0
  122.         call s3mloadsamples
  123.         jp nz,memorystreamfree ;sets zf=0
  124. ;init player state
  125.         ld hl,s3mplayer
  126.         ld de,s3mplayer+1
  127.         ld bc,S3MPLAYER-1
  128.         ld (hl),0
  129.         ldir
  130. ;init channels
  131.         ld ix,s3minfo.chpanning
  132.         ld iy,s3mplayer.channels
  133.         ld a,(s3minfo.chnum)
  134.         ld b,a
  135.         ld c,0
  136. .initchloop
  137.         ld (iy+S3MCHANNEL.index),c
  138.         ld a,(ix)
  139.         call s3msetpanning
  140.         ld de,S3MCHANNEL
  141.         add iy,de
  142.         inc ix
  143.         inc c
  144.         djnz .initchloop
  145. ;init player state
  146.         ld a,(s3mheader.initialtempo)
  147.         call s3msetbpm
  148.         xor a
  149.         call s3msetnextstep
  150.         ld a,(s3mheader.initialspeed)
  151.         ld (s3mplayer.speed),a
  152.         ld a,1
  153.         ld (s3mplayer.speedstep),a
  154.         xor a
  155.         ld (s3mheader.byte1a),a
  156.         ret
  157.  
  158. s3mloadpatterns
  159.         call getpanningfunc
  160.         ld (.getpanning),hl
  161. ;parapointers
  162.         ld a,(s3mheader.ordernum)
  163.         ld e,a
  164.         ld d,0
  165.         ld hl,s3mpatterntable
  166.         add hl,de
  167.         ld (s3minfo.instparapointers),hl
  168.         ld a,(s3mheader.instnum)
  169.         ld e,a
  170.         add hl,de
  171.         add hl,de
  172.         ld (s3minfo.pattparapointers),hl
  173. ;fill channel tables
  174.         ld a,(s3mheader.pattnum)
  175.         ld e,a
  176.         add hl,hl
  177.         add hl,hl
  178.         ld de,s3minfo.choffset
  179.         ld bc,s3minfo.chpanning
  180.         ld ix,s3mheader.chsettings
  181.         ld iy,S3MMAXCHANNELS
  182.         xor a
  183.         ex af,af'
  184. .chloop ld a,(ix)
  185.         cp 16
  186.         jr nc,.choff
  187. .getpanning=$+1
  188.         call 0
  189.         ld (bc),a
  190.         inc bc
  191.         ex af,af'
  192.         ld (de),a
  193.         add a,S3MSTEPDATA
  194.         ex af,af'
  195.         inc de
  196.         inc iyh
  197.         ld a,iyh
  198.         cp OPL4MAXWAVECHANNELS
  199.         jr nc,.channelscapped
  200. .choff  inc hl
  201.         inc ix
  202.         dec iyl
  203.         jr nz,.chloop
  204.         ld a,iyh
  205. .channelscapped
  206.         ld (s3minfo.chnum),a
  207.         ld a,S3MMAXCHANNELS+1
  208.         sub iyh
  209.         ld b,a
  210.         ex af,af'
  211.         dec b
  212.         jr z,.nofill
  213.         ld (de),a
  214.         inc de
  215.         djnz $-2
  216. .nofill cp S3MSTEPDATA*2
  217.         jr nc,$+4
  218.         ld a,S3MSTEPDATA*2
  219.         sub S3MSTEPDATA
  220.         ld l,a
  221.         ld h,0
  222.         ld (s3minfo.chinitsize),hl
  223.         xor a
  224.         ret
  225.  
  226. getpanningfunc
  227.         ld a,(s3mheader.panningmagic)
  228.         cp 252
  229.         ld hl,.readdefaultpanning
  230.         ret z
  231.         ld hl,.chsetttingspanning
  232.         ret
  233. .chsetttingspanning
  234.         cp 8
  235.         ld a,0x03
  236.         ret c
  237.         ld a,0x0c
  238.         ret
  239. .readdefaultpanning
  240.         ld a,(hl)
  241.         and 15
  242.         ret
  243.  
  244. s3mfilestreamseekfast
  245. ;dehl = offset
  246.         ld (.fileoffsetlo),hl
  247.         ld (.fileoffsethi),de
  248.         ld hl,(filestreamcurrentaddr)
  249.         res 6,h
  250.         res 7,h
  251.         ld de,(filereadoffset+0)
  252.         add hl,de
  253.         ld bc,(filereadoffset+2)
  254.         jr nc,$+3
  255.         inc bc
  256.         ex de,hl
  257. .fileoffsetlo=$+1
  258.         ld hl,0
  259.         sub hl,de
  260.         ex de,hl
  261. .fileoffsethi=$+1
  262.         ld hl,0
  263.         sbc hl,bc
  264.         ld a,h
  265.         or l
  266.         or d
  267.         ld b,e
  268.         ld hl,(.fileoffsetlo)
  269.         ld de,(.fileoffsethi)
  270.         jp nz,s3mfilestreamseek
  271.         inc b
  272.         dec b
  273.         ret z
  274.         ld hl,(filestreamcurrentaddr)
  275. .loop   bit 6,h
  276.         call nz,s3mloadfiledata
  277.         inc hl
  278.         djnz .loop
  279.         ld (filestreamcurrentaddr),hl
  280.         ret
  281.  
  282. s3mfilestreamseek
  283. ;dehl = offset
  284.         push ix
  285.         push iy
  286.         ld a,(filehandle)
  287.         ld b,a
  288.         OS_SEEKHANDLE
  289.         ld hl,0xffff
  290.         ld (filestreamcurrentaddr),hl
  291.         pop iy
  292.         pop ix
  293.         ret
  294.  
  295. s3mloadfiledata
  296.         push af,bc,de
  297.         exx
  298.         ex af,af'
  299.         push af,bc,de,hl,ix,iy
  300.         ld a,(filehandle)
  301.         ld b,a
  302.         OS_TELLHANDLE
  303.         ld (filereadoffset+0),hl
  304.         ld (filereadoffset+2),de
  305.         ld de,0x8000
  306.         ld hl,0x4000
  307.         call readstream_file
  308.         pop iy,ix,hl,de,bc,af
  309.         exx
  310.         ex af,af'
  311.         pop de,bc,af
  312.         ld hl,0x8000
  313.         ret
  314.  
  315. filestreamcurrentaddr ds 2
  316. filereadoffset ds 4
  317.  
  318. s3mloadsamples
  319. ;output: zf=1 if samples are loaded, zf=0 otherwise
  320.         ld (.savedsp),sp
  321. .filename=$+1
  322.         ld de,0
  323.         call openstream_file
  324.         or a
  325.         ret nz
  326.         ld a,(s3mheader.instnum)
  327.         call setprogressdelta
  328.         ld hl,0
  329.         ld (filestreamcurrentaddr),hl
  330.         dec hl
  331.         ld (filereadoffset+0),hl
  332.         ld (filereadoffset+2),hl
  333.         ld a,(modfilebufferpage)
  334.         SETPG8000
  335. ;read samples data from file
  336.         ld hl,S3MSAMPLEDATASTART%65536
  337.         ld a,S3MSAMPLEDATASTART/65536
  338.         ld (.sampleaddresslo),hl
  339.         ld (.sampleaddresshi),a
  340.         ld hl,(s3minfo.instparapointers)
  341.         ld iy,s3mwaveheaderbuffer
  342.         ld a,(s3mheader.instnum)
  343.         ld b,a
  344.         ld c,0
  345. .mainloop
  346.         push bc
  347. ;convert instrument parapointer to memory address
  348.         ld e,(hl)
  349.         inc hl
  350.         ld d,(hl)
  351.         dec hl
  352.         ex de,hl
  353.         add hl,hl
  354.         add hl,hl
  355.         add hl,hl
  356.         add hl,hl
  357.         ld bc,S3MHEADERADDR
  358.         add hl,bc
  359.         ex de,hl
  360.         ld ix,de
  361. ;replace parapointer with pointer
  362.         ld (hl),e
  363.         inc hl
  364.         ld (hl),d
  365.         inc hl
  366.         push hl
  367. ;start filling wavetable entry
  368.         bit 0,(ix+S3MINSTRUMENT.flags)
  369.         jr z,.noloop
  370.         ld de,(ix+S3MINSTRUMENT.loopend)
  371.         ld bc,(ix+S3MINSTRUMENT.loopstart)
  372.         ld hl,de
  373.         dec de
  374.         sub hl,bc
  375.         jr nz,.hasloop
  376. .noloop
  377.         ld bc,(ix+S3MINSTRUMENT.length)
  378.         ld de,bc
  379.         dec bc
  380. .hasloop
  381.         ld hl,0xffff
  382.         sub hl,de
  383.         ld (iy+ 3),b ;loop hi
  384.         ld (iy+ 4),c ;loop lo
  385.         ld (iy+ 5),h ;end hi
  386.         ld (iy+ 6),l ;end lo
  387.         ld (iy+ 7),0x00 ;LFO, VIB
  388.         ld (iy+ 8),0xf0 ;AR, D1R
  389.         ld (iy+ 9),0xff ;DL, D2R
  390.         ld (iy+10),0x0f ;rate correction, RR
  391.         ld (iy+11),0x00 ;AM
  392. .sampleaddresslo=$+1
  393.         ld hl,0
  394. .sampleaddresshi=$+1
  395.         ld d,0
  396.         ld a,(ix+S3MINSTRUMENT.flags)
  397.         rrca
  398.         rrca
  399.         rrca
  400.         and 0x80
  401.         or d
  402.         ld (iy+0),a ;8/16 bits data, addr hi
  403.         ld (iy+1),h ;addr mi
  404.         ld (iy+2),l ;addr lo
  405.         ld bc,(ix+S3MINSTRUMENT.length)
  406.         ld a,b
  407.         or c
  408.         jp z,.nextsample
  409. ;upload sample
  410.         push de
  411.         push hl
  412.         ld a,c
  413.         dec bc
  414.         inc b
  415.         ld c,b
  416.         ld b,a
  417.         push bc
  418.         call opl4setmemoryaddress
  419.         ld de,0x1102
  420.         call opl4writewave
  421. ;seek to samples data
  422.         ld d,0
  423.         ld e,(ix+S3MINSTRUMENT.paraptr+0)
  424.         ld l,(ix+S3MINSTRUMENT.paraptr+1)
  425.         ld h,(ix+S3MINSTRUMENT.paraptr+2)
  426.         add hl,hl : rl de
  427.         add hl,hl : rl de
  428.         add hl,hl : rl de
  429.         add hl,hl : rl de
  430.         call s3mfilestreamseekfast
  431.         pop bc
  432.         ld hl,(filestreamcurrentaddr)
  433. ;start uploading
  434.         opl4_wait
  435.         ld a,6
  436.         out (MOON_WREG),a
  437.         bit 2,(ix+S3MINSTRUMENT.flags)
  438.         jr nz,.uploadloop16bits
  439. .uploadloop8bits
  440.         bit 6,h
  441.         call nz,s3mloadfiledata
  442.         ld d,(hl)
  443.         inc hl
  444.         opl4_wait
  445.         ld a,d
  446.         add a,0x80
  447.         out (MOON_WDAT),a
  448.         djnz .uploadloop8bits
  449.         dec c
  450.         jr nz,.uploadloop8bits
  451. ;duplicate the last data sample
  452.         opl4_wait
  453.         ld a,d
  454.         add a,0x80
  455.         out (MOON_WDAT),a
  456.         jr .doneupload
  457. .uploadloop16bits
  458.         bit 6,h
  459.         call nz,s3mloadfiledata
  460.         ld e,(hl)
  461.         inc hl
  462.         bit 6,h
  463.         call nz,s3mloadfiledata
  464.         ld d,(hl)
  465.         inc hl
  466.         opl4_wait
  467.         ld a,d
  468.         add a,0x80
  469.         out (MOON_WDAT),a
  470.         opl4_wait
  471.         ld a,e
  472.         out (MOON_WDAT),a
  473.         djnz .uploadloop16bits
  474.         dec c
  475.         jr nz,.uploadloop16bits
  476.         opl4_wait
  477.         ld a,d
  478.         add a,0x80
  479.         out (MOON_WDAT),a
  480.         opl4_wait
  481.         ld a,e
  482.         out (MOON_WDAT),a
  483. .doneupload
  484.         ld de,0x1002
  485.         call opl4writewave
  486.         ld (filestreamcurrentaddr),hl
  487.         pop hl
  488.         pop de
  489. ;set next write address
  490.         ld bc,(ix+S3MINSTRUMENT.length)
  491.         xor a
  492.         bit 2,(ix+S3MINSTRUMENT.flags)
  493.         jr z,.alreadyinbytes
  494.         sla bc
  495.         rla
  496. .alreadyinbytes
  497.         add hl,bc
  498.         adc a,d
  499.         ld bc,2 ; add +2 to account for duping the last data sample
  500.         add hl,bc
  501.         adc a,b
  502.         ld (.sampleaddresslo),hl
  503.         ld (.sampleaddresshi),a
  504. ;process c2spd
  505.         ld hl,(ix+S3MINSTRUMENT.c2spd)
  506.         push ix
  507.         push iy
  508.         call s3mgettunefactor
  509.         pop iy
  510.         pop ix
  511.         ld (ix+S3MINSTRUMENT.tunefactorcoeff),hl
  512.         ld (ix+S3MINSTRUMENT.tunefactorshift),a
  513. ;draw progress
  514.         push ix
  515.         push iy
  516.         call drawsampleloadingprogress
  517.         jp nz,.cancelloading
  518.         pop iy
  519.         pop ix
  520.         ld a,1
  521. .nextsample
  522.         ld bc,MOONWAVEHEADERSIZE
  523.         add iy,bc
  524.         pop hl
  525.         pop bc
  526.         add a,c
  527.         ld c,a
  528.         exx
  529.         call updateprogress
  530.         exx
  531.         dec b
  532.         jp nz,.mainloop
  533.         ld a,c
  534.         ld (s3minfo.instnum),a
  535.         ld hl,(.sampleaddresslo)
  536.         ld a,(.sampleaddresshi)
  537.         ld bc,-(S3MSAMPLEDATASTART%65536)+1023
  538.         add hl,bc
  539.         adc a,-(S3MSAMPLEDATASTART/65536)
  540.         ld l,h
  541.         srl a : rr l
  542.         srl a : rr l
  543.         ld h,a
  544.         ld (s3minfo.samplesizesinkb),hl
  545. ;switch back to memory steam
  546.         call closestream_file
  547.         ld a,(memorystreamcurrentpage)
  548.         SETPG8000
  549. ;write headers
  550.         ld ix,s3mwaveheaderbuffer
  551.         ld hl,MOONSOUNDROMSIZE%65536
  552.         ld d,MOONSOUNDROMSIZE/65536
  553.         ld bc,S3MWAVEHEADERBUFFERSIZE
  554.         call opl4writememory
  555.         xor a
  556.         jp initprogress
  557. .cancelloading
  558. .savedsp=$+1
  559.         ld sp,0
  560.         call closestream_file
  561.         or 1
  562.         ret
  563.  
  564. s3munload
  565.         call opl4mute
  566.         jp memorystreamfree
  567.  
  568. s3mplay
  569.         call s3mwaittimer
  570.         ld a,(s3mplayer.speedstep)
  571.         dec a
  572.         jp nz,.tn
  573.         ld a,(s3mplayer.speed)
  574.         ld (s3mplayer.speedstep),a
  575.         ld a,(s3mplayer.patterndelay)
  576.         or a
  577.         jr z,.nopatterndelay
  578.         dec a
  579.         ld (s3mplayer.patterndelay),a
  580.         ret
  581. .nopatterndelay
  582.         call s3mreadstepdata
  583.         ld ix,s3mplayer.stepdatabuffer
  584.         ld iy,s3mplayer.channels
  585.         ld a,(s3minfo.chnum)
  586. .t0loop push af
  587.         ld (iy+S3MCHANNEL.tunefactorshiftoverride),0xff
  588.         call s3msetinstrument
  589.         call s3mhandlecommandT0
  590.         ld d,(ix+S3MSTEPDATA.effectcommand)
  591.         ld e,(ix+S3MSTEPDATA.extendedcommand)
  592.         ld hl,0x130d
  593.         sub hl,de
  594.         call nz,s3mnewnote
  595.         ld a,(ix+S3MSTEPDATA.volume)
  596.         cp 255
  597.         jr z,.novolumecmd
  598.         clamp_volume_in_a
  599.         ld (iy+S3MCHANNEL.volume),a
  600. .novolumecmd
  601.         ld a,(iy+S3MCHANNEL.volume)
  602.         call s3msetvolume
  603.         set 7,(iy+S3MCHANNEL.pankeyon)
  604.         call s3mflushpankeyon
  605.         ld de,S3MSTEPDATA
  606.         add ix,de
  607.         ld e,S3MCHANNEL
  608.         add iy,de
  609.         pop af
  610.         dec a
  611.         jp nz,.t0loop
  612.         ret
  613. .tn     ld (s3mplayer.speedstep),a
  614.         ld a,(s3mplayer.arpeggio)
  615.         inc a
  616.         cp 3
  617.         jr c,$+3
  618.         xor a
  619.         ld (s3mplayer.arpeggio),a
  620.         ld ix,s3mplayer.stepdatabuffer
  621.         ld iy,s3mplayer.channels
  622.         ld a,(s3minfo.chnum)
  623.         ld b,a
  624. .tnloop push bc
  625.         call s3mhandlecommandTN
  626.         ld de,S3MSTEPDATA
  627.         add ix,de
  628.         ld e,S3MCHANNEL
  629.         add iy,de
  630.         pop bc
  631.         djnz .tnloop
  632.         ret
  633.  
  634. s3msetinstrument
  635. ;ix = step data
  636. ;iy = channel data
  637.         ld a,(ix+S3MSTEPDATA.instrument)
  638.         or a
  639.         ret z
  640.         ld (iy+S3MCHANNEL.instrument),a
  641.         dec a
  642.         ld hl,(s3minfo.instparapointers)
  643.         ld e,a
  644.         ld d,0
  645.         add hl,de
  646.         add hl,de
  647.         ld e,(hl)
  648.         inc hl
  649.         ld d,(hl)
  650.         push ix
  651.         ld ix,de
  652.         ld de,(ix+S3MINSTRUMENT.tunefactorcoeff)
  653.         ld (iy+S3MCHANNEL.tunefactorcoeff),de
  654.         ld a,(ix+S3MINSTRUMENT.tunefactorshift)
  655.         ld (iy+S3MCHANNEL.tunefactorshift),a
  656.         ld a,(ix+S3MINSTRUMENT.volume)
  657.         ld (iy+S3MCHANNEL.volume),a
  658.         ld (iy+S3MCHANNEL.vibratotableposition),0
  659.         pop ix
  660.         ret
  661.  
  662. s3mhandlecommandT0
  663. ;ix = step data
  664. ;iy = channel data
  665.         ld a,(ix+S3MSTEPDATA.effectcommand)
  666.         cp 23
  667.         ret nc
  668.         ld b,a
  669.         add a,a
  670.         add a,b
  671.         ld (.effectcommandtable),a
  672. .effectcommandtable=$+1
  673.         jr $
  674.         ret : ds 2          ;  0 -
  675.         jp .doeffectA       ;  1 [Set Speed]
  676.         ret : ds 2          ;  2 [Pattern Jump]
  677.         ret : ds 2          ;  3 [Pattern Break]
  678.         jp s3mvolumeslideT0 ;  4 [Volume Slide/Fine Volume Slide up/down]
  679.         jp .doeffectE       ;  5 [Porta Down/Fine Porta Down/Xtra Fine Porta]
  680.         jp .doeffectF       ;  6 [Porta Up/Fine Porta Up/Extra Fine Porta Down]
  681.         ret : ds 2          ;  7 [Porta to note]
  682.         jp .doeffectH       ;  8 [Vibrato]
  683.         ret : ds 2          ;  9 [Tremor]
  684.         jp .doeffectJ       ; 10 [Arpeggio]
  685.         jp s3mvolumeslideT0 ; 11 [Vibrato+Volume Slide]
  686.         jp s3mvolumeslideT0 ; 12 [Porta+Volume Slide]
  687.         ret : ds 2          ; 13 -
  688.         ret : ds 2          ; 14 -
  689.         ret : ds 2          ; 15 [Sample Offset]
  690.         ret : ds 2          ; 16 -
  691.         ret : ds 2          ; 17 [Retrig + Volume Slide]
  692.         jp .doeffectR       ; 18 [Tremolo]
  693.         jp .doeffectS       ; 19 [Extended Command]
  694.         jp .doeffectT       ; 20 [Set Tempo]
  695.         jp .doeffectU       ; 21 [Fine Vibrato]
  696. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 22 [Global Volume]
  697.         ret
  698. .doeffectR
  699.         ld b,(ix+S3MSTEPDATA.effectdata)
  700.         ld c,(iy+S3MCHANNEL.tremolocommand)
  701.         ld a,b
  702.         and 0xf0
  703.         jr z,.skiptremolohi
  704.         xor c
  705.         and 0xf0
  706.         xor c
  707.         ld c,a
  708. .skiptremolohi
  709.         ld a,b
  710.         and 15
  711.         jr z,.skiptremololo
  712.         xor c
  713.         and 15
  714.         xor c
  715.         ld c,a
  716. .skiptremololo
  717.         ld (iy+S3MCHANNEL.tremolocommand),c
  718.         ret
  719. .doeffectJ
  720.         xor a
  721.         ld (s3mplayer.arpeggio),a
  722.         ld hl,(iy+S3MCHANNEL.period)
  723.         jp s3msetfrequency
  724. .doeffectE
  725.         ld a,(ix+S3MSTEPDATA.effectdata)
  726.         or a
  727.         jr z,$+5
  728.         ld (iy+S3MCHANNEL.portaspeed),a
  729.         ld a,(iy+S3MCHANNEL.portaspeed)
  730.         cp 0xe0
  731.         ret c
  732.         ld b,a
  733.         and 15
  734.         ld e,a
  735.         ld d,0
  736.         bit 4,b
  737.         jp z,s3mportadown.slide
  738.         ex de,hl
  739.         add hl,hl
  740.         add hl,hl
  741.         ex de,hl
  742.         jp s3mportadown.slide
  743. .doeffectF
  744.         ld a,(ix+S3MSTEPDATA.effectdata)
  745.         or a
  746.         jr z,$+5
  747.         ld (iy+S3MCHANNEL.portaspeed),a
  748.         ld a,(iy+S3MCHANNEL.portaspeed)
  749.         cp 0xe0
  750.         ret c
  751.         ld b,a
  752.         and 15
  753.         ld e,a
  754.         ld d,0
  755.         bit 4,b
  756.         jp z,s3mportaup.slide
  757.         ex de,hl
  758.         add hl,hl
  759.         add hl,hl
  760.         ex de,hl
  761.         jp s3mportaup.slide
  762. .doeffectH
  763. .doeffectU
  764.         ld a,(ix+S3MSTEPDATA.note)
  765.         cp 254
  766.         jr nc,.skipnote
  767.         ld bc,(iy+S3MCHANNEL.period)
  768.         ld (iy+S3MCHANNEL.tempcommand),bc
  769. .skipnote
  770.         ld b,(ix+S3MSTEPDATA.effectdata)
  771.         ld c,(iy+S3MCHANNEL.vibratocommand)
  772.         ld a,b
  773.         and 0xf0
  774.         jr z,.skipvibratohi
  775.         xor c
  776.         and 0xf0
  777.         xor c
  778.         ld c,a
  779. .skipvibratohi
  780.         ld a,b
  781.         and 15
  782.         jr z,.skipvibratolo
  783.         xor c
  784.         and 15
  785.         xor c
  786.         ld c,a
  787. .skipvibratolo
  788.         ld (iy+S3MCHANNEL.vibratocommand),c
  789.         ret
  790. .doeffectA
  791.         ld a,(ix+S3MSTEPDATA.effectdata)
  792.         ld (s3mplayer.speed),a
  793.         ret
  794. .doeffectT
  795.         ld a,(ix+S3MSTEPDATA.effectdata)
  796.         jp s3msetbpm
  797. .doeffectS
  798.         ld a,(ix+S3MSTEPDATA.extendedcommand)
  799.         ld b,a
  800.         add a,a
  801.         add a,b
  802.         ld (.exteffcommandtable),a
  803. .exteffcommandtable=$+1
  804.         jr $
  805.         ret : ds 2    ;  0 [Set Filter on/off]
  806.         ret : ds 2    ;  1 [Set Glissando on/off]
  807.         jp .doexteff2 ;  2 [Set FineTune]
  808.         jp .doexteff3 ;  3 [Set Vibrato Waveform]
  809.         jp .doexteff4 ;  4 [Set Tremolo Waveform]
  810.         ret : ds 2    ;  5 -
  811.         ret : ds 2    ;  6 -
  812.         ret : ds 2    ;  7 -
  813.         jp .doexteff8 ;  8 [Set Pan Position]
  814.         ret : ds 2    ;  9 -
  815.         jp .doexteffA ; 10 [Stereo Control]
  816.         ret : ds 2    ; 11 [Pattern Loop]
  817.         jp .doexteffC ; 12 [Cut Note]
  818.         jp .doexteffD ; 13 [Delay Note]
  819.         jp .doexteffE ; 14 [Pattern Delay]
  820.         ret           ; 15 [Funk Repeat]
  821. .doexteff8
  822. .doexteffA
  823.         ld a,(ix+S3MSTEPDATA.effectdata)
  824.         jp s3msetpanning
  825. .doexteff2
  826.         ld a,(ix+S3MSTEPDATA.effectdata)
  827.         ld b,a
  828.         add a,a
  829.         add a,b
  830.         get_array_value b,s3mfinetunefactors
  831.         inc hl
  832.         ld c,(hl)
  833.         ld (iy+S3MCHANNEL.tunefactorcoeffoverride),bc
  834.         inc hl
  835.         ld a,(hl)
  836.         ld (iy+S3MCHANNEL.tunefactorshiftoverride),a
  837.         ret
  838. .doexteff3
  839.         ld a,(iy+S3MCHANNEL.wavecontrol)
  840.         ld b,(ix+S3MSTEPDATA.effectdata)
  841.         and 0xfc
  842.         or b
  843.         ld (iy+S3MCHANNEL.wavecontrol),a
  844.         ld (iy+S3MCHANNEL.vibratotableposition),0
  845.         ret
  846. .doexteff4
  847.         ld a,(iy+S3MCHANNEL.wavecontrol)
  848.         ld b,(ix+S3MSTEPDATA.effectdata)
  849.         sla b
  850.         sla b
  851.         and 0xf3
  852.         or b
  853.         ld (iy+S3MCHANNEL.wavecontrol),a
  854.         ld (iy+S3MCHANNEL.tremolotableposition),0
  855.         ret
  856. .doexteffC
  857.         ld a,(ix+S3MSTEPDATA.effectdata)
  858.         or a
  859.         jr z,.channeloff
  860.         ld (iy+S3MCHANNEL.tempcommand),a
  861.         ret
  862. .channeloff
  863.         ld (iy+S3MCHANNEL.volume),a
  864.         jp s3msetvolume
  865. .doexteffD
  866.         ld a,(ix+S3MSTEPDATA.effectdata)
  867.         or a
  868.         ret z
  869.         ld (iy+S3MCHANNEL.tempcommand),a
  870.         ret
  871. .doexteffE
  872.         ld a,(ix+S3MSTEPDATA.effectdata)
  873.         ld (s3mplayer.patterndelay),a
  874.         ret
  875.  
  876. s3mhandlecommandTN
  877. ;ix = step data
  878. ;iy = channel data
  879.         ld a,(ix+S3MSTEPDATA.effectcommand)
  880.         cp 23
  881.         ret nc
  882.         ld b,a
  883.         add a,a
  884.         add a,b
  885.         ld (.effectcommandtable),a
  886. .effectcommandtable=$+1
  887.         jr $
  888.         ret : ds 2       ;  0 -
  889.         ret : ds 2       ;  1 [Set Speed]
  890.         jp .effectB      ;  2 [Pattern Jump]
  891.         jp .effectC      ;  3 [Pattern Break]
  892.         jp s3mvolumeslideTN ; 4 [Volume Slide/Fine Volume Slide up/down]
  893.         jp s3mportadown  ;  5 [Porta Down/Fine Porta Down/Xtra Fine Porta]
  894.         jp s3mportaup    ;  6 [Porta Up/Fine Porta Up/Extra Fine Porta Down]
  895.         jp s3mtoneporta  ;  7 [Porta to note]
  896.         jp s3mvibrato    ;  8 [Vibrato]
  897.         ret : ds 2       ;  9 [Tremor]
  898.         jp .doeffectJ    ; 10 [Arpeggio]
  899.         jp .doeffectK    ; 11 [Vibrato+Volume Slide]
  900.         jp .doeffectL    ; 12 [Porta+Volume Slide]
  901.         ret : ds 2       ; 13 -
  902.         ret : ds 2       ; 14 -
  903.         ret : ds 2       ; 15 [Sample Offset]
  904.         ret : ds 2       ; 16 -
  905.         ret : ds 2       ; 17 [Retrig + Volume Slide]
  906.         jp s3mtremolo    ; 18 [Tremolo]
  907.         jp .doeffectS    ; 19 [Extended Command]
  908.         ret : ds 2       ; 20 [Set Tempo]
  909.         jp s3mfvibrato   ; 21 [Fine Vibrato]
  910. ;;;;;;;;;;;;;;;;;;;;;;;;;; 22 [Global Volume]
  911.         ret
  912. .doeffectK
  913.         call s3mvibrato
  914.         jp s3mvolumeslideTN
  915. .doeffectL
  916.         call s3mtoneporta
  917.         jp s3mvolumeslideTN
  918. .doeffectJ
  919.         ld a,(ix+S3MSTEPDATA.effectdata)
  920.         or a
  921.         ret z
  922.         ld hl,(s3mplayer.arpeggio)
  923.         dec l
  924.         jr z,.datahi
  925.         inc l
  926.         jr nz,.datalo
  927.         ld hl,(iy+S3MCHANNEL.period)
  928.         jp s3msetfrequency
  929. .datahi rrca
  930.         rrca
  931.         rrca
  932.         rrca
  933. .datalo and 15
  934.         add a,(iy+S3MCHANNEL.note)
  935.         cp 96
  936.         jr c,$+4
  937.         ld a,95
  938.         call s3mnotetoperiod
  939.         call s3mtuneperiod
  940.         jp s3msetfrequency
  941. .effectB
  942.         ld a,(s3mplayer.speedstep)
  943.         dec a
  944.         ret nz
  945.         ld a,(ix+S3MSTEPDATA.effectdata)
  946.         call s3mskipmarkers
  947.         ld (s3mplayer.patterntableindex),a
  948.         xor a
  949.         jp s3msetnextstep
  950. .effectC
  951.         ld a,(s3mplayer.speedstep)
  952.         dec a
  953.         ret nz
  954.         ld a,(s3mplayer.patterntableindex)
  955.         inc a
  956.         call s3mskipmarkers
  957.         ld (s3mplayer.patterntableindex),a
  958.         ld a,(ix+S3MSTEPDATA.effectdata)
  959.         ld b,a
  960.         and 0xf0
  961.         xor b
  962.         ld c,a
  963.         xor b
  964.         rrca
  965.         rrca
  966.         rrca
  967.         rrca
  968.         add a,a
  969.         ld b,a
  970.         add a,a
  971.         add a,a
  972.         add a,b
  973.         add a,c
  974.         jp s3msetnextstep
  975. .doeffectS
  976.         ld a,(ix+S3MSTEPDATA.extendedcommand)
  977.         ld b,a
  978.         add a,a
  979.         add a,b
  980.         ld (.exteffcommandtable),a
  981. .exteffcommandtable=$+1
  982.         jr $
  983.         ret : ds 2    ;  0 [Set Filter on/off]
  984.         ret : ds 2    ;  1 [Set Glissando on/off]
  985.         ret : ds 2    ;  2 [Set FineTune]
  986.         ret : ds 2    ;  3 [Set Vibrato Waveform]
  987.         ret : ds 2    ;  4 [Set Tremolo Waveform]
  988.         ret : ds 2    ;  5 -
  989.         ret : ds 2    ;  6 -
  990.         ret : ds 2    ;  7 -
  991.         ret : ds 2    ;  8 [Set Pan Position]
  992.         ret : ds 2    ;  9 -
  993.         ret : ds 2    ; 10 [Stereo Control]
  994.         jp .doexteffB ; 11 [Pattern Loop]
  995.         jp .doexteffC ; 12 [Cut Note]
  996.         jp .doexteffD ; 13 [Delay Note]
  997.         ret : ds 2    ; 14 [Pattern Delay]
  998.         ret           ; 15 [Funk Repeat]
  999. .doexteffB
  1000.         ld a,(s3mplayer.speedstep)
  1001.         dec a
  1002.         ret nz
  1003.         ld a,(ix+S3MSTEPDATA.effectdata)
  1004.         or a
  1005.         jr nz,.checkloopcount
  1006.         ld a,(s3mplayer.patternstepindex)
  1007.         ld (iy+S3MCHANNEL.patternloopstart),a
  1008.         ret
  1009. .checkloopcount
  1010.         ld b,(iy+S3MCHANNEL.patternloopcount)
  1011.         inc b
  1012.         cp b
  1013.         jr c,.restartloop
  1014.         ld (iy+S3MCHANNEL.patternloopcount),b
  1015.         ret z
  1016.         ld a,(iy+S3MCHANNEL.patternloopstart)
  1017.         jp s3msetnextstep
  1018. .restartloop
  1019.         ld (iy+S3MCHANNEL.patternloopcount),0
  1020.         ld a,(iy+S3MCHANNEL.patternloopstart)
  1021.         jp s3msetnextstep
  1022. .doexteffC
  1023.         ld a,(iy+S3MCHANNEL.tempcommand)
  1024.         or a
  1025.         ret z
  1026.         dec a
  1027.         ld (iy+S3MCHANNEL.tempcommand),a
  1028.         ret nz
  1029.         ld (iy+S3MCHANNEL.volume),a
  1030.         jp s3msetvolume
  1031. .doexteffD
  1032.         ld a,(iy+S3MCHANNEL.tempcommand)
  1033.         or a
  1034.         ret z
  1035.         dec a
  1036.         ld (iy+S3MCHANNEL.tempcommand),a
  1037.         ret nz
  1038.         jp s3mnewnote
  1039.  
  1040. s3mnewnote
  1041. ;ix = step data
  1042. ;iy = channel data
  1043.         ld a,(iy+S3MCHANNEL.instrument)
  1044.         or a
  1045.         ret z
  1046.         ld a,(ix+S3MSTEPDATA.effectcommand)
  1047.         cp 0x07
  1048.         jr z,.effectG
  1049.         cp 0x0C
  1050.         jr z,.effectL
  1051.         ld a,(ix+S3MSTEPDATA.note)
  1052.         inc a
  1053.         ret z
  1054.         xor a
  1055.         call s3msetvolume
  1056.         res 7,(iy+S3MCHANNEL.pankeyon)
  1057.         call s3mflushpankeyon
  1058.         ld a,(ix+S3MSTEPDATA.note)
  1059.         cp 254
  1060.         jr nz,.validnote
  1061.         ld (iy+S3MCHANNEL.volume),0
  1062.         ret
  1063. .validnote
  1064.         ld (iy+S3MCHANNEL.note),a
  1065.         call s3mnotetoperiod
  1066.         call s3mtuneperiod
  1067.         ld (iy+S3MCHANNEL.period),hl
  1068.         call s3msetfrequency
  1069.         ld a,(iy+S3MCHANNEL.instrument)
  1070.         cp (iy+S3MCHANNEL.oldinstrument)
  1071.         ret z
  1072.         ld (iy+S3MCHANNEL.oldinstrument),a
  1073.         jp s3msetsamplenumber
  1074. .effectG
  1075.         ld a,(ix+S3MSTEPDATA.effectdata)
  1076.         or a
  1077.         jr z,.effectL
  1078.         ld (iy+S3MCHANNEL.portaspeed),a
  1079. .effectL
  1080.         ld a,(ix+S3MSTEPDATA.note)
  1081.         cp 254
  1082.         ret nc
  1083.         ld (iy+S3MCHANNEL.note),a
  1084.         call s3mnotetoperiod
  1085.         call s3mtuneperiod
  1086.         ld (iy+S3MCHANNEL.tempcommand),hl
  1087.         ret
  1088.  
  1089. s3mskipmarkers
  1090. ;intput: a = pattern table index
  1091. ;output: a = pattern table index pointing at non-marker
  1092.         ld hl,s3mheader.ordernum
  1093.         ld b,(hl)
  1094.         ld e,a
  1095.         ld d,0
  1096.         ld hl,s3mpatterntable
  1097.         add hl,de
  1098. .loop   cp b
  1099.         jr c,$+6
  1100.         xor a
  1101.         ld hl,s3mpatterntable
  1102.         ld c,a
  1103.         ld a,(hl)
  1104.         cp 254
  1105.         ld a,c
  1106.         ret c
  1107.         inc hl
  1108.         inc a
  1109.         jp .loop
  1110.  
  1111. s3mgetpatternpos
  1112. ;a = pattern table index
  1113. ;out: dehl = file stream position
  1114.         ld e,a
  1115.         ld d,0
  1116.         ld hl,s3mpatterntable
  1117.         add hl,de
  1118.         ld e,(hl)
  1119.         ld hl,(s3minfo.pattparapointers)
  1120.         add hl,de
  1121.         add hl,de
  1122. ;parapointer
  1123.         ld a,(hl)
  1124.         inc hl
  1125.         ld h,(hl)
  1126.         ld l,a
  1127.         xor a
  1128.         add hl,hl : rla
  1129.         add hl,hl : rla
  1130.         add hl,hl : rla
  1131.         add hl,hl : rla
  1132.         ld e,a
  1133. ;skip the first two bytes containing pattern data size
  1134.         inc l
  1135.         inc l
  1136.         ret
  1137.  
  1138. memorystreamnextpagewrap
  1139. ;wraps read address rather than resetting to 0x8000
  1140.         push hl
  1141.         call memorystreamnextpage
  1142.         pop hl
  1143.         res 6,h
  1144.         set 7,h
  1145.         ret
  1146.  
  1147. s3msetnextstep
  1148. ;a = step index
  1149. ;output: memory stream at patterntableindex/patternstepindex
  1150.         dec a ;save decremented patternstepindex to cancel out its increment in T0
  1151.         ld (s3mplayer.patternstepindex),a
  1152.         ld a,(s3mplayer.patterntableindex)
  1153.         call s3mgetpatternpos
  1154.         call memorystreamseek
  1155.         ld a,(s3mplayer.patternstepindex)
  1156.         inc a
  1157.         ret z
  1158.         ld b,a
  1159.         ld hl,(memorystreamcurrentaddr)
  1160. .steploop
  1161.         ld a,(hl)
  1162.         or a
  1163.         jr z,.nextstep
  1164. .loop   and 0xe0
  1165.         ld e,d
  1166.         add a,a
  1167.         rl e
  1168.         add a,a
  1169.         rl e
  1170.         rlca
  1171.         adc a,e
  1172.         inc a
  1173.         ld e,a
  1174.         add hl,de
  1175.         bit 6,h
  1176.         call nz,memorystreamnextpagewrap
  1177.         ld a,(hl)
  1178.         or a
  1179.         jp nz,.loop
  1180. .nextstep
  1181.         inc hl
  1182.         djnz .steploop
  1183.         ld (memorystreamcurrentaddr),hl
  1184.         ret
  1185.  
  1186. s3mreadstepdata
  1187. ;input: memory stream
  1188. ;output: filled stepdatabuffer, memory stream at next pattern step
  1189.         ld a,(s3mplayer.patternstepindex)
  1190.         inc a
  1191.         cp S3MPATTERNSTEPCOUNT
  1192.         jr c,.nextpatternstep
  1193.         ld a,(s3mplayer.patterntableindex)
  1194.         inc a
  1195.         call s3mskipmarkers
  1196.         ld (s3mplayer.patterntableindex),a
  1197.         call s3mgetpatternpos
  1198.         call memorystreamseek
  1199.         xor a
  1200. .nextpatternstep
  1201.         ld (s3mplayer.patternstepindex),a
  1202. ;set defaults
  1203.         ld ix,s3mplayer.stepdatabuffer
  1204.         ld (ix+S3MSTEPDATA.note),0xff
  1205.         ld (ix+S3MSTEPDATA.volume),0xff
  1206.         ld (ix+S3MSTEPDATA.instrument),0
  1207.         ld (ix+S3MSTEPDATA.effectcommand),0xff
  1208.         ld hl,s3mplayer.stepdatabuffer
  1209.         ld de,s3mplayer.stepdatabuffer+S3MSTEPDATA
  1210.         ld bc,(s3minfo.chinitsize)
  1211.         ldir
  1212. ;read data
  1213.         ld hl,(memorystreamcurrentaddr)
  1214.         memory_stream_read_byte a
  1215.         or a
  1216.         jr z,.skiploop
  1217. .loop   ld b,a
  1218.         and 0x1f
  1219.         ex de,hl
  1220.         get_array_value l,s3minfo.choffset
  1221.         ex de,hl
  1222.         ld d,0
  1223.         ld ix,s3mplayer.stepdatabuffer
  1224.         add ix,de
  1225.         bit 5,b
  1226.         jr z,.skipnoteinstrument
  1227.         memory_stream_read_byte a
  1228.         cp 254
  1229.         jr nc,.specialnote
  1230.         ld c,a
  1231.         rrca
  1232.         rrca
  1233.         and 0x3c
  1234.         neg
  1235.         add a,c
  1236. .specialnote
  1237.         ld (ix+S3MSTEPDATA.note),a
  1238.         memory_stream_read_byte a
  1239.         ld (ix+S3MSTEPDATA.instrument),a
  1240. .skipnoteinstrument
  1241.         bit 6,b
  1242.         jr z,.skipvolume
  1243.         memory_stream_read_byte a
  1244.         ld (ix+S3MSTEPDATA.volume),a
  1245. .skipvolume
  1246.         bit 7,b
  1247.         jr z,.skipeffect
  1248.         memory_stream_read_byte a
  1249.         memory_stream_read_byte c
  1250.         ld (ix+S3MSTEPDATA.effectcommand),a
  1251.         cp 19
  1252.         ld a,c
  1253.         jr nz,.notextended
  1254.         srl c
  1255.         srl c
  1256.         srl c
  1257.         srl c
  1258.         ld (ix+S3MSTEPDATA.extendedcommand),c
  1259.         and 15
  1260. .notextended
  1261.         ld (ix+S3MSTEPDATA.effectdata),a
  1262. .skipeffect
  1263.         memory_stream_read_byte a
  1264.         or a
  1265.         jr nz,.loop
  1266. .skiploop
  1267.         ld (memorystreamcurrentaddr),hl
  1268.         ret
  1269.  
  1270. s3mnotetoperiod
  1271. ;a = note
  1272. ;out: hl = period
  1273.         add a,a
  1274.         get_array_value a,st3periods
  1275.         inc hl
  1276.         ld h,(hl)
  1277.         ld l,a
  1278.         ret
  1279.  
  1280. s3mtuneperiod
  1281. ;iy = channel data
  1282. ;hl = period
  1283. ;out: hl = period
  1284.         ld bc,(iy+S3MCHANNEL.tunefactorcoeffoverride)
  1285.         ld a,(iy+S3MCHANNEL.tunefactorshiftoverride)
  1286.         or a
  1287.         jp p,.hasoverride
  1288.         ld bc,(iy+S3MCHANNEL.tunefactorcoeff)
  1289.         ld a,(iy+S3MCHANNEL.tunefactorshift)
  1290.         or a
  1291. .hasoverride
  1292.         push af
  1293.         ex de,hl
  1294.         call uintmul16
  1295.         pop af
  1296.         jr z,.noshift
  1297.         ld b,a
  1298. .shiftloop
  1299.         add hl,hl
  1300.         rl de
  1301.         djnz .shiftloop
  1302. .noshift
  1303.         ld hl,-S3MMINPERIOD
  1304.         add hl,de
  1305.         ex de,hl
  1306.         ret c
  1307.         ld hl,S3MMINPERIOD
  1308.         ret
  1309.  
  1310. s3mgettunefactor
  1311. ;hl = c2spd
  1312. ;output: hl = factor, a = shift
  1313. ;poor man's floating point: period*8363/c2spd = (period*factor)>>(16-shift)
  1314.         ld de,0
  1315.         exx
  1316.         ld de,8363
  1317.         ld hl,0
  1318.         call uintdiv32
  1319.         ld a,d
  1320.         or e
  1321.         ret z
  1322.         ex de,hl
  1323.         push hl
  1324.         ld b,16
  1325.         add hl,hl
  1326.         dec b
  1327.         jr nc,$-2
  1328.         ld a,h
  1329.         or l
  1330.         jr z,$+3
  1331.         inc b
  1332.         inc b
  1333.         pop hl
  1334.         ex de,hl
  1335.         ld a,b
  1336. .shiftloop
  1337.         srl de
  1338.         rr hl
  1339.         djnz .shiftloop
  1340.         ret
  1341.  
  1342. s3msetbpm equ modsetbpm
  1343. s3mwaittimer equ modwaittimer
  1344.  
  1345. s3msetfrequency
  1346. ;iy = channel data
  1347. ;hl = period
  1348.         ld a,(modperiodlookuppage)
  1349.         SETPGC000
  1350.         ld a,h
  1351.         sub 0x10
  1352.         jp c,.firsthalf
  1353. ;(hl-4096)/8+4096
  1354.         srl a : rr l
  1355.         srl a : rr l
  1356.         srl a : rr l
  1357.         add a,0x10
  1358.         ld h,a
  1359. .firsthalf
  1360.         add hl,hl
  1361. ;two-bytes lookup
  1362.         ld de,S3MHEADERADDR-2
  1363.         add hl,de
  1364.         ld d,(hl)
  1365.         inc hl
  1366.         ld l,(hl)
  1367.         ld a,(memorystreampages)
  1368.         SETPGC000
  1369.         ld a,(iy+S3MCHANNEL.index)
  1370.         add a,0x38
  1371.         ld e,a
  1372.         call opl4writewave
  1373.         ld d,l
  1374.         ld a,e
  1375.         sub 0x18
  1376.         ld e,a
  1377.         jp opl4writewave
  1378.  
  1379. s3mportaup
  1380. ;iy = channel data
  1381.         ld a,(iy+S3MCHANNEL.portaspeed)
  1382.         cp 0xe0
  1383.         ret nc
  1384.         rlca
  1385.         rlca
  1386.         ld d,a
  1387.         and 0xfc
  1388.         ld e,a
  1389.         xor d
  1390.         ld d,a
  1391. .slide  ld hl,(iy+S3MCHANNEL.period)
  1392.         sub hl,de
  1393.         jr c,.clamp
  1394.         ex de,hl
  1395.         ld hl,-S3MMINPERIOD
  1396.         add hl,de
  1397.         ex de,hl
  1398.         jr c,$+5
  1399. .clamp  ld hl,S3MMINPERIOD
  1400.         ld (iy+S3MCHANNEL.period),hl
  1401.         jp s3msetfrequency
  1402.  
  1403. s3mportadown
  1404. ;iy = channel data
  1405.         ld a,(iy+S3MCHANNEL.portaspeed)
  1406.         cp 0xe0
  1407.         ret nc
  1408.         rlca
  1409.         rlca
  1410.         ld d,a
  1411.         and 0xfc
  1412.         ld e,a
  1413.         xor d
  1414.         ld d,a
  1415. .slide  ld hl,(iy+S3MCHANNEL.period)
  1416.         add hl,de
  1417.         ex de,hl
  1418.         ld hl,-36000
  1419.         add hl,de
  1420.         ex de,hl
  1421.         jr nc,$+5
  1422.         ld hl,35999
  1423.         ld (iy+S3MCHANNEL.period),hl
  1424.         jp s3msetfrequency
  1425.  
  1426. s3mtoneporta
  1427. ;iy = channel data
  1428.         ld hl,(iy+S3MCHANNEL.period)
  1429.         ld bc,(iy+S3MCHANNEL.tempcommand)
  1430.         ld de,hl
  1431.         sub hl,bc
  1432.         ex de,hl
  1433.         jp z,s3msetfrequency ;period == tempcommand
  1434.         ld e,(iy+S3MCHANNEL.portaspeed)
  1435.         ld d,0
  1436.         jr c,.pospitchbend ;period < tempcommand
  1437.         sla de
  1438.         sla de
  1439.         sbc hl,de
  1440.         jr nc,$+5
  1441.         ld hl,0
  1442.         ld de,hl
  1443.         sub hl,bc
  1444.         ex de,hl
  1445.         jr nc,.finalize ;period >= tempcommand
  1446.         ld hl,bc
  1447.         jr .finalize
  1448. .pospitchbend
  1449.         sla de
  1450.         sla de
  1451.         add hl,de
  1452.         ld de,hl
  1453.         sub hl,bc
  1454.         ex de,hl
  1455.         jr c,$+4 ;period < tempcommand
  1456.         ld hl,bc
  1457. .finalize
  1458.         ld (iy+S3MCHANNEL.period),hl
  1459.         jp s3msetfrequency
  1460.  
  1461.         macro s3m_vibrato is_fine
  1462.         ld a,(iy+S3MCHANNEL.vibratotableposition)
  1463.         rrca
  1464.         rrca
  1465.         and 0x1f
  1466.         get_array_value e,modvibratotable
  1467.         ld hl,0
  1468.         ld a,(iy+S3MCHANNEL.vibratocommand)
  1469.         and 15
  1470.         call nz,mul8x8
  1471.         xor a
  1472.         add hl,hl : rla
  1473.         if !is_fine
  1474.         add hl,hl : rla
  1475.         add hl,hl : rla
  1476.         endif
  1477.         ld e,h
  1478.         ld d,a
  1479.         ld hl,(iy+S3MCHANNEL.period)
  1480.         bit 7,(iy+S3MCHANNEL.vibratotableposition)
  1481.         jr z,.periodup
  1482.         sub hl,de
  1483.         jr .finalize
  1484. .periodup
  1485.         add hl,de
  1486. .finalize
  1487.         ld (iy+S3MCHANNEL.tempcommand),hl
  1488.         call s3msetfrequency
  1489.         ld a,(iy+S3MCHANNEL.vibratocommand)
  1490.         rrca
  1491.         rrca
  1492.         and 0x3c
  1493.         add a,(iy+S3MCHANNEL.vibratotableposition)
  1494.         ld (iy+S3MCHANNEL.vibratotableposition),a
  1495.         endm
  1496.  
  1497. s3mfvibrato
  1498. ;iy = channel data
  1499.         s3m_vibrato 1
  1500.         ret
  1501.  
  1502. s3mvibrato
  1503. ;iy = channel data
  1504.         s3m_vibrato 0
  1505.         ret
  1506.  
  1507. s3msetvolume
  1508. ;iy = channel data
  1509. ;a = volume
  1510.         get_array_value d,modvolumetable
  1511.         sll d
  1512.         ld a,(iy+S3MCHANNEL.index)
  1513.         add a,0x50
  1514.         ld e,a
  1515.         jp opl4writewave
  1516.  
  1517. s3msetsamplenumber
  1518. ;iy = channel data
  1519. ;a = sample number
  1520.         add a,0x7f
  1521.         ld d,a
  1522.         ld a,(iy+S3MCHANNEL.index)
  1523.         add a,0x08
  1524.         ld e,a
  1525.         call opl4writewave
  1526. ;wait for the header to load
  1527.         in a,(MOON_STAT)
  1528.         and 3
  1529.         jr nz,$-4
  1530.         ret
  1531.  
  1532. s3mflushpankeyon
  1533. ;iy = channel data
  1534.         ld d,(iy+S3MCHANNEL.pankeyon)
  1535.         ld a,(iy+S3MCHANNEL.index)
  1536.         add a,0x68
  1537.         ld e,a
  1538.         jp opl4writewave
  1539.  
  1540. s3mvolumeslideT0
  1541. ;ix = step data
  1542. ;iy = channel data
  1543.         ld a,(ix+S3MSTEPDATA.effectdata)
  1544.         or a
  1545.         jr z,$+5
  1546.         ld (iy+S3MCHANNEL.volumeslide),a
  1547.         ld a,(iy+S3MCHANNEL.volumeslide)
  1548.         cp 0xf0
  1549.         jr c,.checkslideup
  1550.         and 15
  1551.         ld b,a
  1552.         ld a,(iy+S3MCHANNEL.volume)
  1553.         sub b
  1554.         jr nc,$+3
  1555.         xor a
  1556.         ld (iy+S3MCHANNEL.volume),a
  1557.         jp s3msetvolume
  1558. .checkslideup
  1559.         rrca
  1560.         rrca
  1561.         rrca
  1562.         rrca
  1563.         cp 0xf0
  1564.         ret c
  1565.         and 15
  1566.         add a,(iy+S3MCHANNEL.volume)
  1567.         clamp_volume_in_a
  1568.         ld (iy+S3MCHANNEL.volume),a
  1569.         jp s3msetvolume
  1570.  
  1571. s3mvolumeslideTN
  1572. ;iy = channel data
  1573.         ld a,(iy+S3MCHANNEL.volumeslide)
  1574.         cp 0x10
  1575.         jr nc,.checkslideup
  1576.         ld b,a
  1577.         ld a,(iy+S3MCHANNEL.volume)
  1578.         sub b
  1579.         jr nc,$+3
  1580.         xor a
  1581.         ld (iy+S3MCHANNEL.volume),a
  1582.         jp s3msetvolume
  1583. .checkslideup
  1584.         rrca
  1585.         rrca
  1586.         rrca
  1587.         rrca
  1588.         cp 0x10
  1589.         ret nc
  1590.         add a,(iy+S3MCHANNEL.volume)
  1591.         clamp_volume_in_a
  1592.         ld (iy+S3MCHANNEL.volume),a
  1593.         jp s3msetvolume
  1594.  
  1595. s3msetpanning
  1596. ;iy = channel data
  1597. ;a = panning
  1598.         get_array_value l,modpantable
  1599.         ld a,(iy+S3MCHANNEL.pankeyon)
  1600.         and 0x80
  1601.         or l
  1602.         ld (iy+S3MCHANNEL.pankeyon),a
  1603.         ret
  1604.  
  1605. s3mtremolo
  1606. ;iy = channel data
  1607.         ld a,(iy+S3MCHANNEL.tremolotableposition)
  1608.         rrca
  1609.         rrca
  1610.         and 0x1f
  1611.         get_array_value e,modvibratotable
  1612.         ld hl,0
  1613.         ld a,(iy+S3MCHANNEL.tremolocommand)
  1614.         and 15
  1615.         call nz,mul8x8
  1616.         ld a,h
  1617.         sla l
  1618.         rla
  1619.         sla l
  1620.         rla
  1621.         bit 7,(iy+S3MCHANNEL.tremolotableposition)
  1622.         jr z,.volumeup
  1623.         ld b,a
  1624.         ld a,(iy+S3MCHANNEL.volume)
  1625.         sub b
  1626.         jr nc,.finalize
  1627.         xor a
  1628.         jr .finalize
  1629. .volumeup
  1630.         add a,(iy+S3MCHANNEL.volume)
  1631.         clamp_volume_in_a
  1632. .finalize
  1633.         call s3msetvolume
  1634.         ld a,(iy+S3MCHANNEL.tremolocommand)
  1635.         rrca
  1636.         rrca
  1637.         and 0x3c
  1638.         add a,(iy+S3MCHANNEL.tremolotableposition)
  1639.         ld (iy+S3MCHANNEL.tremolotableposition),a
  1640.         ret
  1641.  
  1642. s3mfinetunefactors
  1643.         db 0x87,0x96,0x01 ;7895
  1644.         db 0x86,0xcd,0x01 ;7941
  1645.         db 0x86,0x0f,0x01 ;7985
  1646.         db 0x85,0x0b,0x01 ;8046
  1647.         db 0x84,0x0a,0x01 ;8107
  1648.         db 0x83,0x0a,0x01 ;8169
  1649.         db 0x82,0x09,0x01 ;8232
  1650.         db 0x81,0x48,0x01 ;8280
  1651.         db 0x80,0x00,0x01 ;8363 (No finetune)
  1652.         db 0xfe,0x7a,0x00 ;8413
  1653.         db 0xfc,0xf9,0x00 ;8463
  1654.         db 0xfb,0x04,0x00 ;8529
  1655.         db 0xf9,0x7f,0x00 ;8581
  1656.         db 0xf7,0x7a,0x00 ;8651
  1657.         db 0xf5,0x6f,0x00 ;8723
  1658.         db 0xf4,0x7b,0x00 ;8757
  1659.  
  1660. st3periods
  1661.         ;    C     C#    D     D#    E     F     F#    G     G#    A     A#    B
  1662.         dw 27392,25856,24384,23040,21696,20480,19328,18240,17216,16256,15360,14496 ;0
  1663.         dw 13696,12928,12192,11520,10848,10240, 9664, 9120, 8608, 8128, 7680, 7248 ;1
  1664.         dw  6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624 ;2
  1665.         dw  3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1812 ;3
  1666.         dw  1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016,  960,  906 ;4
  1667.         dw   856,  808,  762,  720,  678,  640,  604,  570,  538,  508,  480,  453 ;5
  1668.         dw   428,  404,  381,  360,  339,  320,  302,  285,  269,  254,  240,  226 ;6
  1669.         dw   214,  202,  190,  180,  170,  160,  151,  143,  135,  127,  120,  113 ;7
  1670.         dw   107,  101,   95,   90,   85,   80,   75,   71,   67,   63,   60,   56 ;8
  1671. st3periodtablesize=($-st3periods)/2
  1672.