Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local pcmURL = "https://files.catbox.moe/5crejb.raw"
- local bmpURL = "https://files.catbox.moe/llki61.bmp"
- local bmpFilename = "image.bmp"
- local isUnsigned = false
- local inputSampleRate = 40000
- local outputSampleRate = 48000
- local volume = 0.1
- local graphicsMode = 2
- local function downloadBMP(url, filename)
- if not http then error("HTTP API not enabled!") end
- local r = http.get(url, nil, true)
- if not r then error("Failed to download image") end
- local f = fs.open(filename, "wb")
- local c = r.readAll()
- for i = 1, #c, 8192 do f.write(c:sub(i, i + 8191)) end
- f.close() r.close()
- end
- local function readBMP(filename)
- local file = fs.open(filename, "rb")
- if not file then return nil, "Failed to open file" end
- local header = file.read(54)
- local width = string.byte(header, 19) + string.byte(header, 20) * 256
- local height = string.byte(header, 23) + string.byte(header, 24) * 256
- local pixels = {}
- for y = height, 1, -1 do
- pixels[y] = {}
- for x = 1, width do
- local b = file.read(1) local g = file.read(1) local r = file.read(1)
- pixels[y][x] = {r = string.byte(r), g = string.byte(g), b = string.byte(b)}
- end
- end
- file.close()
- return {width = width, height = height, pixels = pixels}
- end
- local function resizeImage(image, newWidth, newHeight)
- local resized = {width = newWidth, height = newHeight, pixels = {}}
- for y = 1, newHeight do
- resized.pixels[y] = {}
- for x = 1, newWidth do
- local srcX = math.floor(x * image.width / newWidth)
- local srcY = math.floor(y * image.height / newHeight)
- resized.pixels[y][x] = image.pixels[srcY][srcX]
- end
- end
- return resized
- end
- local function displayBMPCraftOSPC(image, output, colorMode)
- local screenWidth, screenHeight = output.getSize()
- local imageWidth, imageHeight = image.width, image.height
- local originalPalette = {}
- for i = 0, 255 do originalPalette[i] = {term.getPaletteColor(i)} end
- local originalGraphicsMode = term.getGraphicsMode()
- term.setGraphicsMode(colorMode)
- if colorMode == 2 then
- local cubeSize = 5
- for i = 16, 255 do
- local index = i - 16
- local rIndex = math.floor(index / (cubeSize * cubeSize))
- local gIndex = math.floor((index % (cubeSize * cubeSize)) / cubeSize)
- local bIndex = index % cubeSize
- local r = math.floor(rIndex * 255 / (cubeSize - 1))
- local g = math.floor(gIndex * 255 / (cubeSize - 1))
- local b = math.floor(bIndex * 255 / (cubeSize - 1))
- term.setPaletteColor(i, r / 255, g / 255, b / 255)
- end
- end
- local function adjustBrightness(v) return math.min(255, math.max(0, math.floor(v * 1.2))) end
- local function mapColor(r, g, b)
- r, g, b = adjustBrightness(r), adjustBrightness(g), adjustBrightness(b)
- if colorMode == 2 then
- local cubeSize = 5
- local rIndex = math.floor(r / (255 / (cubeSize - 1)))
- local gIndex = math.floor(g / (255 / (cubeSize - 1)))
- local bIndex = math.floor(b / (255 / (cubeSize - 1)))
- return 16 + rIndex * cubeSize * cubeSize + gIndex * cubeSize + bIndex
- else
- return colors.white
- end
- end
- for y = 0, screenHeight * 9 - 1 do
- for x = 0, screenWidth * 6 - 1 do
- local sourceX = math.floor(x * imageWidth / (screenWidth * 6))
- local sourceY = math.floor(y * imageHeight / (screenHeight * 9))
- local pixel = image.pixels[sourceY + 1][sourceX + 1]
- local color = mapColor(pixel.r, pixel.g, pixel.b)
- output.setPixel(x, y, color)
- end
- end
- print("Image displayed. Press any key to continue.")
- os.pullEvent("key")
- term.setGraphicsMode(originalGraphicsMode)
- for i = 0, 255 do term.setPaletteColor(i, table.unpack(originalPalette[i])) end
- term.setBackgroundColor(colors.black) term.setTextColor(colors.white) term.clear() term.setCursorPos(1, 1)
- end
- local function downloadAndResamplePCM(url, isUnsigned, inputRate, outputRate)
- print("Downloading and resampling PCM audio...")
- local response = http.get(url, nil, true)
- if not response then error("Failed to download PCM file") end
- local raw = response.readAll()
- response.close()
- local inSamples = {}
- for i = 1, #raw do
- local b = string.byte(raw, i)
- if isUnsigned then b = b - 128 end
- inSamples[#inSamples + 1] = b
- end
- local outSamples = {}
- local ratio = inputRate / outputRate
- for i = 1, math.floor(#inSamples / ratio) do
- local src = (i - 1) * ratio + 1
- local idx = math.floor(src)
- local frac = src - idx
- local s1 = inSamples[idx] or 0
- local s2 = inSamples[idx + 1] or s1
- outSamples[i] = s1 + (s2 - s1) * frac
- end
- return outSamples
- end
- local function playPCMBufferLoop(speaker, buffer, volume)
- local chunkSize = 16384
- while true do
- local played = 0
- while played < #buffer do
- local chunk = {}
- for i = 1, chunkSize do
- local idx = played + i
- if idx > #buffer then break end
- local sample = math.floor(buffer[idx] * volume + 0.5)
- if sample > 127 then sample = 127 end
- if sample < -128 then sample = -128 end
- chunk[i] = sample
- end
- if #chunk == 0 then break end
- while not speaker.playAudio(chunk) do
- os.pullEvent("speaker_audio_empty")
- end
- played = played + #chunk
- end
- end
- end
- local function audioTask()
- local speaker = peripheral.find("speaker")
- if not speaker then print("No speaker attached!") return end
- local buffer = downloadAndResamplePCM(pcmURL, isUnsigned, inputSampleRate, outputSampleRate)
- playPCMBufferLoop(speaker, buffer, volume)
- end
- local function imageTask()
- downloadBMP(bmpURL, bmpFilename)
- local image, err = readBMP(bmpFilename)
- if not image then print("BMP error:", err) return end
- if term.setGraphicsMode then
- displayBMPCraftOSPC(image, term, graphicsMode)
- else
- print("CraftOS-PC Graphics Mode not supported")
- end
- end
- parallel.waitForAny(audioTask, imageTask)
Add Comment
Please, Sign In to add comment