Parse FL Studio 2024/2025 playlist items (80-byte records) - #205
Parse FL Studio 2024/2025 playlist items (80-byte records)#205CryptoJones wants to merge 1 commit into
Conversation
FL 2024/2025 (21.2+ / 25.x) grew each playlist item to an 80-byte record: a 20-byte tail (_u4) after FL 21's 28-byte tail (_u3). PlaylistEvent only knew the 32- and 60-byte layouts, so these events failed the size check and their clips were dropped (demberto#177, demberto#199, demberto#200). Add the _u4 block gated on a `fl2025` param, extend SIZES to include 80, and detect it by the fixed size that divides the payload — preferring the 60-byte reading on a 60/80 common multiple so files that parsed before are unaffected. The record layout was verified byte-for-byte against FL Studio 2025 saves, and a synthetic-event test asserts the 80-byte records parse and round-trip. Known limitation (documented in-code): clips edited in FL grow past 80 bytes, so a heavily-edited project's Playlist event can be variable-length and still not match a single fixed size.
|
Additional findings: FL26 needs two more fixes on top of this PR I hit the same wall parsing FL26.1.1 projects (both re-saved FL26 files and legacy FL20.5 files on my rig). This PR's 80-byte layout is correct for FL 2024/2025, but FL26 grows each playlist item to 88 bytes — a further 8-byte tail (_u5) after the 20-byte _u4. Verified byte-for-byte: 32 base + 28 _u3 (FL21) + 20 _u4 (FL2024/25) + 8 _u5 (FL26) = 88.
elif id < TEXT:
if id == EventEnum(0xAC):
size = c.VarInt.parse_stream(stream)
value = stream.read(size)
else:
value = stream.read(4)
With all three changes (this PR's 80-byte + the 88-byte extension + 0xAC varint + phantom-pattern skip) I parseFL26 projects fully: 10 channels / 616 notes, and a 15-channel project at 1302 notes, with legacy FL20.5 filesunaffected (regression-checked). Happy to open a PR with the combined diff + tests if you're interested. Sorry for AI sloping, as I'm really poor at progamming, but it works. |
What
FL Studio 2024/2025 (21.2+ / 25.x) grew each playlist item to an 80-byte record — a 20-byte tail (
_u4) after FL 21's 28-byte tail (_u3).PlaylistEventonly knew the 32- and 60-byte layouts, so FL 2024/2025 playlist events fail the size check and their clips are dropped. Fixes #200 and the same underlying cause behind #199 / #177.The record
Full 80-byte layout, verified byte-for-byte against FL Studio 2025 (25.x) saves:
item_indexselects the item type:< 20480references a channel by iid (an audio clip if that channel'sChannelID.Type == 4, an automation clip if== 5);>= 20480is a pattern clip (pattern_base + pattern#).The change
_u4gated on a newfl2025struct param; extendSIZESto include80.Known limitation (documented in-code)
A freshly placed clip is exactly 80 bytes, but clips edited in FL (fades, slices, resizes) carry extra per-clip data and grow past it — so a heavily-edited project's Playlist event can be variable-length and still not match a single fixed size. Fully general handling would need the project's FL version to disambiguate; this PR fixes the common (fresh / programmatically-written) case without regressing anything.
How this came up
I hit this building FL-Studio-MCP-Server — an MCP server that lets Claude Code drive FL Studio and generate/edit
.flpprojects, with PyFLP powering its offline route. Writing FL 2025 audio-clip arrangements is what surfaced the 80-byte record, so the parse fix belongs upstream. Thanks for PyFLP — it's a joy to build on. 🙏🤖 Generated with Claude Code
Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/