Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- startup.lua (sub-computer listener/player)
- local json = textutils
- local modem = peripheral.find("modem") or error("No modem found!")
- -- Load instrument name from file
- local function load_instrument()
- if not fs.exists("instrument.txt") then
- error("Missing instrument.txt!")
- end
- local file = fs.open("instrument.txt", "r")
- local instrument = file.readLine()
- file.close()
- return instrument
- end
- -- Instrument to port mapping
- local instrumentPorts = {
- gedeckt = 1000,
- steam_whistle = 1001,
- diapason = 1002,
- gamba = 1003,
- posaune = 1004,
- subbass = 1005,
- trompette = 1006,
- vox_humana = 1007,
- piccolo = 1008,
- nassard = 1009
- }
- -- Note color map
- local noteColors = {
- ["F#"] = colors.blue,
- ["F"] = colors.purple,
- ["E"] = colors.cyan,
- ["D#"] = colors.lightGray,
- ["D"] = colors.gray,
- ["C#"] = colors.pink,
- ["C"] = colors.lime,
- ["B"] = colors.yellow,
- ["A#"] = colors.lightBlue,
- ["A"] = colors.magenta,
- ["G#"] = colors.orange,
- ["G"] = colors.white,
- }
- -- Valid octave names and side mapping
- local validOctaves = { "lowest", "lower", "mid", "high", "highest" }
- local octaveSides = {
- lowest = "right",
- lower = "left",
- mid = "front",
- high = "back",
- highest = "bottom"
- }
- -- Clamp invalid octaves
- local function clamp_octave(octave)
- for _, valid in ipairs(validOctaves) do
- if valid == octave then
- return octave
- end
- end
- print("[WARN] Invalid octave: " .. tostring(octave) .. ", clamping to 'mid'")
- return "mid"
- end
- -- Bundled redstone note player
- function play_notes(notes)
- print("[PLAYBACK] Playing notes via bundled redstone...")
- for _, note in ipairs(notes) do
- local color = noteColors[note.note]
- local side = octaveSides[clamp_octave(note.octave)]
- local delay = tonumber(note.start) or 0
- local duration = tonumber(note.duration) or 0.25
- if color and side then
- sleep(delay)
- redstone.setBundledOutput(side, color)
- sleep(duration)
- redstone.setBundledOutput(side, 0)
- else
- print("[WARN] Skipping invalid note: " .. tostring(note.note))
- end
- end
- end
- -- Init
- local instrument = load_instrument()
- local port = instrumentPorts[instrument]
- if not port then error("Invalid instrument: " .. tostring(instrument)) end
- modem.open(port)
- print("[LISTENING] " .. instrument .. " on port " .. port)
- if not fs.exists("songs") then fs.makeDir("songs") end
- -- Event loop
- while true do
- local event, side, sender, replyPort, message, distance = os.pullEvent("modem_message")
- if type(message) == "table" and message.type then
- if message.type == "song_data" and message.instrument == instrument then
- local path = "songs/" .. message.title .. ".json"
- local file = fs.open(path, "w")
- file.write(json.serialize(message))
- file.close()
- print("[RECEIVED] Saved song: " .. message.title)
- elseif message.type == "play_request" and message.title then
- local path = "songs/" .. message.title .. ".json"
- if fs.exists(path) then
- local file = fs.open(path, "r")
- local songData = json.unserialize(file.readAll())
- file.close()
- if songData.instrument == instrument then
- local now = os.time()
- local start_at = message.start_at or now
- local wait = start_at - now
- if wait > 0 then
- print(string.format("[SYNC] Waiting %.2f seconds to start...", wait))
- sleep(wait)
- end
- play_notes(songData.notes)
- end
- else
- print("[WARN] Song not found: " .. message.title)
- end
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement