Skip to content

Commit

Permalink
Safer stream chunk commits for MICC.
Browse files Browse the repository at this point in the history
  • Loading branch information
PoneyClairDeLune committed Jun 16, 2024
1 parent a96c793 commit 2f9023f
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 49 deletions.
32 changes: 16 additions & 16 deletions libs/rochelle@ltgcgo/textRead.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

const encodings = ["utf-8", "utf-16", "utf-16be"];

ReadableStreamDefaultController.prototype.send = ReadableStreamDefaultController.prototype.send || function (data) {
this.unsent = false;
this.enqueue(data);
let commitData = (controller, data) => {
controller.unsent = false;
controller.enqueue(data);
};

let TextReader = class {
Expand Down Expand Up @@ -40,7 +40,7 @@ let TextReader = class {
if (ptr > lastPtr) {
bufferBuilder.push(chunk.subarray(lastPtr));
lastPtr = 0;
console.error(`Read a new chunk.`);
//console.debug(`Read a new chunk.`);
};
// Read a new chunk
let {value, done} = await reader.read();
Expand All @@ -51,7 +51,7 @@ let TextReader = class {
};
if (chunk) {
// Continue the read operation
console.error(`Read byte at chunk pointer ${ptr}.`);
////console.debug(`Read byte at chunk pointer ${ptr}.`);
let e = chunk[ptr];
let commitNow = false;
switch (e) {
Expand All @@ -70,7 +70,7 @@ let TextReader = class {
};
if (commitNow) {
if (bufferBuilder.length) {
console.error(`Building a multi-part buffer.`);
//console.debug(`Building a multi-part buffer. ${ptr}`);
// Add buffer
bufferBuilder.push(chunk.subarray(lastPtr, ptr));
// Calculate buffer size
Expand All @@ -86,30 +86,30 @@ let TextReader = class {
mergedPtr += bufferBuilder[i].length;
};
// Commit buffer
controller.send(mergedBuffer);
commitData(controller, mergedBuffer);
// Clear buffer
bufferBuilder = [];
console.error(`Multi-part buffer write finished.`);
//console.debug(`Multi-part buffer write finished. ${ptr}`);
} else {
// Just commit the current segment
controller.send(chunk.subarray(lastPtr, ptr));
console.error(`Single buffer write finished.`);
commitData(controller, chunk.subarray(lastPtr, ptr));
//console.debug(`Single buffer write finished. ${ptr}`);
};
lastPtr = ptr + 1;
};
lastUnit = e;
} else {
console.error(`No reading available.`);
//console.debug(`No reading available. ${ptr}`);
};
if (finished) {
console.error(`Stream finished.`);
//console.debug(`Stream finished.`);
// Detect remaining buffer
if (lastPtr != ptr) {
bufferBuilder.push(chunk.subarray(lastPtr, ptr));
};
// Commit all remaining buffer
if (bufferBuilder.length) {
console.error(`Building a multi-part buffer.`);
//console.debug(`Building a multi-part buffer.`);
// Calculate buffer size
let mergeLen = 0;
for (let i = 0; i < bufferBuilder.length; i ++) {
Expand All @@ -123,8 +123,8 @@ let TextReader = class {
mergedPtr += bufferBuilder[i].length;
};
// Commit buffer
controller.send(mergedBuffer);
console.error(`Multi-part buffer write finished.`);
commitData(controller, mergedBuffer);
//console.debug(`Multi-part buffer write finished.`);
}
// Close the stream
controller.unsent = false;
Expand All @@ -137,7 +137,7 @@ let TextReader = class {
return sink;
};
static line(stream, splitMode = 0, label) {
let rawStream = this.feedRaw(stream, splitMode).getReader();
let rawStream = this.lineRaw(stream, splitMode).getReader();
let decoder = new TextDecoder(label || encodings[splitMode]);
return new ReadableStream({
"pull": async (controller) => {
Expand Down
73 changes: 42 additions & 31 deletions src/micc/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ let readUintBE = function (buffer, byteLength) {
return result;
};

ReadableStreamDefaultController.prototype.send = ReadableStreamDefaultController.prototype.send || function (data) {
this.unsent = false;
this.enqueue(data);
let commitData = (controller, data) => {
controller.unsent = false;
controller.enqueue(data);
};

let streamDisassemble = function (source) {
Expand Down Expand Up @@ -99,7 +99,7 @@ let streamDisassemble = function (source) {
switch (strBuf) {
case "MThd": {
//console.info("MIDI Header chunk!");
controller.send(u8Enc.encode(`:hd\n`));
commitData(controller, u8Enc.encode(`:hd\n`));
state = 1;
nextState = 3;
finalState = 4;
Expand All @@ -111,7 +111,7 @@ let streamDisassemble = function (source) {
case "MTrk": {
//console.info("MIDI Track chunk!");
trackIndex ++;
controller.send(u8Enc.encode(`:tr#${trackIndex}\n`));
commitData(controller, u8Enc.encode(`:tr#${trackIndex}\n`));
state = 1;
nextState = 3;
finalState = 5;
Expand Down Expand Up @@ -177,7 +177,7 @@ let streamDisassemble = function (source) {
case 3: {
// Write length
//console.info(`Writing length...`);
controller.send(u8Enc.encode(`\tln ${intValue}\n`));
commitData(controller, u8Enc.encode(`\tln ${intValue}\n`));
state = finalState;
ptrStart = ptr + 1;
sectStart = ptrStart + totalPtr;
Expand All @@ -197,18 +197,18 @@ let streamDisassemble = function (source) {
if (i & 1) {
switch (i >> 1) {
case 0: {
controller.send(u8Enc.encode(`\tft ${intValue}\n`));
commitData(controller, u8Enc.encode(`\tft ${intValue}\n`));
break;
};
case 1: {
controller.send(u8Enc.encode(`\ttc ${intValue}\n`));
commitData(controller, u8Enc.encode(`\ttc ${intValue}\n`));
break;
};
case 2: {
if (intValue < 32768) {
controller.send(u8Enc.encode(`\tdv ${intValue}\n`));
commitData(controller, u8Enc.encode(`\tdv ${intValue}\n`));
} else {
controller.send(u8Enc.encode(`\ttd ${intValue}\n`));
commitData(controller, u8Enc.encode(`\ttd ${intValue}\n`));
};
state = 0;
ptrStart = ptr + 1;
Expand All @@ -234,7 +234,7 @@ let streamDisassemble = function (source) {
if (i) {
if (intValue) {
//console.info(`Delta time: ${intValue} (raced)`);
controller.send(u8Enc.encode(`\tdt ${intValue}\n`));
commitData(controller, u8Enc.encode(`\tdt ${intValue}\n`));
intValue = 0;
};
//console.info(`Reading event type...`);
Expand All @@ -260,7 +260,7 @@ let streamDisassemble = function (source) {
} else {
//console.info(`Delta time: ${intValue}`);
if (intValue) {
controller.send(u8Enc.encode(`\tdt ${intValue}\n`));
commitData(controller, u8Enc.encode(`\tdt ${intValue}\n`));
};
intValue = 0;
};
Expand All @@ -269,7 +269,7 @@ let streamDisassemble = function (source) {
case 7: {
// Meta event init, jump to 17 for full reads
//console.info(`Reading meta...`);
controller.send(u8Enc.encode(`\tmt ${e}`));
commitData(controller, u8Enc.encode(`\tmt ${e}`));
state = 2;
nextState = 17;
startNextSect = true;
Expand All @@ -279,7 +279,7 @@ let streamDisassemble = function (source) {
case 15: {
// SysEx event init, jump to 17 for full reads
//console.info(`Reading SysEx...`);
controller.send(u8Enc.encode(`\tse`));
commitData(controller, u8Enc.encode(`\tse`));
state = 2;
nextState = 17;
ptr --;
Expand All @@ -290,7 +290,7 @@ let streamDisassemble = function (source) {
case 16: {
// SysEx multi-segment event init, jump to 17 for full reads
//console.info(`Reading SysEx multi-segment...`);
controller.send(u8Enc.encode(`\tsc`));
commitData(controller, u8Enc.encode(`\tsc`));
state = 2;
nextState = 17;
ptr --;
Expand All @@ -304,14 +304,14 @@ let streamDisassemble = function (source) {
if (i == 0) {
extLen = intValue;
//console.info(`Extension length: ${extLen}`);
controller.send(u8Enc.encode(` (${extLen})`));
commitData(controller, u8Enc.encode(` (${extLen})`));
};
if (i < 0) {} else if (i < extLen) {
//console.info(`Multi-byte sequence read.`);
controller.send(u8Enc.encode(` ${e.toString(16).padStart(2, "0")}`));
commitData(controller, u8Enc.encode(` ${e.toString(16).padStart(2, "0")}`));
} else {
//console.info(`Multi-byte read end.`);
controller.send(u8Enc.encode(`\n`));
commitData(controller, u8Enc.encode(`\n`));
ptr --;
state = 5;
ptrStart = ptr + 1;
Expand All @@ -323,11 +323,11 @@ let streamDisassemble = function (source) {
//console.info(`Note off!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
commitData(controller, u8Enc.encode(` ${e}\n`));
state = 5;
ptrStart = ptr + 1;
} else {
controller.send(u8Enc.encode(`\tof ${`${part}`.padStart(2, "0")} ${e}`));
commitData(controller, u8Enc.encode(`\tof ${`${part}`.padStart(2, "0")} ${e}`));
};
break;
};
Expand All @@ -336,11 +336,11 @@ let streamDisassemble = function (source) {
//console.info(`Note on!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
commitData(controller, u8Enc.encode(` ${e}\n`));
state = 5;
ptrStart = ptr + 1;
} else {
controller.send(u8Enc.encode(`\ton ${`${part}`.padStart(2, "0")} ${e}`));
commitData(controller, u8Enc.encode(`\ton ${`${part}`.padStart(2, "0")} ${e}`));
};
break;
};
Expand All @@ -349,11 +349,11 @@ let streamDisassemble = function (source) {
//console.info(`Note AT!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
commitData(controller, u8Enc.encode(` ${e}\n`));
state = 5;
ptrStart = ptr + 1;
} else {
controller.send(u8Enc.encode(`\tpa ${`${part}`.padStart(2, "0")} ${e}`));
commitData(controller, u8Enc.encode(`\tpa ${`${part}`.padStart(2, "0")} ${e}`));
};
break;
};
Expand All @@ -362,26 +362,26 @@ let streamDisassemble = function (source) {
//console.info(`Control change!`);
let i = ptr - ptrStart;
if (i) {
controller.send(u8Enc.encode(` ${e}\n`));
commitData(controller, u8Enc.encode(` ${e}\n`));
state = 5;
ptrStart = ptr + 1;
} else {
controller.send(u8Enc.encode(`\tcc ${`${part}`.padStart(2, "0")} ${e}`));
commitData(controller, u8Enc.encode(`\tcc ${`${part}`.padStart(2, "0")} ${e}`));
};
break;
};
case 12: {
// Program change
//console.info(`Program change!`);
controller.send(u8Enc.encode(`\tpc ${`${part}`.padStart(2, "0")} ${e}\n`));
commitData(controller, u8Enc.encode(`\tpc ${`${part}`.padStart(2, "0")} ${e}\n`));
state = 5;
ptrStart = ptr + 1;
break;
};
case 13: {
// Channel aftertouch (CAT)
//console.info(`Channel AT!`);
controller.send(u8Enc.encode(`\tca ${`${part}`.padStart(2, "0")} ${e}\n`));
commitData(controller, u8Enc.encode(`\tca ${`${part}`.padStart(2, "0")} ${e}\n`));
state = 5;
ptrStart = ptr + 1;
break;
Expand All @@ -395,7 +395,7 @@ let streamDisassemble = function (source) {
};
intValue |= e << (i << 3);
if (i) {
controller.send(u8Enc.encode(`\tpb ${`${part}`.padStart(2, "0")} ${intValue - 8192}\n`));
commitData(controller, u8Enc.encode(`\tpb ${`${part}`.padStart(2, "0")} ${intValue - 8192}\n`));
state = 5;
ptrStart = ptr + 1;
};
Expand All @@ -414,11 +414,22 @@ let streamDisassemble = function (source) {
};

let streamAssemble = function (source) {
let lineReader = TextReader.line(source).getReader();
let lineIdx = 0;
let chunk, finished = false;
return new ReadableStream({
"pull": async (controller) => {
//
let {value, done} = await lineReader.read();
if (value) {
//
};
if (done) {
controller.close();
} else {
lineIdx ++;
};
}
}, new ByteLengthQueuingStrategy({"highWaterMark": 256}));
});
};

export {
Expand Down
2 changes: 1 addition & 1 deletion test/middleware.htm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<head>
<meta http-equiv="200" charset="utf-8" />
<title>Octavia Middleware</title>
<title>Octavia Middleware (alpha)</title>
<meta content="true" name="HandheldFriendly" />
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
<meta name="application-name" content="Octavia Middleware" />
Expand Down
2 changes: 1 addition & 1 deletion utils/others/asm.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ WritableStream.prototype.from = async function (asyncIt) {
};

console.info(`Reading MIDI assembly...`);
let stream = (await Deno.open(Deno.args[0])).readable);
let stream = streamAssemble((await Deno.open(Deno.args[0])).readable);
console.info(`Streaming contents to the assembler...`);
await (await Deno.open(Deno.args[1] || `${Deno.args[0]}.mid`, {"write": true, "createNew": true})).writable.from(stream);
console.info(`Assembly finished.`);

0 comments on commit 2f9023f

Please sign in to comment.