forked from hkc/cc-stuff
84 lines
2.5 KiB
Lua
84 lines
2.5 KiB
Lua
|
|
||
|
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
|