mirror of
https://github.com/LDDestroier/CC/
synced 2025-02-02 04:09:09 +00:00
Create nbs5.lua
This commit is contained in:
parent
9a7b094003
commit
8f23fa9a3a
303
nbs5.lua
Normal file
303
nbs5.lua
Normal file
@ -0,0 +1,303 @@
|
||||
--[[
|
||||
NoteBlock Song API
|
||||
by MysticT
|
||||
Twekaed by Soni
|
||||
Modified for NBS v5 by LDDestroier (WIP)
|
||||
--]]
|
||||
|
||||
local nbs5 = {}
|
||||
|
||||
-- yield to avoid error
|
||||
local function yield()
|
||||
os.queueEvent("yield")
|
||||
os.pullEvent("yield")
|
||||
end
|
||||
|
||||
-- read short integer (16-bit) from file
|
||||
local function readShort(file)
|
||||
return file.read() + file.read() * 256
|
||||
end
|
||||
_G.readShort = readShort
|
||||
|
||||
|
||||
-- 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, c = ""
|
||||
local len = readInt(file)
|
||||
for i = 1, len do
|
||||
c = file.read()
|
||||
if not c then
|
||||
break
|
||||
end
|
||||
s = s .. string.char(c)
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function makeBitNum(num, bytes)
|
||||
local output = ""
|
||||
for i = 0, bytes - 1 do
|
||||
output = output .. string.char(bit32.band(bit32.rshift(num, i * 8), 0xFF))
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
-- write short integer (16-bit) to file
|
||||
local function writeShort(file, int)
|
||||
file.write(makeBitNum(int, 2))
|
||||
end
|
||||
|
||||
-- write integer (32-bit) to file
|
||||
local function writeInt(file, int)
|
||||
file.write(makeBitNum(int, 4))
|
||||
end
|
||||
|
||||
-- write string to file
|
||||
local function writeString(file, str)
|
||||
writeInt(file, #str)
|
||||
file.write(str)
|
||||
end
|
||||
|
||||
-- read nbs file header
|
||||
local function readNBSHeader(file)
|
||||
local header = {}
|
||||
header.lenght = readShort(file)
|
||||
if header.lenght > 0 then
|
||||
-- old NBS
|
||||
header.nbs_version = 0
|
||||
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)
|
||||
|
||||
else
|
||||
-- NBS v5
|
||||
header.nbs_version = file.read()
|
||||
header.vanilla_instruments = file.read()
|
||||
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)
|
||||
header.looping = file.read()
|
||||
header.max_looping = file.read()
|
||||
header.loop_start = readShort(file)
|
||||
|
||||
end
|
||||
|
||||
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
|
||||
tSong[#tSong + 1] = {}
|
||||
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
|
||||
write(".")
|
||||
local instrument = file.read() + 1
|
||||
if instrument > 16 then
|
||||
return nil, "(v5) Can't convert custom instruments"
|
||||
end
|
||||
|
||||
local note = file.read() - 33
|
||||
local velocity = file.read()
|
||||
local pan = file.read()
|
||||
local pitch_mod = readShort(file)
|
||||
|
||||
if note < 0 or note > 24 then
|
||||
return nil, "(v5) Notes must be in Minecraft's 2 octaves (" .. note .. ")"
|
||||
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 nbs5.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
|
||||
|
||||
-- save a song as an NBS v5 file
|
||||
function nbs5.saveSongNBS(tSong, sPath)
|
||||
|
||||
end
|
||||
|
||||
-- load and convert an .nbs file and save it
|
||||
function nbs5.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.header = header
|
||||
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
|
||||
|
||||
if header.nbs_version == 0 then
|
||||
|
||||
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
|
||||
insts[#insts + 1] = {
|
||||
name = readString(file),
|
||||
file = readString(file),
|
||||
pitch = file.read() + 0,
|
||||
key = (file.read() + 0) ~= 0
|
||||
}
|
||||
end
|
||||
tSong.instruments = insts
|
||||
end)
|
||||
|
||||
else
|
||||
|
||||
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),
|
||||
lock = file.read(),
|
||||
volume = file.read(),
|
||||
pan = file.read()
|
||||
})
|
||||
end
|
||||
tSong.layers = layers
|
||||
|
||||
local insts = {}
|
||||
for i=1, file.read() + 0 do
|
||||
insts[#insts + 1] = {
|
||||
name = readString(file),
|
||||
file = readString(file),
|
||||
pitch = file.read() + 0,
|
||||
key = (file.read() + 0) ~= 0
|
||||
}
|
||||
end
|
||||
tSong.instruments = insts
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
file.close()
|
||||
|
||||
return tSong
|
||||
end
|
||||
|
||||
return nil, "Error opening file "..sPath
|
||||
|
||||
end
|
||||
|
||||
return nbs5
|
Loading…
Reference in New Issue
Block a user