local url = "wss://kc.is.being.pet/ws" local screen = peripheral.wrap("monitor_1") local speakers = { l = peripheral.wrap("speaker_1"), r = peripheral.wrap("speaker_0"), } local ws = assert(http.websocket(url)) local function parse_u16(data) local v = table.remove(data, 1) v = bit.bor(v, bit.blshift(table.remove(data, 1), 8)) return v, data end local metadata_pkt = ws.receive() metadata_pkt = { string.byte(metadata_pkt, 1, #metadata_pkt) } local framerate = table.remove(metadata_pkt, 1) local n_channels = table.remove(metadata_pkt, 1) local sample_rate, data = parse_u16(metadata_pkt) local screen_w, data = parse_u16(data) local screen_h, data = parse_u16(data) local samples_per_frame = math.floor(sample_rate / framerate) print(string.format("FPS: %d", framerate)) print(string.format("Audio: %d channels, %d Hz", n_channels, sample_rate)) print(string.format("Video: %dx%d", screen_w, screen_h)) print(string.format("S/F: %d", samples_per_frame)) local function decode_s8(buf) local buffer = {} for i = 1, #buf do local v = buf[i] if bit32.band(v, 0x80) then v = bit32.bxor(v, 0x7F) - 128 end table.insert(buffer, v) table.insert(buffer, v) end return buffer end local function mkSpeakerCoro(p, b) return function() while not p.playAudio(b) do os.pullEvent("speaker_audio_empty") end end end while true do local video_pkt = ws.receive() local channels = { l = {}, r = {} } local offset = 1 channels.l = decode_s8({ string.byte(video_pkt, offset, offset + samples_per_frame - 1) }) offset = offset + samples_per_frame channels.r = decode_s8({ string.byte(video_pkt, offset, offset + samples_per_frame - 1) }) offset = offset + samples_per_frame for y = 1, screen_h do local tx, bg, fg = {}, {}, {} for x = 1, screen_w do table.insert(tx, string.sub(video_pkt, offset, offset)) local color = string.byte(video_pkt, offset + 1, offset + 1) table.insert(bg, string.format("%x", bit.brshift(color, 4))) table.insert(fg, string.format("%x", bit.band(color, 0xF))) offset = offset + 2 end screen.setCursorPos(1, y) screen.blit(table.concat(tx), table.concat(bg), table.concat(fg)) end for i = 1, 16 do local r, g, b = string.byte(video_pkt, offset, offset + 3) screen.setPaletteColor(bit.blshift(1, i - 1), bit.bor(bit.bor(bit.blshift(r, 16), bit.blshift(g, 8)), b)) offset = offset + 3 end parallel.waitForAll( mkSpeakerCoro(speakers.l, channels.l), mkSpeakerCoro(speakers.r, channels.r)) end