Skip to content

XiaoXianThis/JsFLP

Repository files navigation

jsflp

License: GPL v3 npm

中文文档

A high-fidelity FL Studio project file (.flp) parser and serialiser for Node.js & browsers.

jsflp is a 1:1 TypeScript port of the excellent Python library PyFLP by demberto. Its public API, property names (snake_case), behaviour, exceptions and round-trip guarantees are intentionally identical, while the implementation is zero-runtime-dependency TypeScript that runs in Node.js 18+ and any modern browser.


Highlights

  • High fidelityparse then save round-trips a real-world .flp byte-for-byte. The included null_check test loads FL 20.8.4.flp and asserts Buffer.equals(input, save(parse(input))).
  • Zero runtime dependencies — pure TypeScript. Browser-friendly. Tree- shakable. ESM and CJS builds with bundled .d.ts.
  • PyFLP-compatible APIparse(bytes), save(project), models like Project, Pattern, Note, Channel, Sampler, Mixer, Insert, Slot, Arrangement, Track, VSTPlugin, native plugin classes, etc.
  • Strongly typed — every event, struct field and enum is typed.

Installation

npm install @xiaoxianthis/jsflp

Usage (Node.js)

import { parseFile, saveFile } from "@xiaoxianthis/jsflp/node";

const project = await parseFile("/path/to/song.flp");

console.log(project.title);            // → "PyFLP Test FLP"
console.log(project.tempo);            // → 69.42
console.log(project.version.toString()); // → "20.8.4.2576"
console.log(project.ppq);              // → 96

// Iterate channels
for (const ch of project.channels) {
  console.log(ch.iid, ch.display_name, ch.color);
}

// Iterate patterns
for (const p of project.patterns) {
  console.log(p.iid, p.name, [...p.notes()].length, "notes");
}

// Iterate mixer inserts
for (const insert of project.mixer) {
  console.log(insert.iid, insert.name, insert.volume);
}

// Save back to disk
project.title = "Edited";
await saveFile(project, "/path/to/output.flp");

Usage (Browser / framework-agnostic)

import { parse, save } from "@xiaoxianthis/jsflp";

const buf = new Uint8Array(await file.arrayBuffer());
const project = parse(buf);

const out: Uint8Array = save(project);
const blob = new Blob([out], { type: "application/octet-stream" });

API surface

The public API mirrors PyFLP's exactly. Every public class, enum and function uses the same name as in PyFLP, with snake_case properties preserved (rather than the JS-conventional camelCase):

Domain Top-level classes
Project Project, parse, save, parseFile, saveFile
Channels ChannelRack, Channel, Sampler, Instrument, Layer, Automation, AutomationPoint, DisplayGroup, sub-models like Arp, Delay, FX, Envelope, SamplerLFO, Polyphony, Tracking, Keyboard, Playback, TimeStretching, Content, Filter, Reverb, LevelAdjusts, Time
Patterns Patterns, Pattern, Note, Controller
Mixer Mixer, Insert, Slot, InsertEQ, InsertEQBand, InsertDock
Arrangements Arrangements, Arrangement, Track, ChannelPLItem, PatternPLItem, TimeSignature
Time markers TimeMarker, TimeMarkerType
Plugins VSTPlugin, BooBass, FruitKick, FruityBalance, FruityBloodOverdrive, FruityCenter, FruityFastDist, FruityNotebook2, FruitySend, FruitySoftClipper, FruityStereoEnhancer, Plucked, Soundgoodizer, WrapperPage
Types FLVersion, RGBA, MusicalTime
Exceptions FLPError, HeaderCorrupted, DataCorrupted, EventIDOutOfRange, InvalidEventChunkSize, PropertyCannotBeSet, NoModelsFound, ModelNotFound, VersionNotDetected, ChannelNotFound

Faithful to PyFLP

Care was taken to match PyFLP semantics exactly:

  • The licensee jumble/decode algorithm
  • The pattern/arrangement timemarker disambiguation logic
  • The Optional field semantics (rewind on parse failure, skip on build)
  • The _extra greedy-bytes preservation (any unknown trailing bytes survive a round trip)
  • The maximum inserts/slots tables by FL version
  • The _VolWord/_VolByte/Levels cascade for channel volume/pan
  • Note-name ↔ MIDI-key conversion using sharp names only
  • 64-bit integers are exposed as bigint where they appear in the binary format (rare; mostly internal length prefixes).

Build & contribute

git clone <repo>
cd jsflp
npm install
npm test          # run all 139 unit tests (incl. null_check round-trip)
npm run build     # produce dist/ (ESM + CJS + d.ts)
npm run typecheck

License

GPL-3.0. The original PyFLP project is also licensed under GPL-3.0.

Credits

  • demberto for PyFLP — the source library this is a faithful port of.
  • @codecat / libflp for the licensee jumble algorithm (carried forward via PyFLP).

About

零依赖的 FL Studio 工程文件解析器,可以运行在Node.js或浏览器中 / FL Studio *.flp file parser, on nodejs & browser.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors