/* Extended Module Player * Copyright (C) 1996-1999 Claudio Matsuoka and Hipolito Carraro Jr * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU General Public License. See doc/COPYING * for more information. */ /* * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "load.h" #include "xm.h" #define MAX_SAMP 1024 int xm_load (FILE * f) { int i, j, r; int instr_no = 0; uint8 *patbuf, *p, b; struct xxm_event *event; struct xm_file_header xfh; struct xm_pattern_header xph; struct xm_pattern_header_0102 xph0102; struct xm_instrument_header xih; struct xm_instrument xi; struct xm_sample_header xsh[16]; LOAD_INIT (); fread (&xfh, sizeof (xfh), 1, f); if (strncmp ((char *) xfh.id, "Extended Module: ", 17)) return -1; strncpy (xmp_ctl->name, (char *) xfh.name, 20); L_ENDIAN16 (xfh.version); sprintf (xmp_ctl->type, "Extended Module %d.%02d", xfh.version >> 8, xfh.version & 0xff); L_ENDIAN32 (xfh.headersz); L_ENDIAN16 (xfh.songlen); L_ENDIAN16 (xfh.restart); L_ENDIAN16 (xfh.channels); L_ENDIAN16 (xfh.patterns); L_ENDIAN16 (xfh.instruments); L_ENDIAN16 (xfh.tempo); L_ENDIAN16 (xfh.bpm); L_ENDIAN16 (xfh.flags); xxh->len = xfh.songlen; xxh->rst = xfh.restart; xxh->chn = xfh.channels; xxh->pat = xfh.patterns; xxh->trk = xxh->chn * xxh->pat + 1; xxh->ins = xfh.instruments; xxh->tpo = xfh.tempo; xxh->bpm = xfh.bpm; xxh->flg = xfh.flags & XM_LINEAR_PERIOD_MODE ? XXM_FLG_LINEAR : 0; memcpy (xxo, xfh.order, xxh->len); sprintf (tracker_name, "%-20.20s", xfh.tracker); MODULE_INFO (); /* XM 1.02/1.03 has a different structure. This is a nasty kludge to * re-order the loader and recognize 1.02 files correctly. */ if (xfh.version <= 0x0103) goto load_instruments; load_patterns: PATTERN_INIT (); if (V (0)) report ("Stored patterns: %d ", xxh->pat); /* Endianism fixed by Miodrag Vallat * Mon, 04 Jan 1999 11:17:20 +0100 */ for (i = 0; i < xxh->pat; i++) { if (xfh.version > 0x0102) { fread (&xph, sizeof (xph), 1, f); L_ENDIAN32 (xph.length); L_ENDIAN16 (xph.rows); L_ENDIAN16 (xph.datasize); } else { fread (&xph0102, sizeof (xph0102), 1, f); L_ENDIAN32 (xph0102.length); L_ENDIAN16 (xph0102.datasize); xph.length = xph0102.length; xph.packing = xph0102.packing; xph.rows = xph0102.rows + 1; xph.datasize = xph0102.datasize; } PATTERN_ALLOC (i); if (!(r = xxp[i]->rows = xph.rows)) r = xxp[i]->rows = 0x100; TRACK_ALLOC (i); if (xph.datasize) { p = patbuf = calloc (1, xph.datasize); fread (patbuf, 1, xph.datasize, f); for (j = 0; j < (xxh->chn * r); j++) { if ((p - patbuf) >= xph.datasize) break; event = &EVENT (i, j % xxh->chn, j / xxh->chn); if ((b = *p++) & XM_EVENT_PACKING) { if (b & XM_EVENT_NOTE_FOLLOWS) event->note = *p++; if (b & XM_EVENT_INSTRUMENT_FOLLOWS) { if (*p & XM_END_OF_SONG) break; event->ins = *p++; } if (b & XM_EVENT_VOLUME_FOLLOWS) event->vol = *p++; if (b & XM_EVENT_FXTYPE_FOLLOWS) { event->fxt = *p++; #if 0 if (event->fxt == FX_GLOBALVOL) event->fxt = FX_TRK_VOL; if (event->fxt == FX_G_VOLSLIDE) event->fxt = FX_TRK_VSLIDE; #endif } if (b & XM_EVENT_FXPARM_FOLLOWS) event->fxp = *p++; } else { event->note = b; event->ins = *p++; event->vol = *p++; event->fxt = *p++; event->fxp = *p++; } 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) + 8; break; case 0x0d: /* Pan slide left */ event->f2t = FX_PANSLIDE; event->f2p = (event->vol - 0xd0) << 4; break; case 0x0e: /* Pan slide right */ event->f2t = FX_PANSLIDE; event->f2p = event->vol - 0xe0; break; case 0x0f: /* Tone portamento */ event->f2t = FX_TONEPORTA; event->f2p = (event->vol - 0xf0) << 4; break; } event->vol = 0; } free (patbuf); if (V (0)) report ("."); } } PATTERN_ALLOC (i); xxp[i]->rows = 64; xxt[i * xxh->chn] = calloc (1, sizeof (struct xxm_track) + sizeof (struct xxm_event) * 64); xxt[i * xxh->chn]->rows = 64; for (j = 0; j < xxh->chn; j++) xxp[i]->info[j].index = i * xxh->chn; if (xfh.version <= 0x0103) { if (V (0)) report ("\n"); goto load_samples; } if (V (0)) report ("\n"); load_instruments: if (V (0)) report ("Instruments : %d ", xxh->ins); if (V (1)) report ("\n"); /* ESTIMATED value! We don't know the actual value at this point */ xxh->smp = MAX_SAMP; INSTRUMENT_INIT (); for (i = 0; i < xxh->ins; i++) { fread (&xih, sizeof (xih), 1, f); L_ENDIAN32 (xih.size); L_ENDIAN16 (xih.samples); L_ENDIAN32 (xih.sh_size); strncpy (xxih[i].name, xih.name, 22); str_adj (xxih[i].name); xxih[i].nsm = xih.samples; if (xxih[i].nsm > 16) xxih[i].nsm = 16; if (V (1) && (strlen ((char *) xxih[i].name) || xxih[i].nsm)) report ("[%2X] %-22.22s %2d ", i, xxih[i].name, xxih[i].nsm); if (xxih[i].nsm) { xxi[i] = calloc (sizeof (struct xxm_instrument), xxih[i].nsm); fread (&xi, sizeof (xi) , 1, f); /* Skip reserved space */ fseek (f, xih.size - sizeof (xih) - sizeof (xi), SEEK_CUR); for (j = 0; j < 24; j++) { L_ENDIAN16 (xi.v_env[j]); L_ENDIAN16 (xi.p_env[j]); } L_ENDIAN16 (xi.v_fade); /* Envelope */ xxih[i].rls = xi.v_fade; xxih[i].aei.npt = xi.v_pts; xxih[i].aei.sus = xi.v_sus; xxih[i].aei.lps = xi.v_start; xxih[i].aei.lpe = xi.v_end; xxih[i].aei.flg = xi.v_type; xxih[i].pei.npt = xi.p_pts; xxih[i].pei.sus = xi.p_sus; xxih[i].pei.lps = xi.p_start; xxih[i].pei.lpe = xi.p_end; xxih[i].pei.flg = xi.p_type; if (xxih[i].aei.npt) xxae[i] = calloc (4, xxih[i].aei.npt); else xxih[i].aei.flg &= ~XXM_ENV_ON; if (xxih[i].pei.npt) xxpe[i] = calloc (4, xxih[i].pei.npt); else xxih[i].pei.flg &= ~XXM_ENV_ON; memcpy (xxae[i], xi.v_env, xxih[i].aei.npt * 4); memcpy (xxpe[i], xi.p_env, xxih[i].pei.npt * 4); memcpy (&xxim[i], xi.sample, 96); for (j = 0; j < 96; j++) { if (xxim[i].ins[j] >= xxih[i].nsm) xxim[i].ins[j] = (uint8) XMP_DEF_MAXPAT; } for (j = 0; j < xxih[i].nsm; j++, instr_no++) { fread (&xsh[j], sizeof (xsh[j]), 1, f); L_ENDIAN32 (xsh[j].length); L_ENDIAN32 (xsh[j].loop_start); L_ENDIAN32 (xsh[j].loop_length); xxi[i][j].vol = xsh[j].volume; xxi[i][j].pan = xsh[j].pan; xxi[i][j].xpo = xsh[j].relnote; xxi[i][j].fin = xsh[j].finetune; xxi[i][j].vwf = xi.y_wave; xxi[i][j].vde = xi.y_depth; xxi[i][j].vra = xi.y_rate; xxi[i][j].vsw = xi.y_sweep; xxi[i][j].sid = instr_no; if (instr_no >= MAX_SAMP) continue; strncpy (xxs[instr_no].name, xsh[j].name, 22); str_adj (xxs[instr_no].name); xxs[instr_no].len = xsh[j].length; xxs[instr_no].lps = xsh[j].loop_start; xxs[instr_no].lpe = xsh[j].loop_start + xsh[j].loop_length; xxs[instr_no].flg = xsh[j].type & XM_SAMPLE_16BIT ? WAVE_16_BITS : 0; xxs[instr_no].flg |= xsh[j].type & XM_LOOP_FORWARD ? WAVE_LOOPING : 0; xxs[instr_no].flg |= xsh[j].type & XM_LOOP_PINGPONG ? WAVE_LOOPING | WAVE_BIDIR_LOOP : 0; } for (j = 0; j < xxih[i].nsm; j++) { if (instr_no >= MAX_SAMP) continue; if ((V (1)) && xsh[j].length) report ("%s[%1x] %05x%c%05x %05x %c " "V%02x F%+04d P%02x R%+03d", j ? "\n\t\t\t\t" : "\t", j, xxs[xxi[i][j].sid].len, xxs[xxi[i][j].sid].flg & WAVE_16_BITS ? '+' : ' ', xxs[xxi[i][j].sid].lps, xxs[xxi[i][j].sid].lpe, xxs[xxi[i][j].sid].flg & WAVE_BIDIR_LOOP ? 'B' : xxs[xxi[i][j].sid].flg & WAVE_LOOPING ? 'L' : ' ', xsh[j].volume, xsh[j].finetune, xsh[j].pan, xsh[j].relnote); if (xfh.version > 0x0103) xmp_drv_loadpatch (f, xxi[i][j].sid, xmp_ctl->c4rate, XMP_SMP_DIFF, &xxs[xxi[i][j].sid], NULL); } if (xmp_ctl->verbose == 1) report ("."); } else { /* The sample size is a field of struct xm_instrument_header that * should be in struct xm_instrument according to the (official) * format description. xmp puts the field in the header because * Fasttracker writes the modules this way. BUT there's some * other tracker or conversor out there following the specs * verbatim and thus creating modules incompatible with those * created by Fasttracker. The following piece of code is a * workaround for this problem (allowing xmp to play "Braintomb" * by Jazztiz/ART). (seek -4) */ /* 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. */ fseek (f, xih.size - sizeof (xih), SEEK_CUR); } if ((V (1)) && (strlen ((char *) xxih[i].name) || xih.samples)) report ("\n"); } xxh->smp = instr_no; xxs = realloc (xxs, sizeof (struct xxm_sample) * xxh->smp); if (xfh.version <= 0x0103) { if (xmp_ctl->verbose > 0 && xmp_ctl->verbose < 2) report ("\n"); goto load_patterns; } load_samples: if ((V (0) && xfh.version <= 0x0103) || V (1)) report ("Stored samples : %d ", xxh->smp); /* XM 1.02 stores all samples after the patterns */ if (xfh.version <= 0x0103) { for (i = 0; i < xxh->ins; i++) { for (j = 0; j < xxih[i].nsm; j++) { xmp_drv_loadpatch (f, xxi[i][j].sid, xmp_ctl->c4rate, XMP_SMP_DIFF, &xxs[xxi[i][j].sid], NULL); if (V (0)) report ("."); } } } if (V (0)) report ("\n"); /* If dynamic pan is disabled, XM modules will use the standard * MOD channel panning (LRRL). Moved to module_play () --Hipolito. */ for (i = 0; i < xxh->chn; i++) xxc[i].pan = xmp_ctl->fetch & XMP_CTL_DYNPAN ? 0x80 : (((i + 1) / 2) % 2) * 0xff; xmp_ctl->fetch |= XMP_MODE_FT2; return 0; }