Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
282 changes: 202 additions & 80 deletions patches/midi-file+1.2.4.patch
Original file line number Diff line number Diff line change
@@ -1,86 +1,55 @@
diff --git a/node_modules/midi-file/lib/midi-parser.js b/node_modules/midi-file/lib/midi-parser.js
index 50ed069..93868ee 100644
index 50ed069..f6828a5 100644
--- a/node_modules/midi-file/lib/midi-parser.js
+++ b/node_modules/midi-file/lib/midi-parser.js
@@ -308,9 +308,47 @@ Parser.prototype.readBytes = function(len) {
return bytes
@@ -309,8 +309,15 @@ Parser.prototype.readBytes = function(len) {
}

+var sharedUtf8Decoder = new TextDecoder('utf-8')
+

Parser.prototype.readString = function(len) {
- var bytes = this.readBytes(len)
- return String.fromCharCode.apply(null, bytes)
+ // Strings can be multibyte-encoded or not.
+ // Fast path: all ASCII (bytes < 0x80) -> fromCharCode directly, no TextDecoder.
+ // Slow path: try UTF-8, fall back to Latin-1 if UTF-8 produces replacement chars.
+ var start = this.pos
+ var end = start + len
+ var buffer = this.buffer
+ var allAscii = true
+ for (var i = start; i < end; i++) {
+ if (buffer[i] >= 0x80) { allAscii = false; break }
+ }
+ this.pos = end
+ if (allAscii) {
+ // fromCharCode.apply is the fastest path for small ASCII strings.
+ // For very long strings, the stack can blow up — chunk it.
+ var CHUNK = 0x8000
+ if (len <= CHUNK) {
+ // Use subarray (no copy) when available (Uint8Array); fall back to slice for plain arrays.
+ var view = buffer.subarray ? buffer.subarray(start, end) : buffer.slice(start, end)
+ return String.fromCharCode.apply(null, view)
+ }
+ var out = ''
+ for (var j = start; j < end; j += CHUNK) {
+ var chunkEnd = j + CHUNK < end ? j + CHUNK : end
+ var chunk = buffer.subarray ? buffer.subarray(j, chunkEnd) : buffer.slice(j, chunkEnd)
+ out += String.fromCharCode.apply(null, chunk)
+ }
+ return out
+ }
+ // Non-ASCII: try UTF-8 decode; fall back to Latin-1 (fromCharCode per byte) if
+ // UTF-8 produced replacement chars or didn't shorten the string.
+ var bytes = buffer.subarray ? buffer.subarray(start, end) : buffer.slice(start, end)
+ var multibyteString = sharedUtf8Decoder.decode(bytes)
+ // Latin-1 interpretation: each byte → one codepoint. Length equals `len`.
+ if (multibyteString.length < len && multibyteString.indexOf('\uFFFD') === -1) {
+ // Try UTF-8 first; fall back to Latin-1 if UTF-8 produces replacement chars.
var bytes = this.readBytes(len)
- return String.fromCharCode.apply(null, bytes)
+ var multibyteString = new TextDecoder().decode(bytes)
+ var singlebyteString = String.fromCharCode.apply(null, bytes)
+ if (singlebyteString.length > multibyteString.length && !multibyteString.includes('\uFFFD')) {
+ return multibyteString
+ }
+ // Build Latin-1 string via fromCharCode on the byte values.
+ return String.fromCharCode.apply(null, bytes)
+ return singlebyteString
}

Parser.prototype.readVarInt = function() {
@@ -321,14 +359,19 @@ Parser.prototype.readBytes = function(len) {


Parser.prototype.readVarInt = function() {
var result = 0
- while (!this.eof()) {
- var b = this.readUInt8()
+ var buffer = this.buffer
+ var pos = this.pos
+ var bufferLen = this.bufferLen
+ while (pos < bufferLen) {
+ var b = buffer[pos++]
if (b & 0x80) {
result += (b & 0x7f)
result <<= 7
} else {
// b is last byte
+ this.pos = pos
return result + b
}
}
// premature eof
+ this.pos = pos
return result
}

diff --git a/node_modules/midi-file/lib/midi-writer.js b/node_modules/midi-file/lib/midi-writer.js
index c1a438d..cbd1a73 100644
index c1a438d..4dad1e1 100644
--- a/node_modules/midi-file/lib/midi-writer.js
+++ b/node_modules/midi-file/lib/midi-writer.js
@@ -22,7 +22,7 @@ function writeMidi(data, opts) {
writeTrack(w, tracks[i], opts)
}

- return w.buffer
+ return w.used()
}

function writeHeader(w, header, numTracks) {
@@ -42,7 +42,7 @@ function writeHeader(w, header, numTracks) {
h.writeUInt16(numTracks)
h.writeUInt16(timeDivision)

- w.writeChunk('MThd', h.buffer)
+ w.writeChunk('MThd', h.used())
}

function writeTrack(w, track, opts) {
@@ -57,7 +57,7 @@ function writeTrack(w, track, opts) {

eventTypeByte = writeEvent(t, track[i], eventTypeByte, opts.useByte9ForNoteOff)
}
- w.writeChunk('MTrk', t.buffer)
+ w.writeChunk('MTrk', t.used())
}

function writeEvent(w, event, lastEventTypeByte, useByte9ForNoteOff) {
@@ -80,50 +80,43 @@ function writeEvent(w, event, lastEventTypeByte, useByte9ForNoteOff) {
case 'text':
w.writeUInt8(0xFF)
Expand All @@ -89,59 +58,154 @@ index c1a438d..cbd1a73 100644
- w.writeString(text)
+ w.writeStringWithLength(text)
break;

case 'copyrightNotice':
w.writeUInt8(0xFF)
w.writeUInt8(0x02)
- w.writeVarInt(text.length)
- w.writeString(text)
+ w.writeStringWithLength(text)
break;

case 'trackName':
w.writeUInt8(0xFF)
w.writeUInt8(0x03)
- w.writeVarInt(text.length)
- w.writeString(text)
+ w.writeStringWithLength(text)
break;

case 'instrumentName':
w.writeUInt8(0xFF)
w.writeUInt8(0x04)
- w.writeVarInt(text.length)
- w.writeString(text)
+ w.writeStringWithLength(text)
break;

case 'lyrics':
w.writeUInt8(0xFF)
w.writeUInt8(0x05)
- w.writeVarInt(text.length)
- w.writeString(text)
+ w.writeStringWithLength(text)
break;

case 'marker':
w.writeUInt8(0xFF)
w.writeUInt8(0x06)
- w.writeVarInt(text.length)
- w.writeString(text)
+ w.writeStringWithLength(text)
break;

case 'cuePoint':
w.writeUInt8(0xFF)
w.writeUInt8(0x07)
- w.writeVarInt(text.length)
- w.writeString(text)
+ w.writeStringWithLength(text)
break;

case 'channelPrefix':
@@ -325,11 +318,14 @@ Writer.prototype.writeBytes = function(arr) {
@@ -277,59 +270,84 @@ function writeEvent(w, event, lastEventTypeByte, useByte9ForNoteOff) {
}


-function Writer() {
- this.buffer = []
+function Writer(initialCapacity) {
+ this.buffer = new Uint8Array(initialCapacity || 1024)
+ this.pos = 0
+}
+
+Writer.prototype._ensure = function(n) {
+ var need = this.pos + n
+ var cap = this.buffer.length
+ if (need <= cap) return
+ while (cap < need) cap *= 2
+ var bigger = new Uint8Array(cap)
+ bigger.set(this.buffer.subarray(0, this.pos))
+ this.buffer = bigger
+}
+
+Writer.prototype.used = function() {
+ return this.buffer.subarray(0, this.pos)
}

Writer.prototype.writeUInt8 = function(v) {
- this.buffer.push(v & 0xFF)
+ if (this.pos >= this.buffer.length) this._ensure(1)
+ this.buffer[this.pos++] = v & 0xFF
}
Writer.prototype.writeInt8 = Writer.prototype.writeUInt8

Writer.prototype.writeUInt16 = function(v) {
- var b0 = (v >> 8) & 0xFF,
- b1 = v & 0xFF
-
- this.writeUInt8(b0)
- this.writeUInt8(b1)
+ this._ensure(2)
+ var buf = this.buffer
+ buf[this.pos++] = (v >> 8) & 0xFF
+ buf[this.pos++] = v & 0xFF
}
Writer.prototype.writeInt16 = Writer.prototype.writeUInt16

Writer.prototype.writeUInt24 = function(v) {
- var b0 = (v >> 16) & 0xFF,
- b1 = (v >> 8) & 0xFF,
- b2 = v & 0xFF
-
- this.writeUInt8(b0)
- this.writeUInt8(b1)
- this.writeUInt8(b2)
+ this._ensure(3)
+ var buf = this.buffer
+ buf[this.pos++] = (v >> 16) & 0xFF
+ buf[this.pos++] = (v >> 8) & 0xFF
+ buf[this.pos++] = v & 0xFF
}
Writer.prototype.writeInt24 = Writer.prototype.writeUInt24

Writer.prototype.writeUInt32 = function(v) {
- var b0 = (v >> 24) & 0xFF,
- b1 = (v >> 16) & 0xFF,
- b2 = (v >> 8) & 0xFF,
- b3 = v & 0xFF
-
- this.writeUInt8(b0)
- this.writeUInt8(b1)
- this.writeUInt8(b2)
- this.writeUInt8(b3)
+ this._ensure(4)
+ var buf = this.buffer
+ buf[this.pos++] = (v >> 24) & 0xFF
+ buf[this.pos++] = (v >> 16) & 0xFF
+ buf[this.pos++] = (v >> 8) & 0xFF
+ buf[this.pos++] = v & 0xFF
}

Writer.prototype.writeInt32 = Writer.prototype.writeUInt32


Writer.prototype.writeBytes = function(arr) {
- this.buffer = this.buffer.concat(Array.prototype.slice.call(arr, 0))
+ // arr can be Uint8Array, Buffer, or a plain Array of byte values.
+ var len = arr.length
+ this._ensure(len)
+ var buf = this.buffer
+ if (arr.buffer !== undefined) {
+ // Typed array / Buffer — bulk copy via .set().
+ buf.set(arr, this.pos)
+ this.pos += len
+ } else {
+ for (var i = 0; i < len; i++) {
+ buf[this.pos++] = arr[i] & 0xFF
+ }
+ }
}

Writer.prototype.writeString = function(str) {
- var i, len = str.length, arr = []
- for (i=0; i < len; i++) {
Expand All @@ -157,5 +221,63 @@ index c1a438d..cbd1a73 100644
+ this.writeVarInt(bytes.length)
+ this.writeBytes(bytes)
}

Writer.prototype.writeVarInt = function(v) {
@@ -337,18 +355,46 @@ Writer.prototype.writeVarInt = function(v) {

if (v <= 0x7F) {
this.writeUInt8(v)
- } else {
- var i = v
- var bytes = []
- bytes.push(i & 0x7F)
- i >>= 7
- while (i) {
- var b = i & 0x7F | 0x80
- bytes.push(b)
- i >>= 7
- }
- this.writeBytes(bytes.reverse())
+ return
+ }
+ // Inline the varint emission to avoid allocating a temp array + reverse().
+ // A var-int is at most 5 bytes in MIDI (28-bit values).
+ var b4 = v & 0x7F
+ v >>= 7
+ var b3 = (v & 0x7F) | 0x80
+ v >>= 7
+ if (v === 0) {
+ this._ensure(2)
+ this.buffer[this.pos++] = b3
+ this.buffer[this.pos++] = b4
+ return
+ }
+ var b2 = (v & 0x7F) | 0x80
+ v >>= 7
+ if (v === 0) {
+ this._ensure(3)
+ this.buffer[this.pos++] = b2
+ this.buffer[this.pos++] = b3
+ this.buffer[this.pos++] = b4
+ return
+ }
+ var b1 = (v & 0x7F) | 0x80
+ v >>= 7
+ if (v === 0) {
+ this._ensure(4)
+ this.buffer[this.pos++] = b1
+ this.buffer[this.pos++] = b2
+ this.buffer[this.pos++] = b3
+ this.buffer[this.pos++] = b4
+ return
}
+ var b0 = (v & 0x7F) | 0x80
+ this._ensure(5)
+ this.buffer[this.pos++] = b0
+ this.buffer[this.pos++] = b1
+ this.buffer[this.pos++] = b2
+ this.buffer[this.pos++] = b3
+ this.buffer[this.pos++] = b4
}

Writer.prototype.writeChunk = function(id, data) {
Loading