TIMAS_Bro

player

Feb 11th, 2024
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local inflate do
  2.  
  3.     local floor = math.floor
  4.     local ceil = math.ceil
  5.     local min = math.min
  6.     local max = math.max
  7.  
  8.     -- utility functions
  9.  
  10.     local function memoize(f)
  11.         local cache = {}
  12.         return function(...)
  13.             local key = table.concat({...}, "-")
  14.             if not cache[key] then
  15.                 cache[key] = f(...)
  16.             end
  17.             return cache[key]
  18.         end
  19.     end
  20.  
  21.     local function int(bytes)
  22.         local n = 0
  23.         for i = 1, #bytes do
  24.             n = 256*n + bytes:sub(i, i):byte()
  25.         end
  26.         return n
  27.     end
  28.     int = memoize(int)
  29.  
  30.     local function bint(bits)
  31.         return tonumber(bits, 2) or 0
  32.     end
  33.     bint = memoize(bint)
  34.  
  35.     local function bits(b, width)
  36.         local s = ""
  37.         if type(b) == "number" then
  38.             for i = 1, width do
  39.                 s = b%2 .. s
  40.                 b = floor(b/2)
  41.             end
  42.         else
  43.             for i = 1, #b do
  44.                 s = s .. bits(b:byte(i), 8):reverse()
  45.                 assert(#s == i * 8, s)
  46.             end
  47.         end
  48.         return s
  49.     end
  50.     bits = memoize(bits)
  51.  
  52.     local function fill(bytes, len)
  53.         return bytes:rep(floor(len / #bytes)) .. bytes:sub(1, len % #bytes)
  54.     end
  55.  
  56.     local function zip(t1, t2)
  57.         local zipped = {}
  58.         for i = 1, max(#t1, #t2) do
  59.             zipped[#zipped + 1] = {t1[i], t2[i]}
  60.         end
  61.         return zipped
  62.     end
  63.  
  64.     local function unzip(zipped)
  65.         local t1, t2 = {}, {}
  66.         for i = 1, #zipped do
  67.             t1[#t1 + 1] = zipped[i][1]
  68.             t2[#t2 + 1] = zipped[i][2]
  69.         end
  70.         return t1, t2
  71.     end
  72.  
  73.     local function map(f, t)
  74.         local mapped = {}
  75.         for i = 1, #t do
  76.             mapped[#mapped + 1] = f(t[i], i)
  77.         end
  78.         return mapped
  79.     end
  80.  
  81.     local function filter(pred, t)
  82.         local filtered = {}
  83.         for i = 1, #t do
  84.             if pred(t[i], i) then
  85.                 filtered[#filtered + 1] = t[i]
  86.             end
  87.         end
  88.         return filtered
  89.     end
  90.  
  91.     local function find(key, t)
  92.         if type(key) == "function" then
  93.             for i = 1, #t do
  94.                 if key(t[i]) then
  95.                     return i
  96.                 end
  97.             end
  98.             return nil
  99.         else
  100.             return find(function(x) return x == key end, t)
  101.         end
  102.     end
  103.  
  104.     local function slice(t, i, j, step)
  105.         local sliced = {}
  106.         for k = i < 1 and 1 or i, i < 1 and #t + i or j or #t, step or 1 do
  107.             sliced[#sliced + 1] = t[k]
  108.         end
  109.         return sliced
  110.     end
  111.  
  112.     local function range(i, j)
  113.         local r = {}
  114.         for k = j and i or 0, j or i - 1 do
  115.             r[#r + 1] = k
  116.         end
  117.         return r
  118.     end
  119.  
  120.     -- streams
  121.  
  122.     local function output_stream()
  123.         local stream, buffer = {}, {}
  124.         local curr = 0
  125.  
  126.         function stream:write(bytes)
  127.             for i = 1, #bytes do
  128.                 buffer[#buffer + 1] = bytes:sub(i, i)
  129.             end
  130.             curr = curr + #bytes
  131.         end
  132.  
  133.         function stream:back_read(offset, n)
  134.             local read = {}
  135.             for i = curr - offset + 1, curr - offset + n do
  136.                 read[#read + 1] = buffer[i]
  137.             end
  138.             return table.concat(read)
  139.         end
  140.  
  141.         function stream:back_copy(dist, len)
  142.             local start, copied = curr - dist + 1, {}
  143.             for i = start, min(start + len, curr) do
  144.                 copied[#copied + 1] = buffer[i]
  145.             end
  146.             self:write(fill(table.concat(copied), len))
  147.         end
  148.  
  149.         function stream:pos()
  150.             return curr
  151.         end
  152.  
  153.         function stream:raw()
  154.             return table.concat(buffer)
  155.         end
  156.  
  157.         return stream
  158.     end
  159.  
  160.     local function bit_stream(raw, offset)
  161.         local stream = {}
  162.         local curr = 0
  163.         offset = offset or 0
  164.  
  165.         function stream:read(n, reverse)
  166.             local start = floor(curr/8) + offset + 1
  167.             local bb = ""
  168.             for i = start, start + ceil(n/8) do
  169.                 local b = raw:byte(i)
  170.                 for j = 0, 7 do bb = bb .. bit32.extract(b, j, 1) end
  171.             end
  172.             local b = bb:sub(curr%8 + 1, curr%8 + n)
  173.             curr = curr + n
  174.             return reverse and b or b:reverse()
  175.         end
  176.  
  177.         function stream:seek(n)
  178.             if n == "beg" then
  179.                 curr = 0
  180.             elseif n == "end" then
  181.                 curr = #raw
  182.             else
  183.                 curr = curr + n
  184.             end
  185.             return self
  186.         end
  187.  
  188.         function stream:is_empty()
  189.             return curr >= 8*#raw
  190.         end
  191.  
  192.         function stream:pos()
  193.             return curr
  194.         end
  195.  
  196.         return stream
  197.     end
  198.  
  199.     -- inflate
  200.  
  201.     local CL_LENS_ORDER = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
  202.     local MAX_BITS = 15
  203.     local PT_WIDTH = 8
  204.  
  205.     local function cl_code_lens(stream, hclen)
  206.         local code_lens = {}
  207.         for i = 1, hclen do
  208.             code_lens[#code_lens + 1] = bint(stream:read(3))
  209.         end
  210.         return code_lens
  211.     end
  212.  
  213.     local function code_tree(lens, alphabet)
  214.         alphabet = alphabet or range(#lens)
  215.         local using = filter(function(x, i) return lens[i] and lens[i] > 0 end, alphabet)
  216.         lens = filter(function(x) return x > 0 end, lens)
  217.         local tree = zip(lens, using)
  218.         table.sort(tree, function(a, b)
  219.             if a[1] == b[1] then
  220.                 return a[2] < b[2]
  221.             else
  222.                 return a[1] < b[1]
  223.             end
  224.         end)
  225.         return unzip(tree)
  226.     end
  227.  
  228.     local function codes(lens)
  229.         local codes = {}
  230.         local code = 0
  231.         for i = 1, #lens do
  232.             codes[#codes + 1] = bits(code, lens[i])
  233.             if i < #lens then
  234.                 code = (code + 1)*2^(lens[i + 1] - lens[i])
  235.             end
  236.         end
  237.         return codes
  238.     end
  239.  
  240.     local prefix_table
  241.     local function handle_long_codes(codes, alphabet, pt)
  242.         local i = find(function(x) return #x > PT_WIDTH end, codes)
  243.         local long = slice(zip(codes, alphabet), i)
  244.         i = 0
  245.         repeat
  246.             local prefix = long[i + 1][1]:sub(1, PT_WIDTH)
  247.             local same = filter(function(x) return x[1]:sub(1, PT_WIDTH) == prefix end, long)
  248.             same = map(function(x) return {x[1]:sub(PT_WIDTH + 1), x[2]} end, same)
  249.             pt[prefix] = {rest = prefix_table(unzip(same)), unused = 0}
  250.             i = i + #same
  251.         until i == #long
  252.     end
  253.  
  254.     function prefix_table(codes, alphabet)
  255.         local pt = {}
  256.         if #codes[#codes] > PT_WIDTH then
  257.             handle_long_codes(codes, alphabet, pt)
  258.         end
  259.         for i = 1, #codes do
  260.             local code = codes[i]
  261.             if #code > PT_WIDTH then
  262.                 break
  263.             end
  264.             local entry = {value = alphabet[i], unused = PT_WIDTH - #code}
  265.             if entry.unused == 0 then
  266.                 pt[code] = entry
  267.             else
  268.                 for i = 0, 2^entry.unused - 1 do
  269.                     pt[code .. bits(i, entry.unused)] = entry
  270.                 end
  271.             end
  272.         end
  273.         return pt
  274.     end
  275.  
  276.     local function huffman_decoder(lens, alphabet)
  277.         local base_codes = prefix_table(codes(lens), alphabet)
  278.         return function(stream)
  279.             local codes = base_codes
  280.             local entry
  281.             repeat
  282.                 entry = codes[stream:read(PT_WIDTH, true)]
  283.                 stream:seek(-entry.unused)
  284.                 codes = entry.rest
  285.             until not codes
  286.             return entry.value
  287.         end
  288.     end
  289.  
  290.     local function code_lens(stream, decode, n)
  291.         local lens = {}
  292.         repeat
  293.             local value = decode(stream)
  294.             if value < 16 then
  295.                 lens[#lens + 1] = value
  296.             elseif value == 16 then
  297.                 for i = 1, bint(stream:read(2)) + 3 do
  298.                     lens[#lens + 1] = lens[#lens]
  299.                 end
  300.             elseif value == 17 then
  301.                 for i = 1, bint(stream:read(3)) + 3 do
  302.                     lens[#lens + 1] = 0
  303.                 end
  304.             elseif value == 18 then
  305.                 for i = 1, bint(stream:read(7)) + 11 do
  306.                     lens[#lens + 1] = 0
  307.                 end
  308.             end
  309.         until #lens == n
  310.         return lens
  311.     end
  312.  
  313.     local function code_trees(stream)
  314.         local hlit = bint(stream:read(5)) + 257
  315.         local hdist = bint(stream:read(5)) + 1
  316.         local hclen = bint(stream:read(4)) + 4
  317.         local cl_decode = huffman_decoder(code_tree(cl_code_lens(stream, hclen), CL_LENS_ORDER))
  318.         local ll_decode = huffman_decoder(code_tree(code_lens(stream, cl_decode, hlit)))
  319.         local d_decode = huffman_decoder(code_tree(code_lens(stream, cl_decode, hdist)))
  320.         return ll_decode, d_decode
  321.     end
  322.  
  323.     local function extra_bits(value)
  324.         if value >= 4 and value <= 29 then
  325.             return floor(value/2) - 1
  326.         elseif value >= 265 and value <= 284 then
  327.             return ceil(value/4) - 66
  328.         else
  329.             return 0
  330.         end
  331.     end
  332.     extra_bits = memoize(extra_bits)
  333.  
  334.     local function decode_len(value, bits)
  335.         assert(value >= 257 and value <= 285, "value out of range")
  336.         assert(#bits == extra_bits(value), "wrong number of extra bits")
  337.         if value <= 264 then
  338.             return value - 254
  339.         elseif value == 285 then
  340.             return 258
  341.         end
  342.         local len = 11
  343.         for i = 1, #bits - 1 do
  344.             len = len + 2^(i+2)
  345.         end
  346.         return floor(bint(bits) + len + ((value - 1) % 4)*2^#bits)
  347.     end
  348.     decode_len = memoize(decode_len)
  349.  
  350.     local function a(n)
  351.         if n <= 3 then
  352.             return n + 2
  353.         else
  354.             return a(n-1) + 2*a(n-2) - 2*a(n-3)
  355.         end
  356.     end
  357.     a = memoize(a)
  358.  
  359.     local function decode_dist(value, bits)
  360.         assert(value >= 0 and value <= 29, "value out of range")
  361.         assert(#bits == extra_bits(value), "wrong number of extra bits)")
  362.         return bint(bits) + a(value - 1)
  363.     end
  364.     decode_dist = memoize(decode_dist)
  365.  
  366.     function inflate(data)
  367.         local stream = bit_stream(data)
  368.         local ostream = output_stream()
  369.         repeat
  370.             local bfinal, btype = bint(stream:read(1)), bint(stream:read(2))
  371.             assert(btype == 2, "compression method not supported")
  372.             local ll_decode, d_decode = code_trees(stream)
  373.             while true do
  374.                 local value = ll_decode(stream)
  375.                 if value < 256 then
  376.                     ostream:write(string.char(value))
  377.                 elseif value == 256 then
  378.                     break
  379.                 else
  380.                     local len = decode_len(value, stream:read(extra_bits(value)))
  381.                     value = d_decode(stream)
  382.                     local dist = decode_dist(value, stream:read(extra_bits(value)))
  383.                     ostream:back_copy(dist, len)
  384.                 end
  385.             end
  386.         until bfinal == 1
  387.         return ostream:raw()
  388.     end
  389.  
  390. end
  391. local dfpwm = require "cc.audio.dfpwm"
  392.  
  393. local hexstr = "0123456789abcdef"
  394. local file, err = http.get { url = "http://timuzkas.mywire.org:8000/video.32v", binary = true }
  395. if not file then error(err) end
  396. if file.read(4) ~= "32VD" then file.close() error("Not a 32vid file") end
  397. local width, height, fps, nStreams, flags = ("<HHBBH"):unpack(file.read(8))
  398. local video, audio, subtitles
  399. for _ = 1, nStreams do
  400.     local size, nFrames, frameType = ("<IIB"):unpack(file.read(9))
  401.     print(("%X"):format(file.seek()), size, nFrames, frameType)
  402.     if frameType == 0 and not video then
  403.         local data = file.read(size)
  404.         if bit32.band(flags, 3) == 2 then data = inflate(data) end
  405.         video = {}
  406.         local pos = 1
  407.         local start = os.epoch "utc"
  408.         for i = 1, nFrames do
  409.             if i % 100 == 0 or i >= nFrames - 10 then print(i, os.epoch "utc" - start) start = os.epoch "utc" sleep(0) end
  410.             local frame = {palette = {}}
  411.             local tmp, tmppos = 0, 0
  412.             local use5bit, customcompress = bit32.btest(flags, 16), bit32.band(flags, 3) == 3
  413.             local codetree = {}
  414.             local solidchar, runlen
  415.             local function readField(isColor)
  416.                 if customcompress then
  417.                     if runlen then
  418.                         local c = solidchar
  419.                         runlen = runlen - 1
  420.                         if runlen == 0 then runlen = nil end
  421.                         return c
  422.                     end
  423.                     if not isColor and solidchar then return solidchar end
  424.                     -- MARK: Huffman decoding
  425.                     local node = codetree
  426.                     while true do
  427.                         local n = bit32.extract(tmp, tmppos, 1)
  428.                         tmppos = tmppos - 1
  429.                         if tmppos < 0 then tmp, pos, tmppos = data:byte(pos), pos + 1, 7 end
  430.                         if type(node) ~= "table" then error(("Invalid tree state: position %X, frame %d"):format(pos+file.seek()-size-1, i)) end
  431.                         if type(node[n]) == "number" then
  432.                             local c = node[n]
  433.                             if isColor then
  434.                                 if c > 15 then runlen = 2^(c-15)-1 return assert(solidchar)
  435.                                 else solidchar = c end
  436.                             end
  437.                             return c
  438.                         else node = node[n] end
  439.                     end
  440.                 else
  441.                     local n
  442.                     if tmppos * 5 + 5 > 32 then n = bit32.extract(math.floor(tmp / 0x1000000), tmppos * 5 - 24, 5)
  443.                     else n = bit32.extract(tmp, tmppos * 5, 5) end
  444.                     tmppos = tmppos - 1
  445.                     if tmppos < 0 then tmp, pos = (">I5"):unpack(data, pos) tmppos = 7 end
  446.                     return n
  447.                 end
  448.             end
  449.             if customcompress then
  450.                 -- MARK: Huffman tree reconstruction
  451.                 -- read bit lengths
  452.                 local bitlen = {}
  453.                 if use5bit then
  454.                     for j = 0, 15 do
  455.                         bitlen[j*2+1], bitlen[j*2+2] = {s = j*2, l = bit32.rshift(data:byte(pos+j), 4)}, {s = j*2+1, l = bit32.band(data:byte(pos+j), 0x0F)}
  456.                     end
  457.                     pos = pos + 16
  458.                 else
  459.                     for j = 0, 7 do
  460.                         tmp, pos = (">I5"):unpack(data, pos)
  461.                         bitlen[j*8+1] = {s = j*8+1, l = math.floor(tmp / 0x800000000)}
  462.                         bitlen[j*8+2] = {s = j*8+2, l = math.floor(tmp / 0x40000000) % 32}
  463.                         for k = 3, 8 do bitlen[j*8+k] = {s = j*8+k, l = bit32.extract(tmp, (8-k)*5, 5)} end
  464.                     end
  465.                 end
  466.                 do
  467.                     local j = 1
  468.                     while j <= #bitlen do
  469.                         if bitlen[j].l == 0 then table.remove(bitlen, j)
  470.                         else j = j + 1 end
  471.                     end
  472.                 end
  473.                 if #bitlen == 0 then
  474.                     -- screen is solid character
  475.                     solidchar = data:byte(pos)
  476.                     pos = pos + 1
  477.                 else
  478.                     -- reconstruct codes from bit lengths
  479.                     table.sort(bitlen, function(a, b) if a.l == b.l then return a.s < b.s else return a.l < b.l end end)
  480.                     bitlen[1].c = 0
  481.                     for j = 2, #bitlen do bitlen[j].c = bit32.lshift(bitlen[j-1].c + 1, bitlen[j].l - bitlen[j-1].l) end
  482.                     -- create tree from codes
  483.                     for j = 1, #bitlen do
  484.                         local c = bitlen[j].c
  485.                         local node = codetree
  486.                         for k = bitlen[j].l - 1, 1, -1 do
  487.                             local n = bit32.extract(c, k, 1)
  488.                             if not node[n] then node[n] = {} end
  489.                             node = node[n]
  490.                             if type(node) == "number" then error(("Invalid tree state: position %X, frame %d, #bitlen = %d, current entry = %d"):format(pos, i, #bitlen, j)) end
  491.                         end
  492.                         local n = bit32.extract(c, 0, 1)
  493.                         node[n] = bitlen[j].s
  494.                     end
  495.                     -- read first byte
  496.                     tmp, tmppos, pos = data:byte(pos), 7, pos + 1
  497.                 end
  498.             else readField() end
  499.             for y = 1, height do
  500.                 local line = {"", "", "", {}}
  501.                 for x = 1, width do
  502.                     if pos + 5 + 1 >= #data then print(i, pos, x, y) error() end
  503.                     local n = readField()
  504.                     line[1] = line[1] .. string.char(128 + (n % 0x20))
  505.                     line[4][x] = bit32.btest(n, 0x20)
  506.                 end
  507.                 frame[y] = line
  508.             end
  509.             if customcompress then
  510.                 if tmppos == 7 then pos = pos - 1 end
  511.                 codetree = {}
  512.                 -- MARK: Huffman tree reconstruction
  513.                 -- read bit lengths
  514.                 local bitlen = {}
  515.                 for j = 0, 11 do
  516.                     bitlen[j*2+1], bitlen[j*2+2] = {s = j*2, l = bit32.rshift(data:byte(pos+j), 4)}, {s = j*2+1, l = bit32.band(data:byte(pos+j), 0x0F)}
  517.                 end
  518.                 pos = pos + 12
  519.                 do
  520.                     local j = 1
  521.                     while j <= #bitlen do
  522.                         if bitlen[j].l == 0 then table.remove(bitlen, j)
  523.                         else j = j + 1 end
  524.                     end
  525.                 end
  526.                 if #bitlen == 0 then
  527.                     -- screen is solid color
  528.                     solidchar = data:byte(pos)
  529.                     pos = pos + 1
  530.                     runlen = math.huge
  531.                 else
  532.                     -- reconstruct codes from bit lengths
  533.                     table.sort(bitlen, function(a, b) if a.l == b.l then return a.s < b.s else return a.l < b.l end end)
  534.                     bitlen[1].c = 0
  535.                     for j = 2, #bitlen do bitlen[j].c = bit32.lshift(bitlen[j-1].c + 1, bitlen[j].l - bitlen[j-1].l) end
  536.                     -- create tree from codes
  537.                     for j = 1, #bitlen do
  538.                         local c = bitlen[j].c
  539.                         local node = codetree
  540.                         for k = bitlen[j].l - 1, 1, -1 do
  541.                             local n = bit32.extract(c, k, 1)
  542.                             if not node[n] then node[n] = {} end
  543.                             node = node[n]
  544.                             if type(node) == "number" then error(("Invalid tree state: position %X, frame %d, #bitlen = %d, current entry = %d"):format(pos, i, #bitlen, j)) end
  545.                         end
  546.                         local n = bit32.extract(c, 0, 1)
  547.                         node[n] = bitlen[j].s
  548.                     end
  549.                     -- read first byte
  550.                     tmp, tmppos, pos = data:byte(pos), 7, pos + 1
  551.                 end
  552.                 for y = 1, height do
  553.                     local line = frame[y]
  554.                     for x = 1, width do
  555.                         local c = readField(true)
  556.                         line[2] = line[2] .. hexstr:sub(c+1, c+1)
  557.                     end
  558.                 end
  559.                 runlen = nil
  560.                 for y = 1, height do
  561.                     local line = frame[y]
  562.                     for x = 1, width do
  563.                         local c = readField(true)
  564.                         line[3] = line[3] .. hexstr:sub(c+1, c+1)
  565.                     end
  566.                 end
  567.                 if tmppos == 7 then pos = pos - 1 end
  568.             else
  569.                 for y = 1, height do
  570.                     local line = frame[y]
  571.                     for x = 1, width do
  572.                         local c = data:byte(pos)
  573.                         pos = pos + 1
  574.                         if line[4][x] then c = bit32.bor(bit32.band(bit32.lshift(c, 4), 0xF0), bit32.rshift(c, 4)) end
  575.                         line[2] = line[2] .. hexstr:sub(bit32.band(c, 15)+1, bit32.band(c, 15)+1)
  576.                         line[3] = line[3] .. hexstr:sub(bit32.rshift(c, 4)+1, bit32.rshift(c, 4)+1)
  577.                     end
  578.                     line[4] = nil
  579.                 end
  580.             end
  581.             for n = 1, 16 do frame.palette[n], pos = {data:byte(pos) / 255, data:byte(pos+1) / 255, data:byte(pos+2) / 255}, pos + 3 end
  582.             video[i] = frame
  583.         end
  584.     elseif frameType == 1 and not audio then
  585.         audio = {}
  586.         if bit32.band(flags, 12) == 0 then
  587.             for i = 1, math.ceil(size / 48000) do
  588.                 local data
  589.                 if jit then
  590.                     data = {}
  591.                     for j = 0, 5 do
  592.                         local t = {file.read(math.min(size - (i-1) * 48000 - j * 8000, 8000)):byte(1, -1)}
  593.                         if #t > 0 then for k = 1, #t do data[j*8000+k] = t[k] end end
  594.                     end
  595.                 else data = {file.read(math.min(size - (i-1) * 48000, 48000)):byte(1, -1)} end
  596.                 for j = 1, #data do data[j] = data[j] - 128 end
  597.                 audio[i] = data
  598.             end
  599.         elseif bit32.band(flags, 12) == 4 then
  600.             local decode = dfpwm.make_decoder()
  601.             for i = 1, math.ceil(size / 6000) do
  602.                 local data = file.read(math.min(size - (i-1)*6000, 6000))
  603.                 if not data then break end
  604.                 audio[i] = decode(data)
  605.             end
  606.         end
  607.     elseif frameType == 8 and not subtitles then
  608.         subtitles = {}
  609.         for _ = 1, nFrames do
  610.             local start, length, x, y, color, sz = ("<IIHHBxH"):unpack(file.read(16))
  611.             local text = file.read(sz)
  612.             local sub = {text, hexstr:sub(bit32.band(color, 15)+1, bit32.band(color, 15)+1):rep(#text),
  613.                 hexstr:sub(bit32.rshift(color, 4)+1, bit32.rshift(color, 4)+1):rep(#text), x = x, y = y}
  614.             for n = start, start + length - 1 do
  615.                 subtitles[n] = subtitles[n] or {}
  616.                 subtitles[n][#subtitles[n]+1] = sub
  617.             end
  618.         end
  619.     end
  620. end
  621. file.close()
  622. if not video then error("No video stream found") end
  623. sleep(0)
  624.  
  625. local speaker = peripheral.find "speaker"
  626. term.clear()
  627. local ok, err = pcall(parallel.waitForAll, function()
  628.     local start = os.epoch "utc"
  629.     for f, image in ipairs(video) do
  630.         for i, v in ipairs(image.palette) do term.setPaletteColor(2^(i-1), table.unpack(v)) end
  631.         for y, r in ipairs(image) do
  632.             term.setCursorPos(1, y)
  633.             term.blit(table.unpack(r))
  634.         end
  635.         if subtitles and subtitles[f-1] then
  636.             for _, v in ipairs(subtitles[f-1]) do
  637.                 term.setCursorPos(v.x, v.y)
  638.                 term.blit(table.unpack(v))
  639.             end
  640.         end
  641.         while os.epoch "utc" < start + (f + 1) / fps * 1000 do sleep(1 / fps) end
  642.     end
  643. end, function()
  644.     if not speaker or not speaker.playAudio or not audio then return end
  645.     for _, chunk in ipairs(audio) do
  646.         while not speaker.playAudio(chunk) do repeat local ev, sp = os.pullEvent("speaker_audio_empty") until sp == peripheral.getName(speaker) end
  647.     end
  648. end)
  649. for i = 0, 15 do term.setPaletteColor(2^i, term.nativePaletteColor(2^i)) end
  650. term.setBackgroundColor(colors.black)
  651. term.setTextColor(colors.white)
  652. term.setCursorPos(1, 1)
  653. term.clear()
  654. if not ok then printError(err) end
Add Comment
Please, Sign In to add comment