nonogamer9

MSXCC! a MSX player for ComputerCraft

Oct 6th, 2026
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 40.29 KB | Source Code | 0 0
  1. local OUTPUT_RATE        = 48000
  2. local VGM_RATE           = 44100
  3. local AUDIO_CHUNK        = 2560
  4.  
  5. local DEFAULT_VOLUME     = 0.20
  6.  
  7. local DEFAULT_AY_CLOCK   = 1789773
  8. local DEFAULT_SCC_CLOCK  = 1789773
  9.  
  10. local DEFAULT_LOOP_COUNT = 1
  11.  
  12. local PSG_OVERSAMPLE     = 4
  13. local SCC_OVERSAMPLE     = 4
  14.  
  15. local PSG_TONE_DIV       = 8
  16. local SCC_CLOCK_DIV      = 16
  17. local SCC_MIN_PERIOD     = 8
  18.  
  19. local PSG_GAIN           = 1.0
  20. local SCC_GAIN           = 1.0
  21. local MASTER_GAIN        = 1.0
  22.  
  23. local DC_BLOCK            = true
  24. local HP_R                = 0.995
  25.  
  26. local DITHER              = true
  27.  
  28. local YIELD_SECONDS       = 2.0
  29.  
  30. local MAX_LOOP_GUARD     = 100000
  31.  
  32. print("MSXCC! a MSX player for ComputerCraft")
  33.  
  34. local speaker = peripheral.find("speaker")
  35.  
  36. if not speaker then
  37.     print("No speaker attached!")
  38.     return
  39. end
  40.  
  41. local floor = math.floor
  42. local min = math.min
  43. local max = math.max
  44.  
  45. local unpack = table.unpack or unpack
  46.  
  47. local function u8(s, p)
  48.     return s:byte(p + 1) or 0
  49. end
  50.  
  51. local function u16(s, p)
  52.     return u8(s, p) + u8(s, p + 1) * 256
  53. end
  54.  
  55. local function u32le(s, p)
  56.     return u8(s, p)
  57.         + u8(s, p + 1) * 256
  58.         + u8(s, p + 2) * 65536
  59.         + u8(s, p + 3) * 16777216
  60. end
  61.  
  62. local function signed8(v)
  63.     if v >= 128 then
  64.         return v - 256
  65.     end
  66.     return v
  67. end
  68.  
  69. local function bitOf(v, n)
  70.     return floor(v / (2 ^ n)) % 2
  71. end
  72.  
  73. local function hasBit(v, n)
  74.     return bitOf(v, n) == 1
  75. end
  76.  
  77. local function clamp(v, lo, hi)
  78.     if v < lo then return lo end
  79.     if v > hi then return hi end
  80.     return v
  81. end
  82.  
  83. local function requireBytes(data, pos, count, dataEnd)
  84.     if pos < 1 or pos + count - 1 > dataEnd + 1 then
  85.         error(string.format(
  86.             "Truncated VGM command at offset %X",
  87.             pos - 1
  88.         ))
  89.     end
  90. end
  91.  
  92. local Reader = {}
  93. Reader.__index = Reader
  94.  
  95. function Reader.new(data)
  96.     return setmetatable({
  97.         data = data,
  98.         pos = 1,
  99.         buf = 0,
  100.         bits = 0
  101.     }, Reader)
  102. end
  103.  
  104. function Reader:byte()
  105.     local b = self.data:byte(self.pos)
  106.  
  107.     if not b then
  108.         error("Unexpected end of DEFLATE stream")
  109.     end
  110.  
  111.     self.pos = self.pos + 1
  112.     return b
  113. end
  114.  
  115. function Reader:read(n)
  116.     while self.bits < n do
  117.         self.buf = self.buf + self:byte() * (2 ^ self.bits)
  118.         self.bits = self.bits + 8
  119.     end
  120.  
  121.     local p = 2 ^ n
  122.     local r = self.buf % p
  123.  
  124.     self.buf = (self.buf - r) / p
  125.     self.bits = self.bits - n
  126.  
  127.     return r
  128. end
  129.  
  130. function Reader:alignByte()
  131.     local drop = self.bits % 8
  132.  
  133.     if drop > 0 then
  134.         self:read(drop)
  135.     end
  136. end
  137.  
  138. local function reverseBits(v, n)
  139.     local r = 0
  140.  
  141.     for _ = 1, n do
  142.         r = r * 2 + (v % 2)
  143.         v = floor(v / 2)
  144.     end
  145.  
  146.     return r
  147. end
  148.  
  149. local function makeHuffman(lengths)
  150.     local count = {}
  151.  
  152.     for i = 0, 15 do
  153.         count[i] = 0
  154.     end
  155.  
  156.     for i = 1, #lengths do
  157.         local l = lengths[i]
  158.  
  159.         if l > 0 then
  160.             count[l] = count[l] + 1
  161.         end
  162.     end
  163.  
  164.     local nextCode = {}
  165.     local code = 0
  166.  
  167.     for bits = 1, 15 do
  168.         code = (code + count[bits - 1]) * 2
  169.         nextCode[bits] = code
  170.     end
  171.  
  172.     local tree = {}
  173.  
  174.     for sym = 1, #lengths do
  175.         local l = lengths[sym]
  176.  
  177.         if l > 0 then
  178.             local c = reverseBits(nextCode[l], l)
  179.             nextCode[l] = nextCode[l] + 1
  180.  
  181.             local node = tree
  182.  
  183.             for _ = 1, l do
  184.                 local b = c % 2
  185.                 c = floor(c / 2)
  186.  
  187.                 if not node[b] then
  188.                     node[b] = {}
  189.                 end
  190.  
  191.                 node = node[b]
  192.             end
  193.  
  194.             node.symbol = sym - 1
  195.         end
  196.     end
  197.  
  198.     return tree
  199. end
  200.  
  201. local function huffRead(r, tree)
  202.     local node = tree
  203.  
  204.     while node.symbol == nil do
  205.         local b = r:read(1)
  206.         node = node[b]
  207.  
  208.         if not node then
  209.             error("Invalid DEFLATE Huffman code")
  210.         end
  211.     end
  212.  
  213.     return node.symbol
  214. end
  215.  
  216. local LENGTH_BASE = {
  217.     3,4,5,6,7,8,9,10,
  218.     11,13,15,17,19,23,27,31,
  219.     35,43,51,59,67,83,99,115,
  220.     131,163,195,227,258
  221. }
  222.  
  223. local LENGTH_EXTRA = {
  224.     0,0,0,0,0,0,0,0,
  225.     1,1,1,1,2,2,2,2,
  226.     3,3,3,3,4,4,4,4,
  227.     5,5,5,5,0
  228. }
  229.  
  230. local DIST_BASE = {
  231.     1,2,3,4,5,7,9,13,
  232.     17,25,33,49,65,97,129,193,
  233.     257,385,513,769,1025,1537,2049,3073,
  234.     4097,6145,8193,12289,16385,24577
  235. }
  236.  
  237. local DIST_EXTRA = {
  238.     0,0,0,0,1,1,2,2,
  239.     3,3,4,4,5,5,6,6,
  240.     7,7,8,8,9,9,10,10,
  241.     11,11,12,12,13,13
  242. }
  243.  
  244. local FIXED_LIT
  245. local FIXED_DIST
  246.  
  247. do
  248.     local lit = {}
  249.     local dist = {}
  250.  
  251.     for i = 0, 287 do
  252.         if i <= 143 then
  253.             lit[i + 1] = 8
  254.         elseif i <= 255 then
  255.             lit[i + 1] = 9
  256.         elseif i <= 279 then
  257.             lit[i + 1] = 7
  258.         else
  259.             lit[i + 1] = 8
  260.         end
  261.     end
  262.  
  263.     for i = 1, 32 do
  264.         dist[i] = 5
  265.     end
  266.  
  267.     FIXED_LIT = makeHuffman(lit)
  268.     FIXED_DIST = makeHuffman(dist)
  269. end
  270.  
  271. local CL_ORDER = {
  272.     16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15
  273. }
  274.  
  275. local function dynamicTrees(r)
  276.     local hlit = r:read(5) + 257
  277.     local hdist = r:read(5) + 1
  278.     local hclen = r:read(4) + 4
  279.  
  280.     local cl = {}
  281.  
  282.     for i = 1, 19 do
  283.         cl[i] = 0
  284.     end
  285.  
  286.     for i = 1, hclen do
  287.         cl[CL_ORDER[i] + 1] = r:read(3)
  288.     end
  289.  
  290.     local clTree = makeHuffman(cl)
  291.  
  292.     local lengths = {}
  293.     local total = hlit + hdist
  294.  
  295.     while #lengths < total do
  296.         local sym = huffRead(r, clTree)
  297.  
  298.         if sym <= 15 then
  299.             lengths[#lengths + 1] = sym
  300.  
  301.         elseif sym == 16 then
  302.             if #lengths == 0 then
  303.                 error("Invalid DEFLATE repeat")
  304.             end
  305.  
  306.             local rep = r:read(2) + 3
  307.             local val = lengths[#lengths]
  308.  
  309.             for _ = 1, rep do
  310.                 lengths[#lengths + 1] = val
  311.             end
  312.  
  313.         elseif sym == 17 then
  314.             local rep = r:read(3) + 3
  315.  
  316.             for _ = 1, rep do
  317.                 lengths[#lengths + 1] = 0
  318.             end
  319.  
  320.         elseif sym == 18 then
  321.             local rep = r:read(7) + 11
  322.  
  323.             for _ = 1, rep do
  324.                 lengths[#lengths + 1] = 0
  325.             end
  326.  
  327.         else
  328.             error("Invalid DEFLATE code length symbol")
  329.         end
  330.  
  331.         if #lengths > total then
  332.             error("DEFLATE code lengths overflow")
  333.         end
  334.     end
  335.  
  336.     local lit = {}
  337.     local dist = {}
  338.     local anyDist = false
  339.  
  340.     for i = 1, hlit do
  341.         lit[i] = lengths[i]
  342.     end
  343.  
  344.     for i = 1, hdist do
  345.         dist[i] = lengths[hlit + i]
  346.  
  347.         if dist[i] ~= 0 then
  348.             anyDist = true
  349.         end
  350.     end
  351.  
  352.     if not anyDist then
  353.         dist[1] = 1
  354.     end
  355.  
  356.     return makeHuffman(lit), makeHuffman(dist)
  357. end
  358.  
  359. local function inflate(data)
  360.     local r = Reader.new(data)
  361.  
  362.     local out = {}
  363.     local n = 0
  364.  
  365.     while true do
  366.         local final = r:read(1)
  367.         local btype = r:read(2)
  368.  
  369.         if btype == 0 then
  370.             r:alignByte()
  371.  
  372.             local len = r:byte() + r:byte() * 256
  373.             local nlen = r:byte() + r:byte() * 256
  374.  
  375.             if ((len + nlen) % 65536) ~= 65535 then
  376.                 error("Invalid DEFLATE stored block")
  377.             end
  378.  
  379.             for _ = 1, len do
  380.                 n = n + 1
  381.                 out[n] = r:byte()
  382.             end
  383.  
  384.         elseif btype == 1 or btype == 2 then
  385.             local lt
  386.             local dt
  387.  
  388.             if btype == 1 then
  389.                 lt = FIXED_LIT
  390.                 dt = FIXED_DIST
  391.             else
  392.                 lt, dt = dynamicTrees(r)
  393.             end
  394.  
  395.             while true do
  396.                 local sym = huffRead(r, lt)
  397.  
  398.                 if sym < 256 then
  399.                     n = n + 1
  400.                     out[n] = sym
  401.  
  402.                 elseif sym == 256 then
  403.                     break
  404.  
  405.                 elseif sym <= 285 then
  406.                     local li = sym - 256
  407.  
  408.                     local length = LENGTH_BASE[li]
  409.  
  410.                     local extra = LENGTH_EXTRA[li]
  411.  
  412.                     if extra > 0 then
  413.                         length = length + r:read(extra)
  414.                     end
  415.  
  416.                     local ds = huffRead(r, dt)
  417.  
  418.                     if ds > 29 then
  419.                         error("Invalid DEFLATE distance code")
  420.                     end
  421.  
  422.                     local dist = DIST_BASE[ds + 1]
  423.                     local de = DIST_EXTRA[ds + 1]
  424.  
  425.                     if de > 0 then
  426.                         dist = dist + r:read(de)
  427.                     end
  428.  
  429.                     if dist > n then
  430.                         error("Invalid DEFLATE back-reference")
  431.                     end
  432.  
  433.                     for _ = 1, length do
  434.                         n = n + 1
  435.                         out[n] = out[n - dist]
  436.                     end
  437.  
  438.                 else
  439.                     error("Invalid DEFLATE length symbol")
  440.                 end
  441.             end
  442.  
  443.         else
  444.             error("Reserved DEFLATE block type")
  445.         end
  446.  
  447.         if final == 1 then
  448.             break
  449.         end
  450.     end
  451.  
  452.     local parts = {}
  453.  
  454.     for i = 1, n, 4096 do
  455.         parts[#parts + 1] =
  456.             string.char(unpack(out, i, min(i + 4095, n)))
  457.     end
  458.  
  459.     return table.concat(parts)
  460. end
  461.  
  462. local function gunzip(data)
  463.     if #data < 18 then
  464.         error("VGZ file is too small")
  465.     end
  466.  
  467.     if u8(data, 0) ~= 0x1F or u8(data, 1) ~= 0x8B then
  468.         error("Not a GZIP file")
  469.     end
  470.  
  471.     if u8(data, 2) ~= 8 then
  472.         error("GZIP stream is not DEFLATE")
  473.     end
  474.  
  475.     local flags = u8(data, 3)
  476.  
  477.     if bitOf(flags, 5) ~= 0
  478.         or bitOf(flags, 6) ~= 0
  479.         or bitOf(flags, 7) ~= 0 then
  480.         error("Invalid GZIP flags")
  481.     end
  482.  
  483.     local pos = 11
  484.  
  485.     if hasBit(flags, 2) then
  486.         if pos + 1 > #data then
  487.             error("Truncated GZIP extra field")
  488.         end
  489.  
  490.         local xlen = u16(data, pos - 1)
  491.         pos = pos + 2 + xlen
  492.     end
  493.  
  494.     if hasBit(flags, 3) then
  495.         while pos <= #data and u8(data, pos - 1) ~= 0 do
  496.             pos = pos + 1
  497.         end
  498.  
  499.         pos = pos + 1
  500.     end
  501.  
  502.     if hasBit(flags, 4) then
  503.         while pos <= #data and u8(data, pos - 1) ~= 0 do
  504.             pos = pos + 1
  505.         end
  506.  
  507.         pos = pos + 1
  508.     end
  509.  
  510.     if hasBit(flags, 1) then
  511.         pos = pos + 2
  512.     end
  513.  
  514.     if pos > #data - 8 then
  515.         error("Invalid or truncated GZIP header")
  516.     end
  517.  
  518.     return inflate(data:sub(pos, #data - 8))
  519. end
  520.  
  521. local function loadMusic(filename)
  522.     local f = fs.open(filename, "rb")
  523.  
  524.     if not f then
  525.         error("Could not open: " .. filename)
  526.     end
  527.  
  528.     local data = f.readAll()
  529.     f.close()
  530.  
  531.     if not data or #data == 0 then
  532.         error("File is empty")
  533.     end
  534.  
  535.     if data:sub(1, 4) == "Vgm " then
  536.         return data
  537.     end
  538.  
  539.     if u8(data, 0) == 0x1F and u8(data, 1) == 0x8B then
  540.         print("Decompressing VGZ...")
  541.  
  542.         local vgm = gunzip(data)
  543.  
  544.         if vgm:sub(1, 4) ~= "Vgm " then
  545.             error("Decompressed data is not VGM")
  546.         end
  547.  
  548.         return vgm
  549.     end
  550.  
  551.     error("File is neither VGM nor VGZ")
  552. end
  553.  
  554. local AY_LEVELS = {
  555.     [0] = 0.0,
  556.     0.01375,
  557.     0.02046,
  558.     0.02905,
  559.     0.04234,
  560.     0.06185,
  561.     0.08472,
  562.     0.13691,
  563.     0.16914,
  564.     0.26467,
  565.     0.35272,
  566.     0.44997,
  567.     0.57037,
  568.     0.68728,
  569.     0.84818,
  570.     1.0
  571. }
  572.  
  573. local YM_LEVELS = {
  574.     [0]  = 0.0,
  575.     [1]  = 0.0,
  576.     [2]  = 0.00465,
  577.     [3]  = 0.00772,
  578.     [4]  = 0.01096,
  579.     [5]  = 0.01396,
  580.     [6]  = 0.01700,
  581.     [7]  = 0.02002,
  582.     [8]  = 0.02437,
  583.     [9]  = 0.02969,
  584.     [10] = 0.03507,
  585.     [11] = 0.04039,
  586.     [12] = 0.04854,
  587.     [13] = 0.05834,
  588.     [14] = 0.06806,
  589.     [15] = 0.07778,
  590.     [16] = 0.09252,
  591.     [17] = 0.11109,
  592.     [18] = 0.12975,
  593.     [19] = 0.14849,
  594.     [20] = 0.17667,
  595.     [21] = 0.21155,
  596.     [22] = 0.24639,
  597.     [23] = 0.28110,
  598.     [24] = 0.33373,
  599.     [25] = 0.40043,
  600.     [26] = 0.46738,
  601.     [27] = 0.53443,
  602.     [28] = 0.63517,
  603.     [29] = 0.75801,
  604.     [30] = 0.87993,
  605.     [31] = 1.0
  606. }
  607.  
  608. local function envelopeReload(p)
  609.     local shape = p.envShape
  610.  
  611.     p.envHolding = false
  612.     p.envFirst = true
  613.     p.envReverse = false
  614.  
  615.     if hasBit(shape, 2) then
  616.         p.envLevel = 0
  617.     else
  618.         p.envLevel = p.envSteps - 1
  619.     end
  620. end
  621.  
  622. local function envelopeTick(p)
  623.     if p.envHolding then
  624.         return
  625.     end
  626.  
  627.     local shape = p.envShape
  628.  
  629.     local continueMode = hasBit(shape, 3)
  630.     local attack = hasBit(shape, 2)
  631.     local alternate = hasBit(shape, 1)
  632.     local hold = hasBit(shape, 0)
  633.  
  634.     local top = p.envSteps - 1
  635.  
  636.     local directionUp = attack
  637.  
  638.     if p.envReverse then
  639.         directionUp = not directionUp
  640.     end
  641.  
  642.     if directionUp then
  643.         if p.envLevel < top then
  644.             p.envLevel = p.envLevel + 1
  645.             return
  646.         end
  647.     else
  648.         if p.envLevel > 0 then
  649.             p.envLevel = p.envLevel - 1
  650.             return
  651.         end
  652.     end
  653.  
  654.     if not continueMode then
  655.         p.envLevel = 0
  656.         p.envHolding = true
  657.         p.envFirst = false
  658.         return
  659.     end
  660.  
  661.     if hold then
  662.         if alternate and p.envFirst then
  663.             if attack then
  664.                 p.envLevel = 0
  665.             else
  666.                 p.envLevel = top
  667.             end
  668.         end
  669.  
  670.         p.envHolding = true
  671.         p.envFirst = false
  672.         return
  673.     end
  674.  
  675.     if alternate then
  676.         p.envReverse = not p.envReverse
  677.  
  678.         if p.envReverse then
  679.             if attack then
  680.                 p.envLevel = top - 1
  681.             else
  682.                 p.envLevel = 1
  683.             end
  684.         else
  685.             if attack then
  686.                 p.envLevel = 1
  687.             else
  688.                 p.envLevel = top - 1
  689.             end
  690.         end
  691.  
  692.     else
  693.         if attack then
  694.             p.envLevel = 0
  695.         else
  696.             p.envLevel = top
  697.         end
  698.     end
  699.  
  700.     p.envFirst = false
  701. end
  702.  
  703. local function psgWrite(p, r, v)
  704.     r = r % 16
  705.     v = v % 256
  706.  
  707.     if r == 1 or r == 3 or r == 5 then
  708.         v = v % 16
  709.  
  710.     elseif r == 6 then
  711.         v = v % 32
  712.  
  713.     elseif r >= 8 and r <= 10 then
  714.         v = v % 32
  715.  
  716.     elseif r == 13 then
  717.         v = v % 16
  718.     end
  719.  
  720.     p.reg[r] = v
  721.  
  722.     if r <= 5 then
  723.         local ch = floor(r / 2) + 1
  724.  
  725.         local period =
  726.             p.reg[(ch - 1) * 2]
  727.             + (p.reg[(ch - 1) * 2 + 1] % 16) * 256
  728.  
  729.         if period < 1 then
  730.             period = 1
  731.         end
  732.  
  733.         p.tonePeriod[ch] = period
  734.  
  735.         local limit = period
  736.  
  737.         if p.toneCounter[ch] >= limit then
  738.             p.toneCounter[ch] =
  739.                 p.toneCounter[ch] % limit
  740.         end
  741.  
  742.     elseif r == 6 then
  743.         local period = v % 32
  744.  
  745.         if period < 1 then
  746.             period = 1
  747.         end
  748.  
  749.         p.noisePeriod = period
  750.  
  751.     elseif r == 7 then
  752.         for ch = 1, 3 do
  753.             p.toneEn[ch] =
  754.                 not hasBit(v, ch - 1)
  755.  
  756.             p.noiseEn[ch] =
  757.                 not hasBit(v, ch + 2)
  758.         end
  759.  
  760.     elseif r >= 8 and r <= 10 then
  761.         local ch = r - 7
  762.  
  763.         p.useEnv[ch] = hasBit(v, 4)
  764.  
  765.         local level = v % 16
  766.  
  767.         if p.isYM then
  768.             p.fixedLevel[ch] =
  769.                 YM_LEVELS[level == 0 and 0 or (level * 2 + 1)]
  770.         else
  771.             p.fixedLevel[ch] = AY_LEVELS[level]
  772.         end
  773.  
  774.     elseif r == 11 or r == 12 then
  775.         local ep =
  776.             p.reg[11] +
  777.             p.reg[12] * 256
  778.  
  779.         if ep < 1 then
  780.             ep = 1
  781.         end
  782.  
  783.         p.envPeriod = ep
  784.  
  785.     elseif r == 13 then
  786.         p.envShape = v % 16
  787.         envelopeReload(p)
  788.     end
  789. end
  790.  
  791. local function newPSG(clock, chipType, flags)
  792.     local isYM =
  793.         chipType == 0x10
  794.         or chipType == 0x11
  795.         or chipType == 0x12
  796.         or chipType == 0x13
  797.  
  798.     local effClock = clock
  799.  
  800.     local subRate = OUTPUT_RATE * PSG_OVERSAMPLE
  801.  
  802.     local p = {
  803.         isYM = isYM,
  804.         clock = effClock,
  805.  
  806.         reg = {},
  807.  
  808.         tonePeriod = {1, 1, 1},
  809.         toneCounter = {0, 0, 0},
  810.         toneOut = {0, 0, 0},
  811.  
  812.         toneEn = {false, false, false},
  813.         noiseEn = {false, false, false},
  814.  
  815.         fixedLevel = {0, 0, 0},
  816.         useEnv = {false, false, false},
  817.  
  818.         noisePeriod = 1,
  819.         noiseCounter = 0,
  820.         noiseOut = 1,
  821.  
  822.         lfsr = 1,
  823.  
  824.         envPeriod = 1,
  825.         envCounter = 0,
  826.  
  827.         envShape = 0,
  828.         envLevel = 0,
  829.         envSteps = isYM and 32 or 16,
  830.         envHolding = false,
  831.         envFirst = true,
  832.         envReverse = false,
  833.  
  834.         toneStep =
  835.             effClock / PSG_TONE_DIV / subRate,
  836.  
  837.         noiseStep =
  838.             effClock / 16 / subRate,
  839.  
  840.         envStep =
  841.             effClock /
  842.             (isYM and 8 or 16) /
  843.             subRate,
  844.  
  845.         envLUT = isYM and YM_LEVELS or AY_LEVELS
  846.     }
  847.  
  848.     for i = 0, 15 do
  849.         p.reg[i] = 0
  850.     end
  851.  
  852.     for i = 0, 15 do
  853.         psgWrite(p, i, 0)
  854.     end
  855.  
  856.     psgWrite(p, 7, 0xFF)
  857.  
  858.     p.lfsr = 1
  859.     p.noiseOut = 1
  860.  
  861.     return p
  862. end
  863.  
  864. local function psgSample(p)
  865.     local acc = 0
  866.  
  867.     local tonePeriod = p.tonePeriod
  868.     local toneCounter = p.toneCounter
  869.     local toneOut = p.toneOut
  870.  
  871.     for _ = 1, PSG_OVERSAMPLE do
  872.  
  873.         for ch = 1, 3 do
  874.             local period = tonePeriod[ch]
  875.  
  876.             local counter =
  877.                 toneCounter[ch] +
  878.                 p.toneStep
  879.  
  880.             local limit = period
  881.  
  882.             while counter >= limit do
  883.                 counter = counter - limit
  884.                 toneOut[ch] = 1 - toneOut[ch]
  885.             end
  886.  
  887.             toneCounter[ch] = counter
  888.         end
  889.  
  890.         local nc =
  891.             p.noiseCounter +
  892.             p.noiseStep
  893.  
  894.         local np = p.noisePeriod
  895.  
  896.         while nc >= np do
  897.             nc = nc - np
  898.  
  899.             local l = p.lfsr
  900.  
  901.             p.noiseOut = l % 2
  902.  
  903.             local feedback =
  904.                 ((l % 2) +
  905.                 (floor(l / 8) % 2)) % 2
  906.  
  907.             l = floor(l / 2)
  908.  
  909.             if feedback == 1 then
  910.                 l = l + 65536
  911.             end
  912.  
  913.             p.lfsr = l
  914.         end
  915.  
  916.         p.noiseCounter = nc
  917.  
  918.         local ec =
  919.             p.envCounter +
  920.             p.envStep
  921.  
  922.         local ep = p.envPeriod
  923.  
  924.         while ec >= ep do
  925.             ec = ec - ep
  926.             envelopeTick(p)
  927.         end
  928.  
  929.         p.envCounter = ec
  930.  
  931.         local sum = 0
  932.         local noise = p.noiseOut
  933.  
  934.         for ch = 1, 3 do
  935.             local tone =
  936.                 p.toneEn[ch]
  937.                 and toneOut[ch]
  938.                 or 1
  939.  
  940.             local nz =
  941.                 p.noiseEn[ch]
  942.                 and noise
  943.                 or 1
  944.  
  945.             local level
  946.  
  947.             if p.useEnv[ch] then
  948.                 level = p.envLUT[p.envLevel]
  949.             else
  950.                 level = p.fixedLevel[ch]
  951.             end
  952.  
  953.             sum = sum + tone * nz * level
  954.         end
  955.  
  956.         acc = acc + sum
  957.     end
  958.  
  959.     return acc /
  960.         (PSG_OVERSAMPLE * 3)
  961. end
  962.  
  963. local function newSCC(clock, plus)
  964.     local s = {
  965.         clock = clock,
  966.         plus = plus,
  967.  
  968.         wave = {},
  969.         period = {},
  970.         volume = {},
  971.         enabled = {},
  972.  
  973.         phase = {},
  974.         inc = {}
  975.     }
  976.  
  977.     for ch = 1, 5 do
  978.         s.wave[ch] = {}
  979.  
  980.         for i = 1, 32 do
  981.             s.wave[ch][i] = 0
  982.         end
  983.  
  984.         s.period[ch] = 0
  985.         s.volume[ch] = 0
  986.         s.enabled[ch] = false
  987.         s.phase[ch] = 0
  988.         s.inc[ch] = 0
  989.     end
  990.  
  991.     return s
  992. end
  993.  
  994. local function sccUpdateInc(s, ch)
  995.     local period = s.period[ch]
  996.  
  997.     s.inc[ch] =
  998.         32 * s.clock /
  999.         (SCC_CLOCK_DIV * (period + 1) *
  1000.          OUTPUT_RATE * SCC_OVERSAMPLE)
  1001. end
  1002.  
  1003. local function sccWrite(s, port, addr, value)
  1004.     value = value % 256
  1005.  
  1006.     if port == 0 then
  1007.         if addr < 0x80 then
  1008.             local ch =
  1009.                 floor(addr / 32) + 1
  1010.  
  1011.             local index =
  1012.                 (addr % 32) + 1
  1013.  
  1014.             local v = signed8(value)
  1015.  
  1016.             s.wave[ch][index] = v
  1017.  
  1018.             if not s.plus and ch == 4 then
  1019.                 s.wave[5][index] = v
  1020.             end
  1021.         end
  1022.  
  1023.     elseif port == 4 then
  1024.         if s.plus and addr < 0xA0 then
  1025.             local ch =
  1026.                 floor(addr / 32) + 1
  1027.  
  1028.             local index =
  1029.                 (addr % 32) + 1
  1030.  
  1031.             s.wave[ch][index] =
  1032.                 signed8(value)
  1033.         end
  1034.  
  1035.     elseif port == 1 then
  1036.         if addr < 10 then
  1037.             local ch =
  1038.                 floor(addr / 2) + 1
  1039.  
  1040.             local p = s.period[ch]
  1041.  
  1042.             if addr % 2 == 0 then
  1043.                 p =
  1044.                     (p - p % 256) +
  1045.                     value
  1046.             else
  1047.                 p =
  1048.                     (value % 16) * 256 +
  1049.                     (p % 256)
  1050.             end
  1051.  
  1052.             s.period[ch] = p
  1053.             sccUpdateInc(s, ch)
  1054.         end
  1055.  
  1056.     elseif port == 2 then
  1057.         if addr < 5 then
  1058.             s.volume[addr + 1] =
  1059.                 value % 16
  1060.         end
  1061.  
  1062.     elseif port == 3 then
  1063.         if addr == 0 then
  1064.             for ch = 1, 5 do
  1065.                 s.enabled[ch] =
  1066.                     hasBit(value, ch - 1)
  1067.             end
  1068.         end
  1069.  
  1070.     elseif port == 5 then
  1071.     end
  1072. end
  1073.  
  1074. local function sccSample(s)
  1075.     local acc = 0
  1076.  
  1077.     for _ = 1, SCC_OVERSAMPLE do
  1078.         for ch = 1, 5 do
  1079.             if s.enabled[ch] and s.period[ch] > SCC_MIN_PERIOD then
  1080.                 local ph =
  1081.                     s.phase[ch] +
  1082.                     s.inc[ch]
  1083.  
  1084.                 if ph >= 32 then
  1085.                     ph = ph % 32
  1086.                 end
  1087.  
  1088.                 s.phase[ch] = ph
  1089.  
  1090.                 local sample =
  1091.                     s.wave[ch][floor(ph) + 1]
  1092.  
  1093.                 acc =
  1094.                     acc +
  1095.                     sample *
  1096.                     s.volume[ch]
  1097.             end
  1098.         end
  1099.     end
  1100.  
  1101.     return acc /
  1102.         (128 *
  1103.         15 *
  1104.         5 *
  1105.         SCC_OVERSAMPLE)
  1106. end
  1107.  
  1108. local audioLastYield = os.clock()
  1109.  
  1110. local function flushAudio(buf)
  1111.     if buf.n == 0 then
  1112.         return
  1113.     end
  1114.  
  1115.     while not speaker.playAudio(buf) do
  1116.         os.pullEvent("speaker_audio_empty")
  1117.     end
  1118.  
  1119.     for i = buf.n, 1, -1 do
  1120.         buf[i] = nil
  1121.     end
  1122.  
  1123.     buf.n = 0
  1124.  
  1125.     if os.clock() - audioLastYield >= YIELD_SECONDS then
  1126.         os.queueEvent("msxplayer_yield")
  1127.         os.pullEvent("msxplayer_yield")
  1128.  
  1129.         audioLastYield = os.clock()
  1130.     end
  1131. end
  1132.  
  1133. local filter = {
  1134.     x = 0,
  1135.     y = 0
  1136. }
  1137.  
  1138. local function resetAudioFilter()
  1139.     filter.x = 0
  1140.     filter.y = 0
  1141. end
  1142.  
  1143. local function renderSamples(chips, count, volume, buf)
  1144.     local n = buf.n
  1145.  
  1146.     local psgs = chips.psg
  1147.     local sccs = chips.scc
  1148.  
  1149.     local px = filter.x
  1150.     local py = filter.y
  1151.  
  1152.     local random = math.random
  1153.  
  1154.     for _ = 1, count do
  1155.         local x = 0
  1156.  
  1157.         if psgs then
  1158.             for id = 0, 1 do
  1159.                 local p = psgs[id]
  1160.  
  1161.                 if p then
  1162.                     x =
  1163.                         x +
  1164.                         psgSample(p) *
  1165.                         (p.outputGain or 1) *
  1166.                         PSG_GAIN
  1167.                 end
  1168.             end
  1169.         end
  1170.  
  1171.         if sccs then
  1172.             for id = 0, 1 do
  1173.                 local s = sccs[id]
  1174.  
  1175.                 if s then
  1176.                     x =
  1177.                         x +
  1178.                         sccSample(s) *
  1179.                         (s.outputGain or 1) *
  1180.                         SCC_GAIN
  1181.                 end
  1182.             end
  1183.         end
  1184.  
  1185.         local y
  1186.  
  1187.         if DC_BLOCK then
  1188.             y =
  1189.                 x -
  1190.                 px +
  1191.                 HP_R * py
  1192.  
  1193.             px = x
  1194.             py = y
  1195.         else
  1196.             y = x
  1197.         end
  1198.  
  1199.         local v =
  1200.             y *
  1201.             volume *
  1202.             MASTER_GAIN *
  1203.             127
  1204.  
  1205.         if DITHER then
  1206.             v =
  1207.                 v +
  1208.                 random() -
  1209.                 random()
  1210.         end
  1211.  
  1212.         if v >= 0 then
  1213.             v = floor(v + 0.5)
  1214.         else
  1215.             v = -floor(-v + 0.5)
  1216.         end
  1217.  
  1218.         v = clamp(v, -128, 127)
  1219.  
  1220.         n = n + 1
  1221.         buf[n] = v
  1222.     end
  1223.  
  1224.     buf.n = n
  1225.  
  1226.     filter.x = px
  1227.     filter.y = py
  1228. end
  1229.  
  1230. local sampleAccumulator = 0
  1231.  
  1232. local function resetTiming()
  1233.     sampleAccumulator = 0
  1234. end
  1235.  
  1236. local function renderTicks(chips, ticks, volume, buf)
  1237.     if ticks <= 0 then
  1238.         return
  1239.     end
  1240.  
  1241.     sampleAccumulator =
  1242.         sampleAccumulator +
  1243.         ticks *
  1244.         OUTPUT_RATE /
  1245.         VGM_RATE
  1246.  
  1247.     local samples =
  1248.         floor(sampleAccumulator)
  1249.  
  1250.     sampleAccumulator =
  1251.         sampleAccumulator -
  1252.         samples
  1253.  
  1254.     while samples > 0 do
  1255.         local amount =
  1256.             min(
  1257.                 samples,
  1258.                 AUDIO_CHUNK - buf.n
  1259.             )
  1260.  
  1261.         renderSamples(
  1262.             chips,
  1263.             amount,
  1264.             volume,
  1265.             buf
  1266.         )
  1267.  
  1268.         samples =
  1269.             samples -
  1270.             amount
  1271.  
  1272.         if buf.n >= AUDIO_CHUNK then
  1273.             flushAudio(buf)
  1274.         end
  1275.     end
  1276. end
  1277.  
  1278. local AY_NAMES = {
  1279.     [0x00] = "AY-3-8910",
  1280.     [0x01] = "AY-3-8912",
  1281.     [0x02] = "AY-3-8913",
  1282.     [0x03] = "AY8930",
  1283.     [0x04] = "AY-3-8914",
  1284.  
  1285.     [0x10] = "YM2149",
  1286.     [0x11] = "YM3439",
  1287.     [0x12] = "YMZ284",
  1288.     [0x13] = "YMZ294"
  1289. }
  1290.  
  1291. local function parseExtraHeader(data, h)
  1292.     h.secondClock = {
  1293.         ay = nil,
  1294.         scc = nil
  1295.     }
  1296.  
  1297.     h.volumeModifier = 1.0
  1298.  
  1299.     if h.version < 0x170 then
  1300.         return
  1301.     end
  1302.  
  1303.     if h.dataOffset <= 0x100 then
  1304.         return
  1305.     end
  1306.  
  1307.     if #data < 0x10C then
  1308.         return
  1309.     end
  1310.  
  1311.     local extraStart = 0x100
  1312.  
  1313.     local extraSize =
  1314.         u32le(data, extraStart)
  1315.  
  1316.     if extraSize < 4 then
  1317.         return
  1318.     end
  1319.  
  1320.     if extraStart + extraSize > #data then
  1321.         return
  1322.     end
  1323.  
  1324.     local clockOffset =
  1325.         u32le(data, extraStart + 4)
  1326.  
  1327.     local volumeOffset =
  1328.         u32le(data, extraStart + 8)
  1329.  
  1330.     if clockOffset ~= 0 then
  1331.         local p =
  1332.             extraStart +
  1333.             clockOffset
  1334.  
  1335.         if p + 1 <= #data then
  1336.             local count =
  1337.                 u8(data, p)
  1338.  
  1339.             p = p + 1
  1340.  
  1341.             for _ = 1, count do
  1342.                 if p + 4 >= #data then
  1343.                     break
  1344.                 end
  1345.  
  1346.                 local chipId =
  1347.                     u8(data, p)
  1348.  
  1349.                 local clock =
  1350.                     u32le(data, p + 1)
  1351.  
  1352.                 p = p + 5
  1353.  
  1354.                 if chipId == 0x12 then
  1355.                     h.secondClock.ay = clock
  1356.                 elseif chipId == 0x19 then
  1357.                     h.secondClock.scc = clock
  1358.                 end
  1359.             end
  1360.         end
  1361.     end
  1362.  
  1363.     if h.version >= 0x160 and #data >= 0x80 then
  1364.         local modifier = u8(data, 0x7C)
  1365.  
  1366.         if modifier ~= 0 then
  1367.             local m = modifier
  1368.  
  1369.             if m >= 128 then
  1370.                 m = m - 256
  1371.             end
  1372.  
  1373.             if m == -63 then
  1374.                 m = -64
  1375.             end
  1376.  
  1377.             h.volumeModifier =
  1378.                 2 ^ (m / 32)
  1379.         end
  1380.     end
  1381. end
  1382.  
  1383. local function parseHeader(data)
  1384.     if data:sub(1, 4) ~= "Vgm " then
  1385.         error("Invalid VGM header")
  1386.     end
  1387.  
  1388.     if #data < 0x40 then
  1389.         error("VGM file is too small")
  1390.     end
  1391.  
  1392.     local version =
  1393.         u32le(data, 0x08)
  1394.  
  1395.     local eofRel =
  1396.         u32le(data, 0x04)
  1397.  
  1398.     local dataOffset = 0x40
  1399.  
  1400.     if version >= 0x150 then
  1401.         local rel =
  1402.             u32le(data, 0x34)
  1403.  
  1404.         if rel ~= 0 then
  1405.             dataOffset =
  1406.                 0x34 + rel
  1407.         end
  1408.     end
  1409.  
  1410.     if dataOffset < 0x40
  1411.         or dataOffset >= #data then
  1412.         error("Invalid VGM data offset")
  1413.     end
  1414.  
  1415.     local dataEnd
  1416.  
  1417.     if eofRel ~= 0 then
  1418.         dataEnd =
  1419.             min(
  1420.                 #data,
  1421.                 eofRel + 4
  1422.             )
  1423.     else
  1424.         dataEnd = #data
  1425.     end
  1426.  
  1427.     local ayRaw = 0
  1428.     local sccRaw = 0
  1429.  
  1430.     if version >= 0x151 and #data >= 0x78 then
  1431.         ayRaw =
  1432.             u32le(data, 0x74)
  1433.     end
  1434.  
  1435.     if version >= 0x161 and #data >= 0xA0 then
  1436.         sccRaw =
  1437.             u32le(data, 0x9C)
  1438.     end
  1439.  
  1440.     local ayClock =
  1441.         ayRaw % 0x40000000
  1442.  
  1443.     local sccClock =
  1444.         sccRaw % 0x40000000
  1445.  
  1446.     local h = {
  1447.         version = version,
  1448.  
  1449.         dataOffset = dataOffset,
  1450.         dataEnd = dataEnd,
  1451.  
  1452.         loopOffset = nil,
  1453.  
  1454.         ayClock = ayClock,
  1455.         ayDual = hasBit(ayRaw, 30),
  1456.         ayHardPan = hasBit(ayRaw, 31),
  1457.  
  1458.         ayType = 0,
  1459.         ayFlags = 0,
  1460.  
  1461.         sccClock = sccClock,
  1462.         sccDual = hasBit(sccRaw, 30),
  1463.         sccPlus = hasBit(sccRaw, 31),
  1464.  
  1465.         secondClock = {},
  1466.  
  1467.         volumeModifier = 1.0
  1468.     }
  1469.  
  1470.     if #data >= 0x20 then
  1471.         local loopRel =
  1472.             u32le(data, 0x1C)
  1473.  
  1474.         if loopRel ~= 0 then
  1475.             local loopOffset =
  1476.                 0x1C + loopRel
  1477.  
  1478.             if loopOffset >= dataOffset
  1479.                 and loopOffset < dataEnd then
  1480.                 h.loopOffset =
  1481.                     loopOffset
  1482.             end
  1483.         end
  1484.     end
  1485.  
  1486.     if version >= 0x151
  1487.         and #data >= 0x7A then
  1488.  
  1489.         h.ayType =
  1490.             u8(data, 0x78)
  1491.  
  1492.         h.ayFlags =
  1493.             u8(data, 0x79)
  1494.     end
  1495.  
  1496.     parseExtraHeader(data, h)
  1497.  
  1498.     return h
  1499. end
  1500.  
  1501. local function ensurePSG(chips, id, h)
  1502.     if not chips.psg then
  1503.         chips.psg = {}
  1504.     end
  1505.  
  1506.     if chips.psg[id] then
  1507.         return chips.psg[id]
  1508.     end
  1509.  
  1510.     local clock
  1511.  
  1512.     if id == 0 then
  1513.         clock =
  1514.             h.ayClock ~= 0
  1515.             and h.ayClock
  1516.             or DEFAULT_AY_CLOCK
  1517.     else
  1518.         clock =
  1519.             h.secondClock.ay
  1520.             or h.ayClock
  1521.             or DEFAULT_AY_CLOCK
  1522.     end
  1523.  
  1524.     local p =
  1525.         newPSG(
  1526.             clock,
  1527.             h.ayType,
  1528.             h.ayFlags
  1529.         )
  1530.  
  1531.     chips.psg[id] = p
  1532.  
  1533.     return p
  1534. end
  1535.  
  1536. local function ensureSCC(chips, id, h)
  1537.     if not chips.scc then
  1538.         chips.scc = {}
  1539.     end
  1540.  
  1541.     if chips.scc[id] then
  1542.         return chips.scc[id]
  1543.     end
  1544.  
  1545.     local clock
  1546.  
  1547.     if id == 0 then
  1548.         clock =
  1549.             h.sccClock ~= 0
  1550.             and h.sccClock
  1551.             or nil
  1552.     else
  1553.         clock =
  1554.             h.secondClock.scc
  1555.             or h.sccClock
  1556.             or nil
  1557.     end
  1558.  
  1559.     if not clock or clock == 0 then
  1560.         if h.ayClock and h.ayClock ~= 0 then
  1561.             clock = h.ayClock
  1562.         else
  1563.             clock = DEFAULT_SCC_CLOCK
  1564.         end
  1565.     end
  1566.  
  1567.     local plus = h.sccPlus
  1568.  
  1569.     local s =
  1570.         newSCC(
  1571.             clock,
  1572.             plus
  1573.         )
  1574.  
  1575.     chips.scc[id] = s
  1576.  
  1577.     return s
  1578. end
  1579.  
  1580. local STREAM_LEN = {
  1581.     [0x90] = 5,
  1582.     [0x91] = 5,
  1583.     [0x92] = 6,
  1584.     [0x93] = 11,
  1585.     [0x94] = 2,
  1586.     [0x95] = 5
  1587. }
  1588.  
  1589. local function skipLength(cmd)
  1590.     if cmd == 0x00 then
  1591.         return 1
  1592.     end
  1593.  
  1594.     if cmd == 0x4F
  1595.         or cmd == 0x50 then
  1596.         return 2
  1597.     end
  1598.  
  1599.     if cmd >= 0x30
  1600.         and cmd <= 0x3F then
  1601.         return 2
  1602.     end
  1603.  
  1604.     if cmd >= 0x40
  1605.         and cmd <= 0x4E then
  1606.         return 3
  1607.     end
  1608.  
  1609.     if cmd >= 0x51
  1610.         and cmd <= 0x5F then
  1611.         return 3
  1612.     end
  1613.  
  1614.     if cmd >= 0xA1
  1615.         and cmd <= 0xBF then
  1616.         return 3
  1617.     end
  1618.  
  1619.     if cmd >= 0xC0
  1620.         and cmd <= 0xDF then
  1621.         return 4
  1622.     end
  1623.  
  1624.     if cmd >= 0xE0
  1625.         and cmd <= 0xFF then
  1626.         return 5
  1627.     end
  1628.  
  1629.     return STREAM_LEN[cmd]
  1630. end
  1631.  
  1632. local function playVGM(filename, userVolume, loopCount)
  1633.     print("Loading " .. filename .. "...")
  1634.  
  1635.     local data =
  1636.         loadMusic(filename)
  1637.  
  1638.     local h =
  1639.         parseHeader(data)
  1640.  
  1641.     print(string.format(
  1642.         "VGM %d.%02X",
  1643.         floor(h.version / 256),
  1644.         h.version % 256
  1645.     ))
  1646.  
  1647.     local chips = {
  1648.         psg = {},
  1649.         scc = {}
  1650.     }
  1651.  
  1652.     local psgCount = 0
  1653.     local sccCount = 0
  1654.  
  1655.     if h.ayClock ~= 0 then
  1656.         ensurePSG(chips, 0, h)
  1657.  
  1658.         psgCount = 1
  1659.  
  1660.         if h.ayDual then
  1661.             ensurePSG(chips, 1, h)
  1662.             psgCount = 2
  1663.         end
  1664.  
  1665.         print(
  1666.             (AY_NAMES[h.ayType] or "PSG")
  1667.             .. " #1 clock: "
  1668.             .. h.ayClock
  1669.             .. " Hz"
  1670.         )
  1671.  
  1672.         if h.ayDual then
  1673.             print(
  1674.                 (AY_NAMES[h.ayType] or "PSG")
  1675.                 .. " #2 clock: "
  1676.                 .. (
  1677.                     h.secondClock.ay
  1678.                     or h.ayClock
  1679.                 )
  1680.                 .. " Hz"
  1681.             )
  1682.         end
  1683.     end
  1684.  
  1685.     if h.sccClock ~= 0 then
  1686.         ensureSCC(chips, 0, h)
  1687.  
  1688.         sccCount = 1
  1689.  
  1690.         if h.sccDual then
  1691.             ensureSCC(chips, 1, h)
  1692.             sccCount = 2
  1693.         end
  1694.  
  1695.         print(
  1696.             (
  1697.                 h.sccPlus
  1698.                 and "K052539 SCC+"
  1699.                 or "K051649 SCC"
  1700.             )
  1701.             .. " #1 clock: "
  1702.             .. h.sccClock
  1703.             .. " Hz"
  1704.         )
  1705.  
  1706.         if h.sccDual then
  1707.             print(
  1708.                 (
  1709.                     h.sccPlus
  1710.                     and "K052539 SCC+"
  1711.                     or "K051649 SCC"
  1712.                 )
  1713.                 .. " #2 clock: "
  1714.                 .. (
  1715.                     h.secondClock.scc
  1716.                     or h.sccClock
  1717.                 )
  1718.                 .. " Hz"
  1719.             )
  1720.         end
  1721.     end
  1722.  
  1723.     local position =
  1724.         h.dataOffset + 1
  1725.  
  1726.     local loopPosition
  1727.  
  1728.     if h.loopOffset then
  1729.         loopPosition =
  1730.             h.loopOffset + 1
  1731.     end
  1732.  
  1733.     local loopsPlayed = 0
  1734.     local totalTicks = 0
  1735.  
  1736.     local len62 = 735
  1737.     local len63 = 882
  1738.  
  1739.     local buf = {
  1740.         n = 0
  1741.     }
  1742.  
  1743.     resetTiming()
  1744.     resetAudioFilter()
  1745.  
  1746.     local volume =
  1747.         userVolume *
  1748.         h.volumeModifier
  1749.  
  1750.     volume = clamp(volume, 0, 3.0)
  1751.  
  1752.     local function wait(t)
  1753.         if t <= 0 then
  1754.             return
  1755.         end
  1756.  
  1757.         renderTicks(
  1758.             chips,
  1759.             t,
  1760.             volume,
  1761.             buf
  1762.         )
  1763.  
  1764.         totalTicks =
  1765.             totalTicks + t
  1766.     end
  1767.  
  1768.     print("Playing...")
  1769.  
  1770.     while position <= h.dataEnd do
  1771.         local cmd =
  1772.             u8(data, position - 1)
  1773.  
  1774.         if cmd == 0x66 then
  1775.             if loopPosition
  1776.                 and loopsPlayed < loopCount
  1777.                 and loopsPlayed < MAX_LOOP_GUARD then
  1778.  
  1779.                 loopsPlayed =
  1780.                     loopsPlayed + 1
  1781.  
  1782.                 position =
  1783.                     loopPosition
  1784.             else
  1785.                 break
  1786.             end
  1787.  
  1788.         elseif cmd == 0x61 then
  1789.             requireBytes(
  1790.                 data,
  1791.                 position,
  1792.                 3,
  1793.                 h.dataEnd
  1794.             )
  1795.  
  1796.             wait(
  1797.                 u16(data, position)
  1798.             )
  1799.  
  1800.             position =
  1801.                 position + 3
  1802.  
  1803.         elseif cmd == 0x62 then
  1804.             wait(len62)
  1805.  
  1806.             position =
  1807.                 position + 1
  1808.  
  1809.         elseif cmd == 0x63 then
  1810.             wait(len63)
  1811.  
  1812.             position =
  1813.                 position + 1
  1814.  
  1815.         elseif cmd == 0x64 then
  1816.             requireBytes(
  1817.                 data,
  1818.                 position,
  1819.                 4,
  1820.                 h.dataEnd
  1821.             )
  1822.  
  1823.             local c =
  1824.                 u8(data, position)
  1825.  
  1826.             local n =
  1827.                 u16(data, position + 1)
  1828.  
  1829.             if c == 0x62 then
  1830.                 len62 = n
  1831.             elseif c == 0x63 then
  1832.                 len63 = n
  1833.             end
  1834.  
  1835.             position =
  1836.                 position + 4
  1837.  
  1838.         elseif cmd >= 0x70
  1839.             and cmd <= 0x7F then
  1840.  
  1841.             wait(
  1842.                 (cmd % 16) + 1
  1843.             )
  1844.  
  1845.             position =
  1846.                 position + 1
  1847.  
  1848.         elseif cmd >= 0x80
  1849.             and cmd <= 0x8F then
  1850.  
  1851.             wait(cmd % 16)
  1852.  
  1853.             position =
  1854.                 position + 1
  1855.  
  1856.         elseif cmd == 0xA0 then
  1857.             requireBytes(
  1858.                 data,
  1859.                 position,
  1860.                 3,
  1861.                 h.dataEnd
  1862.             )
  1863.  
  1864.             local rawReg =
  1865.                 u8(data, position)
  1866.  
  1867.             local chipId = 0
  1868.  
  1869.             if h.ayDual
  1870.                 and hasBit(rawReg, 7) then
  1871.                 chipId = 1
  1872.             end
  1873.  
  1874.             local reg =
  1875.                 rawReg % 0x80
  1876.  
  1877.             if reg < 16 then
  1878.                 local p =
  1879.                     ensurePSG(
  1880.                         chips,
  1881.                         chipId,
  1882.                         h
  1883.                     )
  1884.  
  1885.                 psgWrite(
  1886.                     p,
  1887.                     reg,
  1888.                     u8(data, position + 1)
  1889.                 )
  1890.             end
  1891.  
  1892.             position =
  1893.                 position + 3
  1894.  
  1895.         elseif cmd == 0xD2 then
  1896.             requireBytes(
  1897.                 data,
  1898.                 position,
  1899.                 4,
  1900.                 h.dataEnd
  1901.             )
  1902.  
  1903.             local rawPort =
  1904.                 u8(data, position)
  1905.  
  1906.             local chipId = 0
  1907.  
  1908.             if h.sccDual
  1909.                 and hasBit(rawPort, 7) then
  1910.                 chipId = 1
  1911.             end
  1912.  
  1913.             local port =
  1914.                 rawPort % 0x80
  1915.  
  1916.             local s =
  1917.                 ensureSCC(
  1918.                     chips,
  1919.                     chipId,
  1920.                     h
  1921.                 )
  1922.  
  1923.             sccWrite(
  1924.                 s,
  1925.                 port,
  1926.                 u8(data, position + 1),
  1927.                 u8(data, position + 2)
  1928.             )
  1929.  
  1930.             position =
  1931.                 position + 4
  1932.  
  1933.         elseif cmd == 0x67 then
  1934.             requireBytes(
  1935.                 data,
  1936.                 position,
  1937.                 7,
  1938.                 h.dataEnd
  1939.             )
  1940.  
  1941.             if u8(data, position) ~= 0x66 then
  1942.                 error("Malformed VGM data block")
  1943.             end
  1944.  
  1945.             local size =
  1946.                 u32le(data, position + 3)
  1947.  
  1948.             size =
  1949.                 size % 2147483648
  1950.  
  1951.             if size > h.dataEnd - position - 6 then
  1952.                 error("VGM data block exceeds file")
  1953.             end
  1954.  
  1955.             local total =
  1956.                 7 + size
  1957.  
  1958.             requireBytes(
  1959.                 data,
  1960.                 position,
  1961.                 total,
  1962.                 h.dataEnd
  1963.             )
  1964.  
  1965.             position =
  1966.                 position + total
  1967.  
  1968.         elseif cmd == 0x68 then
  1969.             requireBytes(
  1970.                 data,
  1971.                 position,
  1972.                 12,
  1973.                 h.dataEnd
  1974.             )
  1975.  
  1976.             position =
  1977.                 position + 12
  1978.  
  1979.         elseif cmd == 0x00 then
  1980.             position =
  1981.                 position + 1
  1982.  
  1983.         else
  1984.             local len =
  1985.                 skipLength(cmd)
  1986.  
  1987.             if not len then
  1988.                 error(string.format(
  1989.                     "Unsupported VGM command %02X at offset %X",
  1990.                     cmd,
  1991.                     position - 1
  1992.                 ))
  1993.             end
  1994.  
  1995.             requireBytes(
  1996.                 data,
  1997.                 position,
  1998.                 len,
  1999.                 h.dataEnd
  2000.             )
  2001.  
  2002.             position =
  2003.                 position + len
  2004.         end
  2005.     end
  2006.  
  2007.     flushAudio(buf)
  2008.  
  2009.     print(string.format(
  2010.         "Done. %.3f seconds.",
  2011.         totalTicks / VGM_RATE
  2012.     ))
  2013.  
  2014.     if loopsPlayed > 0 then
  2015.         print(
  2016.             "Extra loops played: "
  2017.             .. loopsPlayed
  2018.         )
  2019.     end
  2020. end
  2021.  
  2022. local args = {...}
  2023.  
  2024. local filename =
  2025.     args[1]
  2026.  
  2027. if not filename then
  2028.     write("VGM/VGZ filename: ")
  2029.     filename = read()
  2030. end
  2031.  
  2032. if not filename
  2033.     or filename == "" then
  2034.  
  2035.     print("No filename supplied.")
  2036.     return
  2037. end
  2038.  
  2039. if not fs.exists(filename) then
  2040.     print(
  2041.         "File not found: "
  2042.         .. filename
  2043.     )
  2044.     return
  2045. end
  2046.  
  2047. write(
  2048.     "Volume (0.0-3.0, default "
  2049.     .. DEFAULT_VOLUME
  2050.     .. "): "
  2051. )
  2052.  
  2053. local volume =
  2054.     tonumber(read())
  2055.  
  2056. if not volume
  2057.     or volume < 0
  2058.     or volume > 3 then
  2059.  
  2060.     volume =
  2061.         DEFAULT_VOLUME
  2062. end
  2063.  
  2064. write(
  2065.     "Extra loops (default "
  2066.     .. DEFAULT_LOOP_COUNT
  2067.     .. "): "
  2068. )
  2069.  
  2070. local loopCount =
  2071.     tonumber(read())
  2072.  
  2073. if not loopCount
  2074.     or loopCount < 0 then
  2075.  
  2076.     loopCount =
  2077.         DEFAULT_LOOP_COUNT
  2078. end
  2079.  
  2080. loopCount =
  2081.     floor(loopCount)
  2082.  
  2083. loopCount =
  2084.     min(loopCount, MAX_LOOP_GUARD)
  2085.  
  2086. local ok, err =
  2087.     pcall(
  2088.         playVGM,
  2089.         filename,
  2090.         volume,
  2091.         loopCount
  2092.     )
  2093.  
  2094. if not ok then
  2095.     print("")
  2096.     print("Playback error:")
  2097.     print(err)
  2098. end
Advertisement
Add Comment
Please, Sign In to add comment