帮助反转 Pioneers Rekordbox 软件的 EDB 数据库文件

逆向工程 文件格式
2021-07-07 20:57:55

Pioneers Rekordbox 软件是一款适用于 DJ 的音乐管理工具。它的功能之一是音乐文件的 BPM 检测。不幸的是,它不会将此信息写入文件 ID3 标签的 BPM 框架,而是将检测到的 BPM 保存在它自己的数据库文件中。

我正在编写一个 CLI 工具来帮助我更好地管理我的音乐,我希望它做的一件事是从 rekordbox 数据库中提取每首歌曲的 BPM 数据。

正如 Guntram Blohm 所指出的,BPM 几乎肯定不会存储在两个 ANLZ 文件中。相反,它似乎存储在 Rekordbox 的“database.edb”文件中。我在此处上传了一个示例 edb 文件 [1],其中包含一个 BPM 为“170”的曲目。

根据此论坛主题 [2],edb 格式不是开放格式。


经过更多的研究,它看起来像是一个专有的高性能 SQL 数据库,旨在用于嵌入式应用程序。(经过更深入的研究,该数据库被称为“DeviceSQL”。阅读原作者 Quora 关于它的帖子)。似乎这不是一件容易逆转的事情:(

对于希望从 rekordbox 库中提取 BPM 信息的其他任何人:事实证明,您可以使用 XML 导出。虽然不像读取数据库文件那么自动化,但它是一种很好的标准格式!


老问题: 每个曲目似乎都有两个文件保存在数据库中(数据库只是这些文件的目录树)。这是示例轨道 [4] 的一对文件。检测到该曲目的 BPM 为 170,但我怀疑它会将其存储为浮点数或两倍,因为可以在“169.96”等数字处检测到其他一些曲目。虽然寻找双精度和浮点十六进制表示没有为我产生任何匹配。

我看到文件看起来像标题,例如“PPTH”后跟文件路径。和“PQTZ”,用于 Rekordbox 量化功能。但我对文件格式不太熟悉,所以我无法判断它是否使用标准文件类型。或者更专有的东西。

如果有人有兴趣查看文件并指出我正确的方向,将不胜感激!现在我只是想弄清楚 BPM 是如何存储的。


由于我没有足够的声誉,但我最多只能提供一个链接:(以下是上面括号中参考文献的链接:https : //gist.github.com/EvanPurkhiser/72b37edd4a6ea26fbe73

3个回答

精确的 BPM 实际上在数据文件(文件名)中。DAT(可能整个 BPM 在 edb 中......但我无法确认)所以我已经反转了由 RekordBox 创建的两个数据文件:

文件.DAT
--------
/数字都是大端/
[标签] - 4 字节字符串
4byte - 标签头大小 
4byte - 段大小(包括标签头)
(在多位字段中,msb-to-lsb(从左到右)是大方向)
/////////////////////////////

PMAI——主文件描述符
4byte - 头部大小 (28)
4byte - 总文件大小
4 字节 - ???(1)
4 字节 - ???(65536)
4 字节 - ???(65536)
4 字节 - ???(0)

PPTH - 文件路径
4byte - 头部大小 (16)
4byte - 标签大小
4byte - 数据长度
data_bytes - UTF16(大端)中的文件路径 \0 终止

PVBR - VBR 查找表
4byte - 头部大小 (16)
4byte - 标签大小 (1620) (4*400+4)
4 字节 - 0
  >条目>
    4byte - 文件位置
  >最后一个条目>
    4 字节 - ???

PQTZ - 量化时区
4byte - 头部大小 (24)
4byte - 标签大小
4 字节 - 0
4 字节 - ???(524288=0x80000)
4byte - 条目数
  >条目>
    2byte - 节拍阶段 (1-2-3-4)
    2 字节 - bpm*100
    4byte - 时间索引(毫秒)

PWAV - 低分辨率波形显示数据(5+3bit)
4byte - 头部大小 (20)
4byte - 标签大小 (420)
4byte - 数据大小 (400)
4 字节 - ???(65536)
  >条目>
     3bit - 颜色索引
     5bit - 高度

PWV2 - 最低分辨率波形显示数据(4bit)
4byte - 头部大小 (20)
4byte - 标签大小 (120)
4byte - 数据大小 (100)
4 字节 - ???(65536)
  >条目>
      4 位 - 0
      4bit - 高度

PCOB - CUE 对象 ///第一个 PCOB 用于热提示,第二个 PCOB 用于内存
                        ///只为USB存储生成, 
                        ///否则仅包含存储在edb中的虚拟数据和实际提示数据 
4byte - 头部大小 (24)
4byte - 标签大小
4byte - hotCUE?(1=热指示,0=记忆)
4byte - 提示点数
4byte - 记忆(-1=热提示)
  >入口标签>
    PCPT - 提示点
    4byte - 头部大小 (28)
    4byte - 标签大小 (56)
    4byte - 热指示编号,否则为 0
    4 字节 - 活动(0=不活动/4=活动)
    4 字节 - (65536)
    4 字节 - ???? -----点类型:0xffff ffff = 热提示 //// 内存优先:0xffff xxxxx ----- 内存最后:0x xxxx ffff
      >数据>
        1byte - 提示类型 1 = 单 / 2 = 循环
        1 字节 - 0
        2 字节 - ???(1000)
        4byte - 开始时间(毫秒)
        4byte - 循环结束(如果不使用 -1)
        16 字节 - 0



文件.EXT
--------
PMAI——主文件描述符
4byte - 头部大小 (28)
4byte - 总文件大小
4 字节 - ???(1)
4 字节 - ???(65536)
4 字节 - ???(65536)
4 字节 - ???(0)

PPTH - 文件路径
4byte - 头部大小 (16)
4byte - 标签大小
4byte - 数据长度
data_bytes - UTF16(大端)中的文件路径 \0 终止

PWV3 - 高分辨率波形显示数据
4byte - 头部大小 (24)
4byte - 标签大小
4 字节 - ???(1)
4byte - 数据大小
4 字节 - ???(0x0096 0000)
  >条目>
      3 位 - 颜色 
      5bit - 高度

当我倒车时,文件中没有 PKEY,所以我不知道它是做什么用的(而且在 PC 上似乎只有 0)

所以 BPM 值存储在 PQTZ 标签中(在动态模式下,你可以在同一首歌中使用不同的 BPM,所以这是有道理的)

正如您所发现的,文件格式似乎由带有标签的标题组成。这些标头中的每一个似乎都是 16+ 字节,其中 4 个字节用于标记,4 个字节用于标头长度,4 个字节用于标头 + 数据的大小,还有 4 个我不确定的字节。不幸的是,这些长度字节是big endian,这让我认为 bpm 也可以存储在 big endian IEEE float 中,这可能是您找不到任何东西的原因。

第一个标题,PMAI。似乎是某种信封(它的长度字段是文件本身的大小),其余的标题似乎是各种形式的数据内容。

我写了一个小程序来转储部分名称和长度(请不要将其用作良好样式的示例!):

    #include <stdio.h>
    #include <arpa/inet.h>

    int main(int argc, char **argv) {
            analyze(argv[1]);
    }

    int analyze(char *filename) {
            FILE *fp;
            struct {
                    char tag[4];
                    int  x0;
                    int  x1;
                    int  x2;
            }  header;
            int length;

            if ((fp=fopen(filename, "rb"))==NULL) {
                    perror(filename); return;
            }
            while (fread(&header, sizeof header, 1, fp)) {
                    header.x0=ntohl(header.x0);
                    header.x1=ntohl(header.x1);
                    header.x2=ntohl(header.x2);
                    printf("%04x %4.4s: %08x (%06d) | %08x (%06d) | %08x (%06d)\n",
                            ftell(fp)-sizeof(header),
                            header.tag,
                            header.x0, header.x0,
                            header.x1, header.x1,
                            header.x2, header.x2
                    );
                    if (!memcmp(header.tag, "PMAI", 4)) {   // outer container
                            length=header.x0;               // just skip header
                    } else if (!memcmp(header.tag, "PPTH", 4)) {
                            int i;
                            for (i=0; i<header.x2; i+=2) {
                                    getc(fp);
                                    putchar(getc(fp));
                            }
                            putchar('\n');
                            continue;
                    } else {
                            length=header.x1;               // else skip data
                    }
                    fseek(fp, length-sizeof(header), 1);
            }
    }

产生以下输出:

    $ ./sections ANLZ0000.DAT
    0000 PMAI: 0000001c (000028) | 000028fc (010492) | 00000001 (000001)
    001c PPTH: 00000010 (000016) | 00000100 (000256) | 000000f0 (000240)
    E:\music\247 Hardcore\[+singles]\[247HC055] [12B] Al Storm Ft. Malaya - Everytime We Say Goodbye (Technikore Remix).mp3
    011c PVBR: 00000010 (000016) | 00000654 (001620) | 00000000 (000000)
    0770 PQTZ: 00000018 (000024) | 00001f40 (008000) | 00000000 (000000)
    26b0 PWAV: 00000014 (000020) | 000001a4 (000420) | 00000190 (000400)
    2854 PWV2: 00000014 (000020) | 00000078 (000120) | 00000064 (000100)
    28cc PCOB: 00000018 (000024) | 00000018 (000024) | 00000001 (000001)
    28e4 PCOB: 00000018 (000024) | 00000018 (000024) | 00000000 (000000)

    $ ./sections ANLZ0000.EXT
    0000 PMAI: 0000001c (000028) | 0000cf56 (053078) | 00000001 (000001)
    001c PPTH: 00000010 (000016) | 00000100 (000256) | 000000f0 (000240)
    E:\music\247 Hardcore\[+singles]\[247HC055] [12B] Al Storm Ft. Malaya - Everytime We Say Goodbye (Technikore Remix).mp3
    011c PWV3: 00000018 (000024) | 0000ce26 (052774) | 00000001 (000001)
    cf42 PKEY: 00000014 (000020) | 00000014 (000020) | 0000000c (000012)

因此,PMAI 是容器。PPTH 是 MP3 文件的名称。PVBR 大概是关于可变比特率的信息,PQTZ 是量化,以及 PWAV、PWV2 和 PWV3 各种波形的信息。只剩下 PCOB 和 PKEY 可能包含比特率。不幸的是,如果您查看这些的十六进制转储:

    000028c0  xx xx xx xx xx xx xx xx xx xx xx xx 50 43 4f 42   ............PCOB
    000028d0  00 00 00 18 00 00 00 18 00 00 00 01 00 00 00 00   ................
    000028e0  ff ff ff ff 50 43 4f 42 00 00 00 18 00 00 00 18   ....PCOB........
    000028f0  00 00 00 00 00 00 00 00 ff ff ff ff               ............

    0000cf40  xx xx 50 4b 45 59 00 00 00 14 00 00 00 14 00 00   ..PKEY..........
    0000cf50  00 0c 00 00 00 00

似乎 PCOB 包含 00 00 00 00 ff ff ff ff,而 PKEY 包含 00 00 00 00。这些看起来都不是 170。

这篇文章说“如果 rekordbox 在启动时崩溃,请将 database.backup.edb 重命名为 database.edb,如果它仍然崩溃,请删除所有数据文件”。由于 BPM 似乎没有存储在 ANLZ.* 文件中 - 您也有 database.edb 吗?BPM 可以存储在那里吗?

Microsoft 的可扩展存储引擎 (ESE) 使用 EDB 格式为许多应用程序和服务(Exchange、Active Directory、桌面搜索、Windows Live Mail 等)提供存储后端。

尽管 EDB 格式本身没有记录,但它通过Windows API得到了很好的支持

您还可以通过libesedb访问 EDB 文件的内容

如果您只想以人类可读的方式查看 EDB 文件的内容,那么EseDbViewer工具非常好。