diff --git a/docs/formats/digi-format.txt b/docs/formats/digi-format.txt index fe9edddf..fa7ab798 100644 --- a/docs/formats/digi-format.txt +++ b/docs/formats/digi-format.txt @@ -1,4 +1,4 @@ -xmp/doc/format/digi_format +xmp/docs/format/digi_format analysed by Claudio Matsuoka Sun Feb 21 18:20:32 EST 1999 diff --git a/docs/formats/mfp-format.txt b/docs/formats/mfp-format.txt new file mode 100644 index 00000000..3c8d1b66 --- /dev/null +++ b/docs/formats/mfp-format.txt @@ -0,0 +1,112 @@ + +Magnetic Fields Packer file format + +Format created by Shaun Southern +Format description by Claudio Matsuoka , 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]; + } + } + } + } +} + diff --git a/docs/formats/sfx-format.txt b/docs/formats/sfx-format.txt index 7f4a8f36..e4842d46 100644 --- a/docs/formats/sfx-format.txt +++ b/docs/formats/sfx-format.txt @@ -1,4 +1,4 @@ -xmp/doc/format/sfx_format +xmp/docs/format/sfx_format analysed by Claudio Matsuoka Mon Feb 22 09:29:58 EST 1999 diff --git a/docs/formats/stx-format.txt b/docs/formats/stx-format.txt index 2f268a0b..60dd6dcd 100644 --- a/docs/formats/stx-format.txt +++ b/docs/formats/stx-format.txt @@ -1,4 +1,4 @@ -xmp/doc/format/stx_format +xmp/docs/format/stx_format analysed by Claudio Matsuoka Format: STX diff --git a/src/loaders/mfp_load.c b/src/loaders/mfp_load.c index 556e061a..efebf2e2 100644 --- a/src/loaders/mfp_load.c +++ b/src/loaders/mfp_load.c @@ -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);