/* 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. */ /* * Tue, 30 Jun 1998 20:23:11 +0200 * Reported by John v/d Kamp : * I have this song from Purple Motion called wcharts.s3m, the global * volume was set to 0, creating a devide by 0 error in xmp. There should * be an extra test if it's 0 or not. * * Claudio's fix: global volume ignored */ /* * Sat, 29 Aug 1998 18:50:43 -0500 (CDT) * Reported by Joel Jordan : * S3M files support tempos outside the ranges defined by xmp (that is, * the MOD/XM tempo ranges). S3M's can have tempos from 0 to 255 and speeds * from 0 to 255 as well, since these are handled with separate effects * unlike the MOD format. This becomes an issue in such songs as Skaven's * "Catch that Goblin", which uses speeds above 0x1f. * * Claudio's fix: FX_S3M_TEMPO added. S3M supports speeds from 0 to 255 and * tempos from 32 to 255 (S3M speed == xmp tempo, S3M tempo == xmp BPM). */ /* Wed, 21 Oct 1998 15:03:44 -0500 Geoff Reedy * It appears that xmp has issues loading/playing a specific instrument * used in LUCCA.S3M. * (Fixed by Hipolito in xmp-2.0.0dev34) */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "load.h" #include "s3m.h" #include "period.h" #define NONE 0xff #define FX_S3M_EXTENDED 0xfe static uint16 *pp_ins; /* Parapointers to instruments */ static uint16 *pp_pat; /* Parapointers to patterns */ static uint8 arpeggio_val[32]; /* Effect conversion table */ static uint8 fx[] = { NONE, FX_S3M_TEMPO, FX_JUMP, FX_BREAK, FX_VOLSLIDE, FX_PORTA_DN, FX_PORTA_UP, FX_TONEPORTA, FX_VIBRATO, FX_TREMOR, FX_ARPEGGIO, FX_VIBRA_VSLIDE, FX_TONE_VSLIDE, NONE, NONE, FX_OFFSET, NONE, FX_MULTI_RETRIG, FX_TREMOLO, FX_S3M_EXTENDED, FX_TEMPO, NONE, FX_GLOBALVOL, NONE, NONE, NONE, NONE }; /* Effect translation */ static void xlat_fx (int c, struct xxm_event *e) { uint8 h = MSN (e->fxp), l = LSN (e->fxp); switch (e->fxt = fx[e->fxt]) { case FX_ARPEGGIO: /* Arpeggio */ if (e->fxp) arpeggio_val[c] = e->fxp; else e->fxp = arpeggio_val[c]; break; case FX_TEMPO: /* BPM */ if (e->fxp && e->fxp < 0x21) e->fxp = 0x21; break; case FX_S3M_TEMPO: if (e->fxp <= 0x20) e->fxt = FX_TEMPO; break; case FX_S3M_EXTENDED: /* Extended effects */ e->fxt = FX_EXTENDED; switch (h) { case 0x1: /* Glissando */ e->fxp = LSN (e->fxp) | (EX_GLISS << 4); break; case 0x2: /* Finetune */ e->fxp = LSN (e->fxp) | (EX_FINETUNE << 4); break; case 0x3: /* Vibrato wave */ e->fxp = LSN (e->fxp) | (EX_VIBRATO_WF << 4); break; case 0x4: /* Tremolo wave */ e->fxp = LSN (e->fxp) | (EX_TREMOLO_WF << 4); break; case 0x5: case 0x6: case 0x7: case 0x9: case 0xa: /* Ignore */ e->fxt = e->fxp = 0; break; case 0x8: /* Set pan */ e->fxt = FX_MASTER_PAN; e->fxp = l << 4; break; case 0xb: /* Pattern loop */ e->fxp = LSN (e->fxp) | (EX_PATTERN_LOOP << 4); break; case 0xc: if (!l) e->fxt = e->fxp = 0; } break; case NONE: /* No effect */ e->fxt = e->fxp = 0; break; } } int s3m_load (FILE * f) { int c, r, i, j; struct s3m_adlib_header sah; struct xxm_event *event = 0, dummy; struct s3m_file_header sfh; struct s3m_instrument_header sih; int pat_len; uint8 n, b, x8, tmp[80]; uint16 x16; LOAD_INIT (); /* Load and convert header */ fread (&sfh, 1, sizeof (sfh), f); if (strncmp ((char *) sfh.magic, "SCRM", 4)) return -1; L_ENDIAN16 (sfh.ordnum); L_ENDIAN16 (sfh.insnum); L_ENDIAN16 (sfh.patnum); L_ENDIAN16 (sfh.ffi); str_adj ((char *) sfh.name); strcpy (xmp_ctl->name, (char *) sfh.name); xxh->len = sfh.ordnum; xxh->ins = sfh.insnum; xxh->smp = xxh->ins; xxh->pat = sfh.patnum; pp_ins = calloc (2, xxh->ins); pp_pat = calloc (2, xxh->pat); if (sfh.flags & S3M_AMIGA_RANGE) xxh->flg |= XXM_FLG_MODRNG; if (sfh.flags & S3M_ST300_VOLS) xmp_ctl->fetch |= XMP_CTL_VSALL; /* xmp_ctl->volbase = 4096 / sfh.gv; */ xxh->tpo = sfh.is; xxh->bpm = sfh.it; for (i = 0; i < 32; i++) { if (sfh.chset[i] != S3M_CH_OFF) xxh->chn = i + 1; else continue; xxc[i].pan = sfh.mv & 0x80 ? (((sfh.chset[i] & S3M_CH_PAN) >> 3) * 0xff) & 0xff : 0x80; } xxh->trk = xxh->pat * xxh->chn; fread (xxo, 1, xxh->len, f); #if 0 /* S3M skips pattern 0xfe */ for (i = 0; i < (xxh->len - 1); i++) if (xxo[i] == 0xfe) { memcpy (&xxo[i], &xxo[i + 1], xxh->len - i - 1); xxh->len--; } while (xxh->len && xxo[xxh->len - 1] == 0xff) xxh->len--; #endif for (i = 0; i < xxh->ins; i++) { fread (&pp_ins[i], 2, 1, f); L_ENDIAN16 (pp_ins[i]); } for (i = 0; i < xxh->pat; i++) { fread (&pp_pat[i], 2, 1, f); L_ENDIAN16 (pp_pat[i]); } /* Default pan positions */ for (i = 0, sfh.dp -= 0xfc; !sfh.dp && n && (i < 32); i++) { fread (tmp, 1, 1, f); if (tmp[0] && S3M_PAN_SET) xxc[i].pan = (tmp[0] << 4) & 0xff; } xmp_ctl->c4rate = C4_NTSC_RATE; xmp_ctl->fetch |= XMP_CTL_FINEFX; sprintf (xmp_ctl->type, "SCRM (S3M)"); if (sfh.version == 0x1300) xmp_ctl->fetch |= XMP_CTL_VSALL; switch (sfh.version >> 12) { case 1: sprintf (tracker_name, "Scream Tracker"); xmp_ctl->fetch |= XMP_CTL_ST3GVOL; break; case 2: sprintf (tracker_name, "Imago Orpheus"); break; case 3: sprintf (tracker_name, "Impulse Tracker"); break; default: sprintf (tracker_name, "unknown (%d) version", sfh.version >> 12); } sprintf (tracker_name + strlen (tracker_name), " %d.%02x", (sfh.version & 0x0f00) >> 8, sfh.version & 0xff); MODULE_INFO (); PATTERN_INIT (); /* Read patterns */ if (V (0)) report ("Stored patterns: %d ", xxh->pat); memset (arpeggio_val, 0, 32); for (i = 0; i < xxh->pat; i++) { PATTERN_ALLOC (i); xxp[i]->rows = 64; TRACK_ALLOC (i); if (!pp_pat[i]) continue; fseek (f, pp_pat[i] * 16, SEEK_SET); r = 0; fread (&x16, 2, 1, f); pat_len = x16; L_ENDIAN16 (pat_len); pat_len -= 2; /* Used to be (--pat_len >= 0). Replaced by Rudolf Cejka * , fixes hunt.s3m * ftp://us.aminet.net/pub/aminet/mods/8voic/s3m_hunt.lha */ while (r < xxp[i]->rows) { fread (&b, 1, 1, f); if (b == S3M_EOR) { r++; continue; } c = b & S3M_CH_MASK; event = c >= xxh->chn ? &dummy : &EVENT (i, c, r); if (b & S3M_NI_FOLLOW) { fread (&n, 1, 1, f); switch (n) { case 255: n = 0; break; /* Empty note */ case 254: n = 0x61; break; /* Key off */ default: n = 1 + 12 * MSN (n) + LSN (n); } event->note = n; fread (&n, 1, 1, f); event->ins = n; pat_len -= 2; } if (b & S3M_VOL_FOLLOWS) { fread (&n, 1, 1, f); event->vol = n + 1; pat_len--; } if (b & S3M_FX_FOLLOWS) { fread (&n, 1, 1, f); event->fxt = n; fread (&n, 1, 1, f); event->fxp = n; xlat_fx (c, event); pat_len -= 2; } } if (V (0)) report ("."); } if (V (0)) report ("\n"); if (V (1)) { report ("Stereo enabled : %s\n", sfh.mv % 0x80 ? "yes" : "no"); report ("Pan settings : %s\n", sfh.dp ? "no" : "yes"); } INSTRUMENT_INIT (); /* Read and convert instruments and samples */ if (V (0)) report ("Instruments : %d ", xxh->ins); for (i = 0; i < xxh->ins; i++) { xxi[i] = calloc (sizeof (struct xxm_instrument), 1); fseek (f, pp_ins[i] * 16, SEEK_SET); fread (&x8, 1, 1, f); xxi[i][0].pan = 0x80; xxi[i][0].sid = i; if (x8 >= 2) { /* OPL2 FM instrument */ fread (&sah, 1, sizeof (sah), f); if (strncmp (sah.magic, "SCRI", 4)) return -2; L_ENDIAN16 (sah.c2spd); sah.magic[0] = 0; str_adj ((char *) sah.name); strncpy ((char *) xxih[i].name, sah.name, 24); xxih[i].nsm = 1; xxi[i][0].vol = sah.vol; c2spd_to_note (sah.c2spd, &xxi[i][0].xpo, &xxi[i][0].fin); xxi[i][0].xpo += 12; xmp_drv_loadpatch (f, xxi[i][0].sid, 0, 0, NULL, (char *) &sah.reg); if (V (0) <= 1) { if (V (0)) report ("."); continue; } report ("\n[%2X] %-28.28s ", i, sah.name); for (j = 0; j < 11; j++) report ("%02x ", (uint8) sah.reg[j]); continue; } fread (&sih, 1, sizeof (sih), f); if ((x8 == 1) && strncmp (sih.magic, "SCRS", 4)) return -2; L_ENDIAN16 (sih.memseg); L_ENDIAN32 (sih.length); L_ENDIAN32 (sih.loopbeg); L_ENDIAN32 (sih.loopend); L_ENDIAN16 (sih.c2spd); xxih[i].nsm = !!(xxs[i].len = sih.length); xxs[i].lps = sih.loopbeg; xxs[i].lpe = sih.loopend; xxs[i].flg = sih.flags & 1 ? WAVE_LOOPING : 0; xxs[i].flg |= sih.flags & 4 ? WAVE_16_BITS : 0; xxi[i][0].vol = sih.vol; sih.magic[0] = 0; str_adj ((char *) sih.name); strncpy ((char *) xxih[i].name, sih.name, 24); if ((V (1)) && (strlen ((char *) sih.name) || xxs[i].len)) report ("\n[%2X] %-28.28s %04x%c%04x %04x %c V%02x %5d ", i, sih.name, xxs[i].len, xxs[i].flg & WAVE_16_BITS ?'+' : ' ', xxs[i].lps, xxs[i].lpe, xxs[i].flg & WAVE_LOOPING ? 'L' : ' ', xxi[i][0].vol, sih.c2spd); c2spd_to_note (sih.c2spd, &xxi[i][0].xpo, &xxi[i][0].fin); if (!xxs[i].len) continue; fseek (f, 16L * sih.memseg, SEEK_SET); xmp_drv_loadpatch (f, xxi[i][0].sid, xmp_ctl->c4rate, (sfh.ffi - 1) * XMP_SMP_UNS, &xxs[i], NULL); if (V (0)) report ("."); } if (V (0)) report ("\n"); xmp_ctl->fetch |= XMP_MODE_ST3; return 0; }