Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- **********************
- NBS file reader using the AdvancedNoteBlock from LIP, this is created by Clem105 for treasure disk , all credits goes to MysticT and Soni for the nbs decoding API, original link : https://github.com/SoniEx2/NBSPlayer/blob/master/nbs.lua
- **********************
- ]]--
- -- yield to avoid error
- local function yield()
- os.queueEvent("fake")
- os.pullEvent("fake")
- end
- -- read short integer (16-bit) from file
- local function readShort(file)
- return file.read() + file.read() * 256
- end
- -- read integer (32-bit) from file
- local function readInt(file)
- return file.read() + file.read() * 256 + file.read() * 65536 + file.read() * 16777216
- end
- -- read string from file
- local function readString(file)
- local s = ""
- local len = readInt(file)
- for i = 1, len do
- local c = file.read()
- if not c then
- break
- end
- s = s..string.char(c)
- end
- return s
- end
- -- read nbs file header
- local function readNBSHeader(file)
- local header = {}
- header.lenght = readShort(file)
- header.height = readShort(file)
- header.name = readString(file)
- if header.name == "" then
- header.name = "Untitled"
- end
- header.author = readString(file)
- if header.author == "" then
- header.author = "Unknown"
- end
- header.original_author = readString(file)
- if header.original_author == "" then
- header.original_author = "Unknown"
- end
- header.description = readString(file)
- header.tempo = readShort(file) / 100
- header.autosave = file.read()
- header.autosave_duration = file.read()
- header.time_signature = file.read()
- header.minutes_spent = readInt(file)
- header.left_clicks = readInt(file)
- header.right_clicks = readInt(file)
- header.blocks_added = readInt(file)
- header.blocks_removed = readInt(file)
- header.filename = readString(file)
- return header
- end
- -- jump to the next tick in the file
- local function nextTick(file, tSong)
- local jump = readShort(file)
- for i = 1, jump - 1 do
- table.insert(tSong, {})
- end
- return jump > 0
- end
- -- read the notes in a tick
- -- TODO cleanup, move checks to player:nbs.lua
- local function readTick(file)
- local t = {}
- local n = 0
- local jump = readShort(file)
- while jump > 0 do
- n = n + jump
- local instrument = file.read() + 1
- if instrument > 7 then -- Soni: we actually support 7 instruments
- return nil, "Can't convert custom instruments"
- end
- local note = file.read() - 33
- if note < 0 or note > 24 then
- return nil, "Notes must be in Minecraft's 2 octaves"
- end
- if not t[instrument] then
- t[instrument] = {}
- end
- t[instrument][n] = note
- jump = readShort(file)
- end
- return t
- end
- -- API functions
- -- save a converted song to a file
- function saveSong(tSong, sPath)
- local file = fs.open(sPath, "w")
- if file then
- file.write(textutils.serialize(tSong))
- file.close()
- return true
- end
- return false, "Error opening file "..sPath
- end
- -- load and convert an .nbs file and save it
- function load(sPath, bVerbose)
- local file = fs.open(sPath, "rb")
- if file then
- if bVerbose then
- print("Reading header...")
- end
- local tSong = {}
- local header = readNBSHeader(file)
- tSong.name = header.name
- tSong.author = header.author
- tSong.original_author = header.original_author
- tSong.lenght = header.lenght / header.tempo
- tSong.delay = 1 / header.tempo
- if bVerbose then
- print("Reading ticks...")
- end
- while nextTick(file, tSong) do
- local tick, err = readTick(file, tSong)
- if tick then
- table.insert(tSong, tick)
- else
- file.close()
- return nil, err
- end
- yield()
- end
- pcall(function()
- local layers = {}
- for i=1, header.height do
- table.insert(layers, {name=readString(file), volume=file.read() + 0})
- end
- tSong.layers = layers
- local insts = {}
- for i=1, file.read() + 0 do
- table.insert(insts, {name=readString(file), file=readString(file), pitch=file.read() + 0, key=(file.read() + 0) ~= 0})
- end
- tSong.instruments = insts
- end)
- file.close()
- return tSong
- end
- return nil, "Error opening file "..sPath
- end
- tArgs = {...}
- Files = {}
- sSong = {}
- if #tArgs == 0 then
- error("Usage : >NBSPlayer <Advanced NoteBlockSide> <NbsFile or Nil>")
- elseif peripheral.getType(tArgs[1]) ~= "AdvancedNoteBlock" then
- error("Not finding an AdvancedBlockNote at "..tArgs[1])
- elseif tArgs[2] ~= nil and not fs.exists(tArgs[2]) then
- error("Not finding the corresponding file/directory")
- end
- if not tArgs[2] then
- Files = fs.find("*.nbs")
- for o=1,#Files do
- sSong[o] = load(Files[o])
- end
- else
- sSong[1] = load(tArgs[2])
- end
- nb = peripheral.wrap(tostring(tArgs[1]))
- for o,_ in ipairs(sSong) do
- term.clear()
- delay = sSong[o].delay
- term.setCursorPos(28,8)
- term.write(sSong[o].name)
- term.setCursorPos(20,10)
- term.write("Arranged by "..sSong[o].author)
- term.setCursorPos(16,12)
- term.write("Originally created by "..sSong[o].original_author)
- startTime = os.clock()
- for index,v in ipairs(sSong[o]) do
- if v ~= {} then
- for intstr,tab in ipairs(v) do
- nb.setInstrument(instr)
- for _,note in pairs(tab) do
- nb.setPitch(note)
- nb.triggerNote()
- end
- end
- end
- sleep(delay)
- end
- end
Add Comment
Please, Sign In to add comment