/* 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "load.h" #include "stm.h" #include "period.h" #define FX_NONE 0xff static uint8 fx[] = { FX_NONE, FX_TEMPO, FX_JUMP, FX_BREAK, FX_VOLSLIDE, FX_PORTA_DN, FX_PORTA_UP, FX_TONEPORTA, FX_VIBRATO, FX_TREMOR, FX_ARPEGGIO }; int stm_load (FILE * f) { int i, j; struct xxm_event *event; struct stm_file_header sfh; uint8 b; int bmod2stm = 0; LOAD_INIT (); fread (&sfh, 1, sizeof (sfh), f); if (!strncmp ((char *) sfh.magic, "BMOD2STM", 8)) bmod2stm = 1; if (strncmp ((char *) sfh.magic, "!Scream!", 8) && !bmod2stm) return -1; if (sfh.type != STM_TYPE_MODULE) return -1; if (sfh.vermaj < 1) /* We don't want STX files */ return -1; xxh->pat = sfh.patterns; xxh->trk = xxh->pat * xxh->chn; xxh->tpo = MSN (sfh.tempo); xxh->smp = xxh->ins; xmp_ctl->c4rate = C4_NTSC_RATE; strncpy (xmp_ctl->name, sfh.name, 20); sprintf (xmp_ctl->type, "!Scream! (STM)"); if (bmod2stm) sprintf (tracker_name, "BMOD2STM (%d.%02d)", sfh.vermaj, sfh.vermin); else sprintf (tracker_name, "Scream Tracker %d.%02d", sfh.vermaj, sfh.vermin); MODULE_INFO (); INSTRUMENT_INIT (); if (V (1)) report (" Sample name Len LBeg LEnd L Vol C2Spd\n"); /* Read and convert instruments and samples */ for (i = 0; i < xxh->ins; i++) { xxi[i] = calloc (sizeof (struct xxm_instrument), 1); L_ENDIAN16 (sfh.ins[i].length); L_ENDIAN16 (sfh.ins[i].loopbeg); L_ENDIAN16 (sfh.ins[i].loopend); L_ENDIAN16 (sfh.ins[i].c2spd); xxih[i].nsm = !!(xxs[i].len = sfh.ins[i].length); xxs[i].lps = sfh.ins[i].loopbeg; xxs[i].lpe = sfh.ins[i].loopend; if (xxs[i].lpe == 0xffff) xxs[i].lpe = 0; xxs[i].flg = xxs[i].lpe > 0 ? WAVE_LOOPING : 0; xxi[i][0].vol = sfh.ins[i].volume; xxi[i][0].pan = 0x80; xxi[i][0].sid = i; strncpy ((char *) xxih[i].name, sfh.ins[i].name, 12); str_adj ((char *) xxih[i].name); if ((V (1)) && (strlen ((char *) xxih[i].name) || (xxs[i].len > 1))) { report ("[%2X] %-14.14s %04x %04x %04x %c V%02x %5d\n", i, xxih[i].name, xxs[i].len, xxs[i].lps, xxs[i].lpe, xxs[i].flg & WAVE_LOOPING ? 'L' : ' ', xxi[i][0].vol, sfh.ins[i].c2spd); } sfh.ins[i].c2spd = 8363 * sfh.ins[i].c2spd / 8448; c2spd_to_note (sfh.ins[i].c2spd, &xxi[i][0].xpo, &xxi[i][0].fin); } fread (xxo, 1, 128, f); for (i = 0; i < 128; i++) if (xxo[i] >= xxh->pat) break; xxh->len = i; if (V (0)) report ("Module length : %d patterns\n", xxh->len); PATTERN_INIT (); /* Read and convert patterns */ if (V (0)) report ("Stored patterns: %d ", xxh->pat); for (i = 0; i < xxh->pat; i++) { PATTERN_ALLOC (i); xxp[i]->rows = 64; TRACK_ALLOC (i); for (j = 0; j < 64 * xxh->chn; j++) { event = &EVENT (i, j % xxh->chn, j / xxh->chn); fread (&b, 1, 1, f); memset (event, 0, sizeof (struct xxm_event)); switch (b) { case 251: case 252: case 253: break; case 255: b = 0; default: event->note = b ? 1 + LSN (b) + 12 * (2 + MSN (b)) : 0; fread (&b, 1, 1, f); event->vol = b & 0x07; event->ins = (b & 0xf8) >> 3; fread (&b, 1, 1, f); event->vol += (b & 0xf0) >> 1; if (event->vol > 0x40) event->vol = 0; else event->vol++; event->fxt = fx[LSN (b)]; fread (&b, 1, 1, f); event->fxp = b; switch (event->fxt) { case FX_TEMPO: event->fxp = MSN (event->fxp); break; case FX_NONE: event->fxp = event->fxt = 0; break; } } } if (V (0)) report ("."); } /* Read samples */ if (V (0)) report ("\nStored samples : %d ", xxh->smp); for (i = 0; i < xxh->ins; i++) { xmp_drv_loadpatch (f, xxi[i][0].sid, xmp_ctl->c4rate, 0, &xxs[xxi[i][0].sid], NULL); if (V (0)) report ("."); } if (V (0)) report ("\n"); xmp_ctl->fetch |= XMP_CTL_VSALL | XMP_MODE_ST3; return 0; }