?login_element?

Subversion Repositories NedoOS

Rev

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

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