mirror of
https://github.com/OldUnreal/libxmp.git
synced 2026-07-15 17:09:14 -07:00
Add MFP file format description
Signed-off-by: Claudio Matsuoka <cmatsuoka@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
xmp/doc/format/digi_format
|
||||
xmp/docs/format/digi_format
|
||||
analysed by Claudio Matsuoka <claudio@helllabs.org>
|
||||
Sun Feb 21 18:20:32 EST 1999
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
Magnetic Fields Packer file format
|
||||
|
||||
Format created by Shaun Southern
|
||||
Format description by Claudio Matsuoka <cmatsuoka@gmail.com>, 02-Jan-2010
|
||||
|
||||
The Magnetic Fields Packer format is a packed four channel module format
|
||||
used in games such as Crystal Dragon, Kid Chaos and Tower of Souls. Each
|
||||
module comes in two separate files, the first containing instrument and
|
||||
pattern sequencing information, and the second containing all the samples.
|
||||
|
||||
File prefix is mfp. Samples file prefix is smp. Many mfp files can share
|
||||
the same sample files, in Kid Chaos file names are like mfp.level_1-1 and
|
||||
mfp.level_1-2 for the song file and smp.level_1.set for the samples file.
|
||||
|
||||
For more information: http://www.exotica.org.uk/wiki/Magnetic_Fields_Packer
|
||||
|
||||
|
||||
Offset Size Comment
|
||||
------ ------ ---------------------------------------------
|
||||
0000 8*31 31 instruments definition, 8 bytes per
|
||||
instrument as follows:
|
||||
|
||||
LL FV SS ZZ
|
||||
| || | |
|
||||
| || | +---- loop size in words
|
||||
| || +------- loop start in words
|
||||
| |+--------- volume
|
||||
| +---------- finetune
|
||||
+------------- sample length in words
|
||||
|
||||
00f8 1 Song length in patterns
|
||||
00f9 1 Restart or "Noisetracker byte" (0x7f)
|
||||
00fa 128 Pattern order
|
||||
017a 2 Size of the pattern definition table
|
||||
017c 2 ??? Maybe song length (same as above)
|
||||
017e pat*4 Pattern table with pointers to track data
|
||||
(4 words per pattern, offset 0 is at the end of
|
||||
the pattern table)
|
||||
+pat*4 varies Compressed track data
|
||||
|
||||
|
||||
Compressed track data works with triple indirection track tables. Each
|
||||
track starts at the offset given in the pattern table, with the first
|
||||
track starting at offset 0. Each track table has four one-byte entries
|
||||
containing a pointer to the next level or to note data, relative to the
|
||||
level 1 track table.
|
||||
|
||||
Example:
|
||||
|
||||
Raw data: 04 08 0C 08 10 14 18 1C 1C 1C 1C 1C 20 1C 1C 1C
|
||||
12 14 16 16 16 16 16 16 16 14 14 14 14 14 14 14
|
||||
18 14 14 14 01 53 2C 00 00 00 00 00 00 00 0A 10
|
||||
01 94 2C 28
|
||||
|
||||
Level 1 Level 2 Level 3 Notes
|
||||
|
||||
(offset 00) (offset 04) (offset 10) (offset 24)
|
||||
+----+ +----+ +----+ x2 +------------+
|
||||
| 04 | ----------> | 10 | ----------> | 12 | --------> | E 2 02 C00 |
|
||||
+----+ +----+ +----+ +------------+
|
||||
| 08 | -------+ | 14 | -------+ | 14 | ------+
|
||||
+----+ | +----+ | +----+ | (offset 28)
|
||||
| 0C | ---+ | | 18 | | | 16 | ---+ | +------------+
|
||||
+----+ | | +----+ | +----+ | +-> | --- -- --- |
|
||||
| 08 | | | | 1C | | | 16 | ---+ +------------+
|
||||
+----+ . | +----+ | +----+ |
|
||||
. | | | (offset 2C)
|
||||
. | (offset 08) | (offset 14) | +------------+
|
||||
| +----+ | +----+ +----> | --- -- A10 |
|
||||
+--> | 1C | +--> | 16 | ---+ +------------+
|
||||
+----+ +----+ |
|
||||
| 1C | | 16 | ---+ (offset 30)
|
||||
+----+ +----+ | +------------+
|
||||
| 1C | | 16 | ---+ | C#2 02 C28 |
|
||||
+----+ +----+ | +------------+
|
||||
| 1C | | 16 | ---+
|
||||
+----+ +----+
|
||||
|
||||
Example 2: (empty track)
|
||||
|
||||
Raw data: 04 04 04 04 08 08 08 08 06 06 06 06 00 00 00 00
|
||||
|
||||
Level 1 Level 2 Level 3 Notes
|
||||
|
||||
(offset 00) (offset 04) (offset 08) (offset 0C)
|
||||
+----+ +----+ +----+ x2 +------------+
|
||||
| 04 | -----+----> | 08 | -----+----> | 06 | -----+--> | --- -- --- |
|
||||
+----+ | +----+ | +----+ | +------------+
|
||||
| 04 | -----+ | 08 | -----+ | 06 | -----+
|
||||
+----+ | +----+ | +----+ |
|
||||
| 04 | -----+ | 08 | -----+ | 06 | -----+
|
||||
+----+ | +----+ | +----+ |
|
||||
| 04 | -----+ | 08 | -----+ | 06 | -----+
|
||||
+----+ +----+ +----+
|
||||
|
||||
|
||||
Pseudo-code to depack patterns:
|
||||
|
||||
for (pattern = 0; pattern < num_patterns; pattern++) {
|
||||
for (voice = 0; voice < 4; voice++) {
|
||||
read buffer at pattern_address + pattern_table[pattern][voice];
|
||||
for (row = k = 0; k < 4; k++) { /* iterate first indirection table */
|
||||
for (x = 0; x < 4; x++) { /* iterate second indirection table */
|
||||
for (y = 0; y < 4; y++) { /* iterate third indirection table */
|
||||
note_event = buffer[buffer[buffer[buffer[k] + x] + y] * 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
xmp/doc/format/sfx_format
|
||||
xmp/docs/format/sfx_format
|
||||
analysed by Claudio Matsuoka <claudio@helllabs.org>
|
||||
Mon Feb 22 09:29:58 EST 1999
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
xmp/doc/format/stx_format
|
||||
xmp/docs/format/stx_format
|
||||
analysed by Claudio Matsuoka <claudio@helllabs.org>
|
||||
|
||||
Format: STX
|
||||
|
||||
+16
-10
@@ -35,7 +35,7 @@ struct xmp_loader_info mfp_loader = {
|
||||
static int mfp_test(FILE *f, char *t, const int start)
|
||||
{
|
||||
uint8 buf[384];
|
||||
int i, len, lps, loop_size;
|
||||
int i, len, lps, lsz;
|
||||
|
||||
if (fread(buf, 1, 384, f) < 384)
|
||||
return -1;
|
||||
@@ -44,10 +44,6 @@ static int mfp_test(FILE *f, char *t, const int start)
|
||||
if (buf[249] != 0x7f)
|
||||
return -1;
|
||||
|
||||
/* check song length */
|
||||
if (buf[248] > 0x7f)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 31; i++) {
|
||||
/* check size */
|
||||
len = readmem16b(buf + i * 8);
|
||||
@@ -68,14 +64,17 @@ static int mfp_test(FILE *f, char *t, const int start)
|
||||
return -1;
|
||||
|
||||
/* check loop size */
|
||||
loop_size = readmem16b(buf + i * 8 + 6);
|
||||
if (lps + loop_size - 1 > len)
|
||||
lsz = readmem16b(buf + i * 8 + 6);
|
||||
if (lps + lsz - 1 > len)
|
||||
return -1;
|
||||
|
||||
if (loop_size == 0)
|
||||
if (lsz == 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buf[248] != readmem16b(buf + 378))
|
||||
return -1;
|
||||
|
||||
if (readmem16b(buf + 378) != readmem16b(buf + 380))
|
||||
return -1;
|
||||
|
||||
@@ -136,15 +135,21 @@ static int mfp_load(struct xmp_context *ctx, FILE *f, const int start)
|
||||
}
|
||||
}
|
||||
|
||||
m->xxh->len = read8(f);
|
||||
m->xxh->len = m->xxh->pat = read8(f);
|
||||
read8(f); /* restart */
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
m->xxo[i] = read8(f);
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < 128; i++) {
|
||||
m->xxo[i] = read8(f);
|
||||
if (m->xxo[i] > m->xxh->pat)
|
||||
m->xxh->pat = m->xxo[i];
|
||||
}
|
||||
m->xxh->pat++;
|
||||
#endif
|
||||
|
||||
m->xxh->trk = m->xxh->pat * m->xxh->chn;
|
||||
|
||||
/* Read and convert patterns */
|
||||
@@ -155,8 +160,9 @@ static int mfp_load(struct xmp_context *ctx, FILE *f, const int start)
|
||||
size2 = read16b(f);
|
||||
|
||||
for (i = 0; i < size1; i++) { /* Read pattern table */
|
||||
for (j = 0; j < 4; j++)
|
||||
for (j = 0; j < 4; j++) {
|
||||
pat_table[i][j] = read16b(f);
|
||||
}
|
||||
}
|
||||
|
||||
reportv(ctx, 0, "Stored patterns: %d ", m->xxh->pat);
|
||||
|
||||
Reference in New Issue
Block a user