ts-flp 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +123 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +120 -21
- package/dist/index.js.map +1 -1
- package/dist/src/api/ProjectApi.d.ts +1 -1
- package/dist/src/api/ProjectApi.d.ts.map +1 -1
- package/dist/src/generated/events.generated.d.ts +1 -1
- package/dist/src/generated/events.generated.d.ts.map +1 -1
- package/dist/src/io/BinaryReader.d.ts +1 -0
- package/dist/src/io/BinaryReader.d.ts.map +1 -1
- package/dist/src/parser/FlpParser.d.ts +13 -3
- package/dist/src/parser/FlpParser.d.ts.map +1 -1
- package/dist/test/dump-all-info.d.ts +2 -0
- package/dist/test/dump-all-info.d.ts.map +1 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -268,11 +268,13 @@ function getEventFixedSize(eventId) {
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
// src/io/BinaryReader.ts
|
|
271
|
-
import
|
|
271
|
+
import protobuf from "protobufjs/minimal.js";
|
|
272
272
|
import { SmartBuffer } from "smart-buffer";
|
|
273
273
|
var BinaryReader = class {
|
|
274
274
|
sb;
|
|
275
|
+
source;
|
|
275
276
|
constructor(buffer) {
|
|
277
|
+
this.source = buffer;
|
|
276
278
|
this.sb = SmartBuffer.fromBuffer(buffer);
|
|
277
279
|
}
|
|
278
280
|
/**
|
|
@@ -370,7 +372,7 @@ var BinaryReader = class {
|
|
|
370
372
|
* FL Studio uses this encoding for TEXT and DATA event sizes
|
|
371
373
|
*/
|
|
372
374
|
readVarInt() {
|
|
373
|
-
const remainingBuffer = this.
|
|
375
|
+
const remainingBuffer = this.source.subarray(this.sb.readOffset);
|
|
374
376
|
const reader = protobuf.Reader.create(remainingBuffer);
|
|
375
377
|
const value = reader.uint32();
|
|
376
378
|
this.sb.readOffset += reader.pos;
|
|
@@ -415,13 +417,13 @@ var BinaryReader = class {
|
|
|
415
417
|
* Returns the internal buffer
|
|
416
418
|
*/
|
|
417
419
|
toBuffer() {
|
|
418
|
-
return this.
|
|
420
|
+
return this.source;
|
|
419
421
|
}
|
|
420
422
|
};
|
|
421
423
|
|
|
422
424
|
// src/io/BinaryWriter.ts
|
|
423
425
|
import { SmartBuffer as SmartBuffer2 } from "smart-buffer";
|
|
424
|
-
import
|
|
426
|
+
import protobuf2 from "protobufjs/minimal.js";
|
|
425
427
|
var BinaryWriter = class {
|
|
426
428
|
sb;
|
|
427
429
|
constructor() {
|
|
@@ -531,9 +533,62 @@ function varIntSize(value) {
|
|
|
531
533
|
}
|
|
532
534
|
|
|
533
535
|
// src/parser/FlpParser.ts
|
|
536
|
+
var KNOWN_DWORD_IDS = new Set(
|
|
537
|
+
Object.keys(EVENT_KIND).map(Number).filter((id) => id >= DWORD && id < TEXT)
|
|
538
|
+
);
|
|
534
539
|
var FLP_HEADER_MAGIC = "FLhd";
|
|
535
540
|
var FLP_DATA_MAGIC = "FLdt";
|
|
536
541
|
var FLP_HEADER_SIZE = 6;
|
|
542
|
+
var LOOKAHEAD_BYTES = 200;
|
|
543
|
+
var LOOKAHEAD_VARINT_MAX = 1e5;
|
|
544
|
+
function readVarIntRaw(buf, off, end) {
|
|
545
|
+
let shift = 0;
|
|
546
|
+
let size = 0;
|
|
547
|
+
const start = off;
|
|
548
|
+
while (true) {
|
|
549
|
+
if (off >= end) return { size: -1, bytesRead: 0 };
|
|
550
|
+
const byte = buf[off];
|
|
551
|
+
off++;
|
|
552
|
+
size |= (byte & 127) << shift;
|
|
553
|
+
shift += 7;
|
|
554
|
+
if (!(byte & 128)) break;
|
|
555
|
+
}
|
|
556
|
+
return { size, bytesRead: off - start };
|
|
557
|
+
}
|
|
558
|
+
function scoreAlignment(buf, off, end, bytesToCheck) {
|
|
559
|
+
const limit = Math.min(off + bytesToCheck, end);
|
|
560
|
+
let textDataCount = 0;
|
|
561
|
+
let consecutiveSmallByte = 0;
|
|
562
|
+
let maxConsecutiveSmallByte = 0;
|
|
563
|
+
while (off < limit) {
|
|
564
|
+
const id = buf[off];
|
|
565
|
+
if (id < WORD) {
|
|
566
|
+
off += 2;
|
|
567
|
+
if (id < 32 && !KNOWN_DWORD_IDS.has(id)) {
|
|
568
|
+
consecutiveSmallByte++;
|
|
569
|
+
maxConsecutiveSmallByte = Math.max(maxConsecutiveSmallByte, consecutiveSmallByte);
|
|
570
|
+
} else {
|
|
571
|
+
consecutiveSmallByte = 0;
|
|
572
|
+
}
|
|
573
|
+
} else if (id < DWORD) {
|
|
574
|
+
off += 3;
|
|
575
|
+
consecutiveSmallByte = 0;
|
|
576
|
+
} else if (id < TEXT) {
|
|
577
|
+
off += 5;
|
|
578
|
+
consecutiveSmallByte = 0;
|
|
579
|
+
} else {
|
|
580
|
+
const vi = readVarIntRaw(buf, off + 1, end);
|
|
581
|
+
if (vi.size >= 0 && vi.size < LOOKAHEAD_VARINT_MAX && off + 1 + vi.bytesRead + vi.size <= end) {
|
|
582
|
+
textDataCount++;
|
|
583
|
+
off = off + 1 + vi.bytesRead + vi.size;
|
|
584
|
+
} else {
|
|
585
|
+
return -100;
|
|
586
|
+
}
|
|
587
|
+
consecutiveSmallByte = 0;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return textDataCount * 10 - maxConsecutiveSmallByte * 3;
|
|
591
|
+
}
|
|
537
592
|
function parseFlp(buffer) {
|
|
538
593
|
const reader = new BinaryReader(buffer);
|
|
539
594
|
const headerMagic = reader.readBytes(4).toString("ascii");
|
|
@@ -580,8 +635,32 @@ function parseFlp(buffer) {
|
|
|
580
635
|
payloadSize = 2;
|
|
581
636
|
headerSize2 = 1;
|
|
582
637
|
} else if (eventId < TEXT) {
|
|
583
|
-
|
|
584
|
-
|
|
638
|
+
if (KNOWN_DWORD_IDS.has(eventId)) {
|
|
639
|
+
payloadSize = 4;
|
|
640
|
+
headerSize2 = 1;
|
|
641
|
+
} else {
|
|
642
|
+
const afterDword = eventStart + 1 + 4;
|
|
643
|
+
const vi = readVarIntRaw(buffer, eventStart + 1, eventsEnd);
|
|
644
|
+
if (vi.size < 0 || vi.size > LOOKAHEAD_VARINT_MAX || eventStart + 1 + vi.bytesRead + vi.size > eventsEnd) {
|
|
645
|
+
payloadSize = 4;
|
|
646
|
+
headerSize2 = 1;
|
|
647
|
+
} else if (vi.size === 3) {
|
|
648
|
+
payloadSize = 4;
|
|
649
|
+
headerSize2 = 1;
|
|
650
|
+
} else {
|
|
651
|
+
const afterVarInt = eventStart + 1 + vi.bytesRead + vi.size;
|
|
652
|
+
const dwordScore = scoreAlignment(buffer, afterDword, eventsEnd, LOOKAHEAD_BYTES);
|
|
653
|
+
const varIntScore = scoreAlignment(buffer, afterVarInt, eventsEnd, LOOKAHEAD_BYTES);
|
|
654
|
+
if (varIntScore > dwordScore + 2) {
|
|
655
|
+
payloadSize = vi.size;
|
|
656
|
+
reader.seek(eventStart + 1 + vi.bytesRead);
|
|
657
|
+
headerSize2 = 1 + vi.bytesRead;
|
|
658
|
+
} else {
|
|
659
|
+
payloadSize = 4;
|
|
660
|
+
headerSize2 = 1;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
585
664
|
} else {
|
|
586
665
|
const sizeStart = reader.tell();
|
|
587
666
|
payloadSize = reader.readVarInt();
|
|
@@ -597,12 +676,15 @@ function parseFlp(buffer) {
|
|
|
597
676
|
payload: Buffer.from(payload)
|
|
598
677
|
};
|
|
599
678
|
events.push(event);
|
|
600
|
-
if (eventId === EVENT_ID.PROJECT_FL_VERSION) {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
679
|
+
if (eventId === EVENT_ID.PROJECT_FL_VERSION && flVersion === "0.0.0") {
|
|
680
|
+
const candidate = payload.toString("ascii").replace(/\0/g, "").trim();
|
|
681
|
+
if (/^\d+(\.\d+)+$/.test(candidate)) {
|
|
682
|
+
flVersion = candidate;
|
|
683
|
+
const parts = flVersion.split(".").map((p) => parseInt(p, 10));
|
|
684
|
+
const major = parts[0] ?? 0;
|
|
685
|
+
const minor = parts[1] ?? 0;
|
|
686
|
+
useUnicode = parts.length >= 2 && (major > 11 || major === 11 && minor >= 5);
|
|
687
|
+
}
|
|
606
688
|
}
|
|
607
689
|
}
|
|
608
690
|
let trailingBytes;
|
|
@@ -640,9 +722,13 @@ function serializeFlp(parsed) {
|
|
|
640
722
|
}
|
|
641
723
|
function serializeEvent(event) {
|
|
642
724
|
const writer = new BinaryWriter();
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
725
|
+
if (event.header.length > 0) {
|
|
726
|
+
writer.writeBytes(event.header);
|
|
727
|
+
} else {
|
|
728
|
+
writer.writeU8(event.id);
|
|
729
|
+
if (event.id >= TEXT) {
|
|
730
|
+
writer.writeVarInt(event.payload.length);
|
|
731
|
+
}
|
|
646
732
|
}
|
|
647
733
|
writer.writeBytes(event.payload);
|
|
648
734
|
return writer.toBuffer();
|
|
@@ -664,7 +750,7 @@ function createEvent(id, payload) {
|
|
|
664
750
|
function patchEvents(parsed, patcher) {
|
|
665
751
|
const patchedEvents = parsed.events.map((event, index) => {
|
|
666
752
|
const patched = patcher(event, index);
|
|
667
|
-
if (patched.payload !== event.payload &&
|
|
753
|
+
if (patched.payload !== event.payload && event.header.length > 1) {
|
|
668
754
|
const headerWriter = new BinaryWriter();
|
|
669
755
|
headerWriter.writeU8(patched.id);
|
|
670
756
|
headerWriter.writeVarInt(patched.payload.length);
|
|
@@ -757,18 +843,33 @@ function createNumberPayload(value, kind) {
|
|
|
757
843
|
}
|
|
758
844
|
|
|
759
845
|
// src/api/ProjectApi.ts
|
|
846
|
+
function readBpm(parsed) {
|
|
847
|
+
const tempoEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TEMPO);
|
|
848
|
+
if (tempoEvent) {
|
|
849
|
+
return getEventNumber(tempoEvent) / 1e3;
|
|
850
|
+
}
|
|
851
|
+
const coarseEvent = findFirstEvent(parsed, EVENT_ID.PROJECT__TEMPO_COARSE);
|
|
852
|
+
if (coarseEvent) {
|
|
853
|
+
let bpm = coarseEvent.payload.readUInt16LE(0);
|
|
854
|
+
const fineEvent = findFirstEvent(parsed, EVENT_ID.PROJECT__TEMPO_FINE);
|
|
855
|
+
if (fineEvent) {
|
|
856
|
+
bpm += fineEvent.payload.readUInt16LE(0) / 1e3;
|
|
857
|
+
}
|
|
858
|
+
return bpm;
|
|
859
|
+
}
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
760
862
|
function readProjectMeta(parsed) {
|
|
761
863
|
const titleEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TITLE);
|
|
762
864
|
const commentsEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_COMMENTS);
|
|
763
865
|
const artistsEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_ARTISTS);
|
|
764
866
|
const genreEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_GENRE);
|
|
765
|
-
const tempoEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TEMPO);
|
|
766
867
|
return {
|
|
767
868
|
name: titleEvent ? getEventString(titleEvent, parsed.useUnicode) : null,
|
|
768
869
|
description: commentsEvent ? getEventString(commentsEvent, parsed.useUnicode) : null,
|
|
769
870
|
artist: artistsEvent ? getEventString(artistsEvent, parsed.useUnicode) : null,
|
|
770
871
|
genre: genreEvent ? getEventString(genreEvent, parsed.useUnicode) : null,
|
|
771
|
-
bpm:
|
|
872
|
+
bpm: readBpm(parsed)
|
|
772
873
|
};
|
|
773
874
|
}
|
|
774
875
|
function writeProjectMeta(parsed, meta) {
|
|
@@ -913,9 +1014,7 @@ function parseVstPluginData(payload) {
|
|
|
913
1014
|
}
|
|
914
1015
|
const reader = new BinaryReader(payload);
|
|
915
1016
|
const typeMarker = reader.readU32LE();
|
|
916
|
-
|
|
917
|
-
return { name: null, vendor: null };
|
|
918
|
-
}
|
|
1017
|
+
void typeMarker;
|
|
919
1018
|
let name = null;
|
|
920
1019
|
let vendor = null;
|
|
921
1020
|
while (reader.remaining() >= 12) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/generated/events.generated.ts","../src/io/BinaryReader.ts","../src/io/BinaryWriter.ts","../src/parser/FlpParser.ts","../src/api/ProjectApi.ts"],"sourcesContent":["/**\r\n * Auto-generated event constants from PyFLP\r\n * FL Studio .flp file event IDs and types\r\n *\r\n * Event ID ranges:\r\n * - BYTE (0-63): 1 byte data\r\n * - WORD (64-127): 2 bytes data\r\n * - DWORD (128-191): 4 bytes data\r\n * - TEXT (192-207): Variable length strings (+ some IDs in DATA range)\r\n * - DATA (208+): Variable length binary data\r\n */\r\n\r\n// Base offsets for event ID ranges\r\nexport const BYTE = 0;\r\nexport const WORD = 64;\r\nexport const DWORD = 128;\r\nexport const TEXT = 192;\r\nexport const DATA = 208;\r\n\r\n// IDs for TEXT events that use UTF-16LE in newer FL versions\r\nexport const NEW_TEXT_IDS = [\r\n TEXT + 49, // ArrangementID.Name\r\n TEXT + 39, // DisplayGroupID.Name\r\n TEXT + 47, // TrackID.Name\r\n] as const;\r\n\r\n/**\r\n * Event IDs used by FL Studio project files\r\n * Based on PyFLP's event definitions\r\n */\r\nexport const EVENT_ID = {\r\n // === Project IDs (from project.py) ===\r\n PROJECT_LOOP_ACTIVE: 9,\r\n PROJECT_SHOW_INFO: 10,\r\n PROJECT__VOLUME: 12,\r\n PROJECT_PAN_LAW: 23,\r\n PROJECT_LICENSED: 28,\r\n PROJECT__TEMPO_COARSE: WORD + 2, // 66\r\n PROJECT_PITCH: WORD + 16, // 80\r\n PROJECT__TEMPO_FINE: WORD + 29, // 93\r\n PROJECT_CUR_GROUP_ID: DWORD + 18,\r\n PROJECT_TEMPO: DWORD + 28,\r\n PROJECT_FL_BUILD: DWORD + 31,\r\n PROJECT_TITLE: TEXT + 2, // 194\r\n PROJECT_COMMENTS: TEXT + 3, // 195\r\n PROJECT_URL: TEXT + 5, // 197\r\n PROJECT__RTF_COMMENTS: TEXT + 6, // 198\r\n PROJECT_FL_VERSION: TEXT + 7, // 199\r\n PROJECT_LICENSEE: TEXT + 8, // 200\r\n PROJECT_DATA_PATH: TEXT + 10, // 202\r\n PROJECT_GENRE: TEXT + 14, // 206\r\n PROJECT_ARTISTS: TEXT + 15, // 207\r\n PROJECT_TIMESTAMP: DATA + 29, // 237\r\n\r\n // === Channel IDs (from channel.py) ===\r\n CHANNEL_IS_ENABLED: 0,\r\n CHANNEL__VOL_BYTE: 2,\r\n CHANNEL__PAN_BYTE: 3,\r\n CHANNEL_ZIPPED: 15,\r\n CHANNEL_PING_PONG_LOOP: 20,\r\n CHANNEL_TYPE: 21,\r\n CHANNEL_ROUTED_TO: 22,\r\n CHANNEL_IS_LOCKED: 32,\r\n CHANNEL_NEW: WORD,\r\n CHANNEL_FREQ_TILT: WORD + 5, // 69\r\n CHANNEL_FX_FLAGS: WORD + 6, // 70\r\n CHANNEL_CUTOFF: WORD + 7, // 71\r\n CHANNEL__VOL_WORD: WORD + 8, // 72\r\n CHANNEL__PAN_WORD: WORD + 9, // 73\r\n CHANNEL_PREAMP: WORD + 10, // 74\r\n CHANNEL_FADE_OUT: WORD + 11, // 75\r\n CHANNEL_FADE_IN: WORD + 12, // 76\r\n CHANNEL_RESONANCE: WORD + 19, // 83\r\n CHANNEL_STEREO_DELAY: WORD + 21, // 85\r\n CHANNEL_POGO: WORD + 22, // 86\r\n CHANNEL_TIME_SHIFT: WORD + 25, // 89\r\n CHANNEL_CHILDREN: WORD + 30, // 94\r\n CHANNEL_SWING: WORD + 33, // 97\r\n CHANNEL_RING_MOD: DWORD + 3,\r\n CHANNEL_CUT_GROUP: DWORD + 4,\r\n CHANNEL_ROOT_NOTE: DWORD + 7,\r\n CHANNEL_DELAY_MOD_XY: DWORD + 10,\r\n CHANNEL_REVERB: DWORD + 11,\r\n CHANNEL__STRETCH_TIME: DWORD + 12,\r\n CHANNEL_FINE_TUNE: DWORD + 14,\r\n CHANNEL_SAMPLER_FLAGS: DWORD + 15,\r\n CHANNEL_LAYER_FLAGS: DWORD + 16,\r\n CHANNEL_GROUP_NUM: DWORD + 17,\r\n CHANNEL_AU_SAMPLE_RATE: DWORD + 25,\r\n CHANNEL__NAME: TEXT,\r\n CHANNEL_SAMPLE_PATH: TEXT + 4, // 196\r\n CHANNEL_DELAY: DATA + 1, // 209\r\n CHANNEL_PARAMETERS: DATA + 7, // 215\r\n CHANNEL_ENVELOPE_LFO: DATA + 10, // 218\r\n CHANNEL_LEVELS: DATA + 11, // 219\r\n CHANNEL_POLYPHONY: DATA + 13, // 221\r\n CHANNEL_TRACKING: DATA + 20, // 228\r\n CHANNEL_LEVEL_ADJUSTS: DATA + 21, // 229\r\n CHANNEL_AUTOMATION: DATA + 26, // 234\r\n\r\n // === Plugin IDs (from plugin.py) ===\r\n PLUGIN_COLOR: DWORD,\r\n PLUGIN_ICON: DWORD + 27,\r\n PLUGIN_INTERNAL_NAME: TEXT + 9, // 201\r\n PLUGIN_NAME: TEXT + 11, // 203\r\n PLUGIN_WRAPPER: DATA + 4, // 212\r\n PLUGIN_DATA: DATA + 5, // 213\r\n\r\n // === Display Group IDs ===\r\n DISPLAY_GROUP_NAME: TEXT + 39, // 231\r\n\r\n // === Rack IDs ===\r\n RACK_SWING: 11,\r\n RACK__FIT_TO_STEPS: 13,\r\n RACK_WINDOW_HEIGHT: DWORD + 5,\r\n\r\n // === Mixer IDs (from mixer.py) ===\r\n MIXER_SLOT_INDEX: WORD + 34, // 98\r\n MIXER_INSERT_ICON: WORD + 31, // 95\r\n MIXER_INSERT_OUTPUT: DWORD + 19,\r\n MIXER_INSERT_COLOR: DWORD + 21,\r\n MIXER_INSERT_INPUT: DWORD + 26,\r\n MIXER_INSERT_NAME: TEXT + 12, // 204\r\n MIXER_INSERT_ROUTING: DATA + 27, // 235\r\n MIXER_INSERT_FLAGS: DATA + 28, // 236\r\n} as const;\r\n\r\n/**\r\n * Event data type classification\r\n */\r\nexport type EventKind =\r\n | \"u8\"\r\n | \"i8\"\r\n | \"u16\"\r\n | \"i16\"\r\n | \"u32\"\r\n | \"i32\"\r\n | \"f32\"\r\n | \"text\"\r\n | \"data\"\r\n | \"unknown\";\r\n\r\n/**\r\n * Maps event IDs to their data type\r\n * Used for proper serialization/deserialization\r\n */\r\nexport const EVENT_KIND: Record<number, EventKind> = {\r\n // Project events\r\n [EVENT_ID.PROJECT_LOOP_ACTIVE]: \"u8\",\r\n [EVENT_ID.PROJECT_SHOW_INFO]: \"u8\",\r\n [EVENT_ID.PROJECT__VOLUME]: \"u8\",\r\n [EVENT_ID.PROJECT_PAN_LAW]: \"u8\",\r\n [EVENT_ID.PROJECT_LICENSED]: \"u8\",\r\n [EVENT_ID.PROJECT__TEMPO_COARSE]: \"u16\",\r\n [EVENT_ID.PROJECT_PITCH]: \"i16\",\r\n [EVENT_ID.PROJECT__TEMPO_FINE]: \"u16\",\r\n [EVENT_ID.PROJECT_CUR_GROUP_ID]: \"i32\",\r\n [EVENT_ID.PROJECT_TEMPO]: \"u32\",\r\n [EVENT_ID.PROJECT_FL_BUILD]: \"u32\",\r\n [EVENT_ID.PROJECT_TITLE]: \"text\",\r\n [EVENT_ID.PROJECT_COMMENTS]: \"text\",\r\n [EVENT_ID.PROJECT_URL]: \"text\",\r\n [EVENT_ID.PROJECT__RTF_COMMENTS]: \"text\",\r\n [EVENT_ID.PROJECT_FL_VERSION]: \"text\",\r\n [EVENT_ID.PROJECT_LICENSEE]: \"text\",\r\n [EVENT_ID.PROJECT_DATA_PATH]: \"text\",\r\n [EVENT_ID.PROJECT_GENRE]: \"text\",\r\n [EVENT_ID.PROJECT_ARTISTS]: \"text\",\r\n [EVENT_ID.PROJECT_TIMESTAMP]: \"data\",\r\n\r\n // Channel events\r\n [EVENT_ID.CHANNEL_IS_ENABLED]: \"u8\",\r\n [EVENT_ID.CHANNEL__VOL_BYTE]: \"u8\",\r\n [EVENT_ID.CHANNEL__PAN_BYTE]: \"u8\",\r\n [EVENT_ID.CHANNEL_ZIPPED]: \"u8\",\r\n [EVENT_ID.CHANNEL_PING_PONG_LOOP]: \"u8\",\r\n [EVENT_ID.CHANNEL_TYPE]: \"u8\",\r\n [EVENT_ID.CHANNEL_ROUTED_TO]: \"i8\",\r\n [EVENT_ID.CHANNEL_IS_LOCKED]: \"u8\",\r\n [EVENT_ID.CHANNEL_NEW]: \"u16\",\r\n [EVENT_ID.CHANNEL_FREQ_TILT]: \"u16\",\r\n [EVENT_ID.CHANNEL_FX_FLAGS]: \"u16\",\r\n [EVENT_ID.CHANNEL_CUTOFF]: \"u16\",\r\n [EVENT_ID.CHANNEL__VOL_WORD]: \"u16\",\r\n [EVENT_ID.CHANNEL__PAN_WORD]: \"u16\",\r\n [EVENT_ID.CHANNEL_PREAMP]: \"u16\",\r\n [EVENT_ID.CHANNEL_FADE_OUT]: \"u16\",\r\n [EVENT_ID.CHANNEL_FADE_IN]: \"u16\",\r\n [EVENT_ID.CHANNEL_RESONANCE]: \"u16\",\r\n [EVENT_ID.CHANNEL_STEREO_DELAY]: \"u16\",\r\n [EVENT_ID.CHANNEL_POGO]: \"u16\",\r\n [EVENT_ID.CHANNEL_TIME_SHIFT]: \"u16\",\r\n [EVENT_ID.CHANNEL_CHILDREN]: \"u16\",\r\n [EVENT_ID.CHANNEL_SWING]: \"u16\",\r\n [EVENT_ID.CHANNEL_RING_MOD]: \"u32\",\r\n [EVENT_ID.CHANNEL_CUT_GROUP]: \"u32\",\r\n [EVENT_ID.CHANNEL_ROOT_NOTE]: \"u32\",\r\n [EVENT_ID.CHANNEL_DELAY_MOD_XY]: \"u32\",\r\n [EVENT_ID.CHANNEL_REVERB]: \"u32\",\r\n [EVENT_ID.CHANNEL__STRETCH_TIME]: \"f32\",\r\n [EVENT_ID.CHANNEL_FINE_TUNE]: \"i32\",\r\n [EVENT_ID.CHANNEL_SAMPLER_FLAGS]: \"u32\",\r\n [EVENT_ID.CHANNEL_LAYER_FLAGS]: \"u32\",\r\n [EVENT_ID.CHANNEL_GROUP_NUM]: \"i32\",\r\n [EVENT_ID.CHANNEL_AU_SAMPLE_RATE]: \"u32\",\r\n [EVENT_ID.CHANNEL__NAME]: \"text\",\r\n [EVENT_ID.CHANNEL_SAMPLE_PATH]: \"text\",\r\n [EVENT_ID.CHANNEL_DELAY]: \"data\",\r\n [EVENT_ID.CHANNEL_PARAMETERS]: \"data\",\r\n [EVENT_ID.CHANNEL_ENVELOPE_LFO]: \"data\",\r\n [EVENT_ID.CHANNEL_LEVELS]: \"data\",\r\n [EVENT_ID.CHANNEL_POLYPHONY]: \"data\",\r\n [EVENT_ID.CHANNEL_TRACKING]: \"data\",\r\n [EVENT_ID.CHANNEL_LEVEL_ADJUSTS]: \"data\",\r\n [EVENT_ID.CHANNEL_AUTOMATION]: \"data\",\r\n\r\n // Plugin events\r\n [EVENT_ID.PLUGIN_COLOR]: \"u32\",\r\n [EVENT_ID.PLUGIN_ICON]: \"u32\",\r\n [EVENT_ID.PLUGIN_INTERNAL_NAME]: \"text\",\r\n [EVENT_ID.PLUGIN_NAME]: \"text\",\r\n [EVENT_ID.PLUGIN_WRAPPER]: \"data\",\r\n [EVENT_ID.PLUGIN_DATA]: \"data\",\r\n\r\n // Display Group events\r\n [EVENT_ID.DISPLAY_GROUP_NAME]: \"data\",\r\n\r\n // Rack events\r\n [EVENT_ID.RACK_SWING]: \"u8\",\r\n [EVENT_ID.RACK__FIT_TO_STEPS]: \"u8\",\r\n [EVENT_ID.RACK_WINDOW_HEIGHT]: \"u32\",\r\n\r\n // Mixer events\r\n [EVENT_ID.MIXER_SLOT_INDEX]: \"u16\",\r\n [EVENT_ID.MIXER_INSERT_ICON]: \"i16\",\r\n [EVENT_ID.MIXER_INSERT_OUTPUT]: \"i32\",\r\n [EVENT_ID.MIXER_INSERT_COLOR]: \"u32\",\r\n [EVENT_ID.MIXER_INSERT_INPUT]: \"i32\",\r\n [EVENT_ID.MIXER_INSERT_NAME]: \"text\",\r\n [EVENT_ID.MIXER_INSERT_ROUTING]: \"data\",\r\n [EVENT_ID.MIXER_INSERT_FLAGS]: \"data\",\r\n\r\n};\r\n\r\n/**\r\n * Determines the event kind based on ID\r\n * Falls back to range-based detection if not explicitly mapped\r\n */\r\nexport function getEventKind(eventId: number): EventKind {\r\n // Check explicit mapping first\r\n const mapped = EVENT_KIND[eventId];\r\n if (mapped !== undefined) {\r\n return mapped;\r\n }\r\n\r\n // Fall back to range-based detection\r\n if (eventId < WORD) {\r\n return \"u8\";\r\n } else if (eventId < DWORD) {\r\n return \"u16\";\r\n } else if (eventId < TEXT) {\r\n return \"u32\";\r\n } else if (eventId < DATA || NEW_TEXT_IDS.includes(eventId as 241 | 231 | 239)) {\r\n return \"text\";\r\n } else {\r\n return \"data\";\r\n }\r\n}\r\n\r\n/**\r\n * Returns the fixed size for BYTE/WORD/DWORD events\r\n * Returns -1 for variable-length events (TEXT/DATA)\r\n */\r\nexport function getEventFixedSize(eventId: number): number {\r\n if (eventId < WORD) {\r\n return 1;\r\n } else if (eventId < DWORD) {\r\n return 2;\r\n } else if (eventId < TEXT) {\r\n return 4;\r\n }\r\n return -1; // Variable length\r\n}\r\n","/**\n * Binary reader for FL Studio .flp files\n * Uses smart-buffer for binary reading and protobufjs for VarInt decoding\n */\n\nimport * as protobuf from \"protobufjs/minimal.js\";\nimport { SmartBuffer } from \"smart-buffer\";\n\nexport class BinaryReader {\n private sb: SmartBuffer;\n\n constructor(buffer: Buffer) {\n this.sb = SmartBuffer.fromBuffer(buffer);\n }\n\n /**\n * Returns current read position\n */\n tell(): number {\n return this.sb.readOffset;\n }\n\n /**\n * Seeks to an absolute position\n */\n seek(pos: number): void {\n this.sb.readOffset = pos;\n }\n\n /**\n * Seeks relative to current position\n */\n skip(offset: number): void {\n this.sb.readOffset += offset;\n }\n\n /**\n * Returns total buffer length\n */\n length(): number {\n return this.sb.length;\n }\n\n /**\n * Returns remaining bytes to read\n */\n remaining(): number {\n return this.sb.remaining();\n }\n\n /**\n * Returns true if there are more bytes to read\n */\n hasMore(): boolean {\n return this.sb.remaining() > 0;\n }\n\n /**\n * Reads an unsigned 8-bit integer\n */\n readU8(): number {\n return this.sb.readUInt8();\n }\n\n /**\n * Reads a signed 8-bit integer\n */\n readI8(): number {\n return this.sb.readInt8();\n }\n\n /**\n * Reads an unsigned 16-bit integer (little-endian)\n */\n readU16LE(): number {\n return this.sb.readUInt16LE();\n }\n\n /**\n * Reads a signed 16-bit integer (little-endian)\n */\n readI16LE(): number {\n return this.sb.readInt16LE();\n }\n\n /**\n * Reads an unsigned 32-bit integer (little-endian)\n */\n readU32LE(): number {\n return this.sb.readUInt32LE();\n }\n\n /**\n * Reads a signed 32-bit integer (little-endian)\n */\n readI32LE(): number {\n return this.sb.readInt32LE();\n }\n\n /**\n * Reads a 32-bit float (little-endian)\n */\n readF32LE(): number {\n return this.sb.readFloatLE();\n }\n\n /**\n * Reads a 64-bit float (little-endian)\n */\n readF64LE(): number {\n return this.sb.readDoubleLE();\n }\n\n /**\n * Reads raw bytes\n */\n readBytes(length: number): Buffer {\n return this.sb.readBuffer(length);\n }\n\n /**\n * Reads a VarInt (variable-length integer) using protobufjs\n * FL Studio uses this encoding for TEXT and DATA event sizes\n */\n readVarInt(): number {\n // Get remaining buffer from current position\n const remainingBuffer = this.sb.toBuffer().subarray(this.sb.readOffset);\n const reader = protobuf.Reader.create(remainingBuffer);\n const value = reader.uint32();\n // Advance our position by how many bytes protobufjs consumed\n this.sb.readOffset += reader.pos;\n return value;\n }\n\n /**\n * Reads an ASCII string (null-terminated)\n */\n readAsciiString(length: number): string {\n const str = this.sb.readString(length, \"ascii\");\n // Remove null terminator if present\n const nullPos = str.indexOf(\"\\0\");\n return nullPos === -1 ? str : str.substring(0, nullPos);\n }\n\n /**\n * Reads a UTF-16LE string (null-terminated)\n */\n readUtf16LEString(length: number): string {\n const bytes = this.sb.readBuffer(length);\n const str = bytes.toString(\"utf16le\");\n // Remove null terminator if present\n const nullPos = str.indexOf(\"\\0\");\n return nullPos === -1 ? str : str.substring(0, nullPos);\n }\n\n /**\n * Peeks at bytes without advancing position\n */\n peek(length: number): Buffer {\n const pos = this.sb.readOffset;\n const data = this.sb.readBuffer(length);\n this.sb.readOffset = pos;\n return data;\n }\n\n /**\n * Peeks at a single byte without advancing position\n */\n peekU8(): number {\n const pos = this.sb.readOffset;\n const value = this.sb.readUInt8();\n this.sb.readOffset = pos;\n return value;\n }\n\n /**\n * Returns the internal buffer\n */\n toBuffer(): Buffer {\n return this.sb.toBuffer();\n }\n}\n","/**\n * Binary writer for FL Studio .flp files\n * Uses smart-buffer for binary writing and protobufjs for VarInt encoding\n */\n\nimport { SmartBuffer } from \"smart-buffer\";\nimport * as protobuf from \"protobufjs/minimal.js\";\n\nexport class BinaryWriter {\n private sb: SmartBuffer;\n\n constructor() {\n this.sb = new SmartBuffer();\n }\n\n /**\n * Returns current write position (total bytes written)\n */\n tell(): number {\n return this.sb.writeOffset;\n }\n\n /**\n * Writes an unsigned 8-bit integer\n */\n writeU8(value: number): void {\n this.sb.writeUInt8(value & 0xff);\n }\n\n /**\n * Writes a signed 8-bit integer\n */\n writeI8(value: number): void {\n this.sb.writeInt8(value);\n }\n\n /**\n * Writes an unsigned 16-bit integer (little-endian)\n */\n writeU16LE(value: number): void {\n this.sb.writeUInt16LE(value & 0xffff);\n }\n\n /**\n * Writes a signed 16-bit integer (little-endian)\n */\n writeI16LE(value: number): void {\n this.sb.writeInt16LE(value);\n }\n\n /**\n * Writes an unsigned 32-bit integer (little-endian)\n */\n writeU32LE(value: number): void {\n this.sb.writeUInt32LE(value >>> 0);\n }\n\n /**\n * Writes a signed 32-bit integer (little-endian)\n */\n writeI32LE(value: number): void {\n this.sb.writeInt32LE(value);\n }\n\n /**\n * Writes a 32-bit float (little-endian)\n */\n writeF32LE(value: number): void {\n this.sb.writeFloatLE(value);\n }\n\n /**\n * Writes a 64-bit float (little-endian)\n */\n writeF64LE(value: number): void {\n this.sb.writeDoubleLE(value);\n }\n\n /**\n * Writes raw bytes\n */\n writeBytes(data: Buffer): void {\n this.sb.writeBuffer(data);\n }\n\n /**\n * Writes a VarInt (variable-length integer) using protobufjs\n * FL Studio uses this encoding for TEXT and DATA event sizes\n */\n writeVarInt(value: number): void {\n const writer = protobuf.Writer.create();\n writer.uint32(value);\n const encoded = writer.finish();\n this.sb.writeBuffer(Buffer.from(encoded));\n }\n\n /**\n * Writes an ASCII string (null-terminated)\n */\n writeAsciiString(str: string): void {\n this.sb.writeString(str + \"\\0\", \"ascii\");\n }\n\n /**\n * Writes a UTF-16LE string (null-terminated)\n */\n writeUtf16LEString(str: string): void {\n const buf = Buffer.from(str + \"\\0\", \"utf16le\");\n this.sb.writeBuffer(buf);\n }\n\n /**\n * Gets the final buffer\n */\n toBuffer(): Buffer {\n return this.sb.toBuffer();\n }\n}\n\n/**\n * Encodes a VarInt to a Buffer using protobufjs (standalone utility)\n */\nexport function encodeVarInt(value: number): Buffer {\n const writer = protobuf.Writer.create();\n writer.uint32(value);\n return Buffer.from(writer.finish());\n}\n\n/**\n * Calculates the byte size needed for a VarInt\n */\nexport function varIntSize(value: number): number {\n if (value < 0x80) return 1;\n if (value < 0x4000) return 2;\n if (value < 0x200000) return 3;\n if (value < 0x10000000) return 4;\n return 5;\n}\n","/**\n * FL Studio .flp file parser and serializer\n * Conservative patch approach: preserves all unknown data byte-for-byte\n */\n\nimport { DWORD, EVENT_ID, TEXT, WORD, getEventKind } from \"../generated/events.generated.js\";\nimport { BinaryReader } from \"../io/BinaryReader.js\";\nimport { BinaryWriter } from \"../io/BinaryWriter.js\";\n\n/**\n * Represents a single event in an FLP file\n * Stores raw bytes to enable conservative patching\n */\nexport interface FlpEvent {\n /** Event ID (0-255) */\n id: number;\n /** Data type classification */\n kind: \"u8\" | \"i8\" | \"u16\" | \"i16\" | \"u32\" | \"i32\" | \"f32\" | \"text\" | \"data\" | \"unknown\";\n /** Original header bytes (ID + size for variable-length events) */\n header: Buffer;\n /** Event payload data */\n payload: Buffer;\n}\n\n/**\n * Represents a parsed FLP file\n * Contains all data needed for conservative round-trip\n */\nexport interface ParsedFlp {\n /** FLhd chunk (header) - 14 bytes total */\n headerChunkBytes: Buffer;\n /** FLdt chunk header (magic + size placeholder) - 8 bytes */\n fldtHeaderBytes: Buffer;\n /** All events from the FLdt chunk */\n events: FlpEvent[];\n /** Any trailing bytes after events (should be empty) */\n trailingBytes: Buffer | undefined;\n /** Detected FL version for string encoding */\n flVersion: string;\n /** Whether to use UTF-16LE for strings (FL >= 11.5) */\n useUnicode: boolean;\n}\n\n/**\n * Header structure constants\n */\nconst FLP_HEADER_MAGIC = \"FLhd\";\nconst FLP_DATA_MAGIC = \"FLdt\";\nconst FLP_HEADER_SIZE = 6; // Expected header chunk size\n\n/**\n * Parses an FL Studio project file\n *\n * @param buffer - Raw file data\n * @returns Parsed FLP structure\n * @throws Error if file is corrupted or invalid\n */\nexport function parseFlp(buffer: Buffer): ParsedFlp {\n const reader = new BinaryReader(buffer);\n\n // Read FLhd header chunk\n const headerMagic = reader.readBytes(4).toString(\"ascii\");\n if (headerMagic !== FLP_HEADER_MAGIC) {\n throw new Error(`Invalid header magic: expected 'FLhd', got '${headerMagic}'`);\n }\n\n const headerSize = reader.readU32LE();\n if (headerSize !== FLP_HEADER_SIZE) {\n throw new Error(`Invalid header size: expected ${FLP_HEADER_SIZE}, got ${headerSize}`);\n }\n\n const format = reader.readI16LE();\n const channelCount = reader.readU16LE();\n const ppq = reader.readU16LE();\n\n // Validate format (0 = normal project)\n if (format < -1 || format > 0x50) {\n throw new Error(`Invalid file format: ${format}`);\n }\n\n // Store complete header chunk (14 bytes)\n const headerChunkBytes = buffer.subarray(0, 14);\n\n // Read FLdt data chunk header\n const dataMagic = reader.readBytes(4).toString(\"ascii\");\n if (dataMagic !== FLP_DATA_MAGIC) {\n throw new Error(`Invalid data magic: expected 'FLdt', got '${dataMagic}'`);\n }\n\n const eventsSize = reader.readU32LE();\n\n // Validate events size\n const expectedFileSize = 22 + eventsSize; // 14 (FLhd) + 8 (FLdt header) + events\n if (buffer.length !== expectedFileSize) {\n throw new Error(\n `Data chunk size mismatch: expected file size ${expectedFileSize}, got ${buffer.length}`\n );\n }\n\n // Store FLdt header (8 bytes)\n const fldtHeaderBytes = buffer.subarray(14, 22);\n\n // Parse events\n const events: FlpEvent[] = [];\n let flVersion = \"0.0.0\";\n let useUnicode = false;\n\n const eventsStart = reader.tell();\n const eventsEnd = eventsStart + eventsSize;\n\n while (reader.tell() < eventsEnd) {\n const eventStart = reader.tell();\n const eventId = reader.readU8();\n\n let payloadSize: number;\n let headerSize: number;\n\n // Determine payload size based on event ID range\n if (eventId < WORD) {\n // BYTE range: 1 byte payload\n payloadSize = 1;\n headerSize = 1; // Just the ID\n } else if (eventId < DWORD) {\n // WORD range: 2 bytes payload\n payloadSize = 2;\n headerSize = 1;\n } else if (eventId < TEXT) {\n // DWORD range: 4 bytes payload\n payloadSize = 4;\n headerSize = 1;\n } else {\n // TEXT/DATA range: VarInt-encoded size\n const sizeStart = reader.tell();\n payloadSize = reader.readVarInt();\n headerSize = 1 + (reader.tell() - sizeStart); // ID + VarInt bytes\n }\n\n // Read payload\n const payload = reader.readBytes(payloadSize);\n\n // Extract header from original buffer for byte-perfect round-trip\n const header = buffer.subarray(eventStart, eventStart + headerSize);\n\n // Determine event kind\n const kind = getEventKind(eventId);\n\n const event: FlpEvent = {\n id: eventId,\n kind,\n header: Buffer.from(header),\n payload: Buffer.from(payload),\n };\n\n events.push(event);\n\n // Detect FL version from FLVersion event\n if (eventId === EVENT_ID.PROJECT_FL_VERSION) {\n flVersion = payload.toString(\"ascii\").replace(/\\0/g, \"\");\n const parts = flVersion.split(\".\").map((p) => parseInt(p, 10));\n const major = parts[0] ?? 0;\n const minor = parts[1] ?? 0;\n useUnicode = parts.length >= 2 && (major > 11 || (major === 11 && minor >= 5));\n }\n }\n\n // Check for trailing bytes\n let trailingBytes: Buffer | undefined;\n if (reader.remaining() > 0) {\n trailingBytes = reader.readBytes(reader.remaining());\n }\n\n return {\n headerChunkBytes: Buffer.from(headerChunkBytes),\n fldtHeaderBytes: Buffer.from(fldtHeaderBytes),\n events,\n trailingBytes,\n flVersion,\n useUnicode,\n };\n}\n\n/**\n * Serializes a parsed FLP back to a buffer\n * Recalculates FLdt chunk size if events have changed\n *\n * @param parsed - Parsed FLP structure\n * @returns Serialized buffer\n */\nexport function serializeFlp(parsed: ParsedFlp): Buffer {\n const writer = new BinaryWriter();\n\n // Write FLhd header chunk (preserved byte-for-byte)\n writer.writeBytes(parsed.headerChunkBytes);\n\n // Calculate total events size\n let eventsSize = 0;\n for (const event of parsed.events) {\n eventsSize += serializeEvent(event).length;\n }\n\n // Add trailing bytes if present\n if (parsed.trailingBytes) {\n eventsSize += parsed.trailingBytes.length;\n }\n\n // Write FLdt header with updated size\n writer.writeBytes(Buffer.from(FLP_DATA_MAGIC, \"ascii\"));\n writer.writeU32LE(eventsSize);\n\n // Write all events\n for (const event of parsed.events) {\n writer.writeBytes(serializeEvent(event));\n }\n\n // Write trailing bytes if present\n if (parsed.trailingBytes) {\n writer.writeBytes(parsed.trailingBytes);\n }\n\n return writer.toBuffer();\n}\n\n/**\n * Serializes a single event to bytes\n * Uses original header for unchanged events, recalculates for modified ones\n */\nfunction serializeEvent(event: FlpEvent): Buffer {\n const writer = new BinaryWriter();\n\n // Write event ID\n writer.writeU8(event.id);\n\n // For TEXT/DATA events, we need to write the VarInt size\n if (event.id >= TEXT) {\n writer.writeVarInt(event.payload.length);\n }\n\n // Write payload\n writer.writeBytes(event.payload);\n\n return writer.toBuffer();\n}\n\n/**\n * Creates a new event with the given ID and payload\n */\nexport function createEvent(id: number, payload: Buffer): FlpEvent {\n const kind = getEventKind(id);\n\n // Build header\n const headerWriter = new BinaryWriter();\n headerWriter.writeU8(id);\n\n if (id >= TEXT) {\n headerWriter.writeVarInt(payload.length);\n }\n\n return {\n id,\n kind,\n header: headerWriter.toBuffer(),\n payload: Buffer.from(payload),\n };\n}\n\n/**\n * Applies a patcher function to all events\n * Returns a new ParsedFlp with patched events\n *\n * @param parsed - Original parsed FLP\n * @param patcher - Function that transforms each event\n * @returns New ParsedFlp with patched events\n */\nexport function patchEvents(\n parsed: ParsedFlp,\n patcher: (event: FlpEvent, index: number) => FlpEvent\n): ParsedFlp {\n const patchedEvents = parsed.events.map((event, index) => {\n const patched = patcher(event, index);\n\n // If payload changed, recalculate header for TEXT/DATA events\n if (patched.payload !== event.payload && patched.id >= TEXT) {\n const headerWriter = new BinaryWriter();\n headerWriter.writeU8(patched.id);\n headerWriter.writeVarInt(patched.payload.length);\n return {\n ...patched,\n header: headerWriter.toBuffer(),\n };\n }\n\n return patched;\n });\n\n return {\n ...parsed,\n events: patchedEvents,\n };\n}\n\n/**\n * Finds all events with a specific ID\n */\nexport function findEvents(parsed: ParsedFlp, eventId: number): FlpEvent[] {\n return parsed.events.filter((e) => e.id === eventId);\n}\n\n/**\n * Finds the first event with a specific ID\n */\nexport function findFirstEvent(parsed: ParsedFlp, eventId: number): FlpEvent | undefined {\n return parsed.events.find((e) => e.id === eventId);\n}\n\n/**\n * Gets event payload as a string (handles encoding)\n */\nexport function getEventString(event: FlpEvent, useUnicode: boolean): string {\n if (event.kind !== \"text\") {\n throw new Error(`Event ${event.id} is not a text event`);\n }\n\n if (useUnicode) {\n const str = event.payload.toString(\"utf16le\");\n const nullPos = str.indexOf(\"\\0\");\n return nullPos === -1 ? str : str.substring(0, nullPos);\n } else {\n const str = event.payload.toString(\"ascii\");\n const nullPos = str.indexOf(\"\\0\");\n return nullPos === -1 ? str : str.substring(0, nullPos);\n }\n}\n\n/**\n * Creates a text payload with proper encoding\n */\nexport function createTextPayload(text: string, useUnicode: boolean): Buffer {\n if (useUnicode) {\n return Buffer.from(text + \"\\0\", \"utf16le\");\n } else {\n return Buffer.from(text + \"\\0\", \"ascii\");\n }\n}\n\n/**\n * Gets event payload as a number\n */\nexport function getEventNumber(event: FlpEvent): number {\n const reader = new BinaryReader(event.payload);\n\n switch (event.kind) {\n case \"u8\":\n return reader.readU8();\n case \"i8\":\n return reader.readI8();\n case \"u16\":\n return reader.readU16LE();\n case \"i16\":\n return reader.readI16LE();\n case \"u32\":\n return reader.readU32LE();\n case \"i32\":\n return reader.readI32LE();\n case \"f32\":\n return reader.readF32LE();\n default:\n throw new Error(`Cannot get number from ${event.kind} event`);\n }\n}\n\n/**\n * Creates a numeric payload\n */\nexport function createNumberPayload(\n value: number,\n kind: \"u8\" | \"i8\" | \"u16\" | \"i16\" | \"u32\" | \"i32\" | \"f32\"\n): Buffer {\n const writer = new BinaryWriter();\n\n switch (kind) {\n case \"u8\":\n writer.writeU8(value);\n break;\n case \"i8\":\n writer.writeI8(value);\n break;\n case \"u16\":\n writer.writeU16LE(value);\n break;\n case \"i16\":\n writer.writeI16LE(value);\n break;\n case \"u32\":\n writer.writeU32LE(value);\n break;\n case \"i32\":\n writer.writeI32LE(value);\n break;\n case \"f32\":\n writer.writeF32LE(value);\n break;\n }\n\n return writer.toBuffer();\n}\n","/**\n * High-level API for reading and modifying FL Studio project files\n * Provides typed access to project metadata, samples, plugins, and time info\n */\n\nimport { EVENT_ID } from \"../generated/events.generated.js\";\nimport { BinaryReader } from \"../io/BinaryReader.js\";\nimport { BinaryWriter } from \"../io/BinaryWriter.js\";\nimport {\n createNumberPayload,\n createTextPayload,\n findFirstEvent,\n type FlpEvent,\n getEventNumber,\n getEventString,\n type ParsedFlp,\n patchEvents,\n} from \"../parser/FlpParser.js\";\n\n// ============================================================================\n// Project Metadata\n// ============================================================================\n\n/**\n * Project metadata (name, description, artist, genre, BPM)\n */\nexport interface ProjectMeta {\n name: string | null;\n description: string | null;\n artist: string | null;\n genre: string | null;\n bpm: number | null;\n}\n\n/**\n * Reads project metadata from a parsed FLP\n */\nexport function readProjectMeta(parsed: ParsedFlp): ProjectMeta {\n const titleEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TITLE);\n const commentsEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_COMMENTS);\n const artistsEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_ARTISTS);\n const genreEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_GENRE);\n const tempoEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TEMPO);\n\n return {\n name: titleEvent ? getEventString(titleEvent, parsed.useUnicode) : null,\n description: commentsEvent ? getEventString(commentsEvent, parsed.useUnicode) : null,\n artist: artistsEvent ? getEventString(artistsEvent, parsed.useUnicode) : null,\n genre: genreEvent ? getEventString(genreEvent, parsed.useUnicode) : null,\n bpm: tempoEvent ? getEventNumber(tempoEvent) / 1000 : null,\n };\n}\n\n/**\n * Writes project metadata to a parsed FLP\n * Only modifies fields that are provided (non-undefined)\n */\nexport function writeProjectMeta(parsed: ParsedFlp, meta: Partial<ProjectMeta>): ParsedFlp {\n return patchEvents(parsed, (event: FlpEvent) => {\n // Patch title\n if (meta.name !== undefined && event.id === EVENT_ID.PROJECT_TITLE) {\n return {\n ...event,\n payload: createTextPayload(meta.name ?? \"\", parsed.useUnicode),\n };\n }\n\n // Patch comments/description\n if (meta.description !== undefined && event.id === EVENT_ID.PROJECT_COMMENTS) {\n return {\n ...event,\n payload: createTextPayload(meta.description ?? \"\", parsed.useUnicode),\n };\n }\n\n // Patch artists\n if (meta.artist !== undefined && event.id === EVENT_ID.PROJECT_ARTISTS) {\n return {\n ...event,\n payload: createTextPayload(meta.artist ?? \"\", parsed.useUnicode),\n };\n }\n\n // Patch genre\n if (meta.genre !== undefined && event.id === EVENT_ID.PROJECT_GENRE) {\n return {\n ...event,\n payload: createTextPayload(meta.genre ?? \"\", parsed.useUnicode),\n };\n }\n\n // Patch tempo (stored as BPM * 1000)\n if (meta.bpm && Math.abs(meta.bpm) > 0 && event.id === EVENT_ID.PROJECT_TEMPO) {\n return {\n ...event,\n payload: createNumberPayload(Math.round(Math.abs(meta.bpm) * 1000), \"u32\"),\n };\n }\n\n return event;\n });\n}\n\n// ============================================================================\n// Project Time Info\n// ============================================================================\n\n/**\n * Project creation date and work time\n */\nexport interface ProjectTimeInfo {\n creationDate: Date | null;\n workTimeSeconds: number | null;\n}\n\n// Delphi epoch: December 30, 1899\nconst DELPHI_EPOCH = new Date(1899, 11, 30);\n\n/**\n * Converts Delphi timestamp (days since epoch) to Date\n */\nfunction delphiToDate(days: number): Date {\n const ms = days * 24 * 60 * 60 * 1000;\n return new Date(DELPHI_EPOCH.getTime() + ms);\n}\n\n/**\n * Converts Date to Delphi timestamp (days since epoch)\n */\nfunction dateToDelphiDays(date: Date): number {\n const ms = date.getTime() - DELPHI_EPOCH.getTime();\n return ms / (24 * 60 * 60 * 1000);\n}\n\n/**\n * Reads project time info from a parsed FLP\n * Timestamp event contains: Float64 created_on (days), Float64 time_spent (days)\n */\nexport function readProjectTimeInfo(parsed: ParsedFlp): ProjectTimeInfo {\n const timestampEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TIMESTAMP);\n\n if (!timestampEvent || timestampEvent.payload.length < 16) {\n return {\n creationDate: null,\n workTimeSeconds: null,\n };\n }\n\n const reader = new BinaryReader(timestampEvent.payload);\n const createdOnDays = reader.readF64LE();\n const timeSpentDays = reader.readF64LE();\n\n return {\n creationDate: delphiToDate(createdOnDays),\n workTimeSeconds: timeSpentDays * 24 * 60 * 60, // Convert days to seconds\n };\n}\n\n/**\n * Writes project time info to a parsed FLP\n * Only modifies fields that are provided (non-undefined)\n * \n * If `creationDate` or `workTimeSeconds` is set to `null`, the final value will be set on `0` (Delphi epoch)\n */\nexport function writeProjectTimeInfo(\n parsed: ParsedFlp,\n info: Partial<ProjectTimeInfo>\n): ParsedFlp {\n // Read current values to preserve unmodified fields\n const current = readProjectTimeInfo(parsed);\n\n return patchEvents(parsed, (event: FlpEvent) => {\n if (event.id !== EVENT_ID.PROJECT_TIMESTAMP) {\n return event;\n }\n\n const writer = new BinaryWriter();\n\n // Write creation date\n if (info.creationDate !== undefined && info.creationDate !== null) {\n writer.writeF64LE(dateToDelphiDays(info.creationDate));\n } else if (current.creationDate !== null) {\n writer.writeF64LE(dateToDelphiDays(current.creationDate));\n } else {\n writer.writeF64LE(0);\n }\n\n // Write work time\n if (info.workTimeSeconds !== undefined && info.workTimeSeconds !== null) {\n writer.writeF64LE(info.workTimeSeconds / (24 * 60 * 60)); // Convert seconds to days\n } else if (current.workTimeSeconds !== null) {\n writer.writeF64LE(current.workTimeSeconds / (24 * 60 * 60));\n } else {\n writer.writeF64LE(0);\n }\n\n return {\n ...event,\n payload: writer.toBuffer(),\n };\n });\n}\n\n// ============================================================================\n// Samples\n// ============================================================================\n\n/**\n * Reference to a sample in the project\n */\nexport interface SampleRef {\n /** Index of the event in the events array */\n eventIndex: number;\n /** File path of the sample */\n path: string;\n}\n\n/**\n * Lists all samples in the project\n */\nexport function listSamples(parsed: ParsedFlp): SampleRef[] {\n const samples: SampleRef[] = [];\n\n parsed.events.forEach((event: FlpEvent, index: number) => {\n if (event.id === EVENT_ID.CHANNEL_SAMPLE_PATH) {\n const path = getEventString(event, parsed.useUnicode);\n if (path && path.length > 0) {\n samples.push({\n eventIndex: index,\n path,\n });\n }\n }\n });\n\n return samples;\n}\n\n/**\n * Rewrites sample paths using a mapper function\n */\nexport function rewriteSamplePaths(\n parsed: ParsedFlp,\n mapper: (oldPath: string) => string\n): ParsedFlp {\n return patchEvents(parsed, (event: FlpEvent) => {\n if (event.id !== EVENT_ID.CHANNEL_SAMPLE_PATH) {\n return event;\n }\n\n const oldPath = getEventString(event, parsed.useUnicode);\n if (!oldPath || oldPath.length === 0) {\n return event;\n }\n\n const newPath = mapper(oldPath);\n if (newPath === oldPath) {\n return event;\n }\n\n return {\n ...event,\n payload: createTextPayload(newPath, parsed.useUnicode),\n };\n });\n}\n\n// ============================================================================\n// Plugins (VST)\n// ============================================================================\n\n/**\n * Reference to a plugin in the project\n */\nexport interface PluginRef {\n /** Plugin name (may be null if not available) */\n name: string | null;\n /** Plugin vendor/provider (may be null if not stored in file) */\n vendor: string | null;\n}\n\n/**\n * VST Plugin Event internal IDs (from plugin.py VSTPluginEvent)\n */\nconst VST_EVENT_ID = {\n MIDI: 1,\n FLAGS: 2,\n IO: 30,\n INPUTS: 31,\n OUTPUTS: 32,\n PLUGIN_INFO: 50,\n FOUR_CC: 51,\n GUID: 52,\n STATE: 53,\n NAME: 54,\n PLUGIN_PATH: 55,\n VENDOR: 56,\n} as const;\n\n/**\n * Parses a VST plugin data event to extract name and vendor\n * Based on VSTPluginEvent structure in PyFLP\n */\nfunction parseVstPluginData(payload: Buffer): { name: string | null; vendor: string | null } {\n if (payload.length < 4) {\n return { name: null, vendor: null };\n }\n\n const reader = new BinaryReader(payload);\n\n // First 4 bytes: type marker (8, 10, or 11 for VSTs)\n const typeMarker = reader.readU32LE();\n\n // Skip if not a VST plugin marker\n if (typeMarker !== 8 && typeMarker !== 10 && typeMarker !== 11) {\n return { name: null, vendor: null };\n }\n\n let name: string | null = null;\n let vendor: string | null = null;\n\n // Parse sub-events\n while (reader.remaining() >= 12) {\n // At minimum: 4 (id) + 8 (size)\n const subEventId = reader.readU32LE();\n const dataSize = reader.readU32LE(); // Lower 32 bits of size\n const dataSizeHigh = reader.readU32LE(); // Upper 32 bits (usually 0)\n\n // Combine for 64-bit size (though in practice it's always small)\n const actualSize = dataSize + dataSizeHigh * 0x100000000;\n\n if (actualSize > reader.remaining()) {\n break;\n }\n\n const data = reader.readBytes(actualSize);\n\n // Extract name and vendor\n if (subEventId === VST_EVENT_ID.NAME && actualSize > 0) {\n name = data.toString(\"utf8\").replace(/\\0/g, \"\");\n } else if (subEventId === VST_EVENT_ID.VENDOR && actualSize > 0) {\n vendor = data.toString(\"utf8\").replace(/\\0/g, \"\");\n }\n }\n\n return { name, vendor };\n}\n\n/**\n * Lists all plugins (VST and native) in the project\n * Returns plugin name and vendor where available\n */\nexport function listPlugins(parsed: ParsedFlp): PluginRef[] {\n const plugins: PluginRef[] = [];\n const seenPlugins = new Set<string>();\n\n // Track current channel context\n let currentInternalName: string | null = null;\n let currentPluginName: string | null = null;\n\n for (const event of parsed.events) {\n // Track channel new events as boundaries\n if (event.id === EVENT_ID.CHANNEL_NEW) {\n // Reset context for new channel\n if (currentInternalName || currentPluginName) {\n // Save previous channel's plugin if it wasn't a VST (no plugin data)\n const key = `${currentInternalName ?? \"\"}:${currentPluginName ?? \"\"}`;\n if (!seenPlugins.has(key) && currentInternalName && currentInternalName !== \"Fruity Wrapper\") {\n seenPlugins.add(key);\n plugins.push({\n name: currentPluginName || currentInternalName,\n vendor: null, // Native plugins don't store vendor\n });\n }\n }\n currentInternalName = null;\n currentPluginName = null;\n }\n\n // Track internal name (identifies plugin type)\n if (event.id === EVENT_ID.PLUGIN_INTERNAL_NAME) {\n currentInternalName = getEventString(event, parsed.useUnicode);\n }\n\n // Track display name\n if (event.id === EVENT_ID.PLUGIN_NAME) {\n currentPluginName = getEventString(event, parsed.useUnicode);\n }\n\n // Parse VST plugin data\n if (event.id === EVENT_ID.PLUGIN_DATA && currentInternalName === \"Fruity Wrapper\") {\n const vstData = parseVstPluginData(event.payload);\n if (vstData.name) {\n const key = `vst:${vstData.name}:${vstData.vendor ?? \"\"}`;\n if (!seenPlugins.has(key)) {\n seenPlugins.add(key);\n plugins.push({\n name: vstData.name,\n vendor: vstData.vendor,\n });\n }\n }\n // Reset context after processing VST\n currentInternalName = null;\n currentPluginName = null;\n }\n }\n\n // Handle last channel if any\n if (currentInternalName && currentInternalName !== \"Fruity Wrapper\") {\n const key = `${currentInternalName}:${currentPluginName ?? \"\"}`;\n if (!seenPlugins.has(key)) {\n plugins.push({\n name: currentPluginName || currentInternalName,\n vendor: null,\n });\n }\n }\n\n return plugins;\n}\n\n// ============================================================================\n// FL Version\n// ============================================================================\n\n/**\n * Gets the FL Studio version string from the project\n */\nexport function getFlVersion(parsed: ParsedFlp): string {\n return parsed.flVersion;\n}\n\n/**\n * Gets the PPQ (Pulses Per Quarter note) from the header\n */\nexport function getPPQ(parsed: ParsedFlp): number {\n // PPQ is at offset 12-13 in the header (bytes 12-13 of the 14-byte FLhd chunk)\n const reader = new BinaryReader(parsed.headerChunkBytes);\n reader.seek(12);\n return reader.readU16LE();\n}\n"],"mappings":"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","names":["SmartBuffer","protobuf","headerSize"]}
|
|
1
|
+
{"version":3,"sources":["../src/generated/events.generated.ts","../src/io/BinaryReader.ts","../src/io/BinaryWriter.ts","../src/parser/FlpParser.ts","../src/api/ProjectApi.ts"],"sourcesContent":["/**\r\n * Auto-generated event constants from PyFLP\r\n * FL Studio .flp file event IDs and types\r\n *\r\n * Event ID ranges:\r\n * - BYTE (0-63): 1 byte data\r\n * - WORD (64-127): 2 bytes data\r\n * - DWORD (128-191): 4 bytes data\r\n * - TEXT (192-207): Variable length strings (+ some IDs in DATA range)\r\n * - DATA (208+): Variable length binary data\r\n */\r\n\r\n// Base offsets for event ID ranges\r\nexport const BYTE = 0;\r\nexport const WORD = 64;\r\nexport const DWORD = 128;\r\nexport const TEXT = 192;\r\nexport const DATA = 208;\r\n\r\n// IDs for TEXT events that use UTF-16LE in newer FL versions\r\nexport const NEW_TEXT_IDS = [\r\n TEXT + 49, // ArrangementID.Name\r\n TEXT + 39, // DisplayGroupID.Name\r\n TEXT + 47, // TrackID.Name\r\n] as const;\r\n\r\n/**\r\n * Event IDs used by FL Studio project files\r\n * Based on PyFLP's event definitions\r\n */\r\nexport const EVENT_ID = {\r\n // === Project IDs (from project.py) ===\r\n PROJECT_LOOP_ACTIVE: 9,\r\n PROJECT_SHOW_INFO: 10,\r\n PROJECT__VOLUME: 12,\r\n PROJECT_PAN_LAW: 23,\r\n PROJECT_LICENSED: 28,\r\n PROJECT__TEMPO_COARSE: WORD + 2, // 66\r\n PROJECT_PITCH: WORD + 16, // 80\r\n PROJECT__TEMPO_FINE: WORD + 29, // 93\r\n PROJECT_CUR_GROUP_ID: DWORD + 18,\r\n PROJECT_TEMPO: DWORD + 28,\r\n PROJECT_FL_BUILD: DWORD + 31,\r\n PROJECT_TITLE: TEXT + 2, // 194\r\n PROJECT_COMMENTS: TEXT + 3, // 195\r\n PROJECT_URL: TEXT + 5, // 197\r\n PROJECT__RTF_COMMENTS: TEXT + 6, // 198\r\n PROJECT_FL_VERSION: TEXT + 7, // 199\r\n PROJECT_LICENSEE: TEXT + 8, // 200\r\n PROJECT_DATA_PATH: TEXT + 10, // 202\r\n PROJECT_GENRE: TEXT + 14, // 206\r\n PROJECT_ARTISTS: TEXT + 15, // 207\r\n PROJECT_TIMESTAMP: DATA + 29, // 237\r\n\r\n // === Channel IDs (from channel.py) ===\r\n CHANNEL_IS_ENABLED: 0,\r\n CHANNEL__VOL_BYTE: 2,\r\n CHANNEL__PAN_BYTE: 3,\r\n CHANNEL_ZIPPED: 15,\r\n CHANNEL_PING_PONG_LOOP: 20,\r\n CHANNEL_TYPE: 21,\r\n CHANNEL_ROUTED_TO: 22,\r\n CHANNEL_IS_LOCKED: 32,\r\n CHANNEL_NEW: WORD,\r\n CHANNEL_FREQ_TILT: WORD + 5, // 69\r\n CHANNEL_FX_FLAGS: WORD + 6, // 70\r\n CHANNEL_CUTOFF: WORD + 7, // 71\r\n CHANNEL__VOL_WORD: WORD + 8, // 72\r\n CHANNEL__PAN_WORD: WORD + 9, // 73\r\n CHANNEL_PREAMP: WORD + 10, // 74\r\n CHANNEL_FADE_OUT: WORD + 11, // 75\r\n CHANNEL_FADE_IN: WORD + 12, // 76\r\n CHANNEL_RESONANCE: WORD + 19, // 83\r\n CHANNEL_STEREO_DELAY: WORD + 21, // 85\r\n CHANNEL_POGO: WORD + 22, // 86\r\n CHANNEL_TIME_SHIFT: WORD + 25, // 89\r\n CHANNEL_CHILDREN: WORD + 30, // 94\r\n CHANNEL_SWING: WORD + 33, // 97\r\n CHANNEL_RING_MOD: DWORD + 3,\r\n CHANNEL_CUT_GROUP: DWORD + 4,\r\n CHANNEL_ROOT_NOTE: DWORD + 7,\r\n CHANNEL_DELAY_MOD_XY: DWORD + 10,\r\n CHANNEL_REVERB: DWORD + 11,\r\n CHANNEL__STRETCH_TIME: DWORD + 12,\r\n CHANNEL_FINE_TUNE: DWORD + 14,\r\n CHANNEL_SAMPLER_FLAGS: DWORD + 15,\r\n CHANNEL_LAYER_FLAGS: DWORD + 16,\r\n CHANNEL_GROUP_NUM: DWORD + 17,\r\n CHANNEL_AU_SAMPLE_RATE: DWORD + 25,\r\n CHANNEL__NAME: TEXT,\r\n CHANNEL_SAMPLE_PATH: TEXT + 4, // 196\r\n CHANNEL_DELAY: DATA + 1, // 209\r\n CHANNEL_PARAMETERS: DATA + 7, // 215\r\n CHANNEL_ENVELOPE_LFO: DATA + 10, // 218\r\n CHANNEL_LEVELS: DATA + 11, // 219\r\n CHANNEL_POLYPHONY: DATA + 13, // 221\r\n CHANNEL_TRACKING: DATA + 20, // 228\r\n CHANNEL_LEVEL_ADJUSTS: DATA + 21, // 229\r\n CHANNEL_AUTOMATION: DATA + 26, // 234\r\n\r\n // === Plugin IDs (from plugin.py) ===\r\n PLUGIN_COLOR: DWORD,\r\n PLUGIN_ICON: DWORD + 27,\r\n PLUGIN_INTERNAL_NAME: TEXT + 9, // 201\r\n PLUGIN_NAME: TEXT + 11, // 203\r\n PLUGIN_WRAPPER: DATA + 4, // 212\r\n PLUGIN_DATA: DATA + 5, // 213\r\n\r\n // === Display Group IDs ===\r\n DISPLAY_GROUP_NAME: TEXT + 39, // 231\r\n\r\n // === Rack IDs ===\r\n RACK_SWING: 11,\r\n RACK__FIT_TO_STEPS: 13,\r\n RACK_WINDOW_HEIGHT: DWORD + 5,\r\n\r\n // === Mixer IDs (from mixer.py) ===\r\n MIXER_SLOT_INDEX: WORD + 34, // 98\r\n MIXER_INSERT_ICON: WORD + 31, // 95\r\n MIXER_INSERT_OUTPUT: DWORD + 19,\r\n MIXER_INSERT_COLOR: DWORD + 21,\r\n MIXER_INSERT_INPUT: DWORD + 26,\r\n MIXER_INSERT_NAME: TEXT + 12, // 204\r\n MIXER_INSERT_ROUTING: DATA + 27, // 235\r\n MIXER_INSERT_FLAGS: DATA + 28, // 236\r\n} as const;\r\n\r\n/**\r\n * Event data type classification\r\n */\r\nexport type EventKind =\r\n | 'u8'\r\n | 'i8'\r\n | 'u16'\r\n | 'i16'\r\n | 'u32'\r\n | 'i32'\r\n | 'f32'\r\n | 'text'\r\n | 'data'\r\n | 'unknown';\r\n\r\n/**\r\n * Maps event IDs to their data type\r\n * Used for proper serialization/deserialization\r\n */\r\nexport const EVENT_KIND: Record<number, EventKind> = {\r\n // Project events\r\n [EVENT_ID.PROJECT_LOOP_ACTIVE]: 'u8',\r\n [EVENT_ID.PROJECT_SHOW_INFO]: 'u8',\r\n [EVENT_ID.PROJECT__VOLUME]: 'u8',\r\n [EVENT_ID.PROJECT_PAN_LAW]: 'u8',\r\n [EVENT_ID.PROJECT_LICENSED]: 'u8',\r\n [EVENT_ID.PROJECT__TEMPO_COARSE]: 'u16',\r\n [EVENT_ID.PROJECT_PITCH]: 'i16',\r\n [EVENT_ID.PROJECT__TEMPO_FINE]: 'u16',\r\n [EVENT_ID.PROJECT_CUR_GROUP_ID]: 'i32',\r\n [EVENT_ID.PROJECT_TEMPO]: 'u32',\r\n [EVENT_ID.PROJECT_FL_BUILD]: 'u32',\r\n [EVENT_ID.PROJECT_TITLE]: 'text',\r\n [EVENT_ID.PROJECT_COMMENTS]: 'text',\r\n [EVENT_ID.PROJECT_URL]: 'text',\r\n [EVENT_ID.PROJECT__RTF_COMMENTS]: 'text',\r\n [EVENT_ID.PROJECT_FL_VERSION]: 'text',\r\n [EVENT_ID.PROJECT_LICENSEE]: 'text',\r\n [EVENT_ID.PROJECT_DATA_PATH]: 'text',\r\n [EVENT_ID.PROJECT_GENRE]: 'text',\r\n [EVENT_ID.PROJECT_ARTISTS]: 'text',\r\n [EVENT_ID.PROJECT_TIMESTAMP]: 'data',\r\n\r\n // Channel events\r\n [EVENT_ID.CHANNEL_IS_ENABLED]: 'u8',\r\n [EVENT_ID.CHANNEL__VOL_BYTE]: 'u8',\r\n [EVENT_ID.CHANNEL__PAN_BYTE]: 'u8',\r\n [EVENT_ID.CHANNEL_ZIPPED]: 'u8',\r\n [EVENT_ID.CHANNEL_PING_PONG_LOOP]: 'u8',\r\n [EVENT_ID.CHANNEL_TYPE]: 'u8',\r\n [EVENT_ID.CHANNEL_ROUTED_TO]: 'i8',\r\n [EVENT_ID.CHANNEL_IS_LOCKED]: 'u8',\r\n [EVENT_ID.CHANNEL_NEW]: 'u16',\r\n [EVENT_ID.CHANNEL_FREQ_TILT]: 'u16',\r\n [EVENT_ID.CHANNEL_FX_FLAGS]: 'u16',\r\n [EVENT_ID.CHANNEL_CUTOFF]: 'u16',\r\n [EVENT_ID.CHANNEL__VOL_WORD]: 'u16',\r\n [EVENT_ID.CHANNEL__PAN_WORD]: 'u16',\r\n [EVENT_ID.CHANNEL_PREAMP]: 'u16',\r\n [EVENT_ID.CHANNEL_FADE_OUT]: 'u16',\r\n [EVENT_ID.CHANNEL_FADE_IN]: 'u16',\r\n [EVENT_ID.CHANNEL_RESONANCE]: 'u16',\r\n [EVENT_ID.CHANNEL_STEREO_DELAY]: 'u16',\r\n [EVENT_ID.CHANNEL_POGO]: 'u16',\r\n [EVENT_ID.CHANNEL_TIME_SHIFT]: 'u16',\r\n [EVENT_ID.CHANNEL_CHILDREN]: 'u16',\r\n [EVENT_ID.CHANNEL_SWING]: 'u16',\r\n [EVENT_ID.CHANNEL_RING_MOD]: 'u32',\r\n [EVENT_ID.CHANNEL_CUT_GROUP]: 'u32',\r\n [EVENT_ID.CHANNEL_ROOT_NOTE]: 'u32',\r\n [EVENT_ID.CHANNEL_DELAY_MOD_XY]: 'u32',\r\n [EVENT_ID.CHANNEL_REVERB]: 'u32',\r\n [EVENT_ID.CHANNEL__STRETCH_TIME]: 'f32',\r\n [EVENT_ID.CHANNEL_FINE_TUNE]: 'i32',\r\n [EVENT_ID.CHANNEL_SAMPLER_FLAGS]: 'u32',\r\n [EVENT_ID.CHANNEL_LAYER_FLAGS]: 'u32',\r\n [EVENT_ID.CHANNEL_GROUP_NUM]: 'i32',\r\n [EVENT_ID.CHANNEL_AU_SAMPLE_RATE]: 'u32',\r\n [EVENT_ID.CHANNEL__NAME]: 'text',\r\n [EVENT_ID.CHANNEL_SAMPLE_PATH]: 'text',\r\n [EVENT_ID.CHANNEL_DELAY]: 'data',\r\n [EVENT_ID.CHANNEL_PARAMETERS]: 'data',\r\n [EVENT_ID.CHANNEL_ENVELOPE_LFO]: 'data',\r\n [EVENT_ID.CHANNEL_LEVELS]: 'data',\r\n [EVENT_ID.CHANNEL_POLYPHONY]: 'data',\r\n [EVENT_ID.CHANNEL_TRACKING]: 'data',\r\n [EVENT_ID.CHANNEL_LEVEL_ADJUSTS]: 'data',\r\n [EVENT_ID.CHANNEL_AUTOMATION]: 'data',\r\n\r\n // Plugin events\r\n [EVENT_ID.PLUGIN_COLOR]: 'u32',\r\n [EVENT_ID.PLUGIN_ICON]: 'u32',\r\n [EVENT_ID.PLUGIN_INTERNAL_NAME]: 'text',\r\n [EVENT_ID.PLUGIN_NAME]: 'text',\r\n [EVENT_ID.PLUGIN_WRAPPER]: 'data',\r\n [EVENT_ID.PLUGIN_DATA]: 'data',\r\n\r\n // Display Group events\r\n [EVENT_ID.DISPLAY_GROUP_NAME]: 'data',\r\n\r\n // Rack events\r\n [EVENT_ID.RACK_SWING]: 'u8',\r\n [EVENT_ID.RACK__FIT_TO_STEPS]: 'u8',\r\n [EVENT_ID.RACK_WINDOW_HEIGHT]: 'u32',\r\n\r\n // Mixer events\r\n [EVENT_ID.MIXER_SLOT_INDEX]: 'u16',\r\n [EVENT_ID.MIXER_INSERT_ICON]: 'i16',\r\n [EVENT_ID.MIXER_INSERT_OUTPUT]: 'i32',\r\n [EVENT_ID.MIXER_INSERT_COLOR]: 'u32',\r\n [EVENT_ID.MIXER_INSERT_INPUT]: 'i32',\r\n [EVENT_ID.MIXER_INSERT_NAME]: 'text',\r\n [EVENT_ID.MIXER_INSERT_ROUTING]: 'data',\r\n [EVENT_ID.MIXER_INSERT_FLAGS]: 'data',\r\n};\r\n\r\n/**\r\n * Determines the event kind based on ID\r\n * Falls back to range-based detection if not explicitly mapped\r\n */\r\nexport function getEventKind(eventId: number): EventKind {\r\n // Check explicit mapping first\r\n const mapped = EVENT_KIND[eventId];\r\n if (mapped !== undefined) {\r\n return mapped;\r\n }\r\n\r\n // Fall back to range-based detection\r\n if (eventId < WORD) {\r\n return 'u8';\r\n } else if (eventId < DWORD) {\r\n return 'u16';\r\n } else if (eventId < TEXT) {\r\n return 'u32';\r\n } else if (eventId < DATA || NEW_TEXT_IDS.includes(eventId as 241 | 231 | 239)) {\r\n return 'text';\r\n } else {\r\n return 'data';\r\n }\r\n}\r\n\r\n/**\r\n * Returns the fixed size for BYTE/WORD/DWORD events\r\n * Returns -1 for variable-length events (TEXT/DATA)\r\n */\r\nexport function getEventFixedSize(eventId: number): number {\r\n if (eventId < WORD) {\r\n return 1;\r\n } else if (eventId < DWORD) {\r\n return 2;\r\n } else if (eventId < TEXT) {\r\n return 4;\r\n }\r\n return -1; // Variable length\r\n}\r\n","/**\n * Binary reader for FL Studio .flp files\n * Uses smart-buffer for binary reading and protobufjs for VarInt decoding\n */\n\nimport protobuf from \"protobufjs/minimal.js\";\nimport { SmartBuffer } from \"smart-buffer\";\n\nexport class BinaryReader {\n private sb: SmartBuffer;\n private source: Buffer;\n\n constructor(buffer: Buffer) {\n this.source = buffer;\n this.sb = SmartBuffer.fromBuffer(buffer);\n }\n\n /**\n * Returns current read position\n */\n tell(): number {\n return this.sb.readOffset;\n }\n\n /**\n * Seeks to an absolute position\n */\n seek(pos: number): void {\n this.sb.readOffset = pos;\n }\n\n /**\n * Seeks relative to current position\n */\n skip(offset: number): void {\n this.sb.readOffset += offset;\n }\n\n /**\n * Returns total buffer length\n */\n length(): number {\n return this.sb.length;\n }\n\n /**\n * Returns remaining bytes to read\n */\n remaining(): number {\n return this.sb.remaining();\n }\n\n /**\n * Returns true if there are more bytes to read\n */\n hasMore(): boolean {\n return this.sb.remaining() > 0;\n }\n\n /**\n * Reads an unsigned 8-bit integer\n */\n readU8(): number {\n return this.sb.readUInt8();\n }\n\n /**\n * Reads a signed 8-bit integer\n */\n readI8(): number {\n return this.sb.readInt8();\n }\n\n /**\n * Reads an unsigned 16-bit integer (little-endian)\n */\n readU16LE(): number {\n return this.sb.readUInt16LE();\n }\n\n /**\n * Reads a signed 16-bit integer (little-endian)\n */\n readI16LE(): number {\n return this.sb.readInt16LE();\n }\n\n /**\n * Reads an unsigned 32-bit integer (little-endian)\n */\n readU32LE(): number {\n return this.sb.readUInt32LE();\n }\n\n /**\n * Reads a signed 32-bit integer (little-endian)\n */\n readI32LE(): number {\n return this.sb.readInt32LE();\n }\n\n /**\n * Reads a 32-bit float (little-endian)\n */\n readF32LE(): number {\n return this.sb.readFloatLE();\n }\n\n /**\n * Reads a 64-bit float (little-endian)\n */\n readF64LE(): number {\n return this.sb.readDoubleLE();\n }\n\n /**\n * Reads raw bytes\n */\n readBytes(length: number): Buffer {\n return this.sb.readBuffer(length);\n }\n\n /**\n * Reads a VarInt (variable-length integer) using protobufjs\n * FL Studio uses this encoding for TEXT and DATA event sizes\n */\n readVarInt(): number {\n // Get remaining buffer from current position\n const remainingBuffer = this.source.subarray(this.sb.readOffset);\n const reader = protobuf.Reader.create(remainingBuffer);\n const value = reader.uint32();\n // Advance our position by how many bytes protobufjs consumed\n this.sb.readOffset += reader.pos;\n return value;\n }\n\n /**\n * Reads an ASCII string (null-terminated)\n */\n readAsciiString(length: number): string {\n const str = this.sb.readString(length, \"ascii\");\n // Remove null terminator if present\n const nullPos = str.indexOf(\"\\0\");\n return nullPos === -1 ? str : str.substring(0, nullPos);\n }\n\n /**\n * Reads a UTF-16LE string (null-terminated)\n */\n readUtf16LEString(length: number): string {\n const bytes = this.sb.readBuffer(length);\n const str = bytes.toString(\"utf16le\");\n // Remove null terminator if present\n const nullPos = str.indexOf(\"\\0\");\n return nullPos === -1 ? str : str.substring(0, nullPos);\n }\n\n /**\n * Peeks at bytes without advancing position\n */\n peek(length: number): Buffer {\n const pos = this.sb.readOffset;\n const data = this.sb.readBuffer(length);\n this.sb.readOffset = pos;\n return data;\n }\n\n /**\n * Peeks at a single byte without advancing position\n */\n peekU8(): number {\n const pos = this.sb.readOffset;\n const value = this.sb.readUInt8();\n this.sb.readOffset = pos;\n return value;\n }\n\n /**\n * Returns the internal buffer\n */\n toBuffer(): Buffer {\n return this.source;\n }\n}\n","/**\n * Binary writer for FL Studio .flp files\n * Uses smart-buffer for binary writing and protobufjs for VarInt encoding\n */\n\nimport { SmartBuffer } from \"smart-buffer\";\nimport protobuf from \"protobufjs/minimal.js\";\n\nexport class BinaryWriter {\n private sb: SmartBuffer;\n\n constructor() {\n this.sb = new SmartBuffer();\n }\n\n /**\n * Returns current write position (total bytes written)\n */\n tell(): number {\n return this.sb.writeOffset;\n }\n\n /**\n * Writes an unsigned 8-bit integer\n */\n writeU8(value: number): void {\n this.sb.writeUInt8(value & 0xff);\n }\n\n /**\n * Writes a signed 8-bit integer\n */\n writeI8(value: number): void {\n this.sb.writeInt8(value);\n }\n\n /**\n * Writes an unsigned 16-bit integer (little-endian)\n */\n writeU16LE(value: number): void {\n this.sb.writeUInt16LE(value & 0xffff);\n }\n\n /**\n * Writes a signed 16-bit integer (little-endian)\n */\n writeI16LE(value: number): void {\n this.sb.writeInt16LE(value);\n }\n\n /**\n * Writes an unsigned 32-bit integer (little-endian)\n */\n writeU32LE(value: number): void {\n this.sb.writeUInt32LE(value >>> 0);\n }\n\n /**\n * Writes a signed 32-bit integer (little-endian)\n */\n writeI32LE(value: number): void {\n this.sb.writeInt32LE(value);\n }\n\n /**\n * Writes a 32-bit float (little-endian)\n */\n writeF32LE(value: number): void {\n this.sb.writeFloatLE(value);\n }\n\n /**\n * Writes a 64-bit float (little-endian)\n */\n writeF64LE(value: number): void {\n this.sb.writeDoubleLE(value);\n }\n\n /**\n * Writes raw bytes\n */\n writeBytes(data: Buffer): void {\n this.sb.writeBuffer(data);\n }\n\n /**\n * Writes a VarInt (variable-length integer) using protobufjs\n * FL Studio uses this encoding for TEXT and DATA event sizes\n */\n writeVarInt(value: number): void {\n const writer = protobuf.Writer.create();\n writer.uint32(value);\n const encoded = writer.finish();\n this.sb.writeBuffer(Buffer.from(encoded));\n }\n\n /**\n * Writes an ASCII string (null-terminated)\n */\n writeAsciiString(str: string): void {\n this.sb.writeString(str + \"\\0\", \"ascii\");\n }\n\n /**\n * Writes a UTF-16LE string (null-terminated)\n */\n writeUtf16LEString(str: string): void {\n const buf = Buffer.from(str + \"\\0\", \"utf16le\");\n this.sb.writeBuffer(buf);\n }\n\n /**\n * Gets the final buffer\n */\n toBuffer(): Buffer {\n return this.sb.toBuffer();\n }\n}\n\n/**\n * Encodes a VarInt to a Buffer using protobufjs (standalone utility)\n */\nexport function encodeVarInt(value: number): Buffer {\n const writer = protobuf.Writer.create();\n writer.uint32(value);\n return Buffer.from(writer.finish());\n}\n\n/**\n * Calculates the byte size needed for a VarInt\n */\nexport function varIntSize(value: number): number {\n if (value < 0x80) return 1;\n if (value < 0x4000) return 2;\n if (value < 0x200000) return 3;\n if (value < 0x10000000) return 4;\n return 5;\n}\n","/**\n * FL Studio .flp file parser and serializer\n * Conservative patch approach: preserves all unknown data byte-for-byte\n *\n * Uses look-ahead scoring to handle events in the DWORD range (128-191)\n * that may use either fixed 4-byte encoding or VarInt-encoded variable\n * length payloads. For each unknown event in this range, both\n * interpretations are scored by parsing ahead ~200 bytes and counting\n * how many TEXT/DATA events (with valid VarInt sizes) are reachable.\n * The interpretation producing more valid TEXT/DATA events wins.\n */\n\nimport {\n DWORD,\n EVENT_ID,\n EVENT_KIND,\n TEXT,\n WORD,\n getEventKind,\n} from '../generated/events.generated.js';\nimport { BinaryReader } from '../io/BinaryReader.js';\nimport { BinaryWriter } from '../io/BinaryWriter.js';\n\n/** Event IDs in the DWORD range (128-191) that are explicitly mapped in EVENT_KIND. */\nconst KNOWN_DWORD_IDS: ReadonlySet<number> = new Set(\n Object.keys(EVENT_KIND)\n .map(Number)\n .filter((id) => id >= DWORD && id < TEXT),\n);\n\n/**\n * Represents a single event in an FLP file\n * Stores raw bytes to enable conservative patching\n */\nexport interface FlpEvent {\n /** Event ID (0-255) */\n id: number;\n /** Data type classification */\n kind: 'u8' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32' | 'text' | 'data' | 'unknown';\n /** Original header bytes (ID + size for variable-length events) */\n header: Buffer;\n /** Event payload data */\n payload: Buffer;\n}\n\n/**\n * Represents a parsed FLP file\n * Contains all data needed for conservative round-trip\n */\nexport interface ParsedFlp {\n /** FLhd chunk (header) - 14 bytes total */\n headerChunkBytes: Buffer;\n /** FLdt chunk header (magic + size placeholder) - 8 bytes */\n fldtHeaderBytes: Buffer;\n /** All events from the FLdt chunk */\n events: FlpEvent[];\n /** Any trailing bytes after events (should be empty) */\n trailingBytes: Buffer | undefined;\n /** Detected FL version for string encoding */\n flVersion: string;\n /** Whether to use UTF-16LE for strings (FL >= 11.5) */\n useUnicode: boolean;\n}\n\n/**\n * Header structure constants\n */\nconst FLP_HEADER_MAGIC = 'FLhd';\nconst FLP_DATA_MAGIC = 'FLdt';\nconst FLP_HEADER_SIZE = 6; // Expected header chunk size\nconst LOOKAHEAD_BYTES = 200;\nconst LOOKAHEAD_VARINT_MAX = 100_000;\n\n/**\n * Reads a VarInt directly from a raw buffer at the given offset.\n * Returns `{ size, bytesRead }` or `{ size: -1, bytesRead: 0 }` on failure.\n */\nfunction readVarIntRaw(\n buf: Buffer,\n off: number,\n end: number,\n): { size: number; bytesRead: number } {\n let shift = 0;\n let size = 0;\n const start = off;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n if (off >= end) return { size: -1, bytesRead: 0 };\n const byte = buf[off]!;\n off++;\n size |= (byte & 0x7f) << shift;\n shift += 7;\n if (!(byte & 0x80)) break;\n }\n return { size, bytesRead: off - start };\n}\n\n/**\n * Scores an alignment hypothesis by parsing ahead from `off` for up to\n * `bytesToCheck` bytes. TEXT/DATA events with valid VarInt sizes are\n * the strongest signal of correct alignment; runs of low-value unknown\n * BYTE events (typical UTF-16-LE misread) are penalised.\n */\nfunction scoreAlignment(buf: Buffer, off: number, end: number, bytesToCheck: number): number {\n const limit = Math.min(off + bytesToCheck, end);\n let textDataCount = 0;\n let consecutiveSmallByte = 0;\n let maxConsecutiveSmallByte = 0;\n\n while (off < limit) {\n const id = buf[off]!;\n\n if (id < WORD) {\n off += 2;\n if (id < 32 && !KNOWN_DWORD_IDS.has(id)) {\n consecutiveSmallByte++;\n maxConsecutiveSmallByte = Math.max(maxConsecutiveSmallByte, consecutiveSmallByte);\n } else {\n consecutiveSmallByte = 0;\n }\n } else if (id < DWORD) {\n off += 3;\n consecutiveSmallByte = 0;\n } else if (id < TEXT) {\n off += 5;\n consecutiveSmallByte = 0;\n } else {\n const vi = readVarIntRaw(buf, off + 1, end);\n if (vi.size >= 0 && vi.size < LOOKAHEAD_VARINT_MAX && off + 1 + vi.bytesRead + vi.size <= end) {\n textDataCount++;\n off = off + 1 + vi.bytesRead + vi.size;\n } else {\n return -100;\n }\n consecutiveSmallByte = 0;\n }\n }\n\n return textDataCount * 10 - maxConsecutiveSmallByte * 3;\n}\n\n/**\n * Parses an FL Studio project file\n *\n * @param buffer - Raw file data\n * @returns Parsed FLP structure\n * @throws Error if file is corrupted or invalid\n */\nexport function parseFlp(buffer: Buffer): ParsedFlp {\n const reader = new BinaryReader(buffer);\n\n // Read FLhd header chunk\n const headerMagic = reader.readBytes(4).toString('ascii');\n if (headerMagic !== FLP_HEADER_MAGIC) {\n throw new Error(`Invalid header magic: expected 'FLhd', got '${headerMagic}'`);\n }\n\n const headerSize = reader.readU32LE();\n if (headerSize !== FLP_HEADER_SIZE) {\n throw new Error(`Invalid header size: expected ${FLP_HEADER_SIZE}, got ${headerSize}`);\n }\n\n const format = reader.readI16LE();\n const channelCount = reader.readU16LE();\n const ppq = reader.readU16LE();\n\n // Validate format (0 = normal project)\n if (format < -1 || format > 0x50) {\n throw new Error(`Invalid file format: ${format}`);\n }\n\n // Store complete header chunk (14 bytes)\n const headerChunkBytes = buffer.subarray(0, 14);\n\n // Read FLdt data chunk header\n const dataMagic = reader.readBytes(4).toString('ascii');\n if (dataMagic !== FLP_DATA_MAGIC) {\n throw new Error(`Invalid data magic: expected 'FLdt', got '${dataMagic}'`);\n }\n\n const eventsSize = reader.readU32LE();\n\n // Validate events size\n const expectedFileSize = 22 + eventsSize; // 14 (FLhd) + 8 (FLdt header) + events\n if (buffer.length !== expectedFileSize) {\n throw new Error(\n `Data chunk size mismatch: expected file size ${expectedFileSize}, got ${buffer.length}`,\n );\n }\n\n // Store FLdt header (8 bytes)\n const fldtHeaderBytes = buffer.subarray(14, 22);\n\n // Parse events\n const events: FlpEvent[] = [];\n let flVersion = '0.0.0';\n let useUnicode = false;\n\n const eventsStart = reader.tell();\n const eventsEnd = eventsStart + eventsSize;\n\n while (reader.tell() < eventsEnd) {\n const eventStart = reader.tell();\n const eventId = reader.readU8();\n\n let payloadSize: number;\n let headerSize: number;\n\n if (eventId < WORD) {\n payloadSize = 1;\n headerSize = 1;\n } else if (eventId < DWORD) {\n payloadSize = 2;\n headerSize = 1;\n } else if (eventId < TEXT) {\n if (KNOWN_DWORD_IDS.has(eventId)) {\n payloadSize = 4;\n headerSize = 1;\n } else {\n // Unknown DWORD-range event: use look-ahead to decide encoding\n const afterDword = eventStart + 1 + 4;\n const vi = readVarIntRaw(buffer, eventStart + 1, eventsEnd);\n\n if (vi.size < 0 || vi.size > LOOKAHEAD_VARINT_MAX || eventStart + 1 + vi.bytesRead + vi.size > eventsEnd) {\n payloadSize = 4;\n headerSize = 1;\n } else if (vi.size === 3) {\n // VarInt(3) produces the same total footprint as DWORD; prefer DWORD\n payloadSize = 4;\n headerSize = 1;\n } else {\n const afterVarInt = eventStart + 1 + vi.bytesRead + vi.size;\n const dwordScore = scoreAlignment(buffer, afterDword, eventsEnd, LOOKAHEAD_BYTES);\n const varIntScore = scoreAlignment(buffer, afterVarInt, eventsEnd, LOOKAHEAD_BYTES);\n\n if (varIntScore > dwordScore + 2) {\n payloadSize = vi.size;\n reader.seek(eventStart + 1 + vi.bytesRead);\n headerSize = 1 + vi.bytesRead;\n } else {\n payloadSize = 4;\n headerSize = 1;\n }\n }\n }\n } else {\n // TEXT / DATA: always VarInt-encoded size\n const sizeStart = reader.tell();\n payloadSize = reader.readVarInt();\n headerSize = 1 + (reader.tell() - sizeStart);\n }\n\n const payload = reader.readBytes(payloadSize);\n const header = buffer.subarray(eventStart, eventStart + headerSize);\n const kind = getEventKind(eventId);\n\n const event: FlpEvent = {\n id: eventId,\n kind,\n header: Buffer.from(header),\n payload: Buffer.from(payload),\n };\n\n events.push(event);\n\n // Detect FL version from the first FLVersion event\n if (eventId === EVENT_ID.PROJECT_FL_VERSION && flVersion === '0.0.0') {\n const candidate = payload.toString('ascii').replace(/\\0/g, '').trim();\n if (/^\\d+(\\.\\d+)+$/.test(candidate)) {\n flVersion = candidate;\n const parts = flVersion.split('.').map((p) => parseInt(p, 10));\n const major = parts[0] ?? 0;\n const minor = parts[1] ?? 0;\n useUnicode = parts.length >= 2 && (major > 11 || (major === 11 && minor >= 5));\n }\n }\n }\n\n // Check for trailing bytes\n let trailingBytes: Buffer | undefined;\n if (reader.remaining() > 0) {\n trailingBytes = reader.readBytes(reader.remaining());\n }\n\n return {\n headerChunkBytes: Buffer.from(headerChunkBytes),\n fldtHeaderBytes: Buffer.from(fldtHeaderBytes),\n events,\n trailingBytes,\n flVersion,\n useUnicode,\n };\n}\n\n/**\n * Serializes a parsed FLP back to a buffer\n * Recalculates FLdt chunk size if events have changed\n *\n * @param parsed - Parsed FLP structure\n * @returns Serialized buffer\n */\nexport function serializeFlp(parsed: ParsedFlp): Buffer {\n const writer = new BinaryWriter();\n\n // Write FLhd header chunk (preserved byte-for-byte)\n writer.writeBytes(parsed.headerChunkBytes);\n\n // Calculate total events size\n let eventsSize = 0;\n for (const event of parsed.events) {\n eventsSize += serializeEvent(event).length;\n }\n\n // Add trailing bytes if present\n if (parsed.trailingBytes) {\n eventsSize += parsed.trailingBytes.length;\n }\n\n // Write FLdt header with updated size\n writer.writeBytes(Buffer.from(FLP_DATA_MAGIC, 'ascii'));\n writer.writeU32LE(eventsSize);\n\n // Write all events\n for (const event of parsed.events) {\n writer.writeBytes(serializeEvent(event));\n }\n\n // Write trailing bytes if present\n if (parsed.trailingBytes) {\n writer.writeBytes(parsed.trailingBytes);\n }\n\n return writer.toBuffer();\n}\n\n/**\n * Serializes a single event to bytes.\n *\n * For unchanged events the original header is emitted verbatim, ensuring a\n * byte-identical round-trip. For newly created events (empty header) the\n * header is rebuilt: TEXT/DATA events get a VarInt-encoded size prefix,\n * BYTE/WORD/DWORD events get only the 1-byte ID.\n */\nfunction serializeEvent(event: FlpEvent): Buffer {\n const writer = new BinaryWriter();\n\n if (event.header.length > 0) {\n writer.writeBytes(event.header);\n } else {\n writer.writeU8(event.id);\n if (event.id >= TEXT) {\n writer.writeVarInt(event.payload.length);\n }\n }\n\n writer.writeBytes(event.payload);\n\n return writer.toBuffer();\n}\n\n/**\n * Creates a new event with the given ID and payload.\n *\n * For TEXT/DATA events (id >= 192) the header includes a VarInt size prefix.\n * For BYTE/WORD/DWORD events the header is a single byte (the event ID).\n */\nexport function createEvent(id: number, payload: Buffer): FlpEvent {\n const kind = getEventKind(id);\n\n const headerWriter = new BinaryWriter();\n headerWriter.writeU8(id);\n\n if (id >= TEXT) {\n headerWriter.writeVarInt(payload.length);\n }\n\n return {\n id,\n kind,\n header: headerWriter.toBuffer(),\n payload: Buffer.from(payload),\n };\n}\n\n/**\n * Applies a patcher function to all events\n * Returns a new ParsedFlp with patched events\n *\n * @param parsed - Original parsed FLP\n * @param patcher - Function that transforms each event\n * @returns New ParsedFlp with patched events\n */\nexport function patchEvents(\n parsed: ParsedFlp,\n patcher: (event: FlpEvent, index: number) => FlpEvent,\n): ParsedFlp {\n const patchedEvents = parsed.events.map((event, index) => {\n const patched = patcher(event, index);\n\n // If payload changed and the original event used a VarInt-encoded header\n // (header > 1 byte), recalculate the header with the new size.\n if (patched.payload !== event.payload && event.header.length > 1) {\n const headerWriter = new BinaryWriter();\n headerWriter.writeU8(patched.id);\n headerWriter.writeVarInt(patched.payload.length);\n return {\n ...patched,\n header: headerWriter.toBuffer(),\n };\n }\n\n return patched;\n });\n\n return {\n ...parsed,\n events: patchedEvents,\n };\n}\n\n/**\n * Finds all events with a specific ID\n */\nexport function findEvents(parsed: ParsedFlp, eventId: number): FlpEvent[] {\n return parsed.events.filter((e) => e.id === eventId);\n}\n\n/**\n * Finds the first event with a specific ID\n */\nexport function findFirstEvent(parsed: ParsedFlp, eventId: number): FlpEvent | undefined {\n return parsed.events.find((e) => e.id === eventId);\n}\n\n/**\n * Gets event payload as a string (handles encoding)\n */\nexport function getEventString(event: FlpEvent, useUnicode: boolean): string {\n if (event.kind !== 'text') {\n throw new Error(`Event ${event.id} is not a text event`);\n }\n\n if (useUnicode) {\n const str = event.payload.toString('utf16le');\n const nullPos = str.indexOf('\\0');\n return nullPos === -1 ? str : str.substring(0, nullPos);\n } else {\n const str = event.payload.toString('ascii');\n const nullPos = str.indexOf('\\0');\n return nullPos === -1 ? str : str.substring(0, nullPos);\n }\n}\n\n/**\n * Creates a text payload with proper encoding\n */\nexport function createTextPayload(text: string, useUnicode: boolean): Buffer {\n if (useUnicode) {\n return Buffer.from(text + '\\0', 'utf16le');\n } else {\n return Buffer.from(text + '\\0', 'ascii');\n }\n}\n\n/**\n * Gets event payload as a number\n */\nexport function getEventNumber(event: FlpEvent): number {\n const reader = new BinaryReader(event.payload);\n\n switch (event.kind) {\n case 'u8':\n return reader.readU8();\n case 'i8':\n return reader.readI8();\n case 'u16':\n return reader.readU16LE();\n case 'i16':\n return reader.readI16LE();\n case 'u32':\n return reader.readU32LE();\n case 'i32':\n return reader.readI32LE();\n case 'f32':\n return reader.readF32LE();\n default:\n throw new Error(`Cannot get number from ${event.kind} event`);\n }\n}\n\n/**\n * Creates a numeric payload\n */\nexport function createNumberPayload(\n value: number,\n kind: 'u8' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32',\n): Buffer {\n const writer = new BinaryWriter();\n\n switch (kind) {\n case 'u8':\n writer.writeU8(value);\n break;\n case 'i8':\n writer.writeI8(value);\n break;\n case 'u16':\n writer.writeU16LE(value);\n break;\n case 'i16':\n writer.writeI16LE(value);\n break;\n case 'u32':\n writer.writeU32LE(value);\n break;\n case 'i32':\n writer.writeI32LE(value);\n break;\n case 'f32':\n writer.writeF32LE(value);\n break;\n }\n\n return writer.toBuffer();\n}\n","/**\n * High-level API for reading and modifying FL Studio project files\n * Provides typed access to project metadata, samples, plugins, and time info\n */\n\nimport { EVENT_ID } from '../generated/events.generated.js';\nimport { BinaryReader } from '../io/BinaryReader.js';\nimport { BinaryWriter } from '../io/BinaryWriter.js';\nimport {\n createNumberPayload,\n createTextPayload,\n findFirstEvent,\n type FlpEvent,\n getEventNumber,\n getEventString,\n type ParsedFlp,\n patchEvents,\n} from '../parser/FlpParser.js';\n\n// ============================================================================\n// Project Metadata\n// ============================================================================\n\n/**\n * Project metadata (name, description, artist, genre, BPM)\n */\nexport interface ProjectMeta {\n name: string | null;\n description: string | null;\n artist: string | null;\n genre: string | null;\n bpm: number | null;\n}\n\n/**\n * Reads the BPM value from the parsed FLP.\n *\n * Primary: PROJECT_TEMPO (DWORD+28) stores BPM × 1000 as u32.\n * Legacy fallback: _TEMPO_COARSE (WORD+2) + _TEMPO_FINE (WORD+29).\n */\nfunction readBpm(parsed: ParsedFlp): number | null {\n const tempoEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TEMPO);\n if (tempoEvent) {\n return getEventNumber(tempoEvent) / 1000;\n }\n\n const coarseEvent = findFirstEvent(parsed, EVENT_ID.PROJECT__TEMPO_COARSE);\n if (coarseEvent) {\n let bpm = coarseEvent.payload.readUInt16LE(0);\n const fineEvent = findFirstEvent(parsed, EVENT_ID.PROJECT__TEMPO_FINE);\n if (fineEvent) {\n bpm += fineEvent.payload.readUInt16LE(0) / 1000;\n }\n return bpm;\n }\n\n return null;\n}\n\n/**\n * Reads project metadata from a parsed FLP\n */\nexport function readProjectMeta(parsed: ParsedFlp): ProjectMeta {\n const titleEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TITLE);\n const commentsEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_COMMENTS);\n const artistsEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_ARTISTS);\n const genreEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_GENRE);\n\n return {\n name: titleEvent ? getEventString(titleEvent, parsed.useUnicode) : null,\n description: commentsEvent ? getEventString(commentsEvent, parsed.useUnicode) : null,\n artist: artistsEvent ? getEventString(artistsEvent, parsed.useUnicode) : null,\n genre: genreEvent ? getEventString(genreEvent, parsed.useUnicode) : null,\n bpm: readBpm(parsed),\n };\n}\n\n/**\n * Writes project metadata to a parsed FLP\n * Only modifies fields that are provided (non-undefined)\n */\nexport function writeProjectMeta(parsed: ParsedFlp, meta: Partial<ProjectMeta>): ParsedFlp {\n return patchEvents(parsed, (event: FlpEvent) => {\n // Patch title\n if (meta.name !== undefined && event.id === EVENT_ID.PROJECT_TITLE) {\n return {\n ...event,\n payload: createTextPayload(meta.name ?? '', parsed.useUnicode),\n };\n }\n\n // Patch comments/description\n if (meta.description !== undefined && event.id === EVENT_ID.PROJECT_COMMENTS) {\n return {\n ...event,\n payload: createTextPayload(meta.description ?? '', parsed.useUnicode),\n };\n }\n\n // Patch artists\n if (meta.artist !== undefined && event.id === EVENT_ID.PROJECT_ARTISTS) {\n return {\n ...event,\n payload: createTextPayload(meta.artist ?? '', parsed.useUnicode),\n };\n }\n\n // Patch genre\n if (meta.genre !== undefined && event.id === EVENT_ID.PROJECT_GENRE) {\n return {\n ...event,\n payload: createTextPayload(meta.genre ?? '', parsed.useUnicode),\n };\n }\n\n // Patch tempo (stored as BPM * 1000)\n if (meta.bpm && Math.abs(meta.bpm) > 0 && event.id === EVENT_ID.PROJECT_TEMPO) {\n return {\n ...event,\n payload: createNumberPayload(Math.round(Math.abs(meta.bpm) * 1000), 'u32'),\n };\n }\n\n return event;\n });\n}\n\n// ============================================================================\n// Project Time Info\n// ============================================================================\n\n/**\n * Project creation date and work time\n */\nexport interface ProjectTimeInfo {\n creationDate: Date | null;\n workTimeSeconds: number | null;\n}\n\n// Delphi epoch: December 30, 1899\nconst DELPHI_EPOCH = new Date(1899, 11, 30);\n\n/**\n * Converts Delphi timestamp (days since epoch) to Date\n */\nfunction delphiToDate(days: number): Date {\n const ms = days * 24 * 60 * 60 * 1000;\n return new Date(DELPHI_EPOCH.getTime() + ms);\n}\n\n/**\n * Converts Date to Delphi timestamp (days since epoch)\n */\nfunction dateToDelphiDays(date: Date): number {\n const ms = date.getTime() - DELPHI_EPOCH.getTime();\n return ms / (24 * 60 * 60 * 1000);\n}\n\n/**\n * Reads project time info from a parsed FLP\n * Timestamp event contains: Float64 created_on (days), Float64 time_spent (days)\n */\nexport function readProjectTimeInfo(parsed: ParsedFlp): ProjectTimeInfo {\n const timestampEvent = findFirstEvent(parsed, EVENT_ID.PROJECT_TIMESTAMP);\n\n if (!timestampEvent || timestampEvent.payload.length < 16) {\n return {\n creationDate: null,\n workTimeSeconds: null,\n };\n }\n\n const reader = new BinaryReader(timestampEvent.payload);\n const createdOnDays = reader.readF64LE();\n const timeSpentDays = reader.readF64LE();\n\n return {\n creationDate: delphiToDate(createdOnDays),\n workTimeSeconds: timeSpentDays * 24 * 60 * 60, // Convert days to seconds\n };\n}\n\n/**\n * Writes project time info to a parsed FLP\n * Only modifies fields that are provided (non-undefined)\n *\n * If `creationDate` or `workTimeSeconds` is set to `null`, the final value will be set on `0` (Delphi epoch)\n */\nexport function writeProjectTimeInfo(parsed: ParsedFlp, info: Partial<ProjectTimeInfo>): ParsedFlp {\n // Read current values to preserve unmodified fields\n const current = readProjectTimeInfo(parsed);\n\n return patchEvents(parsed, (event: FlpEvent) => {\n if (event.id !== EVENT_ID.PROJECT_TIMESTAMP) {\n return event;\n }\n\n const writer = new BinaryWriter();\n\n // Write creation date\n if (info.creationDate !== undefined && info.creationDate !== null) {\n writer.writeF64LE(dateToDelphiDays(info.creationDate));\n } else if (current.creationDate !== null) {\n writer.writeF64LE(dateToDelphiDays(current.creationDate));\n } else {\n writer.writeF64LE(0);\n }\n\n // Write work time\n if (info.workTimeSeconds !== undefined && info.workTimeSeconds !== null) {\n writer.writeF64LE(info.workTimeSeconds / (24 * 60 * 60)); // Convert seconds to days\n } else if (current.workTimeSeconds !== null) {\n writer.writeF64LE(current.workTimeSeconds / (24 * 60 * 60));\n } else {\n writer.writeF64LE(0);\n }\n\n return {\n ...event,\n payload: writer.toBuffer(),\n };\n });\n}\n\n// ============================================================================\n// Samples\n// ============================================================================\n\n/**\n * Reference to a sample in the project\n */\nexport interface SampleRef {\n /** Index of the event in the events array */\n eventIndex: number;\n /** File path of the sample */\n path: string;\n}\n\n/**\n * Lists all samples in the project\n */\nexport function listSamples(parsed: ParsedFlp): SampleRef[] {\n const samples: SampleRef[] = [];\n\n parsed.events.forEach((event: FlpEvent, index: number) => {\n if (event.id === EVENT_ID.CHANNEL_SAMPLE_PATH) {\n const path = getEventString(event, parsed.useUnicode);\n if (path && path.length > 0) {\n samples.push({\n eventIndex: index,\n path,\n });\n }\n }\n });\n\n return samples;\n}\n\n/**\n * Rewrites sample paths using a mapper function\n */\nexport function rewriteSamplePaths(\n parsed: ParsedFlp,\n mapper: (oldPath: string) => string,\n): ParsedFlp {\n return patchEvents(parsed, (event: FlpEvent) => {\n if (event.id !== EVENT_ID.CHANNEL_SAMPLE_PATH) {\n return event;\n }\n\n const oldPath = getEventString(event, parsed.useUnicode);\n if (!oldPath || oldPath.length === 0) {\n return event;\n }\n\n const newPath = mapper(oldPath);\n if (newPath === oldPath) {\n return event;\n }\n\n return {\n ...event,\n payload: createTextPayload(newPath, parsed.useUnicode),\n };\n });\n}\n\n// ============================================================================\n// Plugins (VST)\n// ============================================================================\n\n/**\n * Reference to a plugin in the project\n */\nexport interface PluginRef {\n /** Plugin name (may be null if not available) */\n name: string | null;\n /** Plugin vendor/provider (may be null if not stored in file) */\n vendor: string | null;\n}\n\n/**\n * VST Plugin Event internal IDs (from plugin.py VSTPluginEvent)\n */\nconst VST_EVENT_ID = {\n MIDI: 1,\n FLAGS: 2,\n IO: 30,\n INPUTS: 31,\n OUTPUTS: 32,\n PLUGIN_INFO: 50,\n FOUR_CC: 51,\n GUID: 52,\n STATE: 53,\n NAME: 54,\n PLUGIN_PATH: 55,\n VENDOR: 56,\n} as const;\n\n/**\n * Parses a VST plugin data event to extract name and vendor\n * Based on VSTPluginEvent structure in PyFLP\n */\nfunction parseVstPluginData(payload: Buffer): { name: string | null; vendor: string | null } {\n if (payload.length < 4) {\n return { name: null, vendor: null };\n }\n\n const reader = new BinaryReader(payload);\n\n // First 4 bytes: wrapper marker.\n // Historically seen values include 8/10/11, but newer FL versions can use\n // other markers (e.g. 12). We read and ignore the exact value here because\n // this parser is only called for \"Fruity Wrapper\" plugin data.\n const typeMarker = reader.readU32LE();\n void typeMarker;\n\n let name: string | null = null;\n let vendor: string | null = null;\n\n // Parse sub-events\n while (reader.remaining() >= 12) {\n // At minimum: 4 (id) + 8 (size)\n const subEventId = reader.readU32LE();\n const dataSize = reader.readU32LE(); // Lower 32 bits of size\n const dataSizeHigh = reader.readU32LE(); // Upper 32 bits (usually 0)\n\n // Combine for 64-bit size (though in practice it's always small)\n const actualSize = dataSize + dataSizeHigh * 0x100000000;\n\n if (actualSize > reader.remaining()) {\n break;\n }\n\n const data = reader.readBytes(actualSize);\n\n // Extract name and vendor\n if (subEventId === VST_EVENT_ID.NAME && actualSize > 0) {\n name = data.toString('utf8').replace(/\\0/g, '');\n } else if (subEventId === VST_EVENT_ID.VENDOR && actualSize > 0) {\n vendor = data.toString('utf8').replace(/\\0/g, '');\n }\n }\n\n return { name, vendor };\n}\n\n/**\n * Lists all plugins (VST and native) in the project\n * Returns plugin name and vendor where available\n */\nexport function listPlugins(parsed: ParsedFlp): PluginRef[] {\n const plugins: PluginRef[] = [];\n const seenPlugins = new Set<string>();\n\n // Track current channel context\n let currentInternalName: string | null = null;\n let currentPluginName: string | null = null;\n\n for (const event of parsed.events) {\n // Track channel new events as boundaries\n if (event.id === EVENT_ID.CHANNEL_NEW) {\n // Reset context for new channel\n if (currentInternalName || currentPluginName) {\n // Save previous channel's plugin if it wasn't a VST (no plugin data)\n const key = `${currentInternalName ?? ''}:${currentPluginName ?? ''}`;\n if (\n !seenPlugins.has(key) &&\n currentInternalName &&\n currentInternalName !== 'Fruity Wrapper'\n ) {\n seenPlugins.add(key);\n plugins.push({\n name: currentPluginName || currentInternalName,\n vendor: null, // Native plugins don't store vendor\n });\n }\n }\n currentInternalName = null;\n currentPluginName = null;\n }\n\n // Track internal name (identifies plugin type)\n if (event.id === EVENT_ID.PLUGIN_INTERNAL_NAME) {\n currentInternalName = getEventString(event, parsed.useUnicode);\n }\n\n // Track display name\n if (event.id === EVENT_ID.PLUGIN_NAME) {\n currentPluginName = getEventString(event, parsed.useUnicode);\n }\n\n // Parse VST plugin data\n if (event.id === EVENT_ID.PLUGIN_DATA && currentInternalName === 'Fruity Wrapper') {\n const vstData = parseVstPluginData(event.payload);\n if (vstData.name) {\n const key = `vst:${vstData.name}:${vstData.vendor ?? ''}`;\n if (!seenPlugins.has(key)) {\n seenPlugins.add(key);\n plugins.push({\n name: vstData.name,\n vendor: vstData.vendor,\n });\n }\n }\n // Reset context after processing VST\n currentInternalName = null;\n currentPluginName = null;\n }\n }\n\n // Handle last channel if any\n if (currentInternalName && currentInternalName !== 'Fruity Wrapper') {\n const key = `${currentInternalName}:${currentPluginName ?? ''}`;\n if (!seenPlugins.has(key)) {\n plugins.push({\n name: currentPluginName || currentInternalName,\n vendor: null,\n });\n }\n }\n\n return plugins;\n}\n\n// ============================================================================\n// FL Version\n// ============================================================================\n\n/**\n * Gets the FL Studio version string from the project\n */\nexport function getFlVersion(parsed: ParsedFlp): string {\n return parsed.flVersion;\n}\n\n/**\n * Gets the PPQ (Pulses Per Quarter note) from the header\n */\nexport function getPPQ(parsed: ParsedFlp): number {\n // PPQ is at offset 12-13 in the header (bytes 12-13 of the 14-byte FLhd chunk)\n const reader = new BinaryReader(parsed.headerChunkBytes);\n reader.seek(12);\n return reader.readU16LE();\n}\n"],"mappings":"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","names":["SmartBuffer","protobuf","headerSize"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* High-level API for reading and modifying FL Studio project files
|
|
3
3
|
* Provides typed access to project metadata, samples, plugins, and time info
|
|
4
4
|
*/
|
|
5
|
-
import { type ParsedFlp } from
|
|
5
|
+
import { type ParsedFlp } from '../parser/FlpParser.js';
|
|
6
6
|
/**
|
|
7
7
|
* Project metadata (name, description, artist, genre, BPM)
|
|
8
8
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../../../src/api/ProjectApi.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAOL,KAAK,SAAS,EAEf,MAAM,wBAAwB,CAAC;AAMhC;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../../../src/api/ProjectApi.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAOL,KAAK,SAAS,EAEf,MAAM,wBAAwB,CAAC;AAMhC;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AA2BD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,CAa9D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,SAAS,CA4CzF;AAMD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,IAAI,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAqBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,eAAe,CAkBtE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,SAAS,CAkCjG;AAMD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,EAAE,CAgB1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAClC,SAAS,CAqBX;AAMD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,iEAAiE;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAoED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,EAAE,CAwE1D;AAMD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAKhD"}
|
|
@@ -107,7 +107,7 @@ export declare const EVENT_ID: {
|
|
|
107
107
|
/**
|
|
108
108
|
* Event data type classification
|
|
109
109
|
*/
|
|
110
|
-
export type EventKind =
|
|
110
|
+
export type EventKind = 'u8' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32' | 'text' | 'data' | 'unknown';
|
|
111
111
|
/**
|
|
112
112
|
* Maps event IDs to their data type
|
|
113
113
|
* Used for proper serialization/deserialization
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.generated.d.ts","sourceRoot":"","sources":["../../../src/generated/events.generated.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,eAAO,MAAM,IAAI,IAAI,CAAC;AACtB,eAAO,MAAM,IAAI,KAAK,CAAC;AACvB,eAAO,MAAM,KAAK,MAAM,CAAC;AACzB,eAAO,MAAM,IAAI,MAAM,CAAC;AACxB,eAAO,MAAM,IAAI,MAAM,CAAC;AAGxB,eAAO,MAAM,YAAY,mCAIf,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+FX,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB,IAAI,GACJ,IAAI,GACJ,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"events.generated.d.ts","sourceRoot":"","sources":["../../../src/generated/events.generated.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,eAAO,MAAM,IAAI,IAAI,CAAC;AACtB,eAAO,MAAM,IAAI,KAAK,CAAC;AACvB,eAAO,MAAM,KAAK,MAAM,CAAC;AACzB,eAAO,MAAM,IAAI,MAAM,CAAC;AACxB,eAAO,MAAM,IAAI,MAAM,CAAC;AAGxB,eAAO,MAAM,YAAY,mCAIf,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+FX,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB,IAAI,GACJ,IAAI,GACJ,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CA+FhD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAmBvD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASzD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BinaryReader.d.ts","sourceRoot":"","sources":["../../../src/io/BinaryReader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAc;
|
|
1
|
+
{"version":3,"file":"BinaryReader.d.ts","sourceRoot":"","sources":["../../../src/io/BinaryReader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAK1B;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIvB;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI1B;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIjC;;;OAGG;IACH,UAAU,IAAI,MAAM;IAUpB;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAOvC;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAQzC;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAO5B;;OAEG;IACH,MAAM,IAAI,MAAM;IAOhB;;OAEG;IACH,QAAQ,IAAI,MAAM;CAGnB"}
|