Skip to content

Commit

Permalink
A fully bug-fixed MII disassembler.
Browse files Browse the repository at this point in the history
  • Loading branch information
PoneyClairDeLune committed Jun 14, 2024
1 parent 8f44d02 commit a0c3ff5
Showing 1 changed file with 49 additions and 33 deletions.
82 changes: 49 additions & 33 deletions src/micc/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ ReadableStreamDefaultController.prototype.send = function (data) {
let streamDisassemble = function (source) {
let reader = source.getReader();
let totalPtr = 0, ptr = 0, ptrStart = 0, chunk;
let sectStart = 0, sectLength = 0;
let sectStart = 0, sectLength = 0, sectInfoReady = false;
let state = 0, strBuf = "",
nextState = 0, // transient state
finalState = 0, // final state to jump to
Expand All @@ -61,46 +61,59 @@ let streamDisassemble = function (source) {
while (controller.unsent) {
// Chunk read handling
if (!chunk || ptr >= chunk.length) {
console.debug(`[Reader] Reading a new chunk.`);
//console.info(`[Reader] Reading a new chunk.`);
let {value, done} = await reader.read();
if (chunk) {
totalPtr += chunk.length;
console.debug(`[Reader] Submitted the last chunk.`);
//console.info(`[Reader] Submitted the last chunk.`);
};
ptr = 0;
chunk = value;
if (done) {
console.debug(`[Reader] All chunks have been read.`);
//console.info(`[Reader] All chunks have been read.`);
controller.close();
return;
};
};
// Enforce restart
let realPtr = totalPtr + ptr;
// Read a byte
let e = chunk[ptr];
console.debug(`${`${e}`.padStart(3, "0")}-${e.toString(16).padStart(2, "0")}(${String.fromCharCode(Math.max(32, e))}) L: ${ptr - ptrStart}, S: ${ptrStart}, I: ${ptr}, TS: ${totalPtr + ptrStart}, TI: ${totalPtr + ptr}, TL: ${chunk.length} [${state}]`);
//console.info(`${`${e}`.padStart(3, "0")}-${e.toString(16).padStart(2, "0")}(${String.fromCharCode(Math.max(32, e))}) L: ${ptr - ptrStart}, S: ${ptrStart}, I: ${ptr}, TS: ${totalPtr + ptrStart}, TI: ${totalPtr + ptr}, TL: ${chunk.length} [${state}]`);
if (state > 4 && sectInfoReady && (realPtr - sectStart) >= sectLength) {
//console.info(`Section length reached (${sectStart} + ${sectLength}). Reset to section head finders.`);
controller.enqueue(u8Enc.encode(`\n`));
state = 0;
sectStart = 0;
sectLength = 0;
sectInfoReady = false;
};
switch (state) {
case 0: { // Chunk marker search
console.debug("Searching for chunk markers...");
//console.info("Searching for chunk markers...");
strBuf += String.fromCharCode(e);
switch (strBuf) {
case "MThd": {
console.debug("MIDI Header chunk!");
//console.info("MIDI Header chunk!");
controller.send(u8Enc.encode(`:hd\n`));
state = 1;
nextState = 3;
finalState = 4;
ptrStart = ptr + 1;
strBuf = "";
sectInfoReady = false;
break;
};
case "MTrk": {
console.debug("MIDI Track chunk!");
//console.info("MIDI Track chunk!");
trackIndex ++;
controller.send(u8Enc.encode(`:tr#${trackIndex}\n`));
state = 1;
nextState = 3;
finalState = 5;
ptrStart = ptr + 1;
strBuf = "";
sectInfoReady = false;
break;
};
default: {
Expand All @@ -113,7 +126,7 @@ let streamDisassemble = function (source) {
};
case 1: {
// 32-bit length int read
console.debug(`Reading uint32...`);
//console.info(`Reading uint32...`);
let i = ptr - ptrStart;
if (!i) {
intValue = 0;
Expand All @@ -131,17 +144,17 @@ let streamDisassemble = function (source) {
};
case 2: {
// VLV int read
console.debug(`Reading VLV...`);
//console.info(`Reading VLV...`);
let i = ptr - ptrStart;
if (!i) {
intValue = 0;
};
intValue = intValue << 7;
intValue |= e & 127;
if (e < 128 || i >= 3) {
console.debug(`VLV read done: ${intValue}.`);
//console.info(`VLV read done: ${intValue}.`);
if (i) {
console.debug(`This is a multi-byte VLV read.`);
//console.info(`This is a multi-byte VLV read.`);
ptr ++;
};
state = nextState;
Expand All @@ -155,15 +168,18 @@ let streamDisassemble = function (source) {
};
case 3: {
// Write length
console.debug(`Writing length...`);
//console.info(`Writing length...`);
controller.send(u8Enc.encode(`\tln ${intValue}\n`));
state = finalState;
ptrStart = ptr + 1;
sectStart = ptrStart + totalPtr;
sectLength = intValue;
sectInfoReady = true;
break;
};
case 4: {
// MIDI head read
console.debug(`Reading MThd...`);
//console.info(`Reading MThd...`);
let i = ptr - ptrStart;
if (!(i & 1)) {
intValue = 0;
Expand Down Expand Up @@ -197,7 +213,7 @@ let streamDisassemble = function (source) {
};
case 5: {
// Read delta time
console.debug(`Reading delta time...`);
//console.info(`Reading delta time...`);
state = 2;
nextState = 6;
ptr --;
Expand All @@ -207,7 +223,7 @@ let streamDisassemble = function (source) {
// Write delta time and jump to different event types
let i = ptr - ptrStart;
if (i) {
console.debug(`Reading event type...`);
//console.info(`Reading event type...`);
switch (e) {
case 240: {
state = 15;
Expand All @@ -228,7 +244,7 @@ let streamDisassemble = function (source) {
};
};
} else {
console.debug(`Delta time: ${intValue}`);
//console.info(`Delta time: ${intValue}`);
if (intValue) {
controller.send(u8Enc.encode(`\tdt ${intValue}\n`));
};
Expand All @@ -237,7 +253,7 @@ let streamDisassemble = function (source) {
};
case 7: {
// Meta event init, jump to 17 for full reads
console.debug(`Reading meta...`);
//console.info(`Reading meta...`);
controller.send(u8Enc.encode(`\tmt ${e}`));
state = 2;
nextState = 17;
Expand All @@ -247,7 +263,7 @@ let streamDisassemble = function (source) {
};
case 15: {
// SysEx event init, jump to 17 for full reads
console.debug(`Reading SysEx...`);
//console.info(`Reading SysEx...`);
controller.send(u8Enc.encode(`\tse`));
state = 2;
nextState = 17;
Expand All @@ -258,7 +274,7 @@ let streamDisassemble = function (source) {
};
case 16: {
// SysEx multi-segment event init, jump to 17 for full reads
console.debug(`Reading SysEx multi-segment...`);
//console.info(`Reading SysEx multi-segment...`);
controller.send(u8Enc.encode(`\tsc`));
state = 2;
nextState = 17;
Expand All @@ -272,14 +288,14 @@ let streamDisassemble = function (source) {
let i = ptr - ptrStart;
if (i == 0) {
extLen = intValue;
console.debug(`Extension length: ${extLen}`);
controller.send(u8Enc.encode(` ${extLen}`));
//console.info(`Extension length: ${extLen}`);
controller.send(u8Enc.encode(` (${extLen})`));
};
if (i < 0) {} else if (i < extLen) {
console.debug(`Multi-byte sequence read.`);
//console.info(`Multi-byte sequence read.`);
controller.send(u8Enc.encode(` ${e.toString(16).padStart(2, "0")}`));
} else {
console.debug(`Multi-byte read end.`);
//console.info(`Multi-byte read end.`);
controller.send(u8Enc.encode(`\n`));
ptr --;
state = 5;
Expand All @@ -289,7 +305,7 @@ let streamDisassemble = function (source) {
};
case 8: {
// Note off
console.debug(`Note off!`);
//console.info(`Note off!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
Expand All @@ -302,7 +318,7 @@ let streamDisassemble = function (source) {
};
case 9: {
// Note on
console.debug(`Note on!`);
//console.info(`Note on!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
Expand All @@ -315,7 +331,7 @@ let streamDisassemble = function (source) {
};
case 10: {
// Note aftertouch (PAT)
console.debug(`Note AT!`);
//console.info(`Note AT!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
Expand All @@ -328,7 +344,7 @@ let streamDisassemble = function (source) {
};
case 11: {
// Control change
console.debug(`Control change!`);
//console.info(`Control change!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
Expand All @@ -341,23 +357,23 @@ let streamDisassemble = function (source) {
};
case 12: {
// Program change
console.debug(`Program change!`);
//console.info(`Program change!`);
controller.send(u8Enc.encode(`\tpc ${part.toString(16)} ${e}\n`));
state = 5;
ptrStart = ptr + 1;
break;
};
case 13: {
// Channel aftertouch (CAT)
console.debug(`Channel AT!`);
//console.info(`Channel AT!`);
controller.send(u8Enc.encode(`\tca ${part.toString(16)} ${e}\n`));
state = 5;
ptrStart = ptr + 1;
break;
};
case 14: {
// Pitch bend
console.debug(`Pitch bend!`);
//console.info(`Pitch bend!`);
let i = ptr - ptrStart;
if (!i) {
intValue = 0;
Expand All @@ -371,13 +387,13 @@ let streamDisassemble = function (source) {
break;
};
default: {
console.debug("Unhandled state.");
//console.info("Unhandled state.");
controller.close();
};
};
ptr ++;
};
console.debug("Data pulled.");
//console.info("Data pulled.");
}
}, new ByteLengthQueuingStrategy({"highWaterMark": 256}));
return sink;
Expand Down

0 comments on commit a0c3ff5

Please sign in to comment.