Advertisement
ozozx235

nbsPlayer.lua

Mar 30th, 2024
692
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.83 KB | None | 0 0
  1. function readBool(bin, i)
  2.     bool = string.byte(bin,i) == 1
  3.     return i+1, bool
  4. end
  5.  
  6. function readInt(bin, i, prog)
  7.     buffer = 0
  8.     for j=1,prog do
  9.         -- print(buffer)
  10.         buffer = string.byte(bin,i+j-1)*math.pow(16,2*(j-1)) + buffer
  11.     end
  12.     -- print(i..": Int("..buffer..")")
  13.     return i+prog, buffer
  14. end
  15.  
  16. function readByte(bin, i, prog)
  17.     for j=1,prog do
  18.         -- print(buffer)
  19.         buffer = buffer .. " " .. string.byte(bin,i+j-1)
  20.     end
  21.     return i+prog, buffer
  22. end
  23.  
  24. function readStr(bin, i)
  25.     i, prog = readInt(bin, i, 4)
  26.     buffer = ""
  27.     -- print(i..": "..prog)
  28.     -- print(prog)
  29.     for j=1,prog do
  30.         buffer = buffer .. "" .. string.char(string.byte(bin,i+j-1))
  31.     end
  32.     return i+prog, buffer
  33. end
  34.  
  35. function skip(bin, i, prog)
  36.     return i+prog
  37. end
  38.  
  39. function readHeader(bin, i)
  40.     i = skip(bin, i, 2)
  41.     i, ver = readInt(bin, i, 1)
  42.     -- print("NBS Version: " .. ver)
  43.     i, vanInst = readInt(bin, i, 1)
  44.     -- print("Number of Vanilla Instruments: " .. vanInst)
  45.     i, tikLen = readInt(bin, i, 2)
  46.     -- print("Length in Ticks: " .. tikLen)
  47.     i, lyr = readInt(bin, i, 2)
  48.     -- print("Number of Layers (inaccurate): " .. lyr)
  49.     -- print("SNAME")
  50.     i, sName = readStr(bin, i)
  51.     -- print("Song Name: " .. sName)
  52.     -- print("ANAME")
  53.     i, authName = readStr(bin, i)
  54.     -- print("Author: " .. authName)
  55.     -- print("OGANAME")
  56.     i, ogAuthName = readStr(bin, i)
  57.     -- print("Original Author: " .. ogAuthName)
  58.     -- print("DESC")
  59.     i, desc = readStr(bin, i)
  60.     -- print("Description: " .. desc)
  61.     i, tempo = readInt(bin, i, 2)
  62.     -- print("Tempo (Ticks/Sec)*100: " .. tempo)
  63.     i, aSave = readBool(bin, i)
  64.     -- print("Auto-Save?: " .. (aSave and "Yes" or "No"))
  65.     i, aSaveT = readInt(bin, i, 1)
  66.     -- print("Auto-Save Time: " .. aSaveT)
  67.     i, tSign = readInt(bin, i, 1)
  68.     -- print("Time Signature:0 "..tSign.."/4")
  69.     i, minSpent = readInt(bin, i, 4)
  70.     -- print("Minutes Spent On Project: " .. minSpent)
  71.     i, lClick = readInt(bin, i, 4)
  72.     -- print("Left Clicks: " .. lClick)
  73.     i, rClick = readInt(bin, i, 4)
  74.     -- print("Right Clicks: " .. rClick)
  75.     i, nbAdd = readInt(bin, i, 4)
  76.     -- print("Noteblocks Added: " .. nbAdd)
  77.     i, nbRem = readInt(bin, i, 4)
  78.     -- print("Noteblocks Removed: " .. nbRem)
  79.     -- print("PORT")
  80.     i, port = readStr(bin, i)
  81.     -- print("Imported MIDI / Scematic File: " .. port)
  82.     i, loop = readBool(bin, i)
  83.     -- print("Looping?: " .. (loop and "Yes" or "No"))
  84.     i, mLoop = readInt(bin, i, 1)
  85.     -- print("Max Times Looped: " .. mLoop)
  86.     i, loopIdx = readInt(bin, i, 2)
  87.     -- print("Loop Start Tick: " .. loopIdx)
  88.     songHead = {version=ver, vInstruments=vanInst, tLength=tikLen,layerCount=lyr, songName=sName, chartAuthor=authName, songAuthor=ogAuthName, description=desc, tempo=tempo,autoSave=aSave,saveTime=aSaveT,timeSignature=tSign, minutesSpent=minSpent, leftClicks=lClick, rightClicks=rClick,notesAdded=nbAdd,notesRemoved=nbRem, importedFile=port, isLooping=loop,maxLoops=mLoop,loopStart=loopIdx}
  89.     return i, songHead
  90.    
  91. end
  92.  
  93. function readNote(bin, i, cft, idx, reps)
  94.     jumpNT = nil
  95.     if cft then
  96.         i, jumpNT = readInt(bin, i, 2)
  97.         -- print("Wait " .. jumpNT .. " Ticks")
  98.         if jumpNT == 0 then
  99.             return i, nil, false, idx
  100.         end
  101.     end
  102.     i, jumpNL = readInt(bin, i, 2)
  103.     if jumpNL == 0 and not cft then
  104.         -- print("prepare for pause")
  105.         return readNote(bin,i,true,idx,reps)
  106.     end
  107.     -- print(jumpNL .. " Jumps From Last Layer")
  108.     i, inst = readInt(bin, i, 1)
  109.     -- print("Instrument: " .. (inst < 16 and band[inst] or "Custom?"))
  110.     i, nKey = readInt(bin, i, 1)
  111.     -- print("Key: "..nKey)
  112.     i, vol = readInt(bin, i, 1)
  113.     -- print("Volume: "..vol .. "%")
  114.     i, stere = readInt(bin, i, 1)
  115.     -- print("Stereo Position: "..stere)
  116.     i, pit = readInt(bin, i, 2)
  117.     -- print("Pitch: "..pit)
  118.     note = {jumpTNNote = jumpNT, jumpTNLayer = jumpNL, instrument = inst, noteKey = nKey, volume = vol, stereo = stere, pitch = pit}
  119.     if reps > 1 then
  120.         return readNote(bin,i,false,idx+1,reps-1)
  121.     else
  122.         return i, note, false, idx+1
  123.     end
  124. end
  125.  
  126. function dec2hex(size, num)
  127.     hnum = string.format("%x",num)
  128.     op = hnum
  129.     if #hnum < size*2 then
  130.         for i=1, size*2-#hnum do
  131.             op = "0"..op
  132.         end
  133.     end
  134.     return op
  135. end-- REDUNDANT
  136.  
  137. function readBinaryNote(bin, i, cft, idx, reps)
  138.     jumpNT = nil
  139.     if cft then
  140.         i, jumpNT = readInt(bin, i, 2)
  141.         print(dec2hex(2,jumpNT) .. " Jumps From Last Note")
  142.     end
  143.     i, jumpNL = readInt(bin, i, 2)
  144.     if jumpNL == 0 and not cft then
  145.         print("prepare for pause")
  146.         return readBinaryNote(bin,i,true,idx,reps)
  147.     end
  148.     print(dec2hex(2,jumpNL) .. " Jumps From Last Layer")
  149.     i, inst = readInt(bin, i, 1)
  150.     print("Instrument: " .. dec2hex(1,inst))
  151.     i, nKey = readInt(bin, i, 1)
  152.     print("Key: "..dec2hex(1,nKey))
  153.     i, vol = readInt(bin, i, 1)
  154.     print("Volume: "..dec2hex(1,vol))
  155.     i, stere = readInt(bin, i, 1)
  156.     print("Stereo Position: "..dec2hex(1,stere))
  157.     i, pit = readInt(bin, i, 2)
  158.     print("Pitch: "..dec2hex(2,pit))
  159.     note = {jumpTNNote = jumpNT, jumpTNLayer = jumpNL, instrument = inst, noteKey = nKey, volume = vol, stereo = stere, pitch = pit}
  160.     if reps > 1 then
  161.         return readBinaryNote(bin,i,false,idx+1,reps-1)
  162.     else
  163.         return i, note, false, idx+1
  164.     end
  165. end-- REDUNDANT
  166.  
  167. function skipNotes(bin, i, cft, count, idx)
  168.     jumpNT = nil
  169.     if cft then
  170.         i, jumpNT = readInt(bin, i, 2)
  171.         if jumpNT == 0 then
  172.             -- print("ENDING")
  173.             -- print(idx)
  174.             return i, count, idx
  175.         else
  176.             -- print("JUMPED")
  177.             idx = idx + jumpNT
  178.         end
  179.     end
  180.     i, jumpNL = readInt(bin, i, 2)
  181.     if jumpNL == 0 and not cft then
  182.         return skipNotes(bin, i, true, count, idx)
  183.     end
  184.     i = skip(bin,i,6)
  185.     return skipNotes(bin, i, false, count+1, idx)
  186. end
  187.  
  188. function readLayer(bin, i, lIdex, reps)
  189.     i, lName = readStr(bin, i)
  190.     -- print(lName .. " layer")
  191.     i, lock = readBool(bin, i)
  192.     -- print((lock and "Layer locked" or "Layer Unlocked"))
  193.     i, vol = readInt(bin,i,1)
  194.     -- print("Layer Volume: " .. vol .. "%")
  195.     i, stere = readInt(bin,i,1)
  196.     -- print("Stereo Position: "..stere)
  197.     layer = {layerName=lName,isLocked=lock,volume=vol,stereo=stere}
  198.     if reps > 1 then
  199.         return readLayer(bin,i,lIdex+1,reps-1)
  200.     end
  201.     return i, layer, lIdex+1
  202. end
  203.  
  204. function skipLayers(bin, i, lIdex, count)
  205.     -- print(lIdex)
  206.     -- print("SKIPPING")
  207.     -- print(i)
  208.     -- print(readInt(bin,i, 4))
  209.     i = readStr(bin, i)
  210.     i = skip(bin, i, 3)
  211.     if lIdex+1 < header.layerCount then
  212.         return skipLayers(bin,i,lIdex+1,count+1)
  213.     end
  214.     return i, count+1, lIdex+1
  215. end
  216.  
  217. function readCustom(bin, i, cIdex, reps)
  218.     i, cName = readStr(bin, i)
  219.     -- print("Instrument: " .. cName)
  220.     i, cFile = readStr(bin, i)
  221.     -- print("Path: " .. cFile)
  222.     i, key = readInt(bin,i,1)
  223.     -- print("Default Key: " .. key)
  224.     i, vis = readBool(bin, i)
  225.     -- print((vis and "Visuallise" or "Don't Visuallise"))
  226.     custom = {CustomName=lName,filePath=cFile,defaultKey=key,isvisuallised=vis}
  227.     if reps > 1 then
  228.         return readCustom(bin,i,cIdex+1,reps-1)
  229.     end
  230.     return i, custom, cIdex+1
  231. end
  232.  
  233. function YNPrompt(str)
  234.     print(str)
  235.     ans=read()
  236.     if ans=="y" or ans =="Y" then
  237.         return true
  238.     elseif ans=="n" or ans=="N" then
  239.         return false
  240.     else
  241.         print("Invalid input")
  242.         return YNPrompt(str)
  243.     end
  244. end-- REDUNDANT
  245.  
  246. function validateFile(bin)
  247.     -- print("VALIDATING")
  248.     i, header = readHeader(bin, 1)
  249.     lyStart = skipNotes(bin, i, true, 0, 0)
  250.     -- print("lyStart: "..lyStart)
  251.     cuStart = skipLayers(bin, lyStart, 0, 0)
  252.     _, cInsts = readInt(bin, cuStart, 1)
  253.     if cInsts < 0 then
  254.         printError("Song Contains Custom Instruments (Unsupported)")
  255.         return nil, nil, nil
  256.     end
  257.     -- print("HEADER VALID")
  258.     j=i
  259.     cft = true
  260.     nIdx = 0
  261.     while j<lyStart do
  262.         -- print(j.."/"..lyStart)
  263.         j, note, cft, nIdx = readNote(bin, j, cft, nIdx, 1)
  264.         if note then
  265.             if note.noteKey > 57 or note.noteKey < 33 then
  266.                 printError("Notes are Keyed Outside of 2 Octave Spectrum at ".. nIdx .. " pitch " .. note.noteKey)
  267.                 -- printError(j.."/"..lyStart)
  268.                 return nil, nil, nil
  269.             end
  270.             if not note.stereo == 100 then
  271.                 printError("Stereo Unsupported")
  272.                 return nil, nil, nil
  273.             end
  274.             if not note.pitch == 0 then
  275.                 printError("Notes are Fine Pitched (Unsupported)")
  276.                 return nil, nil, nil
  277.             end
  278.         end
  279.     end
  280.     -- print("NOTES VALID")
  281.     -- print("scanning from byte: "..j.."/"..#bin)
  282.     layers = {}
  283.     lIdx = 1
  284.     while j<cuStart do
  285.         j, layers[lIdx], tlIdx = readLayer(bin,j, lIdx, 1)
  286.         if not layers[lIdx].stereo == 100 then
  287.             printError("Stereo Unsupported")
  288.             return nil, nil, nil
  289.         end
  290.         lIdx = tlIdx
  291.     end
  292.     -- print("VALIDATED")
  293.     return i, header, layers
  294. end
  295.  
  296. function findSpeak()
  297.     spk = nil
  298.     for k,v in pairs(peripheral.getNames()) do
  299.         if peripheral.getType(v) == "speaker" and not spk then
  300.             spk = peripheral.wrap(v)
  301.         end
  302.     end
  303.     return spk
  304. end
  305.  
  306. local tArgs = { ... }
  307. bin = nil
  308. -- print("RUNNING")
  309. if #tArgs<1 then
  310.         if fs.exists("/disk") then
  311.             flist = fs.list("/disk")
  312.             for k,v in pairs(flist) do
  313.                 if string.find(v,".nbs") then
  314.                     -- print(v)
  315.                     bin = fs.open("/disk/"..v,"rb").readAll()
  316.                 end
  317.             end
  318.             if not bin then
  319.                 print("No File Specified or on Disk")
  320.                 return
  321.             end
  322.         end
  323.         -- print("No File")
  324.         -- return
  325.     elseif not fs.exists(tArgs[1]) or (fs.exists(tArgs[1]) and fs.isDir(tArgs[1])) then
  326.         print("Not a File Bozo")
  327.         return
  328.     else
  329.         -- print(fs.getName(tArgs[1]) .. " Exists!")
  330.         bin = fs.open(tArgs[1],"rb").readAll()
  331. end
  332. -- print(#bin .. "b")
  333. i=1
  334. i, header, layers= validateFile(bin)
  335. if not i then
  336.     return
  337. end
  338. -- print("Notes start at offset " .. i)
  339. speak = findSpeak()
  340. if not speak then
  341.     printError("No Speaker Found")
  342.     return
  343. end
  344. notStart = i
  345. idex = 0
  346. mtnt = true
  347. lyStart = skipNotes(bin, i, mtnt, 0, 0)
  348. lIdex = 0
  349. -- cuStart = skipLayers(bin, lyStart, 0, 0)
  350. -- cIdex = 0
  351. -- cuStart, cInsts = readInt(bin, cuStart, 1)
  352. -- print(cInsts .. " Custom Instruments")
  353. print("Now Playing " .. header.songName .. " by " .. header.songAuthor)
  354. -- tick = true
  355. band = {[0]="harp", "bass", "basedrum", "snare", "hat", "guitar", "flute", "bell", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling"}
  356. -- print(layers[2].volume)
  357. -- print(7.5*(100/header.tempo))
  358. while i < lyStart do
  359.     i, note, mtnt, idex = readNote(bin, i, mtnt, idex, 1)
  360.     if note then
  361.         if note.jumpTNNote then
  362.             sleep((note.jumpTNNote)*(100/header.tempo))
  363.             lIdex = 0
  364.             -- print((tick and "tick" or "tock"))
  365.             -- tick = not tick
  366.         end
  367.         lIdex = lIdex + note.jumpTNLayer
  368.         -- print(lIdex)
  369.         vol = ((layers[lIdex].volume * note.volume)/10000)*3
  370.         speak.playNote(band[note.instrument],vol,note.noteKey-33)
  371.     end
  372. end
  373. print("Joever")
  374. -- print(bin.read())
  375. -- print(bin.readLine(true))
  376. -- bin.close()
  377.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
  378.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement