Help - Search - Members - Calendar
Full Version: Foobar playlist format (.fpl) description?
Hydrogenaudio Forums > Hosted Forums > foobar2000 > General - (fb2k)
Zacw
I've been hunting for awhile for a description of the .fpl playlist format. I've got a 'classical music jukebox' program that shuffles classical playlists (in bland old m3u format) while keeping different parts of works grouped together; I'd like to use the additional info in .fpl playlists (especially the duration, if it's saved!) for more features.

I found this Perl script when I searched the board
http://tate.undef.jp/read-fpl.txt

but a test playlist I saved doesn't seem to fit in with what this expects, at leas as I understand it from my very-rusty Perl knowledge!

Unless I'm mistaken, there ought to be a 4 byte identifier, followed by 4 byte count of rows, followed by the first row with a 4-byte file type number and 4 bytes for the length of the subsequent string. What i observe is a 20-byte block before the first string, instead of 16, none of which seem to relate to the size of the string. Also, the initial identifier is 0xE1 A0 9C 91 instead of 0x 82 68 D0 E3.

Any links to some document with a quick description would be helpful :-)

-Zac
mazy
i know that the new developer of 'mpeg audio catalogue' has made delphi components for reading and writing fpl playlists ...
Zacw
QUOTE(mazy @ Apr 16 2006, 02:32 AM) *

i know that the new developer of 'mpeg audio catalogue' has made delphi components for reading and writing fpl playlists ...


Delphi? Good gravy, lol. You mean this?
http://www.dv.co.yu/mpgscript/mpgtools.htm

Hmm, this stuff doesn't look like it's been updated since 1999, so I don't think.fpl support's included with this version.. Is there a newer link?

-Zac
mazy
no, this one: http://mac.sourceforge.net/
Zacw
QUOTE(mazy @ Apr 16 2006, 03:12 PM) *



Ah, thanks for the link. I looked it over, and it appears to pretty much be wrong, too. The format must have changed with the most recent release. Here is what I have ascertained thus far for the format:

A) First 16 bytes always the same (E1 A0 9C 91 F8 3C 77 42 85 2C 3B CC 14 01 D3 F2)
B) A 4-byte value indicating the length of the following string (bigendian)
C) An extremely long string, containing filenames beginning with file://, and followed by field names and field name values seperated by 00. Sometimes the values follow the names, sometimes they don't, sometimes there are values and no names. Sometimes, blocks of values follow blocks of names. I don't understand this.
D) After the string is a 4-byte value indicating how many items are in the playlist.
E) Next is what seems to be a long list of data, with each info block starting with the sequence 00 01 00 00.

Beyond this I'm at a loss. I can't find any reference to the #samples or the total time in seconds or miliseconds, so I'm not sure what to do. I'll note that each block of info is very sparse, with lots of 0 bytes, suggesting almost everything there is a small-valued integer. Dunno what those integers mean, however.


-Zac
(who now has a headache...)
Gambit
QUOTE(Zacw @ Apr 17 2006, 01:11 AM) *
Beyond this I'm at a loss. I can't find any reference to the #samples or the total time in seconds or miliseconds, so I'm not sure what to do. I'll note that each block of info is very sparse, with lots of 0 bytes, suggesting almost everything there is a small-valued integer. Dunno what those integers mean, however.

As far as I can remember, duration info is not stored. It's been a while though since I wrote that component. It should be fairly easy though to update it to support 0.9.
Zacw
QUOTE(Gambit @ Apr 16 2006, 08:37 PM) *

As far as I can remember, duration info is not stored. It's been a while though since I wrote that component. It should be fairly easy though to update it to support 0.9.



Looks like it will involve a bit of substantial updating; the playlist file now stores replaygain and duration info. I have figured out a big part of the formatting I think:

After the list of filenames and tags etc. you have a big block of numbers. The first byte is the count of items in the playlist. For each file there is then a sequence of 53 bytes consisting of the following sequence:

A) 4 byte integer, unknown meaning. Seems to be a single-digit integer value, often 1 or 3
B) 4 byte integer, unknown meaning. Varies depending on location in playlist.
C) 4 bytes, always 0?
D) 4 byte integer specifying the file size
E) 4 bytes, always 0?
F) 8 bytes, unknown meaning
G) 8 byte floating point value representing duration in seconds
H) 4 bytes, probably floating point album replaygain value (7AC4 = -1.00 if none)
I) 4 byte floating point representing track replaygain value (7AC4 = -1.00 if none)
J) 4 bytes, probably representing an album peak value (80BF = 1.00 if none)
K) 4 byte floating point track peak value (80BF = 1.00 if none)
L) 1-byte integer representing the number of 4-byte integers following


After L comes a varaible number of integer values whose meaning is unknown to me. All the numbers are very low.

I hope this is useful to someone besides me, and that they don't change it again on the next release :-P

-Zac
(feeling a bit like an archaeologist)
AKX
Attempting to resurrect this thread. =)

So, is there any chance of getting an official description of the format?

I'm trying to write a Python-based HTTP streaming server that could use the FooBar2000 database as its library source. So far, I've, thanks to Zacw's efforts, managed to read the "data section" and the item count correctly, but after that, I've no idea what's going on.
AKX
Double-post and all, but a couple hours of hacking has brought me to a state where I can now read all the items from the file... but the "integer table" is still a mystery for me. I'm _guessing_ it's some sort of a pointer table (key, value, key, value) to the global string table (henceforth "data table") on the top of the file, but the offsets don't quite make sense. See for yourself: this is the dump from my program so far.

It can read the header, the data table and split/enumerate its entries (since they all seemed to be \0-delimited):
CODE
Data length: 617
Data entr.s: 50
   0     : file://H:\whatever\M-FLO\m-flo astromantic\06 m-flo - way u move (dragon ash).mp3
   1     : album
   2     : artist
   3     : comment
   4     : date
   5     : genre
   6     : title
   7     : tracknumber
   8     : astromantic
   9     : m-flo
   10    : --==More Volume Please==--
   11    : 2004
   12    : Hip-Hop
   13    : way u move (dragon ash)
   14    : 6
   15    : enc_delay
   16    : 576
   17    : enc_padding
   18    : 1440
   19    : mp3_accurate_length
   20    : yes
   21    : bitrate
   22    : 192
   23    : codec
   24    : MP3
   25    : encoding
   26    : lossy
   27    : channels
   28    : 2
   29    : samplerate
   30    : 44100
   31    : mp3_stereo_mode
   32    : stereo
   33    : tool
   34    : LAME3.92
   35    : codec_profile
   36    : CBR
   37    : tagtype
   38    : id3v2|id3v1
   39    : file://E:\Music\mp3\Minotaur Shock\Chiff-Chaffs & Willow Warblers\04 Minotaur Shock - Moray Arrival.mp3
   40    : Chiff-Chaffs & Willow Warblers
   41    : Minotaur Shock
   42    : 2001
   43    : Electronic
   44    : Moray Arrival
   45    : 04
   46    : 2004
   47    : 204
   48    : extrainfo
   49    : VBR

Then it begins enumerating the items, which it does properly (at least the file sizes and durations both seem to be correct):
CODE
<__main__.FPLFile instance at 0x00A455A8>
  albumpeak            -1.0
  dtn                  49
  duration             490.56
  rgalbum              -1000.0
  rgtrack              -1000.0
  size                 11776995
  trackpeak            -1.0
  unk1                 1
  unk2                 0
  unk3                 0
  unk4                 0
  unk5                 128107706786250000
252 bytes read, offset 37d
8:10

But then comes the "item table" (the low integer values Zacw mentions). I think this is a key-value mapping of some sort, indexing the data table. This would make sense, since a playlist is bound to contain many instances of the same string. Then again, this limits the amount of unique strings to.. a bit over 4 billion. 2^32.
The first four entries seem bogus, perhaps 4 (edit: or 5) more unknowns added since Zacw's studies (which reminds me: The item table item count is not one byte, but four.) If four, this would set entry #5, or "82" in our example, as the first real data entry. It would then make sense that this is the pointer for the actual file path, and the rest are key-value pairs. However, like my script says, the data table does not have entry #82, so there's some other magic going on. Also, both files quote 82 as itemdata #5. (The first three entries do change though.)

CODE
00007 tracknumber
00012 Hip-Hop
00022 192
00000 file://H:\whatever\M-FLO\m-flo astromantic\06 m-flo - way u move (dragon ash).mp3
00082 <not found>
00001 album
00088 <not found>
00002 artist
00095 <not found>
00003 comment
00103 <not found>
00004 date
00108 <not found>
00005 genre
00114 <not found>
00006 title
00120 <not found>
00007 tracknumber
00132 <not found>
00144 <not found>
00150 <not found>
00177 <not found>
00182 <not found>
00190 <not found>
00214 <not found>
00216 <not found>
00226 <not found>
00230 <not found>
00242 <not found>
00247 <not found>
00267 <not found>
00271 <not found>
00279 <not found>
00283 <not found>
00289 <not found>
00293 <not found>
00302 <not found>
00308 <not found>
00317 <not found>
00319 <not found>
00330 <not found>
00336 <not found>
00352 <not found>
00359 <not found>
00364 <not found>
00373 <not found>
00387 <not found>
00391 <not found>
00399 <not found>

And, as you can see, there's a lot of entries in the item table. tongue.gif
The correct data for this file is:
CODE
Artist Name : m-flo
Track Title : way u move (dragon ash)
Album Title : astromantic
Date : 2004
Genre : Hip-Hop
Track Number : 6
Comment : --==More Volume Please==--

Here's the next file, for comparison and fun.
CODE
<__main__.FPLFile instance at 0x00A45670>
  albumpeak            -1.0
  dtn                  44
  duration             308.813333333
  rgalbum              -1000.0
  rgtrack              -1000.0
  size                 7876736
  trackpeak            -1.0
  unk1                 1
  unk2                 411
  unk3                 0
  unk4                 0
  unk5                 127327008231875000
232 bytes read, offset 465
5:8
00006 title
00011 2004
00019 mp3_accurate_length
00000 file://H:\whatever\M-FLO\m-flo astromantic\06 m-flo - way u move (dragon ash).mp3
00082 <not found>
00001 album
00088 <not found>
00002 artist
00103 <not found>
00003 comment
00108 <not found>
00004 date
00114 <not found>
00005 genre
00120 <not found>
00006 title
00515 <not found>
00546 <not found>
00561 <not found>
00566 <not found>
00577 <not found>
00591 <not found>
00216 <not found>
00226 <not found>
00230 <not found>
00594 <not found>
00247 <not found>
00267 <not found>
00271 <not found>
00599 <not found>
00283 <not found>
00289 <not found>
00293 <not found>
00302 <not found>
00308 <not found>
00317 <not found>
00319 <not found>
00330 <not found>
00603 <not found>
00613 <not found>
00336 <not found>
00352 <not found>
00391 <not found>
00399 <not found>

The correct data here is
CODE
Artist Name : Minotaur Shock
Track Title : Moray Arrival
Album Title : Chiff-Chaffs & Willow Warblers
Date : 2001
Genre : Electronic
Track Number : 04


~~

I hope someone can make some sense of this data. I'll try and continue hacking tonight and tomorrow and so on.

Would, of course, be nice if someone (=the developer of FB2k) would come up with some official documentation on the file format. I found the m3u and m3u8 (what's that anyway?) exports lacking - only the filename? ._.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2008 Invision Power Services, Inc.