.XM
来自音MAD维基
XM即“扩展模块”(Extended Module),是FastTracker 2的一种模块音乐格式。
编辑与播放
XM文件可以使用OpenMPT进行编辑与播放。安卓系统上可以使用Xmp Mod Player进行播放。
文件结构
以下内容参考了MilkyTracker的文档[1]和OpenMPT的相关代码[2],并根据实际情况进行了修正。
总体结构
一个XM文件通常为以下结构:
- XM文件头
- "Extended Module: " 0x1a 模块名称 Tracker名称 XM版本号 文件头长度
- Channel总数 Pattern总数 Instrument总数 频率表类型 默认BPM 默认Tempo Pattern顺序
- 各Pattern
- 头部长度 压缩类型 行数
- (压缩过的)音符数据
- 各Instrument
- 头部信息
- 头部长度 名称 类型 Sample总数
- (若Sample总数大于0则有额外头部数据)
- 各Sample的头部信息
- 头部长度 循环起点 循环终点 音量 音调微调 类型 声像 相关音符编号 保留位 名称
- 各Sample的采样数据(使用了差分编码)
- 头部信息
音符数据
各Pattern的音符数据按照各Channel从左到右再按各行从上至下存放(含空音符)。下表给出了一个音符的各项属性:
大小 | 数据类型 | 属性名称 |
---|---|---|
1 | Byte | 音符(1~96对应C1~B8,97为终止符,0为空音符) |
1 | Byte | 使用的Instrument编号(1~128,注意是从1开始) |
1 | Byte | 音量(可以为音量效果) |
1 | Byte | 效果类型 |
1 | Byte | 效果参数 |
在多数情况下,音符数据会进行压缩以减小文件体积。下面是一段读取一个音符的伪代码[3]:
dbyt = getbyte(); if (dbyt AND 0x80) { if (dbyt AND 0x01) c_note = getbyte(); if (dbyt AND 0x02) c_inst = getbyte(); if (dbyt AND 0x04) c_vol = getbyte(); if (dbyt AND 0x08) c_effect = getbyte(); if (dbyt AND 0x10) c_param = getbyte(); } else { c_note = dbyt; current_row++; }
采样数据
采样数据使用了差分编码以在压缩时(如使用pkzip)获得更高压缩比。采样每个点的值的数据类型由Sample类型决定,0~3为 char
类型,4为 signed int
类型。下面是一段读取采样数据的伪代码[4]:
signed byte old, new; old = 0; for i = 0 to data_len { new = sample[i] + old; sample[i] = new; old = new; }
下面是使用Python 3实现的一段代码:
class XMSample: def doParseSampleFromBytes(self, data): self.sample = list(data) typeMax = 0x80 if self.type == 4: # 16-bit signed int typeMax *= 0x100 old = 0 for i in range(self.length): old = self.sample[i] = (self.sample[i] + old + typeMax) % (typeMax * 2) - typeMax
- ↑ https://github.com/milkytracker/MilkyTracker/blob/master/resources/reference/xm-form.txt
- ↑ https://github.com/OpenMPT/openmpt/blob/master/soundlib/Load_xm.cpp
- ↑ https://github.com/milkytracker/MilkyTracker/blob/master/resources/reference/xm-form.txt#L347
- ↑ https://github.com/milkytracker/MilkyTracker/blob/master/resources/reference/xm-form.txt#L303
|