UNPKG

nbs-reader

Version:

This package is a library that processes Note Block Studio nbs files in Note.js.

242 lines (238 loc) 8.05 kB
var fs = require("fs"); function decodeText(octets) { var string = ""; var i = 0; while (i < octets.length) { var octet = octets[i]; var bytesNeeded = 0; var codePoint = 0; if (octet <= 0x7F) { bytesNeeded = 0; codePoint = octet & 0xFF; } else if (octet <= 0xDF) { bytesNeeded = 1; codePoint = octet & 0x1F; } else if (octet <= 0xEF) { bytesNeeded = 2; codePoint = octet & 0x0F; } else if (octet <= 0xF4) { bytesNeeded = 3; codePoint = octet & 0x07; } if (octets.length - i - bytesNeeded > 0) { var k = 0; while (k < bytesNeeded) { octet = octets[i + k + 1]; codePoint = (codePoint << 6) | (octet & 0x3F); k += 1; } } else { codePoint = 0xFFFD; bytesNeeded = octets.length - i; } string += String.fromCodePoint(codePoint); i += bytesNeeded + 1; } return string }; module.exports = ((path) => { var pos = 0; var _; var Get = (Data, Byte, Little, Converter) => { var out = Data.substring(pos, pos + (Byte * 2)); if (Little) out = out.match(/.{2}/g).reverse().join(""); pos += Byte * 2; if (!Converter) return out; else return Converter(out); } var Int = (Data) => parseInt(Data, 16); var Chars = (Data) => { if (Data.length == 0) return ""; return decodeText(new Uint8Array(Data.match(/.{2}/g).map(x => parseInt(x, 16)))); } var GetNbsChar = (Data) => { var len = Get(Data, 4, true, Int); return Get(Data, len, false, Chars); }; var ReadByte = (Data) => Get(Data, 1, true, Int); var data = fs.readFileSync(path) var hex = data.toString("hex").toUpperCase(); var length = Get(hex, 2, true, Int); function opennbs() { var nbs = { OpenNbs: true, Version: ReadByte(hex), VanillaInstruments: ReadByte(hex), Length: Get(hex, 2, true, Int), Layers: Get(hex, 2, true, Int), SongName: GetNbsChar(hex), SongAuthor: GetNbsChar(hex), OriginalAuthor: GetNbsChar(hex), Description: GetNbsChar(hex), Tempo: Get(hex, 2, true, Int) / 100, AutoSave: { Enable: new Boolean(ReadByte(hex)), Duration: ReadByte(hex) }, TimeSignature: ReadByte(hex), MinutesSpent: Get(hex, 4, true, Int), LeftClicks: Get(hex, 4, true, Int), RightClicks: Get(hex, 4, true, Int), BlocksAdded: Get(hex, 4, true, Int), BlocksRemoved: Get(hex, 4, true, Int), FileName: GetNbsChar(hex), Loop: { Enable: new Boolean(ReadByte(hex)), Count: ReadByte(hex), StartTick: Get(hex, 2, true, Int) }, Notes: [], CustomInstruments: [] }; var notes = []; var tick = -1; var layernotes = {}; while (true) { var jumps = Get(hex, 2, true, Int); if (jumps == 0) { break; } else if (jumps > 1) { for (var i = 0; i < jumps - 1; i++) { notes[tick + i + 1] = []; } } tick += jumps; var layer = -1; while (true) { jumps = Get(hex, 2, true, Int); if (jumps == 0) { break; } layer += jumps; var note = { Tick: tick, Layer: layer, Inst: ReadByte(hex), Key: ReadByte(hex), Velocity: ReadByte(hex), Panning: ReadByte(hex), Pitch: Get(hex, 2, true, Int) }; if (notes[tick]) notes[tick].push(note); else notes[tick] = [note]; if (layer < nbs.Layers) if (layernotes[layer]) layernotes[layer][tick] = note; else { layernotes[layer] = {}; layernotes[layer][tick] = note; } } } var layers = nbs.Layers; nbs.Layers = []; for (var i = 0; i < layers; i++) { var layer = { Name: GetNbsChar(hex), Locked: new Boolean(ReadByte(hex)), Volume: ReadByte(hex), Panning: ReadByte(hex), Notes: layernotes[i] }; nbs.Layers.push(layer); } nbs.Notes = notes; var len = ReadByte(hex); for (var i = 0; i < len; i++) { nbs.CustomInstruments.push({ Name: GetNbsChar(hex), FileName: GetNbsChar(hex), Pitch: ReadByte(hex), PressKey: new Boolean(ReadByte(hex)) }); } return nbs; } if (length == 0) return opennbs(); var nbs = { OpenNbs: false, Version: 0, VanillaInstruments: 10, Length: length + 1, Layers: Get(hex, 2, true, Int), SongName: GetNbsChar(hex), SongAuthor: GetNbsChar(hex), OriginalAuthor: GetNbsChar(hex), Description: GetNbsChar(hex), Tempo: Get(hex, 2, true, Int) / 100, AutoSave: { Enable: new Boolean(ReadByte(hex)), Duration: ReadByte(hex) }, TimeSignature: ReadByte(hex), MinutesSpent: Get(hex, 4, true, Int), LeftClicks: Get(hex, 4, true, Int), RightClicks: Get(hex, 4, true, Int), BlocksAdded: Get(hex, 4, true, Int), BlocksRemoved: Get(hex, 4, true, Int), FileName: GetNbsChar(hex), Loop: { Enable: false, Count: 0, StartTick: 0 }, Notes: [], CustomInstruments: [] } var notes = []; var tick = -1; var jumps = 0; var layernotes = {}; while (true) { jumps = Get(hex, 2, true, Int); if (jumps == 0) { break; } else if (jumps > 1) { for (var i = 0; i < jumps - 1; i++) { notes[tick + i + 1] = []; } } tick += jumps; var layer = -1; while (true) { jumps = Get(hex, 2, true, Int); if (jumps == 0) { break; } layer += jumps; var note = { Tick: tick, Layer: layer, Inst: ReadByte(hex), Key: ReadByte(hex), Velocity: 100, Panning: 100, Pitch: 0 }; if (notes[tick]) notes[tick].push(note); else notes[tick] = [note]; if (layer < nbs.Layers) if (layernotes[layer]) layernotes[layer][tick] = note; else { layernotes[layer] = {}; layernotes[layer][tick] = note; } } } var layers = nbs.Layers; nbs.Layers = []; for (var i = 0; i < layers; i++) { var layer = { Name: GetNbsChar(hex), Volume: ReadByte(hex), Notes: layernotes[i] }; nbs.Layers.push(layer); } nbs.Notes = notes; var len = ReadByte(hex); for (var i = 0; i < len; i++) { nbs.CustomInstruments.push({ Name: GetNbsChar(hex), FileName: GetNbsChar(hex), Pitch: ReadByte(hex), PressKey: new Boolean(ReadByte(hex)) }); } return nbs; });