/* Extended Module Player * Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Fri, 26 Jun 1998 17:45:59 +1000 Andrew Leahy * Finally got it working on the DEC Alpha running DEC UNIX! In the pattern * reading loop I found I was getting "0" for (p-patbuf) and "0" for * xph.datasize, the next if statement (where it tries to read the patbuf) * would then cause a seg_fault. * * Sun Sep 27 12:07:12 EST 1998 Claudio Matsuoka * Extended Module 1.02 stores data in a different order, we must handle * this accordingly. MAX_SAMP used as a workaround to check the number of * samples recognized by the player. */ #include "loader.h" #include "xm.h" static int xm_test(HIO_HANDLE *, char *, const int); static int xm_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_xm = { "Fast Tracker II", xm_test, xm_load }; static int xm_test(HIO_HANDLE *f, char *t, const int start) { char buf[20]; if (hio_read(buf, 1, 17, f) < 17) /* ID text */ return -1; if (memcmp(buf, "Extended Module: ", 17)) return -1; libxmp_read_title(f, t, 20); return 0; } static int load_xm_pattern(struct module_data *m, int num, int version, HIO_HANDLE *f) { const int headsize = version > 0x0102 ? 9 : 8; struct xmp_module *mod = &m->mod; struct xm_pattern_header xph; struct xmp_event *event; uint8 *patbuf, *pat, b; int j, r; int size; xph.length = hio_read32l(f); xph.packing = hio_read8(f); xph.rows = version > 0x0102 ? hio_read16l(f) : hio_read8(f) + 1; /* Sanity check */ if (xph.rows > 256) { goto err; } xph.datasize = hio_read16l(f); hio_seek(f, xph.length - headsize, SEEK_CUR); if (hio_error(f)) { goto err; } r = xph.rows; if (r == 0) { r = 0x100; } if (libxmp_alloc_pattern_tracks(mod, num, r) < 0) { goto err; } if (xph.datasize == 0) { return 0; } size = xph.datasize; pat = patbuf = calloc(1, size); if (patbuf == NULL) { goto err; } hio_read(patbuf, 1, size, f); for (j = 0; j < (mod->chn * r); j++) { /*if ((pat - patbuf) >= xph.datasize) break; */ event = &EVENT(num, j % mod->chn, j / mod->chn); if (--size < 0) { goto err2; } if ((b = *pat++) & XM_EVENT_PACKING) { if (b & XM_EVENT_NOTE_FOLLOWS) { if (--size < 0) goto err2; event->note = *pat++; } if (b & XM_EVENT_INSTRUMENT_FOLLOWS) { if (--size < 0) goto err2; event->ins = *pat++; } if (b & XM_EVENT_VOLUME_FOLLOWS) { if (--size < 0) goto err2; event->vol = *pat++; } if (b & XM_EVENT_FXTYPE_FOLLOWS) { if (--size < 0) goto err2; event->fxt = *pat++; } if (b & XM_EVENT_FXPARM_FOLLOWS) { if (--size < 0) goto err2; event->fxp = *pat++; } } else { size -= 4; if (size < 0) goto err2; event->note = b; event->ins = *pat++; event->vol = *pat++; event->fxt = *pat++; event->fxp = *pat++; } /* Sanity check */ switch (event->fxt) { case 18: case 19: case 22: case 23: case 24: case 26: case 28: case 30: case 31: case 32: event->fxt = 0; } if (event->fxt > 34) { event->fxt = 0; } if (event->note == 0x61) { /* See OpenMPT keyoff+instr.xm test case */ if (event->fxt == 0x0e && MSN(event->fxp) == 0x0d) { event->note = XMP_KEY_OFF; } else { event->note = event->ins ? XMP_KEY_FADE : XMP_KEY_OFF; } } else if (event->note > 0) { event->note += 12; } if (event->fxt == 0x0e) { if (MSN(event->fxp) == EX_FINETUNE) { unsigned char val = (LSN(event->fxp) - 8) & 0xf; event->fxp = (EX_FINETUNE << 4) | val; } switch (event->fxp) { case 0x43: case 0x73: event->fxp--; break; } } if (!event->vol) { continue; } /* Volume set */ if ((event->vol >= 0x10) && (event->vol <= 0x50)) { event->vol -= 0x0f; continue; } /* Volume column effects */ switch (event->vol >> 4) { case 0x06: /* Volume slide down */ event->f2t = FX_VOLSLIDE_2; event->f2p = event->vol - 0x60; break; case 0x07: /* Volume slide up */ event->f2t = FX_VOLSLIDE_2; event->f2p = (event->vol - 0x70) << 4; break; case 0x08: /* Fine volume slide down */ event->f2t = FX_EXTENDED; event->f2p = (EX_F_VSLIDE_DN << 4) | (event->vol - 0x80); break; case 0x09: /* Fine volume slide up */ event->f2t = FX_EXTENDED; event->f2p = (EX_F_VSLIDE_UP << 4) | (event->vol - 0x90); break; case 0x0a: /* Set vibrato speed */ event->f2t = FX_VIBRATO; event->f2p = (event->vol - 0xa0) << 4; break; case 0x0b: /* Vibrato */ event->f2t = FX_VIBRATO; event->f2p = event->vol - 0xb0; break; case 0x0c: /* Set panning */ event->f2t = FX_SETPAN; event->f2p = (event->vol - 0xc0) << 4; break; case 0x0d: /* Pan slide left */ event->f2t = FX_PANSL_NOMEM; event->f2p = (event->vol - 0xd0) << 4; break; case 0x0e: /* Pan slide right */ event->f2t = FX_PANSL_NOMEM; event->f2p = event->vol - 0xe0; break; case 0x0f: /* Tone portamento */ event->f2t = FX_TONEPORTA; event->f2p = (event->vol - 0xf0) << 4; /* From OpenMPT TonePortamentoMemory.xm: * "Another nice bug (...) is the combination of both * portamento commands (Mx and 3xx) in the same cell: * The 3xx parameter is ignored completely, and the Mx * parameter is doubled. (M2 3FF is the same as M4 000) */ if (event->fxt == FX_TONEPORTA || event->fxt == FX_TONE_VSLIDE) { if (event->fxt == FX_TONEPORTA) { event->fxt = 0; } else { event->fxt = FX_VOLSLIDE; } event->fxp = 0; if (event->f2p < 0x80) { event->f2p <<= 1; } else { event->f2p = 0xff; } } /* From OpenMPT porta-offset.xm: * "If there is a portamento command next to an offset * command, the offset command is ignored completely. In * particular, the offset parameter is not memorized." */ if (event->fxt == FX_OFFSET && event->f2t == FX_TONEPORTA) { event->fxt = event->fxp = 0; } break; } event->vol = 0; } free(patbuf); return 0; err2: free(patbuf); err: return -1; } static int load_patterns(struct module_data *m, int version, HIO_HANDLE *f) { struct xmp_module *mod = &m->mod; int i, j; mod->pat++; if (libxmp_init_pattern(mod) < 0) { return -1; } D_(D_INFO "Stored patterns: %d", mod->pat - 1); for (i = 0; i < mod->pat - 1; i++) { if (load_xm_pattern(m, i, version, f) < 0) { goto err; } } /* Alloc one extra pattern */ { int t = i * mod->chn; if (libxmp_alloc_pattern(mod, i) < 0) { goto err; } mod->xxp[i]->rows = 64; if (libxmp_alloc_track(mod, t, 64) < 0) { goto err; } for (j = 0; j < mod->chn; j++) { mod->xxp[i]->index[j] = t; } } return 0; err: return -1; } /* Packed structures size */ #define XM_INST_HEADER_SIZE 33 #define XM_INST_SIZE 208 /* grass.near.the.house.xm defines 23 samples in instrument 1. FT2 docs * specify at most 16. See https://github.com/libxmp/libxmp/issues/168 * for more details. */ #define XM_MAX_SAMPLES_PER_INST 32 static int load_instruments(struct module_data *m, int version, HIO_HANDLE *f) { struct xmp_module *mod = &m->mod; struct xm_instrument_header xih; struct xm_instrument xi; struct xm_sample_header xsh[XM_MAX_SAMPLES_PER_INST]; int sample_num = 0; long total_sample_size; int i, j; uint8 buf[208]; D_(D_INFO "Instruments: %d", mod->ins); /* ESTIMATED value! We don't know the actual value at this point */ mod->smp = MAX_SAMPLES; if (libxmp_init_instrument(m) < 0) { return -1; } for (i = 0; i < mod->ins; i++) { long instr_pos = hio_tell(f); struct xmp_instrument *xxi = &mod->xxi[i]; /* Modules converted with MOD2XM 1.0 always say we have 31 * instruments, but file may end abruptly before that. Also covers * XMLiTE stripped modules and truncated files. This test will not * work if file has trailing garbage. */ if (hio_read(buf, 33, 1, f) != 1) { D_(D_WARN "short read in instrument header data"); break; } xih.size = readmem32l(buf); /* Instrument size */ memcpy(xih.name, buf + 4, 22); /* Instrument name */ xih.type = buf[26]; /* Instrument type (always 0) */ xih.samples = readmem16l(buf + 27); /* Number of samples */ xih.sh_size = readmem32l(buf + 29); /* Sample header size */ /* Sanity check */ if (xih.samples > XM_MAX_SAMPLES_PER_INST || (xih.samples > 0 && xih.sh_size > 0x100)) { D_(D_CRIT "instrument %d: samples:%d sample header size:%d", i + 1, xih.samples, xih.sh_size); return -1; } libxmp_instrument_name(mod, i, xih.name, 22); xxi->nsm = xih.samples; D_(D_INFO "instrument:%2X (%s) samples:%2d", i, xxi->name, xxi->nsm); if (xxi->nsm == 0) { /* Sample size should be in struct xm_instrument according to * the official format description, but FT2 actually puts it in * struct xm_instrument header. There's a tracker or converter * that follow the specs, so we must handle both cases (see * "Braintomb" by Jazztiz/ART). */ /* Umm, Cyke O'Path sent me a couple of * mods ("Breath of the Wind" and "Broken Dimension") that * reserve the instrument data space after the instrument header * even if the number of instruments is set to 0. In these modules * the instrument header size is marked as 263. The following * generalization should take care of both cases. */ if (hio_seek(f, (int)xih.size - XM_INST_HEADER_SIZE, SEEK_CUR) < 0) { return -1; } continue; } if (libxmp_alloc_subinstrument(mod, i, xxi->nsm) < 0) { return -1; } if (xih.size < XM_INST_HEADER_SIZE) { return -1; } /* for BoobieSqueezer (see http://boobie.rotfl.at/) * It works pretty much the same way as Impulse Tracker's sample * only mode, where it will strip off the instrument data. */ if (xih.size < XM_INST_HEADER_SIZE + XM_INST_SIZE) { memset(&xi, 0, sizeof(struct xm_instrument)); hio_seek(f, xih.size - XM_INST_HEADER_SIZE, SEEK_CUR); } else { uint8 *b = buf; if (hio_read(buf, 208, 1, f) != 1) { D_(D_CRIT "short read in instrument data"); return -1; } memcpy(xi.sample, b, 96); /* Sample map */ b += 96; for (j = 0; j < 24; j++) { xi.v_env[j] = readmem16l(b); /* Points for volume envelope */ b += 2; } for (j = 0; j < 24; j++) { xi.p_env[j] = readmem16l(b); /* Points for pan envelope */ b += 2; } xi.v_pts = *b++; /* Number of volume points */ xi.p_pts = *b++; /* Number of pan points */ xi.v_sus = *b++; /* Volume sustain point */ xi.v_start = *b++; /* Volume loop start point */ xi.v_end = *b++; /* Volume loop end point */ xi.p_sus = *b++; /* Pan sustain point */ xi.p_start = *b++; /* Pan loop start point */ xi.p_end = *b++; /* Pan loop end point */ xi.v_type = *b++; /* Bit 0:On 1:Sustain 2:Loop */ xi.p_type = *b++; /* Bit 0:On 1:Sustain 2:Loop */ xi.y_wave = *b++; /* Vibrato waveform */ xi.y_sweep = *b++; /* Vibrato sweep */ xi.y_depth = *b++; /* Vibrato depth */ xi.y_rate = *b++; /* Vibrato rate */ xi.v_fade = readmem16l(b); /* Volume fadeout */ /* Skip reserved space */ if (hio_seek(f, (int)xih.size - (XM_INST_HEADER_SIZE + XM_INST_SIZE), SEEK_CUR) < 0) { return -1; } /* Envelope */ xxi->rls = xi.v_fade << 1; xxi->aei.npt = xi.v_pts; xxi->aei.sus = xi.v_sus; xxi->aei.lps = xi.v_start; xxi->aei.lpe = xi.v_end; xxi->aei.flg = xi.v_type; xxi->pei.npt = xi.p_pts; xxi->pei.sus = xi.p_sus; xxi->pei.lps = xi.p_start; xxi->pei.lpe = xi.p_end; xxi->pei.flg = xi.p_type; if (xxi->aei.npt <= 0 || xxi->aei.npt > 12 /*XMP_MAX_ENV_POINTS */ ) { xxi->aei.flg &= ~XMP_ENVELOPE_ON; } else { memcpy(xxi->aei.data, xi.v_env, xxi->aei.npt * 4); } if (xxi->pei.npt <= 0 || xxi->pei.npt > 12 /*XMP_MAX_ENV_POINTS */ ) { xxi->pei.flg &= ~XMP_ENVELOPE_ON; } else { memcpy(xxi->pei.data, xi.p_env, xxi->pei.npt * 4); } for (j = 12; j < 108; j++) { xxi->map[j].ins = xi.sample[j - 12]; if (xxi->map[j].ins >= xxi->nsm) xxi->map[j].ins = -1; } } /* Read subinstrument and sample parameters */ for (j = 0; j < xxi->nsm; j++, sample_num++) { struct xmp_subinstrument *sub = &xxi->sub[j]; struct xmp_sample *xxs; uint8 *b = buf; D_(D_INFO " sample index:%d sample id:%d", j, sample_num); if (sample_num >= mod->smp) { if (libxmp_realloc_samples(m, mod->smp * 3 / 2) < 0) return -1; } xxs = &mod->xxs[sample_num]; if (hio_read(buf, 40, 1, f) != 1) { D_(D_CRIT "short read in sample data"); return -1; } xsh[j].length = readmem32l(b); /* Sample length */ b += 4; /* Sanity check */ if (xsh[j].length > MAX_SAMPLE_SIZE) { D_(D_CRIT "sanity check: %d: bad sample size", j); return -1; } xsh[j].loop_start = readmem32l(b); /* Sample loop start */ b += 4; xsh[j].loop_length = readmem32l(b); /* Sample loop length */ b += 4; xsh[j].volume = *b++; /* Volume */ xsh[j].finetune = *b++; /* Finetune (-128..+127) */ xsh[j].type = *b++; /* Flags */ xsh[j].pan = *b++; /* Panning (0-255) */ xsh[j].relnote = *(int8 *) b++; /* Relative note number */ xsh[j].reserved = *b++; memcpy(xsh[j].name, b, 22); sub->vol = xsh[j].volume; sub->pan = xsh[j].pan; sub->xpo = xsh[j].relnote; sub->fin = xsh[j].finetune; sub->vwf = xi.y_wave; sub->vde = xi.y_depth << 2; sub->vra = xi.y_rate; sub->vsw = xi.y_sweep; sub->sid = sample_num; libxmp_copy_adjust(xxs->name, xsh[j].name, 22); xxs->len = xsh[j].length; xxs->lps = xsh[j].loop_start; xxs->lpe = xsh[j].loop_start + xsh[j].loop_length; xxs->flg = 0; if (xsh[j].type & XM_SAMPLE_16BIT) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } xxs->flg |= xsh[j].type & XM_LOOP_FORWARD ? XMP_SAMPLE_LOOP : 0; xxs->flg |= xsh[j].type & XM_LOOP_PINGPONG ? XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR : 0; D_(D_INFO " size:%06x loop start:%06x loop end:%06x %c V%02x F%+04d P%02x R%+03d %s", mod->xxs[sub->sid].len, mod->xxs[sub->sid].lps, mod->xxs[sub->sid].lpe, mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' : mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->fin, sub->pan, sub->xpo, mod->xxs[sub->sid].flg & XMP_SAMPLE_16BIT ? " (16 bit)" : ""); } /* Read actual sample data */ total_sample_size = 0; for (j = 0; j < xxi->nsm; j++) { struct xmp_subinstrument *sub = &xxi->sub[j]; int flags; flags = SAMPLE_FLAG_DIFF; #ifndef LIBXMP_CORE_PLAYER if (xsh[j].reserved == 0xad) { flags = SAMPLE_FLAG_ADPCM; } #endif if (version > 0x0103) { D_(D_INFO " read sample: index:%d sample id:%d", j, sub->sid); if (libxmp_load_sample(m, f, flags, &mod->xxs[sub->sid], NULL) < 0) { return -1; } if (flags & SAMPLE_FLAG_ADPCM) { D_(D_INFO " sample is adpcm"); total_sample_size += 16 + ((xsh[j].length + 1) >> 1); } else { total_sample_size += xsh[j].length; } } } /* Reposition correctly in case of 16-bit sample having odd in-file length. * See "Lead Lined for '99", reported by Dennis Mulleneers. */ if (hio_seek(f, instr_pos + xih.size + 40 * xih.samples + total_sample_size, SEEK_SET) < 0) { return -1; } } /* Final sample number adjustment */ if (libxmp_realloc_samples(m, sample_num) < 0) { return -1; } return 0; } static int xm_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xm_file_header xfh; char tracker_name[21]; int len; uint8 buf[80]; LOAD_INIT(); if (hio_read(buf, 80, 1, f) != 1) { D_(D_CRIT "error reading header"); return -1; } memcpy(xfh.id, buf, 17); /* ID text */ memcpy(xfh.name, buf + 17, 20); /* Module name */ /* */ /* skip 0x1a */ memcpy(xfh.tracker, buf + 38, 20); /* Tracker name */ xfh.version = readmem16l(buf + 58); /* Version number, minor-major */ xfh.headersz = readmem32l(buf + 60); /* Header size */ xfh.songlen = readmem16l(buf + 64); /* Song length */ xfh.restart = readmem16l(buf + 66); /* Restart position */ xfh.channels = readmem16l(buf + 68); /* Number of channels */ xfh.patterns = readmem16l(buf + 70); /* Number of patterns */ xfh.instruments = readmem16l(buf + 72); /* Number of instruments */ xfh.flags = readmem16l(buf + 74); /* 0=Amiga freq table, 1=Linear */ xfh.tempo = readmem16l(buf + 76); /* Default tempo */ xfh.bpm = readmem16l(buf + 78); /* Default BPM */ /* Sanity checks */ if (xfh.songlen > 256 || xfh.patterns > 256 || xfh.instruments > 255) { D_(D_CRIT "Sanity check: %d %d %d", xfh.songlen, xfh.patterns, xfh.instruments); return -1; } if (xfh.restart > 255 || xfh.channels > XMP_MAX_CHANNELS) { D_(D_CRIT "Sanity check: %d %d", xfh.restart, xfh.channels); return -1; } if (xfh.tempo >= 32 || xfh.bpm < 32 || xfh.bpm > 255) { if (memcmp("MED2XM", xfh.tracker, 6)) { D_(D_CRIT "Sanity check: %d %d", xfh.tempo, xfh.bpm); return -1; } } /* Honor header size -- needed by BoobieSqueezer XMs */ len = xfh.headersz - 0x14; if (len < 0 || len > 256) { D_(D_CRIT "Sanity check: %d", len); return -1; } if (hio_read(xfh.order, len, 1, f) != 1) { /* Pattern order table */ D_(D_CRIT "error reading orders"); return -1; } strncpy(mod->name, (char *)xfh.name, 20); mod->len = xfh.songlen; mod->chn = xfh.channels; mod->pat = xfh.patterns; mod->ins = xfh.instruments; mod->rst = xfh.restart; mod->spd = xfh.tempo; mod->bpm = xfh.bpm; mod->trk = mod->chn * mod->pat + 1; m->c4rate = C4_NTSC_RATE; m->period_type = xfh.flags & XM_LINEAR_PERIOD_MODE ? PERIOD_LINEAR : PERIOD_AMIGA; memcpy(mod->xxo, xfh.order, mod->len); /*tracker_name[20] = 0;*/ snprintf(tracker_name, 21, "%-20.20s", xfh.tracker); for (i = 20; i >= 0; i--) { if (tracker_name[i] == 0x20) tracker_name[i] = 0; if (tracker_name[i]) break; } /* OpenMPT accurately emulates weird FT2 bugs */ if (!strncmp(tracker_name, "FastTracker v2.00", 17) || !strncmp(tracker_name, "OpenMPT ", 8)) { m->quirk |= QUIRK_FT2BUGS; } #ifndef LIBXMP_CORE_PLAYER if (xfh.headersz == 0x0113) { strcpy(tracker_name, "unknown tracker"); m->quirk &= ~QUIRK_FT2BUGS; } else if (*tracker_name == 0) { strcpy(tracker_name, "Digitrakker"); /* best guess */ m->quirk &= ~QUIRK_FT2BUGS; } /* See MMD1 loader for explanation */ if (!strncmp(tracker_name, "MED2XM by J.Pynnone", 19)) { if (mod->bpm <= 10) { mod->bpm = 125 * (0x35 - mod->bpm * 2) / 33; } m->quirk &= ~QUIRK_FT2BUGS; } if (!strncmp(tracker_name, "FastTracker v 2.00", 18)) { strcpy(tracker_name, "old ModPlug Tracker"); m->quirk &= ~QUIRK_FT2BUGS; } libxmp_set_type(m, "%s XM %d.%02d", tracker_name, xfh.version >> 8, xfh.version & 0xff); #else libxmp_set_type(m, tracker_name); #endif MODULE_INFO(); /* Honor header size */ if (hio_seek(f, start + xfh.headersz + 60, SEEK_SET) < 0) { return -1; } /* XM 1.02/1.03 has a different patterns and instruments order */ if (xfh.version <= 0x0103) { if (load_instruments(m, xfh.version, f) < 0) { return -1; } if (load_patterns(m, xfh.version, f) < 0) { return -1; } } else { if (load_patterns(m, xfh.version, f) < 0) { return -1; } if (load_instruments(m, xfh.version, f) < 0) { return -1; } } D_(D_INFO "Stored samples: %d", mod->smp); /* XM 1.02 stores all samples after the patterns */ if (xfh.version <= 0x0103) { for (i = 0; i < mod->ins; i++) { for (j = 0; j < mod->xxi[i].nsm; j++) { int sid = mod->xxi[i].sub[j].sid; if (libxmp_load_sample(m, f, SAMPLE_FLAG_DIFF, &mod->xxs[sid], NULL) < 0) { return -1; } } } } for (i = 0; i < mod->chn; i++) { mod->xxc[i].pan = 0x80; } m->quirk |= QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; return 0; }