Every clip placed in the playlist is one playlist item. The playlist items event (233) holds them all, as 32-byte records with nothing between them. There is one such event for the whole project, because these versions have a single playlist.
Record
Earlier versions wrote 28-byte records. The 32-byte record has a group field at offset 14, and the fields after it sit four bytes later than before. No source records which version made the change. This site places it at 9.0, together with the change to 24-byte note records, because FL Studio 9.0.0 introduced “note & Playlist clip grouping”, according to Image-Line’s changelog. That is an inference.
The layout is the one PyFLP reads for every file from before FL Studio 21. Every number is little-endian, and positions and lengths are in ticks.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 4 | u32 | position | Where the item starts in the playlist, in ticks. |
| 4 | 2 | u16 | pattern_base | 20480 (00 50). See What an item plays. |
| 6 | 2 | u16 | item_index | What the item plays: a pattern or a channel. |
| 8 | 4 | u32 | length | The item’s length, in ticks. |
| 12 | 2 | u16 | track | The track the item sits on, counted backwards. See Track numbers. |
| 14 | 2 | u16 | group | The item group. |
| 16 | 2 | bytes | unknown | Unknown. |
| 18 | 2 | u16 | item_flags | Item flags. PyFLP notes a muted flag from version 9.0. |
| 20 | 4 | bytes | unknown | Unknown. |
| 24 | 4 | u32 or f32 | start_offset | Start offset within the clip. See Start and end offsets. |
| 28 | 4 | u32 or f32 | end_offset | End offset within the clip. |
An event size can be a whole number of both the old and the new record: 224 bytes is eight 28-byte records or seven 32-byte ones. So the version decides which record to read. An event that is not a whole number of 32-byte records, or a record without 20480 at offset 4, means the file is damaged or not of this variant.
What an item plays
An item plays either a pattern or a channel’s clip, such as an audio or automation
clip. PyFLP tells them apart by comparing item_index with
pattern_base:
- Greater than
pattern_base: a pattern. The pattern index isitem_indexminuspattern_base. - Otherwise: a channel. The value is the channel index.
PyFLP notes that pattern items in this event date from version 7.0 and channel items from 2.0.1.
Start and end offsets
The last two fields say which part of the clip plays. DawVert and FLParser read them
as whole ticks for a pattern clip and as 32-bit floats for an audio clip. A value of
−1.0, or FF FF FF FF, means no offset is set.
Track numbers
The track field counts down from the last track. The playlist in these
versions has 199 tracks, so subtract the field from 198 to get the track:
track index = 198 − track
So the first track, index 0, is stored as 198. This is how both PyFLP and FLParser read files from before version 12.9.1.