chipmunkbot3/util/nbs-file.js
2024-02-11 21:23:41 -05:00

170 lines
3.5 KiB
JavaScript

// const fs = require('fs')
// const path = require('path')
// const instrumentNames = require('./instrument-names.json')
function parse (buf) {
// const buf = fs.readFileSync(filepath)
let i = 0
let songLength = 0
let format = 0
let vanillaInstrumentCount = 0
songLength = readShort()
if (songLength === 0) {
format = readByte()
}
if (format >= 1) {
vanillaInstrumentCount = readByte()
}
if (format >= 3) {
songLength = readShort()
}
const layerCount = readShort()
const songName = readString()
const songAuthor = readString()
const songOriginalAuthor = readString()
const songDescription = readString()
const tempo = readShort()
const autoSaving = readByte()
const autoSavingDuration = readByte()
const timeSignature = readByte()
const minutesSpent = readInt()
const leftClicks = readInt()
const rightClicks = readInt()
const blocksAdded = readInt()
const blocksRemoved = readInt()
const origFileName = readString()
let loop = 0
let maxLoopCount = 0
let loopStartTick = 0
if (format >= 4) {
loop = readByte()
maxLoopCount = readByte()
loopStartTick = readShort()
}
const nbsNotes = []
let tick = -1
while (true) {
const tickJumps = readShort()
if (tickJumps === 0) break
tick += tickJumps
let layer = -1
while (true) {
const layerJumps = readShort()
if (layerJumps === 0) break
layer += layerJumps
const note = NBSNote()
note.tick = tick
note.layer = layer
note.instrument = readByte()
note.key = readByte()
if (format >= 4) {
note.velocity = readByte()
note.panning = readByte()
note.pitch = readShort()
}
nbsNotes.push(note)
}
}
const nbsLayers = []
if (i <= buf.length) {
for (let j = 0; j < layerCount; j++) {
const layer = NBSLayer()
layer.name = readString()
if (format >= 4) {
layer.lock = readByte()
}
layer.volume = readByte()
if (format >= 2) {
layer.stereo = readByte()
}
nbsLayers.push(layer)
}
}
return {
songLength,
format,
vanillaInstrumentCount,
layerCount,
songName,
songAuthor,
songOriginalAuthor,
songDescription,
tempo,
autoSaving,
autoSavingDuration,
timeSignature,
minutesSpent,
leftClicks,
rightClicks,
blocksAdded,
blocksRemoved,
origFileName,
loop,
maxLoopCount,
loopStartTick,
nbsNotes,
nbsLayers
}
function readByte () {
return buf.readInt8(i++)
}
function readShort () {
const byte1 = buf.readUint8(i++)
const byte2 = buf.readUint8(i++)
return (byte1 + (byte2 << 8))
}
function readInt () {
const byte1 = buf.readUint8(i++)
const byte2 = buf.readUint8(i++)
const byte3 = buf.readUint8(i++)
const byte4 = buf.readUint8(i++)
return (byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24))
}
function readString () {
let length = readInt()
let str = ''
for (; length > 0; --length) {
let c = String.fromCharCode(readByte())
if (c === String.fromCharCode(0x0D)) {
c = ' '
}
str += c
}
return str
}
}
function NBSNote () {
return {
tick: null,
layer: null,
instrument: null,
key: null,
velocity: 100,
panning: 100,
pitch: 0
}
}
function NBSLayer () {
return {
name: null,
lock: 0,
volume: null,
stereo: 100
}
}
module.exports = { parse, NBSNote, NBSLayer }