nonogamer9

NekoTracker: A Tracker Player for Computercraft

Oct 10th, 2026
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 61.79 KB | Source Code | 0 0
  1. local speaker = peripheral.find("speaker")
  2. if not speaker then error("No speaker attached!") end
  3.  
  4. local SPEAKER_RATE = 48000
  5. local MIX_RATE = SPEAKER_RATE
  6. local TARGET_CHUNK = 16384
  7.  
  8. local AMIGA_CLOCK = 3546895
  9. local INTERPOLATE = true
  10. local RAMP_SAMPLES = 64
  11. local SOFT_KNEE = 100
  12. local LOOP_SONG = true
  13. local MAX_BG_VOICES = 48
  14.  
  15. local floor, min, max = math.floor, math.min, math.max
  16. local sin, sqrt = math.sin, math.sqrt
  17. local band, bor, lshift, rshift = bit32.band, bit32.bor, bit32.lshift, bit32.rshift
  18.  
  19. local song
  20.  
  21. local NOTE_OFF, NOTE_CUT, NOTE_FADE = -1, -2, -3
  22. local LE = 0x40
  23. local EMPTY = { n = 0, i = 0, vc = 0, vv = 0, e = 0, p = 0 }
  24. local EMPTYROW = {}
  25. local EMPTYPAT = { rows = 64 }
  26.  
  27. local D = ""
  28. local function u8(p) return D:byte(p + 1) or 0 end
  29. local function s8(p) local v = u8(p); return v > 127 and v - 256 or v end
  30. local function u16(p) return u8(p) + u8(p + 1) * 256 end
  31. local function s16(p) local v = u16(p); return v > 32767 and v - 65536 or v end
  32. local function u32(p) return u16(p) + u16(p + 2) * 65536 end
  33. local function u16be(p) return u8(p) * 256 + u8(p + 1) end
  34.  
  35. local function readS8(dp, len)
  36.     local t, byte = {}, string.byte
  37.     for j = 1, len do
  38.         local b = byte(D, dp + j) or 0
  39.         t[j] = b > 127 and b - 256 or b
  40.     end
  41.     return t
  42. end
  43.  
  44. local function unrollPingPong(s, which)
  45.     local ls, ll
  46.     if which == "sus" then ls, ll = s.susStart, s.susLen else ls, ll = s.loopStart, s.loopLen end
  47.     if ll < 2 then return end
  48.     local d, le = s.data, ls + ll
  49.     local nd = {}
  50.     for i = 1, le do nd[i] = d[i] end
  51.     local k = le
  52.     for i = le - 1, ls + 2, -1 do
  53.         k = k + 1
  54.         nd[k] = d[i]
  55.     end
  56.     local newLen = k
  57.     if which == "sus" then
  58.         for i = le + 1, s.len do
  59.             newLen = newLen + 1
  60.             nd[newLen] = d[i]
  61.         end
  62.         s.susLen = k - ls
  63.     else
  64.         s.loopLen = k - ls
  65.     end
  66.     s.data, s.len = nd, newLen
  67. end
  68.  
  69. local function signExt(v, w)
  70.     local h = 2 ^ (w - 1)
  71.     if v >= h then return v - 2 * h end
  72.     return v
  73. end
  74.  
  75. local function itDecompress(p, len, is16, it215)
  76.     local out, n = {}, 0
  77.     local blkMax = is16 and 0x4000 or 0x8000
  78.     local startW = is16 and 17 or 9
  79.     while n < len do
  80.         if p >= #D then break end
  81.         local clen = u16(p)
  82.         p = p + 2
  83.         local bp, bitbuf, bitcnt = p, 0, 0
  84.         local function rb(nb)
  85.             while bitcnt < nb do
  86.                 bitbuf = bitbuf + u8(bp) * 2 ^ bitcnt
  87.                 bp = bp + 1
  88.                 bitcnt = bitcnt + 8
  89.             end
  90.             local v = bitbuf % 2 ^ nb
  91.             bitbuf = (bitbuf - v) / 2 ^ nb
  92.             bitcnt = bitcnt - nb
  93.             return v
  94.         end
  95.         local blk = min(blkMax, len - n)
  96.         local width, d1, d2, cnt = startW, 0, 0, 0
  97.         while cnt < blk do
  98.             if width < 1 or width > startW then error("corrupt IT sample") end
  99.             local value = rb(width)
  100.             local handled = false
  101.             if is16 then
  102.                 if width < 7 then
  103.                     if value == 2 ^ (width - 1) then
  104.                         local v = rb(4) + 1
  105.                         width = (v < width) and v or v + 1
  106.                         handled = true
  107.                     end
  108.                 elseif width < 17 then
  109.                     local border = floor(0xFFFF / 2 ^ (17 - width)) - 8
  110.                     if value > border and value <= border + 16 then
  111.                         local v = value - border
  112.                         width = (v < width) and v or v + 1
  113.                         handled = true
  114.                     end
  115.                 elseif value >= 0x10000 then
  116.                     width = (value + 1) % 256
  117.                     handled = true
  118.                 end
  119.             else
  120.                 if width < 7 then
  121.                     if value == 2 ^ (width - 1) then
  122.                         local v = rb(3) + 1
  123.                         width = (v < width) and v or v + 1
  124.                         handled = true
  125.                     end
  126.                 elseif width < 9 then
  127.                     local border = floor(0xFF / 2 ^ (9 - width)) - 4
  128.                     if value > border and value <= border + 8 then
  129.                         local v = value - border
  130.                         width = (v < width) and v or v + 1
  131.                         handled = true
  132.                     end
  133.                 elseif value >= 0x100 then
  134.                     width = (value + 1) % 256
  135.                     handled = true
  136.                 end
  137.             end
  138.             if not handled then
  139.                 local v
  140.                 if is16 then
  141.                     v = (width < 16) and signExt(value, width) or signExt(value % 65536, 16)
  142.                 else
  143.                     v = (width < 8) and signExt(value, width) or signExt(value % 256, 8)
  144.                 end
  145.                 d1 = d1 + v
  146.                 d2 = d2 + d1
  147.                 if is16 then
  148.                     d1 = ((d1 + 32768) % 65536) - 32768
  149.                     d2 = ((d2 + 32768) % 65536) - 32768
  150.                 else
  151.                     d1 = ((d1 + 128) % 256) - 128
  152.                     d2 = ((d2 + 128) % 256) - 128
  153.                 end
  154.                 n = n + 1
  155.                 out[n] = it215 and d2 or d1
  156.                 cnt = cnt + 1
  157.             end
  158.         end
  159.         p = p + clen
  160.     end
  161.     if is16 then
  162.         for i = 1, #out do out[i] = out[i] / 256 end
  163.     end
  164.     for i = #out + 1, len do out[i] = 0 end
  165.     return out
  166. end
  167.  
  168. local function envValue(env, tk)
  169.     local pts = env.pts
  170.     local n = #pts
  171.     if tk <= pts[1][1] then return pts[1][2] end
  172.     for i = 2, n do
  173.         local b = pts[i]
  174.         if tk <= b[1] then
  175.             local a = pts[i - 1]
  176.             local dx = b[1] - a[1]
  177.             if dx <= 0 then return b[2] end
  178.             return a[2] + (b[2] - a[2]) * (tk - a[1]) / dx
  179.         end
  180.     end
  181.     return pts[n][2]
  182. end
  183.  
  184. local function advanceEnv(env, t, key)
  185.     local pts = env.pts
  186.     local pos = t[key]
  187.     if env.sustain and not t.keyoff then
  188.         local se = pts[env.susEnd][1]
  189.         if pos >= se then
  190.             t[key] = pts[env.susStart][1]
  191.             return
  192.         end
  193.     end
  194.     pos = pos + 1
  195.     if env.loop and pos >= pts[env.loopEnd][1] then
  196.         pos = pts[env.loopStart][1]
  197.     end
  198.     t[key] = pos
  199. end
  200.  
  201. local function makeEnv(pts, on, sus, susStart, susEnd, loop, loopStart, loopEnd)
  202.     if not on or #pts < 1 then return nil end
  203.     local n = #pts
  204.     local function cl(i) return max(1, min(n, i)) end
  205.     return { pts = pts, sustain = sus, susStart = cl(susStart), susEnd = cl(susEnd),
  206.              loop = loop, loopStart = cl(loopStart), loopEnd = cl(loopEnd) }
  207. end
  208.  
  209. local function convertLetter(L, par)
  210.     local isIT = song.fmt == "IT"
  211.     local hi, lo = rshift(par, 4), band(par, 15)
  212.     if L == 1 then return 0x30, par
  213.     elseif L == 2 then return 0x0B, par
  214.     elseif L == 3 then
  215.         if isIT then return 0x3B, par end
  216.         return 0x0D, par
  217.     elseif L == 4 then return 0x38, par
  218.     elseif L == 5 then
  219.         if par >= 0xF0 then return 0x0E, 0x20 + lo
  220.         elseif par >= 0xE0 then return 0x21, 0x20 + lo end
  221.         return 0x02, par
  222.     elseif L == 6 then
  223.         if par >= 0xF0 then return 0x0E, 0x10 + lo
  224.         elseif par >= 0xE0 then return 0x21, 0x10 + lo end
  225.         return 0x01, par
  226.     elseif L == 7 then return 0x03, par
  227.     elseif L == 8 then return 0x04, par
  228.     elseif L == 9 then return 0x1D, par
  229.     elseif L == 10 then return 0x00, par
  230.     elseif L == 11 then return 0x39, par
  231.     elseif L == 12 then return 0x3A, par
  232.     elseif L == 13 and isIT then return 0x2C, par
  233.     elseif L == 14 and isIT then return 0x37, par
  234.     elseif L == 15 then return 0x09, par
  235.     elseif L == 17 then return 0x1B, par
  236.     elseif L == 18 then return 0x07, par
  237.     elseif L == 19 then
  238.         if hi == 3 then return 0x0E, 0x40 + lo
  239.         elseif hi == 4 then return 0x0E, 0x70 + lo
  240.         elseif hi == 6 then return 0x3E, lo
  241.         elseif hi == 7 then return 0x35, lo
  242.         elseif hi == 0xA then return 0x36, lo
  243.         elseif hi >= 0xB and hi <= 0xE then return 0x0E, par end
  244.         return 0, 0
  245.     elseif L == 20 then
  246.         if par >= 0x20 then return 0x31, par end
  247.         if isIT then return 0x32, par end
  248.         return 0, 0
  249.     elseif L == 21 then return 0x34, par
  250.     elseif L == 22 then
  251.         if isIT then return 0x10, min(64, floor(par / 2)) end
  252.         return 0x10, min(64, par)
  253.     elseif L == 23 and isIT then return 0x11, par
  254.     end
  255.     return 0, 0
  256. end
  257.  
  258. local function loadMOD()
  259.     local sg = { fmt = "MOD", pm = 1, minPer = 113, maxPer = 856, slideMul = 1, mem = false,
  260.         insMode = false, vibScale = 2, gvolScale = 1, gvol = 64, speed = 6, tempo = 125,
  261.         samples = {}, patterns = {}, order = {}, mute = {}, restart = 1, holdTone = true }
  262.     local pos = 20
  263.     for i = 1, 31 do
  264.         local len = u16be(pos + 22) * 2
  265.         local fine = band(u8(pos + 24), 15)
  266.         if fine > 7 then fine = fine - 16 end
  267.         local ls, ll = u16be(pos + 26) * 2, u16be(pos + 28) * 2
  268.         sg.samples[i] = { len = len, vol = min(64, u8(pos + 25)), loopStart = ls, loopLen = ll,
  269.             loop = ll > 2 and ls < len, fine = fine, c4spd = 8363, ref = 49, tune = 0, gvol = 1 }
  270.         if ls + ll > len then sg.samples[i].loopLen = max(0, len - ls) end
  271.         pos = pos + 30
  272.     end
  273.     local songLength = min(128, max(1, u8(950)))
  274.     local rst = u8(951)
  275.     sg.songLength = songLength
  276.     sg.restart = (rst < songLength) and rst + 1 or 1
  277.  
  278.     local maxPattern = 0
  279.     for i = 1, 128 do
  280.         local v = u8(951 + i)
  281.         sg.order[i] = v
  282.         if v > maxPattern then maxPattern = v end
  283.     end
  284.  
  285.     local tag = D:sub(1081, 1084)
  286.     local ch = 4
  287.     if tag == "M.K." or tag == "M!K!" or tag == "FLT4" or tag == "4CHN" then ch = 4
  288.     elseif tag == "6CHN" then ch = 6
  289.     elseif tag == "8CHN" or tag == "OKTA" or tag == "CD81" or tag == "FLT8" then ch = 8
  290.     else
  291.         local n = tag:match("^(%d%d)CH") or tag:match("^(%d)CHN")
  292.         if n then ch = tonumber(n) end
  293.     end
  294.     sg.channels = ch
  295.  
  296.     pos = 1084
  297.     for p = 0, maxPattern do
  298.         local pat = { rows = 64 }
  299.         for row = 1, 64 do
  300.             local r = {}
  301.             for c = 1, ch do
  302.                 local b1, b2, b3, b4 = u8(pos), u8(pos + 1), u8(pos + 2), u8(pos + 3)
  303.                 pos = pos + 4
  304.                 if b1 ~= 0 or b2 ~= 0 or b3 ~= 0 or b4 ~= 0 then
  305.                     r[c] = { n = bor(lshift(band(b1, 15), 8), b2), i = bor(band(b1, 0xF0), rshift(b3, 4)),
  306.                              vc = 0, vv = 0, e = band(b3, 15), p = b4 }
  307.                 end
  308.             end
  309.             pat[row] = r
  310.         end
  311.         sg.patterns[p] = pat
  312.     end
  313.  
  314.     for i = 1, 31 do
  315.         local s = sg.samples[i]
  316.         s.data = readS8(pos, s.len)
  317.         pos = pos + s.len
  318.     end
  319.     return sg
  320. end
  321.  
  322. local function loadS3M()
  323.     local ordNum, insNum, patNum = u16(32), u16(34), u16(36)
  324.     local sflags, cwt, ffi = u16(38), u16(40), u16(42)
  325.     local sg = { fmt = "S3M", pm = 2, minPer = 1, maxPer = 32767, slideMul = 4, mem = true,
  326.         insMode = false, vibScale = 8, gvolScale = 1, samples = {}, patterns = {}, order = {},
  327.         mute = {}, restart = 1, songLength = max(1, ordNum), letters = true, markers = true,
  328.         shareG = true, holdTone = false, nnaOn = false,
  329.         fastVol = band(sflags, 64) ~= 0 or cwt == 0x1300 }
  330.     sg.gvol = u8(48)
  331.     if sg.gvol == 0 or sg.gvol > 64 then sg.gvol = 64 end
  332.     sg.speed = u8(49); if sg.speed == 0 then sg.speed = 6 end
  333.     sg.tempo = u8(50); if sg.tempo < 32 then sg.tempo = 125 end
  334.  
  335.     local nch = 0
  336.     for c = 0, 31 do
  337.         local cs = u8(64 + c)
  338.         if cs ~= 255 and band(cs, 0x7F) < 16 then
  339.             nch = c + 1
  340.             if cs >= 128 then sg.mute[c + 1] = true end
  341.         end
  342.     end
  343.     if nch == 0 then nch = 1 end
  344.     sg.channels = nch
  345.  
  346.     for i = 1, ordNum do sg.order[i] = u8(96 + i - 1) end
  347.     local insBase = 96 + ordNum
  348.     local patBase = insBase + insNum * 2
  349.  
  350.     for i = 1, insNum do
  351.         local ptr = u16(insBase + (i - 1) * 2) * 16
  352.         local s = { len = 0, vol = 0, loopStart = 0, loopLen = 0, loop = false, fine = 0,
  353.                     c4spd = 8363, ref = 49, tune = 0, gvol = 1, data = {} }
  354.         if ptr > 0 and u8(ptr) == 1 then
  355.             local dataOff = (u8(ptr + 13) * 65536 + u16(ptr + 14)) * 16
  356.             local len, ls, le = u32(ptr + 16), u32(ptr + 20), u32(ptr + 24)
  357.             local flg = u8(ptr + 31)
  358.             local is16 = band(flg, 4) ~= 0
  359.             local bps = is16 and 2 or 1
  360.             if dataOff + len * bps > #D then len = max(0, floor((#D - dataOff) / bps)) end
  361.             s.vol = min(64, u8(ptr + 28))
  362.             s.c4spd = u32(ptr + 32)
  363.             if s.c4spd == 0 then s.c4spd = 8363 end
  364.             local data = {}
  365.             if is16 then
  366.                 for j = 1, len do
  367.                     local v = u16(dataOff + (j - 1) * 2)
  368.                     if ffi == 1 then v = v > 32767 and v - 65536 or v else v = v - 32768 end
  369.                     data[j] = v / 256
  370.                 end
  371.             else
  372.                 for j = 1, len do
  373.                     local b = u8(dataOff + j - 1)
  374.                     if ffi == 1 then data[j] = b > 127 and b - 256 or b else data[j] = b - 128 end
  375.                 end
  376.             end
  377.             s.data, s.len = data, len
  378.             if band(flg, 1) ~= 0 and le > ls and ls < len then
  379.                 s.loop, s.loopStart, s.loopLen = true, ls, min(le, len) - ls
  380.             end
  381.         end
  382.         sg.samples[i] = s
  383.     end
  384.  
  385.     for p = 0, patNum - 1 do
  386.         local ptr = u16(patBase + p * 2) * 16
  387.         local pat = { rows = 64 }
  388.         for r = 1, 64 do pat[r] = {} end
  389.         if ptr > 0 then
  390.             local pos = ptr + 2
  391.             for r = 1, 64 do
  392.                 local row = pat[r]
  393.                 while true do
  394.                     local what = u8(pos)
  395.                     pos = pos + 1
  396.                     if what == 0 then break end
  397.                     local cell = { n = 0, i = 0, vc = 0, vv = 0, e = 0, p = 0 }
  398.                     if band(what, 32) ~= 0 then
  399.                         local note = u8(pos)
  400.                         cell.i = u8(pos + 1)
  401.                         pos = pos + 2
  402.                         if note == 254 then cell.n = NOTE_CUT
  403.                         elseif note ~= 255 then cell.n = rshift(note, 4) * 12 + band(note, 15) + 1 end
  404.                     end
  405.                     if band(what, 64) ~= 0 then
  406.                         cell.vc, cell.vv = 1, min(64, u8(pos))
  407.                         pos = pos + 1
  408.                     end
  409.                     if band(what, 128) ~= 0 then
  410.                         local cmd, par = u8(pos), u8(pos + 1)
  411.                         pos = pos + 2
  412.                         if cmd > 0 and cmd < 27 then cell.e, cell.p = LE + cmd, par end
  413.                     end
  414.                     local c = band(what, 31) + 1
  415.                     if c <= nch then row[c] = cell end
  416.                 end
  417.             end
  418.         end
  419.         sg.patterns[p] = pat
  420.     end
  421.     return sg
  422. end
  423.  
  424. local function xmVol(v)
  425.     if v < 0x10 then return 0, 0 end
  426.     if v <= 0x50 then return 1, v - 0x10 end
  427.     local hi, lo = rshift(v, 4), band(v, 15)
  428.     if hi == 6 then return 2, lo
  429.     elseif hi == 7 then return 3, lo
  430.     elseif hi == 8 then return 4, lo
  431.     elseif hi == 9 then return 5, lo
  432.     elseif hi == 0xA then return 6, lo
  433.     elseif hi == 0xB then return 7, lo
  434.     elseif hi == 0xF then return 11, lo * 16 end
  435.     return 0, 0
  436. end
  437.  
  438. local function loadXM()
  439.     local hdr = u32(60)
  440.     local songLen, rst, nch, npat, nins = u16(64), u16(66), u16(68), u16(70), u16(72)
  441.     local flags = u16(74)
  442.     local sg = { fmt = "XM", pm = 3, minPer = 0, maxPer = 9600, slideMul = 4, mem = true,
  443.         insMode = true, vibScale = 8, gvolScale = 1, gvol = 64, samples = {}, patterns = {},
  444.         order = {}, mute = {}, instruments = {}, channels = nch, holdTone = true,
  445.         songLength = max(1, min(256, songLen)), linear = band(flags, 1) ~= 0 }
  446.     sg.restart = (rst < sg.songLength) and rst + 1 or 1
  447.     if not sg.linear then sg.pm, sg.minPer, sg.maxPer = 2, 1, 32767 end
  448.     sg.speed = u16(76); if sg.speed == 0 then sg.speed = 6 end
  449.     sg.tempo = u16(78); if sg.tempo < 32 then sg.tempo = 125 end
  450.     for i = 1, 256 do sg.order[i] = u8(80 + i - 1) end
  451.  
  452.     local pos = 60 + hdr
  453.     for p = 0, npat - 1 do
  454.         local hl = u32(pos)
  455.         local rows = u16(pos + 5)
  456.         local psize = u16(pos + 7)
  457.         local dp = pos + hl
  458.         local pat = { rows = rows }
  459.         for r = 1, rows do pat[r] = {} end
  460.         if psize > 0 then
  461.             for r = 1, rows do
  462.                 local row = pat[r]
  463.                 for c = 1, nch do
  464.                     local b = u8(dp)
  465.                     dp = dp + 1
  466.                     local note, ins, vol, eff, par = 0, 0, 0, 0, 0
  467.                     if b >= 128 then
  468.                         if band(b, 1) ~= 0 then note = u8(dp); dp = dp + 1 end
  469.                         if band(b, 2) ~= 0 then ins = u8(dp); dp = dp + 1 end
  470.                         if band(b, 4) ~= 0 then vol = u8(dp); dp = dp + 1 end
  471.                         if band(b, 8) ~= 0 then eff = u8(dp); dp = dp + 1 end
  472.                         if band(b, 16) ~= 0 then par = u8(dp); dp = dp + 1 end
  473.                     else
  474.                         note, ins, vol, eff, par = b, u8(dp), u8(dp + 1), u8(dp + 2), u8(dp + 3)
  475.                         dp = dp + 4
  476.                     end
  477.                     if note ~= 0 or ins ~= 0 or vol ~= 0 or eff ~= 0 or par ~= 0 then
  478.                         local vc, vv = xmVol(vol)
  479.                         if note == 97 then note = NOTE_OFF end
  480.                         if eff >= LE then eff, par = 0, 0 end
  481.                         row[c] = { n = note, i = ins, vc = vc, vv = vv, e = eff, p = par }
  482.                     end
  483.                 end
  484.             end
  485.         end
  486.         sg.patterns[p] = pat
  487.         pos = pos + hl + psize
  488.     end
  489.  
  490.     for i = 1, nins do
  491.         local p = pos
  492.         local hs = max(29, u32(p))
  493.         local ns = u16(p + 27)
  494.         local inst = { samples = {}, keymap = {}, gvol = 1, fadeDec = 0 }
  495.         if ns > 0 then
  496.             local shs = u32(p + 29)
  497.             if shs < 18 then shs = 40 end
  498.             for n = 1, 96 do inst.keymap[n] = u8(p + 33 + n - 1) + 1 end
  499.             local nv = min(12, u8(p + 225))
  500.             local pts = {}
  501.             for k = 0, nv - 1 do
  502.                 pts[#pts + 1] = { u16(p + 129 + k * 4), min(64, u16(p + 131 + k * 4)) }
  503.             end
  504.             local vt = u8(p + 233)
  505.             inst.venv = makeEnv(pts, band(vt, 1) ~= 0, band(vt, 2) ~= 0,
  506.                 u8(p + 227) + 1, u8(p + 227) + 1, band(vt, 4) ~= 0, u8(p + 228) + 1, u8(p + 229) + 1)
  507.             inst.fadeDec = u16(p + 239) * 2
  508.             local vdepth = band(u8(p + 237), 15)
  509.             if vdepth > 0 then
  510.                 inst.av = { type = u8(p + 235), sweep = u8(p + 236), depth = vdepth,
  511.                             rate = band(u8(p + 238), 63) }
  512.             end
  513.  
  514.             local sp = p + hs
  515.             local dpos = sp + ns * shs
  516.             for k = 1, ns do
  517.                 local h = sp + (k - 1) * shs
  518.                 local len, ls, ll = u32(h), u32(h + 4), u32(h + 8)
  519.                 local typ = band(u8(h + 14), 0xFF)
  520.                 local is16 = band(typ, 16) ~= 0
  521.                 local rawLen = len
  522.                 if is16 then len, ls, ll = floor(len / 2), floor(ls / 2), floor(ll / 2) end
  523.                 local s = { len = len, vol = min(64, u8(h + 12)), loopStart = 0, loopLen = 0,
  524.                     loop = false, fine = 0, c4spd = 8363, ref = 49, gvol = 1,
  525.                     tune = s8(h + 16) + s8(h + 13) / 128 }
  526.                 local data, acc = {}, 0
  527.                 if is16 then
  528.                     for j = 1, len do
  529.                         acc = acc + s16(dpos + (j - 1) * 2)
  530.                         if acc > 32767 then acc = acc - 65536 elseif acc < -32768 then acc = acc + 65536 end
  531.                         data[j] = acc / 256
  532.                     end
  533.                 else
  534.                     for j = 1, len do
  535.                         acc = acc + s8(dpos + j - 1)
  536.                         if acc > 127 then acc = acc - 256 elseif acc < -128 then acc = acc + 256 end
  537.                         data[j] = acc
  538.                     end
  539.                 end
  540.                 s.data = data
  541.                 local lt = band(typ, 3)
  542.                 if lt ~= 0 and ll > 0 and ls < len then
  543.                     s.loop, s.loopStart, s.loopLen = true, ls, min(ll, len - ls)
  544.                     if lt == 2 then unrollPingPong(s, "loop") end
  545.                 end
  546.                 inst.samples[k] = s
  547.                 dpos = dpos + rawLen
  548.             end
  549.             pos = dpos
  550.         else
  551.             pos = p + hs
  552.         end
  553.         sg.instruments[i] = inst
  554.     end
  555.     return sg
  556. end
  557.  
  558. local ITTONEP = { 1, 4, 8, 16, 32, 64, 96, 128, 255 }
  559. local ITVIBTYPE = { [0] = 0, [1] = 2, [2] = 1, [3] = 0 }
  560.  
  561. local function itVol(v)
  562.     if v <= 64 then return 1, v
  563.     elseif v <= 74 then return 5, v - 65
  564.     elseif v <= 84 then return 4, v - 75
  565.     elseif v <= 94 then return 3, v - 85
  566.     elseif v <= 104 then return 2, v - 95
  567.     elseif v <= 114 then return 13, (v - 105) * 4
  568.     elseif v <= 124 then return 12, (v - 115) * 4
  569.     elseif v >= 193 and v <= 202 then return 11, ITTONEP[min(9, max(1, v - 193))] or 1
  570.     elseif v >= 203 and v <= 212 then return 7, v - 203 end
  571.     return 0, 0
  572. end
  573.  
  574. local function loadIT()
  575.     local ordNum, insNum, smpNum, patNum = u16(32), u16(34), u16(36), u16(38)
  576.     local flags = u16(44)
  577.     local sg = { fmt = "IT", pm = 3, minPer = 0, maxPer = 9600, slideMul = 4, mem = true,
  578.         insMode = band(flags, 4) ~= 0, vibScale = 6, gvolScale = 0.5, samples = {}, patterns = {},
  579.         order = {}, mute = {}, instruments = {}, restart = 1, songLength = max(1, ordNum),
  580.         linear = band(flags, 8) ~= 0, letters = true, markers = true, holdTone = false,
  581.         shareG = band(flags, 32) ~= 0, chnvol = {} }
  582.     sg.nnaOn = sg.insMode
  583.     sg.gvol = min(64, floor(u8(48) / 2))
  584.     if not sg.linear then sg.pm, sg.minPer, sg.maxPer = 2, 1, 32767 end
  585.     if sg.gvol == 0 then sg.gvol = 64 end
  586.     sg.speed = u8(50); if sg.speed == 0 then sg.speed = 6 end
  587.     sg.tempo = u8(51); if sg.tempo < 32 then sg.tempo = 125 end
  588.     for c = 0, 63 do
  589.         if u8(64 + c) >= 128 then sg.mute[c + 1] = true end
  590.         sg.chnvol[c + 1] = min(64, u8(128 + c))
  591.     end
  592.     for i = 1, ordNum do sg.order[i] = u8(192 + i - 1) end
  593.  
  594.     local insBase = 192 + ordNum
  595.     local smpBase = insBase + insNum * 4
  596.     local patBase = smpBase + smpNum * 4
  597.  
  598.     for i = 1, smpNum do
  599.         local p = u32(smpBase + (i - 1) * 4)
  600.         local s = { len = 0, vol = 0, loopStart = 0, loopLen = 0, loop = false, fine = 0,
  601.                     c4spd = 8363, ref = 61, tune = 0, gvol = 1, data = {} }
  602.         if p > 0 and D:sub(p + 1, p + 4) == "IMPS" then
  603.             local flg, cvt = u8(p + 18), u8(p + 46)
  604.             local len = u32(p + 48)
  605.             local ls, le = u32(p + 52), u32(p + 56)
  606.             local sls, sle = u32(p + 64), u32(p + 68)
  607.             local dp = u32(p + 72)
  608.             local is16 = band(flg, 2) ~= 0
  609.             local signed = band(cvt, 1) ~= 0
  610.             s.gvol = min(64, u8(p + 17)) / 64
  611.             s.vol = min(64, u8(p + 19))
  612.             s.c4spd = u32(p + 60)
  613.             if s.c4spd == 0 then s.c4spd = 8363 end
  614.             local vdepth = u8(p + 77)
  615.             if vdepth > 0 then
  616.                 s.av = { type = ITVIBTYPE[u8(p + 79)] or 0, sweep = u8(p + 78), depth = min(64, vdepth),
  617.                          rate = u8(p + 76) }
  618.             end
  619.             if band(flg, 1) ~= 0 and len > 0 and dp > 0 then
  620.                 local bps = is16 and 2 or 1
  621.                 if band(flg, 8) == 0 and dp + len * bps > #D then
  622.                     len = max(0, floor((#D - dp) / bps))
  623.                 end
  624.                 local data
  625.                 if band(flg, 8) ~= 0 then
  626.                     local ok, res = pcall(itDecompress, dp, len, is16, band(cvt, 4) ~= 0)
  627.                     if ok then data = res else data = {}; for j = 1, len do data[j] = 0 end end
  628.                 else
  629.                     data = {}
  630.                     local acc = 0
  631.                     local delta = band(cvt, 4) ~= 0
  632.                     for j = 1, len do
  633.                         local v
  634.                         if is16 then
  635.                             v = u16(dp + (j - 1) * 2)
  636.                             if signed then v = v > 32767 and v - 65536 or v else v = v - 32768 end
  637.                             if delta then
  638.                                 acc = acc + v
  639.                                 if acc > 32767 then acc = acc - 65536 elseif acc < -32768 then acc = acc + 65536 end
  640.                                 v = acc
  641.                             end
  642.                             v = v / 256
  643.                         else
  644.                             v = u8(dp + j - 1)
  645.                             if signed then v = v > 127 and v - 256 or v else v = v - 128 end
  646.                             if delta then
  647.                                 acc = acc + v
  648.                                 if acc > 127 then acc = acc - 256 elseif acc < -128 then acc = acc + 256 end
  649.                                 v = acc
  650.                             end
  651.                         end
  652.                         data[j] = v
  653.                     end
  654.                 end
  655.                 s.data, s.len = data, len
  656.                 local pingN, pingS = false, false
  657.                 if band(flg, 16) ~= 0 and le > ls and ls < len then
  658.                     s.loop, s.loopStart, s.loopLen = true, ls, min(le, len) - ls
  659.                     pingN = band(flg, 64) ~= 0
  660.                 end
  661.                 if band(flg, 32) ~= 0 and sle > sls and sls < len then
  662.                     s.sus, s.susStart, s.susLen = true, sls, min(sle, len) - sls
  663.                     pingS = band(flg, 128) ~= 0
  664.                 end
  665.                 if s.loop and pingN then unrollPingPong(s, "loop") end
  666.                 if s.sus and pingS and not s.loop then unrollPingPong(s, "sus") end
  667.             end
  668.         end
  669.         sg.samples[i] = s
  670.     end
  671.  
  672.     if sg.insMode then
  673.         for i = 1, insNum do
  674.             local p = u32(insBase + (i - 1) * 4)
  675.             if p > 0 and D:sub(p + 1, p + 4) == "IMPI" then
  676.                 local inst = { notemap = {}, gvol = min(128, u8(p + 24)) / 128,
  677.                                fadeDec = u16(p + 20) * 64,
  678.                                nna = min(3, u8(p + 17)), dct = min(3, u8(p + 18)), dca = min(2, u8(p + 19)) }
  679.                 for n = 0, 119 do
  680.                     inst.notemap[n + 1] = { u8(p + 64 + n * 2) + 1, u8(p + 65 + n * 2) }
  681.                 end
  682.                 local ef, num = u8(p + 304), min(25, u8(p + 305))
  683.                 local pts = {}
  684.                 for k = 0, num - 1 do
  685.                     pts[#pts + 1] = { u16(p + 311 + k * 3), min(64, u8(p + 310 + k * 3)) }
  686.                 end
  687.                 inst.venv = makeEnv(pts, band(ef, 1) ~= 0, band(ef, 4) ~= 0,
  688.                     u8(p + 308) + 1, u8(p + 309) + 1, band(ef, 2) ~= 0, u8(p + 306) + 1, u8(p + 307) + 1)
  689.                 local pf = u8(p + 468)
  690.                 if band(pf, 1) ~= 0 and band(pf, 128) == 0 then
  691.                     local pn = min(25, u8(p + 469))
  692.                     local ppts = {}
  693.                     for k = 0, pn - 1 do
  694.                         ppts[#ppts + 1] = { u16(p + 475 + k * 3), s8(p + 474 + k * 3) }
  695.                     end
  696.                     inst.penv = makeEnv(ppts, true, band(pf, 4) ~= 0,
  697.                         u8(p + 472) + 1, u8(p + 473) + 1, band(pf, 2) ~= 0, u8(p + 470) + 1, u8(p + 471) + 1)
  698.                 end
  699.                 sg.instruments[i] = inst
  700.             end
  701.         end
  702.     end
  703.  
  704.     local maxCh = 1
  705.     for p = 0, patNum - 1 do
  706.         local ptr = u32(patBase + p * 4)
  707.         local rows = 64
  708.         local pat = {}
  709.         if ptr > 0 then
  710.             rows = u16(ptr + 2)
  711.             if rows < 1 then rows = 64 end
  712.             for r = 1, rows do pat[r] = {} end
  713.             local pos = ptr + 8
  714.             local lmask, lnote, lins, lvol, lcmd, lpar = {}, {}, {}, {}, {}, {}
  715.             for r = 1, rows do
  716.                 local row = pat[r]
  717.                 while true do
  718.                     local cv = u8(pos)
  719.                     pos = pos + 1
  720.                     if cv == 0 then break end
  721.                     local ch = band(cv - 1, 63)
  722.                     local mask
  723.                     if band(cv, 128) ~= 0 then
  724.                         mask = u8(pos)
  725.                         pos = pos + 1
  726.                         lmask[ch] = mask
  727.                     else
  728.                         mask = lmask[ch] or 0
  729.                     end
  730.                     local note, ins, vol, cmd, par
  731.                     if band(mask, 1) ~= 0 then note = u8(pos); pos = pos + 1; lnote[ch] = note
  732.                     elseif band(mask, 16) ~= 0 then note = lnote[ch] end
  733.                     if band(mask, 2) ~= 0 then ins = u8(pos); pos = pos + 1; lins[ch] = ins
  734.                     elseif band(mask, 32) ~= 0 then ins = lins[ch] end
  735.                     if band(mask, 4) ~= 0 then vol = u8(pos); pos = pos + 1; lvol[ch] = vol
  736.                     elseif band(mask, 64) ~= 0 then vol = lvol[ch] end
  737.                     if band(mask, 8) ~= 0 then
  738.                         cmd, par = u8(pos), u8(pos + 1)
  739.                         pos = pos + 2
  740.                         lcmd[ch], lpar[ch] = cmd, par
  741.                     elseif band(mask, 128) ~= 0 then cmd, par = lcmd[ch], lpar[ch] end
  742.  
  743.                     local cell = { n = 0, i = ins or 0, vc = 0, vv = 0, e = 0, p = 0 }
  744.                     if note then
  745.                         if note < 120 then cell.n = note + 1
  746.                         elseif note == 254 then cell.n = NOTE_CUT
  747.                         elseif note == 255 then cell.n = NOTE_OFF
  748.                         else cell.n = NOTE_FADE end
  749.                     end
  750.                     if vol then cell.vc, cell.vv = itVol(vol) end
  751.                     if cmd and cmd > 0 and cmd < 27 then cell.e, cell.p = LE + cmd, par or 0 end
  752.                     row[ch + 1] = cell
  753.                     if ch + 1 > maxCh then maxCh = ch + 1 end
  754.                 end
  755.             end
  756.         else
  757.             for r = 1, rows do pat[r] = {} end
  758.         end
  759.         pat.rows = rows
  760.         sg.patterns[p] = pat
  761.     end
  762.     sg.channels = maxCh
  763.     return sg
  764. end
  765.  
  766. local tracks = {}
  767. local bg = {}
  768. local speed, bpm = 6, 125
  769. local pendingOrder, pendingBreak, loopTarget, rowRepeat, fineDelay = nil, nil, nil, 0, 0
  770. local rowNow = 1
  771.  
  772. local MEMEFF = { [1] = true, [2] = true, [5] = true, [6] = true, [7] = true, [9] = true,
  773.                  [10] = true, [0x11] = true, [0x1B] = true, [0x1D] = true }
  774.  
  775. local function newTrack(c)
  776.     return { sample = nil, inst = nil, instNum = 0, cursor = 0, per = 0, tper = 0, step = 0, baseF = 0,
  777.         volume = 64, volumeScale = 0, cvol = (song.chnvol and song.chnvol[c]) or 64, active = false,
  778.         effect = 0, eData = 0, vc = 0, vv = 0,
  779.         portSpeed = 0, vibSpeed = 0, vibDepth = 0, vibPos = 0, tremSpeed = 0, tremDepth = 0, tremPos = 0,
  780.         vibOff = 0, tremOff = 0, arp = 0, mem = {}, keyoff = false, notefade = false,
  781.         envPos = 0, penvPos = 0, fade = 65536, venvOff = false, penvOff = false,
  782.         loopRow = 1, loopCnt = 0, tremorPos = 0, tremorOff = false,
  783.         vibWave = 0, tremWave = 0, vibFine = false, fineOv = nil, fineSemi = 0, curScale = 0, ghost = nil,
  784.         av = nil, avPos = 0, avAmp = 0, avOff = 0, hiOff = 0, nna = 0,
  785.         vNote = 0, vSmp = 0, vIns = 0, muted = song.mute[c] }
  786. end
  787.  
  788. local function slideUp(t, amt)
  789.     if song.pm == 3 then t.per = min(t.per + amt, song.maxPer)
  790.     else t.per = max(t.per - amt, song.minPer) end
  791. end
  792.  
  793. local function slideDown(t, amt)
  794.     if song.pm == 3 then t.per = max(t.per - amt, 0)
  795.     else t.per = min(t.per + amt, song.maxPer) end
  796. end
  797.  
  798. local function tonePorta(t, spd)
  799.     local amt = spd * song.slideMul
  800.     if t.per < t.tper then t.per = min(t.tper, t.per + amt)
  801.     elseif t.per > t.tper then t.per = max(t.tper, t.per - amt) end
  802. end
  803.  
  804. local function notePitch(smp, note)
  805.     if song.pm == 1 then return note end
  806.     if song.pm == 2 then return 14317456 / (smp.c4spd * 2 ^ ((note - smp.ref + smp.tune) / 12)) end
  807.     return (note - 1 + smp.tune) * 64
  808. end
  809.  
  810. local function pickSample(num, note)
  811.     if song.insMode then
  812.         local inst = song.instruments[num]
  813.         if not inst then return nil end
  814.         if song.fmt == "XM" then
  815.             local k = inst.keymap[note] or 1
  816.             return inst.samples[k], note, inst, k
  817.         end
  818.         local nm = inst.notemap[note]
  819.         if not nm then return nil end
  820.         return song.samples[nm[2]], nm[1], inst, nm[2]
  821.     end
  822.     return song.samples[num], note, nil, num
  823. end
  824.  
  825. local function getLoop(s, keyoff)
  826.     if s.sus and not keyoff and s.susLen > 0 then return true, s.susStart, s.susLen end
  827.     if s.loop and s.loopLen > 0 then return true, s.loopStart, s.loopLen end
  828.     return false, 0, 0
  829. end
  830.  
  831. local function makeGhost(t)
  832.     local s = t.sample
  833.     if t.active and s and s.len > 0 and t.curScale > 0 then
  834.         local hasLoop, ls, ll = getLoop(s, t.keyoff)
  835.         t.ghost = { data = s.data, len = s.len, cur = t.cursor, step = t.step, vol = t.curScale,
  836.                     hasLoop = hasLoop, ls = ls, le = ls + ll, ll = ll }
  837.     end
  838. end
  839.  
  840. local function killVoice(v)
  841.     makeGhost(v)
  842.     v.active = false
  843. end
  844.  
  845. local function applyKeyOff(v)
  846.     v.keyoff = true
  847.     local inst = v.inst
  848.     if not (inst and inst.venv) then
  849.         if song.fmt == "IT" and inst then
  850.             if inst.fadeDec > 0 then v.notefade = true else v.fade = 0 end
  851.         else
  852.             v.volume = 0
  853.         end
  854.     end
  855. end
  856.  
  857. local function noteCut(t)
  858.     if song.fmt == "IT" then killVoice(t) else t.volume = 0 end
  859. end
  860.  
  861. local function spawnBG(t, c)
  862.     if t.muted then return nil end
  863.     local v = { chan = c, sample = t.sample, inst = t.inst, cursor = t.cursor, step = t.step,
  864.         baseF = t.baseF, curScale = t.curScale, volumeScale = t.volumeScale, volume = t.volume,
  865.         cvol = t.cvol, envPos = t.envPos, penvPos = t.penvPos, fade = t.fade, keyoff = t.keyoff,
  866.         notefade = t.notefade, active = true, tremOff = 0, tremorOff = false, venvOff = t.venvOff,
  867.         penvOff = t.penvOff, av = t.av, avPos = t.avPos, avAmp = t.avAmp, avOff = t.avOff,
  868.         note = t.vNote, smpNum = t.vSmp, insNum = t.vIns }
  869.     if #bg >= MAX_BG_VOICES then
  870.         for i = 1, #bg do
  871.             if bg[i].active then killVoice(bg[i]) break end
  872.         end
  873.     end
  874.     bg[#bg + 1] = v
  875.     return v
  876. end
  877.  
  878. local function dnaCheck(c, inst, insNum, smpNum, note)
  879.     local dct, dca = inst.dct, inst.dca
  880.     for i = 1, #bg do
  881.         local v = bg[i]
  882.         if v.active and v.chan == c and v.insNum == insNum then
  883.             local dup = (dct == 1 and v.note == note) or (dct == 2 and v.smpNum == smpNum) or dct == 3
  884.             if dup then
  885.                 if dca == 0 then killVoice(v)
  886.                 elseif dca == 1 then applyKeyOff(v)
  887.                 else v.notefade = true end
  888.             end
  889.         end
  890.     end
  891. end
  892.  
  893. local function startCell(t, cell, c, cmd)
  894.     local n, ins = cell.n, cell.i
  895.     local isTone = (cmd == 3 or cmd == 5 or cmd == 0x3A or cell.vc == 11)
  896.     if ins > 0 then t.instNum = ins end
  897.     if n > 0 then
  898.         local smp, nn, inst, smpNum = pickSample(t.instNum, n)
  899.         if smp and smp.len > 0 then
  900.             if isTone and t.sample and (t.active or song.holdTone) then
  901.                 t.tper = notePitch(smp, nn)
  902.                 if ins > 0 then
  903.                     t.volume = t.sample.vol
  904.                     if song.insMode then
  905.                         t.keyoff, t.fade, t.envPos, t.penvPos, t.notefade = false, 65536, 0, 0, false
  906.                     end
  907.                 end
  908.             else
  909.                 if song.nnaOn and t.active and t.sample and t.curScale > 0 and t.nna ~= 0 then
  910.                     local v = spawnBG(t, c)
  911.                     if v then
  912.                         if t.nna == 2 then applyKeyOff(v)
  913.                         elseif t.nna == 3 then v.notefade = true end
  914.                     end
  915.                 else
  916.                     makeGhost(t)
  917.                 end
  918.                 if song.nnaOn and inst and inst.dct and inst.dct ~= 0 then
  919.                     dnaCheck(c, inst, t.instNum, smpNum, nn)
  920.                 end
  921.                 t.sample, t.inst = smp, inst
  922.                 t.per = notePitch(smp, nn)
  923.                 t.tper = t.per
  924.                 t.cursor = 0
  925.                 t.active = true
  926.                 t.curScale = 0
  927.                 t.fineOv = nil
  928.                 t.fineSemi = 0
  929.                 if band(t.vibWave, 4) == 0 then t.vibPos = 0 end
  930.                 if band(t.tremWave, 4) == 0 then t.tremPos = 0 end
  931.                 t.tremorPos = 0
  932.                 t.keyoff, t.notefade, t.fade, t.envPos, t.penvPos = false, false, 65536, 0, 0
  933.                 t.venvOff, t.penvOff = false, false
  934.                 t.nna = inst and inst.nna or 0
  935.                 t.vNote, t.vSmp, t.vIns = nn, smpNum, t.instNum
  936.                 t.av = smp.av or (inst and inst.av) or nil
  937.                 t.avPos, t.avAmp, t.avOff = 0, 0, 0
  938.                 if ins > 0 then t.volume = smp.vol end
  939.             end
  940.         end
  941.     elseif n == NOTE_OFF then
  942.         applyKeyOff(t)
  943.     elseif n == NOTE_FADE then
  944.         t.notefade = true
  945.     elseif n == NOTE_CUT then
  946.         killVoice(t)
  947.     elseif ins > 0 then
  948.         if song.insMode then
  949.             local inst = song.instruments[ins]
  950.             if inst then t.inst = inst end
  951.             if t.sample then t.volume = t.sample.vol end
  952.             t.keyoff, t.notefade, t.fade, t.envPos, t.penvPos = false, false, 65536, 0, 0
  953.         else
  954.             local smp = song.samples[ins]
  955.             if smp and smp.len > 0 then t.volume = smp.vol end
  956.         end
  957.     end
  958. end
  959.  
  960. local function voiceScale(t)
  961.     local s = t.sample
  962.     local v = t.volume + t.tremOff
  963.     if v < 0 then v = 0 elseif v > 64 then v = 64 end
  964.     local scale = v / 64 * (t.cvol / 64) * song.gvol / 64 * s.gvol
  965.     local inst = t.inst
  966.     if inst then
  967.         if inst.venv and not t.venvOff then scale = scale * envValue(inst.venv, t.envPos) / 64 end
  968.         scale = scale * t.fade / 65536 * inst.gvol
  969.     end
  970.     if t.tremorOff then scale = 0 end
  971.     return scale
  972. end
  973.  
  974. local function applyPitchMods(t, f)
  975.     local semis = t.avOff
  976.     local inst = t.inst
  977.     if inst and inst.penv and not t.penvOff then
  978.         semis = semis + envValue(inst.penv, t.penvPos) / 2
  979.     end
  980.     if semis ~= 0 then f = f * 2 ^ (semis / 12) end
  981.     if f > 131072 then f = 131072 end
  982.     return f / MIX_RATE
  983. end
  984.  
  985. local function finalizeChannel(t)
  986.     local s = t.sample
  987.     if not s then
  988.         t.step, t.volumeScale = 0, 0
  989.         return
  990.     end
  991.     t.volumeScale = voiceScale(t)
  992.  
  993.     local pm = song.pm
  994.     if pm ~= 3 and t.per <= 0 then
  995.         t.step, t.volumeScale = 0, 0
  996.         return
  997.     end
  998.     local per = t.per + t.vibOff
  999.     local f
  1000.     if pm == 1 then
  1001.         if per < 1 then per = 1 end
  1002.         f = AMIGA_CLOCK / per
  1003.         local fine = t.fineOv or s.fine
  1004.         if fine ~= 0 then f = f * 2 ^ (fine / 96) end
  1005.         if t.arp ~= 0 then f = f * 2 ^ (t.arp / 12) end
  1006.     elseif pm == 2 then
  1007.         if per < 1 then per = 1 end
  1008.         f = 14317456 / per
  1009.         if t.arp ~= 0 then f = f * 2 ^ (t.arp / 12) end
  1010.     else
  1011.         f = s.c4spd * 2 ^ ((per / 64 + t.arp + t.fineSemi - (s.ref - 1)) / 12)
  1012.     end
  1013.     t.baseF = f
  1014.     t.step = applyPitchMods(t, f)
  1015. end
  1016.  
  1017. local function avWave(kind, pos)
  1018.     if kind == 1 then return pos < 128 and 1 or -1
  1019.     elseif kind == 2 then return (((64 - floor((pos + 1) / 2)) % 128) - 64) / 64
  1020.     elseif kind == 3 then return (((64 + floor((pos + 1) / 2)) % 128) - 64) / 64 end
  1021.     return sin(pos * 0.02454369)
  1022. end
  1023.  
  1024. local function advanceChannel(t)
  1025.     if not t.active then return end
  1026.     local inst = t.inst
  1027.     if inst then
  1028.         if inst.venv and not t.venvOff then advanceEnv(inst.venv, t, "envPos") end
  1029.         if inst.penv then advanceEnv(inst.penv, t, "penvPos") end
  1030.         if t.keyoff or t.notefade then
  1031.             if inst.fadeDec > 0 and t.fade > 0 then t.fade = max(0, t.fade - inst.fadeDec) end
  1032.             if t.fade <= 0 then
  1033.                 t.fade = 0
  1034.                 killVoice(t)
  1035.                 return
  1036.             end
  1037.         end
  1038.     end
  1039.     local av = t.av
  1040.     if av then
  1041.         local full = av.depth * 256
  1042.         if av.sweep == 0 then
  1043.             t.avAmp = full
  1044.         elseif song.fmt == "IT" then
  1045.             t.avAmp = min(full, t.avAmp + av.sweep * 2)
  1046.         elseif not t.keyoff then
  1047.             t.avAmp = min(full, t.avAmp + full / av.sweep)
  1048.         end
  1049.         t.avOff = avWave(av.type, t.avPos) * (t.avAmp / 256) / 64
  1050.         t.avPos = (t.avPos + av.rate) % 256
  1051.     end
  1052. end
  1053.  
  1054. local function updateBG(v)
  1055.     if not v.active then return end
  1056.     v.volumeScale = voiceScale(v)
  1057.     v.step = applyPitchMods(v, v.baseF)
  1058.     advanceChannel(v)
  1059.     if v.active and (v.keyoff or v.notefade) and v.volumeScale <= 0.00001 then killVoice(v) end
  1060. end
  1061.  
  1062. local function retrigVol(v, x)
  1063.     if x == 1 then v = v - 1 elseif x == 2 then v = v - 2 elseif x == 3 then v = v - 4
  1064.     elseif x == 4 then v = v - 8 elseif x == 5 then v = v - 16
  1065.     elseif x == 6 then v = floor(v * 2 / 3) elseif x == 7 then v = floor(v / 2)
  1066.     elseif x == 9 then v = v + 1 elseif x == 10 then v = v + 2 elseif x == 11 then v = v + 4
  1067.     elseif x == 12 then v = v + 8 elseif x == 13 then v = v + 16
  1068.     elseif x == 14 then v = floor(v * 3 / 2) elseif x == 15 then v = v * 2 end
  1069.     return max(0, min(64, v))
  1070. end
  1071.  
  1072. local function waveform(kind, pos)
  1073.     local p = pos % 64
  1074.     if kind == 1 then
  1075.         local m = (p % 32) * 8
  1076.         if p < 32 then return m / 255 end
  1077.         return -(255 - m) / 255
  1078.     elseif kind == 2 then
  1079.         return p < 32 and 1 or -1
  1080.     end
  1081.     return sin(p * 0.09817477)
  1082. end
  1083.  
  1084. local function doVibrato(t)
  1085.     local d = t.vibDepth * song.vibScale
  1086.     if t.vibFine then d = d * 0.25 end
  1087.     t.vibOff = waveform(band(t.vibWave, 3), t.vibPos) * d
  1088.     t.vibPos = (t.vibPos + t.vibSpeed) % 64
  1089. end
  1090.  
  1091. local function slideAmount(data)
  1092.     local hi = rshift(data, 4)
  1093.     if hi > 0 then return hi end
  1094.     return -band(data, 15)
  1095. end
  1096.  
  1097. local function dSlide(par)
  1098.     local hi, lo = rshift(par, 4), band(par, 15)
  1099.     if lo == 0 then return 0, hi
  1100.     elseif hi == 0 then return 0, -lo
  1101.     elseif lo == 15 then return hi, 0
  1102.     elseif hi == 15 then return -lo, 0 end
  1103.     return 0, 0
  1104. end
  1105.  
  1106. local function clampVol(v)
  1107.     if v < 0 then return 0 elseif v > 64 then return 64 end
  1108.     return v
  1109. end
  1110.  
  1111. local function resolveLetter(t, L, par)
  1112.     local m = t.mem
  1113.     if L == 4 or L == 11 or L == 12 then
  1114.         if par == 0 then par = m.vs or 0 else m.vs = par end
  1115.     elseif L == 5 or L == 6 then
  1116.         if par == 0 then par = m.pu or 0 else m.pu = par end
  1117.     elseif L == 7 then
  1118.         local key = song.shareG and "pu" or "g"
  1119.         if par == 0 then par = m[key] or 0 else m[key] = par end
  1120.     elseif L == 9 then
  1121.         if par == 0 then par = m.i or 0 else m.i = par end
  1122.     elseif L == 10 then
  1123.         if par == 0 then par = m.j or 0 else m.j = par end
  1124.     elseif L == 14 then
  1125.         if par == 0 then par = m.n or 0 else m.n = par end
  1126.     elseif L == 15 then
  1127.         if par == 0 then par = m.o or 0 else m.o = par end
  1128.     elseif L == 17 then
  1129.         if par == 0 then par = m.q or 0 else m.q = par end
  1130.     elseif L == 19 then
  1131.         if par == 0 then par = m.s or 0 else m.s = par end
  1132.     elseif L == 20 then
  1133.         if par < 0x20 then
  1134.             if par == 0 then par = m.t or 0 else m.t = par end
  1135.         end
  1136.     elseif L == 23 then
  1137.         if par == 0 then par = m.w or 0 else m.w = par end
  1138.     end
  1139.     return convertLetter(L, par)
  1140. end
  1141.  
  1142. local function doS7(t, c, p)
  1143.     if p <= 2 then
  1144.         for i = 1, #bg do
  1145.             local v = bg[i]
  1146.             if v.active and v.chan == c then
  1147.                 if p == 0 then killVoice(v)
  1148.                 elseif p == 1 then applyKeyOff(v)
  1149.                 else v.notefade = true end
  1150.             end
  1151.         end
  1152.     elseif p >= 3 and p <= 6 then t.nna = p - 3
  1153.     elseif p == 7 then t.venvOff = true
  1154.     elseif p == 8 then t.venvOff = false
  1155.     elseif p == 0xB then t.penvOff = true
  1156.     elseif p == 0xC then t.penvOff = false
  1157.     end
  1158. end
  1159.  
  1160. local function processChannelTick(t, tick, c)
  1161.     local cmd, data, vc, vv = t.effect, t.eData, t.vc, t.vv
  1162.     t.vibOff, t.tremOff, t.arp, t.tremorOff = 0, 0, 0, false
  1163.  
  1164.     if t.delayTick and t.delayTick == tick then
  1165.         local cl = t.delayCell
  1166.         t.delayTick, t.delayCell = nil, nil
  1167.         startCell(t, cl, c, 0x0E)
  1168.         if cl.vc == 1 then t.volume = cl.vv end
  1169.     end
  1170.  
  1171.     local sub, sd = rshift(data, 4), band(data, 15)
  1172.  
  1173.     if tick == 0 then
  1174.         if vc == 1 then t.volume = vv
  1175.         elseif vc == 4 then t.volume = max(0, t.volume - vv)
  1176.         elseif vc == 5 then t.volume = min(64, t.volume + vv)
  1177.         elseif vc == 6 then if vv > 0 then t.vibSpeed = vv end
  1178.         elseif vc == 7 then if vv > 0 then t.vibDepth = vv end
  1179.         elseif vc == 11 then if vv > 0 then t.portSpeed = vv end
  1180.         end
  1181.         if cmd == 0xC then
  1182.             t.volume = min(data, 64)
  1183.         elseif cmd == 0xF then
  1184.             if data > 0 and data < 32 then speed = data
  1185.             elseif data >= 32 then bpm = max(32, min(255, data)) end
  1186.         elseif cmd == 0x30 then
  1187.             if data > 0 then speed = data end
  1188.         elseif cmd == 0x31 then
  1189.             bpm = max(32, min(255, data))
  1190.         elseif cmd == 0xD then
  1191.             pendingBreak = floor(data / 16) * 10 + (data % 16) + 1
  1192.         elseif cmd == 0x3B then
  1193.             pendingBreak = data + 1
  1194.         elseif cmd == 0xB then
  1195.             pendingOrder = data + 1
  1196.         elseif cmd == 0x3 or cmd == 0x5 then
  1197.             if cmd == 0x3 and data > 0 then t.portSpeed = data end
  1198.         elseif cmd == 0x4 or cmd == 0x6 or cmd == 0x34 then
  1199.             if cmd ~= 0x6 and data > 0 then
  1200.                 t.vibFine = (cmd == 0x34)
  1201.                 if sub > 0 then t.vibSpeed = sub end
  1202.                 if sd > 0 then t.vibDepth = sd end
  1203.             end
  1204.         elseif cmd == 0x7 then
  1205.             if data > 0 then
  1206.                 if sub > 0 then t.tremSpeed = sub end
  1207.                 if sd > 0 then t.tremDepth = sd end
  1208.             end
  1209.         elseif cmd == 0x9 then
  1210.             if t.active then
  1211.                 local off = data * 256 + t.hiOff * 65536
  1212.                 local s = t.sample
  1213.                 if (song.fmt == "IT" or song.fmt == "S3M") and s and off >= s.len and not s.loop then
  1214.                     off = 0
  1215.                 end
  1216.                 t.cursor = off
  1217.             end
  1218.         elseif cmd == 0xE then
  1219.             if sub == 0x1 then slideUp(t, sd * song.slideMul)
  1220.             elseif sub == 0x2 then slideDown(t, sd * song.slideMul)
  1221.             elseif sub == 0x6 then
  1222.                 if sd == 0 then t.loopRow = rowNow
  1223.                 else
  1224.                     if t.loopCnt == 0 then t.loopCnt = sd else t.loopCnt = t.loopCnt - 1 end
  1225.                     if t.loopCnt > 0 then loopTarget = t.loopRow end
  1226.                 end
  1227.             elseif sub == 0x4 then t.vibWave = sd
  1228.             elseif sub == 0x5 then
  1229.                 if song.pm == 1 then t.fineOv = (sd > 7) and sd - 16 or sd
  1230.                 elseif song.fmt == "XM" and song.pm == 3 then t.fineSemi = (sd - 8) / 8 end
  1231.             elseif sub == 0x7 then t.tremWave = sd
  1232.             elseif sub == 0xA then t.volume = min(64, t.volume + sd)
  1233.             elseif sub == 0xB then t.volume = max(0, t.volume - sd)
  1234.             elseif sub == 0xC then if sd == 0 then noteCut(t) end
  1235.             end
  1236.         elseif cmd == 0x10 then
  1237.             song.gvol = min(64, data)
  1238.         elseif cmd == 0x14 then
  1239.             if data == 0 then applyKeyOff(t) end
  1240.         elseif cmd == 0x15 then
  1241.             t.envPos = data
  1242.         elseif cmd == 0x21 then
  1243.             if sub == 1 then slideUp(t, sd) elseif sub == 2 then slideDown(t, sd) end
  1244.         elseif cmd == 0x2C then
  1245.             t.cvol = min(64, data)
  1246.         elseif cmd == 0x35 then
  1247.             doS7(t, c, sd)
  1248.         elseif cmd == 0x36 then
  1249.             t.hiOff = sd
  1250.         elseif cmd == 0x37 then
  1251.             local f, n = dSlide(data)
  1252.             t.cvol = clampVol(t.cvol + f)
  1253.         elseif cmd == 0x38 or cmd == 0x39 or cmd == 0x3A then
  1254.             local f, n = dSlide(data)
  1255.             t.volume = clampVol(t.volume + f)
  1256.             if song.fastVol then t.volume = clampVol(t.volume + n) end
  1257.         end
  1258.     else
  1259.         if vc == 2 then t.volume = max(0, t.volume - vv)
  1260.         elseif vc == 3 then t.volume = min(64, t.volume + vv)
  1261.         elseif vc == 12 then slideUp(t, vv * song.slideMul)
  1262.         elseif vc == 13 then slideDown(t, vv * song.slideMul)
  1263.         elseif vc == 11 then tonePorta(t, t.portSpeed)
  1264.         end
  1265.         if vc == 7 and cmd ~= 0x4 and cmd ~= 0x6 and cmd ~= 0x34 and cmd ~= 0x39 then doVibrato(t) end
  1266.         if cmd == 0x0 then
  1267.             if data > 0 then
  1268.                 local phase = tick % 3
  1269.                 if phase == 1 then t.arp = sub elseif phase == 2 then t.arp = sd end
  1270.             end
  1271.         elseif cmd == 0x1 then slideUp(t, data * song.slideMul)
  1272.         elseif cmd == 0x2 then slideDown(t, data * song.slideMul)
  1273.         elseif cmd == 0x3 or cmd == 0x5 then
  1274.             tonePorta(t, t.portSpeed)
  1275.             if cmd == 0x5 then t.volume = max(0, min(64, t.volume + slideAmount(data))) end
  1276.         elseif cmd == 0x4 or cmd == 0x6 or cmd == 0x34 then
  1277.             doVibrato(t)
  1278.             if cmd == 0x6 then t.volume = max(0, min(64, t.volume + slideAmount(data))) end
  1279.         elseif cmd == 0x7 then
  1280.             t.tremOff = waveform(band(t.tremWave, 3), t.tremPos) * t.tremDepth * 4
  1281.             t.tremPos = (t.tremPos + t.tremSpeed) % 64
  1282.         elseif cmd == 0xA then
  1283.             t.volume = max(0, min(64, t.volume + slideAmount(data)))
  1284.         elseif cmd == 0x38 then
  1285.             local _, n = dSlide(data)
  1286.             t.volume = clampVol(t.volume + n)
  1287.         elseif cmd == 0x39 then
  1288.             local _, n = dSlide(data)
  1289.             t.volume = clampVol(t.volume + n)
  1290.             doVibrato(t)
  1291.         elseif cmd == 0x3A then
  1292.             local _, n = dSlide(data)
  1293.             t.volume = clampVol(t.volume + n)
  1294.             tonePorta(t, t.portSpeed)
  1295.         elseif cmd == 0x37 then
  1296.             local _, n = dSlide(data)
  1297.             t.cvol = clampVol(t.cvol + n)
  1298.         elseif cmd == 0x11 then
  1299.             song.gvol = max(0, min(64, song.gvol + (sub - sd) * song.gvolScale))
  1300.         elseif cmd == 0x1B then
  1301.             if sd > 0 and tick % sd == 0 then
  1302.                 makeGhost(t)
  1303.                 t.cursor = 0
  1304.                 t.curScale = 0
  1305.                 t.volume = retrigVol(t.volume, sub)
  1306.             end
  1307.         elseif cmd == 0x1D then
  1308.             local period = sub + sd + 2
  1309.             if t.tremorPos % period >= sub + 1 then t.tremorOff = true end
  1310.             t.tremorPos = t.tremorPos + 1
  1311.         elseif cmd == 0xE then
  1312.             if sub == 0x9 then
  1313.                 if sd > 0 and tick % sd == 0 then makeGhost(t); t.cursor = 0; t.curScale = 0 end
  1314.             elseif sub == 0xC then
  1315.                 if tick == sd then noteCut(t) end
  1316.             end
  1317.         elseif cmd == 0x14 then
  1318.             if tick == data then applyKeyOff(t) end
  1319.         elseif cmd == 0x32 then
  1320.             if data < 0x10 then bpm = max(32, bpm - data)
  1321.             elseif data < 0x20 then bpm = min(255, bpm + sd) end
  1322.         end
  1323.     end
  1324.  
  1325.     finalizeChannel(t)
  1326.     advanceChannel(t)
  1327. end
  1328.  
  1329. local rawBuffer, outputBuffer = {}, {}
  1330. local shapeErr = 0
  1331.  
  1332. local function renderLinear(buf, i0, i1, data, len, cur, step, vol, vinc, hasLoop, ls, le, ll)
  1333.     for i = i0, i1 do
  1334.         if hasLoop then
  1335.             if cur >= le then cur = ls + (cur - le) % ll end
  1336.         elseif cur >= len then
  1337.             return cur, vol, true
  1338.         end
  1339.         local ip = floor(cur)
  1340.         local v0 = data[ip + 1] or 0
  1341.         local v1 = data[ip + 2]
  1342.         if hasLoop and ip + 1 >= le then v1 = data[ls + 1] end
  1343.         if not v1 then v1 = v0 end
  1344.         buf[i] = buf[i] + (v0 + (v1 - v0) * (cur - ip)) * vol
  1345.         cur = cur + step
  1346.         vol = vol + vinc
  1347.     end
  1348.     return cur, vol, false
  1349. end
  1350.  
  1351. local function renderNearest(buf, i0, i1, data, len, cur, step, vol, vinc, hasLoop, ls, le, ll)
  1352.     for i = i0, i1 do
  1353.         if hasLoop then
  1354.             if cur >= le then cur = ls + (cur - le) % ll end
  1355.         elseif cur >= len then
  1356.             return cur, vol, true
  1357.         end
  1358.         buf[i] = buf[i] + (data[floor(cur) + 1] or 0) * vol
  1359.         cur = cur + step
  1360.         vol = vol + vinc
  1361.     end
  1362.     return cur, vol, false
  1363. end
  1364.  
  1365. local render = INTERPOLATE and renderLinear or renderNearest
  1366.  
  1367. local function advanceSilent(count, len, cur, step, hasLoop, ls, le, ll)
  1368.     cur = cur + step * count
  1369.     if hasLoop then
  1370.         if cur >= le then cur = ls + (cur - le) % ll end
  1371.         return cur, false
  1372.     elseif cur >= len then
  1373.         return cur, true
  1374.     end
  1375.     return cur, false
  1376. end
  1377.  
  1378. local function mixVoice(t, count, invNorm)
  1379.     local g = t.ghost
  1380.     if g then
  1381.         t.ghost = nil
  1382.         local n = min(count, RAMP_SAMPLES)
  1383.         local v = g.vol * invNorm
  1384.         render(rawBuffer, 1, n, g.data, g.len, g.cur, g.step, v, -v / n,
  1385.                g.hasLoop, g.ls, g.le, g.ll)
  1386.     end
  1387.  
  1388.     local s = t.sample
  1389.     if t.active and s and s.len > 0 then
  1390.         local target = (t.step > 0) and t.volumeScale or 0
  1391.         local from = t.curScale
  1392.         local hasLoop, ls, ll = getLoop(s, t.keyoff)
  1393.         local le = ls + ll
  1394.         local cur, ended, _
  1395.         if from == 0 and target == 0 then
  1396.             cur, ended = advanceSilent(count, s.len, t.cursor, t.step, hasLoop, ls, le, ll)
  1397.         else
  1398.             local ramp = min(count, RAMP_SAMPLES)
  1399.             cur, _, ended = render(rawBuffer, 1, ramp, s.data, s.len, t.cursor, t.step,
  1400.                 from * invNorm, (target - from) * invNorm / ramp, hasLoop, ls, le, ll)
  1401.             if not ended and ramp < count then
  1402.                 cur, _, ended = render(rawBuffer, ramp + 1, count, s.data, s.len, cur, t.step,
  1403.                     target * invNorm, 0, hasLoop, ls, le, ll)
  1404.             end
  1405.         end
  1406.         t.cursor = cur
  1407.         t.curScale = target
  1408.         if ended then t.active = false end
  1409.     else
  1410.         t.curScale = 0
  1411.     end
  1412. end
  1413.  
  1414. local function mixSamples(count)
  1415.     local nch = song.channels
  1416.     local invNorm = 1 / (sqrt(max(4, min(16, nch))) * 1.1)
  1417.     for i = 1, count do rawBuffer[i] = 0 end
  1418.  
  1419.     for c = 1, nch do
  1420.         local t = tracks[c]
  1421.         if t and not t.muted then mixVoice(t, count, invNorm) end
  1422.     end
  1423.     for i = 1, #bg do mixVoice(bg[i], count, invNorm) end
  1424.     for i = #bg, 1, -1 do
  1425.         if not bg[i].active then table.remove(bg, i) end
  1426.     end
  1427.  
  1428.     local err = shapeErr
  1429.     local range = 128 - SOFT_KNEE
  1430.     for i = 1, count do
  1431.         local x = rawBuffer[i]
  1432.         local ax = x < 0 and -x or x
  1433.         if ax > SOFT_KNEE then
  1434.             local u = (ax - SOFT_KNEE) / range
  1435.             ax = SOFT_KNEE + range * u / (1 + u)
  1436.             x = x < 0 and -ax or ax
  1437.         end
  1438.         local v = x + err
  1439.         local q = floor(v + 0.5)
  1440.         if q > 127 then q = 127 elseif q < -128 then q = -128 end
  1441.         err = v - q
  1442.         if err > 1 or err < -1 then err = 0 end
  1443.         outputBuffer[i] = q
  1444.     end
  1445.     shapeErr = err
  1446.     return outputBuffer, count
  1447. end
  1448.  
  1449. local chunkBuffer = {}
  1450.  
  1451. local function flushAudio(buf, bufSize)
  1452.     if bufSize == 0 then return end
  1453.     local chunkSize = 4096
  1454.     for i = 1, bufSize, chunkSize do
  1455.         local chunkIdx = 1
  1456.         local endRange = min(i + chunkSize - 1, bufSize)
  1457.         for j = i, endRange do
  1458.             chunkBuffer[chunkIdx] = buf[j]
  1459.             chunkIdx = chunkIdx + 1
  1460.         end
  1461.         local oldLen = #chunkBuffer
  1462.         if oldLen >= chunkIdx then
  1463.             for j = chunkIdx, oldLen do chunkBuffer[j] = nil end
  1464.         end
  1465.         while not speaker.playAudio(chunkBuffer) do
  1466.             local tmr = os.startTimer(0.25)
  1467.             while true do
  1468.                 local ev, id = os.pullEvent()
  1469.                 if ev == "speaker_audio_empty" then
  1470.                     os.cancelTimer(tmr)
  1471.                     break
  1472.                 elseif ev == "timer" and id == tmr then
  1473.                     break
  1474.                 end
  1475.             end
  1476.         end
  1477.     end
  1478.     os.queueEvent("nt_yield")
  1479.     os.pullEvent("nt_yield")
  1480. end
  1481.  
  1482. local function playSong()
  1483.     local nch = song.channels
  1484.     local curOrder, curRow = 1, 1
  1485.     local idleSkips = 0
  1486.     local acc = 0
  1487.     local pending, pendingCount = {}, 0
  1488.     local lastOrder = 0
  1489.  
  1490.     while true do
  1491.         local pIdx = song.order[curOrder]
  1492.         local pat = pIdx and song.patterns[pIdx]
  1493.         if pIdx and not pat and song.fmt == "XM" then pat = EMPTYPAT end
  1494.  
  1495.         if curOrder > song.songLength then
  1496.             if not LOOP_SONG then break end
  1497.             curOrder, curRow = song.restart, 1
  1498.         elseif song.markers and pIdx == 255 then
  1499.             if not LOOP_SONG then break end
  1500.             curOrder, curRow = song.restart, 1
  1501.             idleSkips = idleSkips + 1
  1502.             if idleSkips > song.songLength + 1 then break end
  1503.         elseif song.markers and pIdx == 254 then
  1504.             curOrder, curRow = curOrder + 1, 1
  1505.             idleSkips = idleSkips + 1
  1506.             if idleSkips > song.songLength + 1 then break end
  1507.         elseif not pat then
  1508.             curOrder, curRow = curOrder + 1, 1
  1509.             idleSkips = idleSkips + 1
  1510.             if idleSkips > song.songLength + 1 then break end
  1511.         elseif curRow > pat.rows then
  1512.             curOrder, curRow = curOrder + 1, 1
  1513.         else
  1514.             idleSkips = 0
  1515.             if curOrder ~= lastOrder then
  1516.                 lastOrder = curOrder
  1517.                 for c = 1, nch do
  1518.                     tracks[c].loopRow, tracks[c].loopCnt = 1, 0
  1519.                 end
  1520.             end
  1521.             rowNow = curRow
  1522.             pendingOrder, pendingBreak, loopTarget, rowRepeat, fineDelay = nil, nil, nil, 0, 0
  1523.             local rowData = pat[curRow] or EMPTYROW
  1524.  
  1525.             for c = 1, nch do
  1526.                 local t = tracks[c]
  1527.                 local cell = rowData[c] or EMPTY
  1528.                 local cmd, data = cell.e, cell.p
  1529.                 if song.letters and cmd >= LE then
  1530.                     cmd, data = resolveLetter(t, cmd - LE, data)
  1531.                 elseif song.mem and MEMEFF[cmd] then
  1532.                     local key = (cmd == 5 or cmd == 6) and 10 or cmd
  1533.                     if data == 0 then data = t.mem[key] or 0 else t.mem[key] = data end
  1534.                 end
  1535.                 t.effect, t.eData, t.vc, t.vv = cmd, data, cell.vc, cell.vv
  1536.                 t.delayTick, t.delayCell = nil, nil
  1537.                 if cmd == 0xE then
  1538.                     local sub, sd = rshift(data, 4), band(data, 15)
  1539.                     if sub == 0xE then rowRepeat = max(rowRepeat, sd) end
  1540.                     if sub == 0xD and sd > 0 and (cell.n ~= 0 or cell.i ~= 0) then
  1541.                         t.delayTick, t.delayCell = sd, cell
  1542.                     end
  1543.                 elseif cmd == 0x3E then
  1544.                     fineDelay = max(fineDelay, data)
  1545.                 end
  1546.                 if not t.delayTick then startCell(t, cell, c, cmd) end
  1547.             end
  1548.  
  1549.             local tick = 0
  1550.             while tick < speed * (1 + rowRepeat) + fineDelay do
  1551.                 for c = 1, nch do processChannelTick(tracks[c], tick, c) end
  1552.                 for i = 1, #bg do updateBG(bg[i]) end
  1553.  
  1554.                 acc = acc + MIX_RATE * 2.5 / bpm
  1555.                 local n = floor(acc)
  1556.                 acc = acc - n
  1557.                 if n > 0 then
  1558.                     local audio, cnt = mixSamples(n)
  1559.                     for i = 1, cnt do pending[pendingCount + i] = audio[i] end
  1560.                     pendingCount = pendingCount + cnt
  1561.                     if pendingCount >= TARGET_CHUNK then
  1562.                         flushAudio(pending, pendingCount)
  1563.                         pendingCount = 0
  1564.                     end
  1565.                 end
  1566.                 tick = tick + 1
  1567.             end
  1568.  
  1569.             if pendingOrder or pendingBreak then
  1570.                 curOrder = pendingOrder or (curOrder + 1)
  1571.                 curRow = pendingBreak or 1
  1572.                 if curOrder > song.songLength then
  1573.                     if not LOOP_SONG then break end
  1574.                     curOrder = song.restart
  1575.                 end
  1576.                 local np = song.patterns[song.order[curOrder]]
  1577.                 if np and curRow > np.rows then curRow = 1 end
  1578.             elseif loopTarget then
  1579.                 curRow = loopTarget
  1580.             else
  1581.                 curRow = curRow + 1
  1582.             end
  1583.         end
  1584.     end
  1585.  
  1586.     if pendingCount > 0 then flushAudio(pending, pendingCount) end
  1587. end
  1588.  
  1589. local function detectFormat(filename)
  1590.     if D:sub(1, 17) == "Extended Module: " then return "XM" end
  1591.     if D:sub(1, 4) == "IMPM" then return "IT" end
  1592.     if D:sub(45, 48) == "SCRM" then return "S3M" end
  1593.     local ext = filename:lower():match("%.(%w+)$")
  1594.     if ext == "xm" then return "XM" elseif ext == "it" then return "IT" elseif ext == "s3m" then return "S3M" end
  1595.     if #D >= 1084 then return "MOD" end
  1596.     return nil
  1597. end
  1598.  
  1599. print("NekoTracker: A ComputerCraft Tracker player by nonogamer9")
  1600. write("Filename: ")
  1601. local filename = read()
  1602. if not fs.exists(filename) then error("File not found: " .. filename) end
  1603.  
  1604. local f = fs.open(filename, "rb")
  1605. D = f.readAll() or ""
  1606. f.close()
  1607.  
  1608. local fmt = detectFormat(filename)
  1609. if not fmt then error("Unrecognised or truncated module file") end
  1610.  
  1611. local loaders = { MOD = loadMOD, S3M = loadS3M, XM = loadXM, IT = loadIT }
  1612. local ok, res = pcall(loaders[fmt])
  1613. D = ""
  1614. if not ok then error("Failed to load " .. fmt .. ": " .. tostring(res)) end
  1615. song = res
  1616.  
  1617. speed, bpm = song.speed, song.tempo
  1618. for c = 1, song.channels do tracks[c] = newTrack(c) end
  1619.  
  1620. print("Format: " .. song.fmt)
  1621. print("Detected Channels: " .. song.channels)
  1622. print("Playing: " .. filename)
  1623.  
  1624. playSong()
  1625. print("Playback finished!")
Add Comment
Please, Sign In to add comment