static int mfp_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k, x, y; struct xmp_event *event; struct stat st; char smp_filename[PATH_MAX]; HIO_HANDLE *s; int size1, size2; int pat_addr, pat_table[128][4]; uint8 buf[1024], mod_event[4]; int row; LOAD_INIT(); set_type(m, "Magnetic Fields Packer"); MODULE_INFO(); mod->chn = 4; mod->ins = mod->smp = 31; if (instrument_init(mod) < 0) return -1; for (i = 0; i < 31; i++) { int loop_size; if (subinstrument_alloc(mod, i, 1) < 0) return -1; mod->xxs[i].len = 2 * hio_read16b(f); mod->xxi[i].sub[0].fin = (int8)(hio_read8(f) << 4); mod->xxi[i].sub[0].vol = hio_read8(f); mod->xxs[i].lps = 2 * hio_read16b(f); loop_size = hio_read16b(f); mod->xxs[i].lpe = mod->xxs[i].lps + 2 * loop_size; mod->xxs[i].flg = loop_size > 1 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].rls = 0xfff; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; D_(D_INFO "[%2X] %04x %04x %04x %c V%02x %+d", i, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, loop_size > 1 ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4); } mod->len = mod->pat = hio_read8(f); hio_read8(f); /* restart */ for (i = 0; i < 128; i++) mod->xxo[i] = hio_read8(f); #if 0 for (i = 0; i < 128; i++) { mod->xxo[i] = hio_read8(f); if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; #endif mod->trk = mod->pat * mod->chn; /* Read and convert patterns */ if (pattern_init(mod) < 0) return -1; size1 = hio_read16b(f); size2 = hio_read16b(f); for (i = 0; i < size1; i++) { /* Read pattern table */ for (j = 0; j < 4; j++) { pat_table[i][j] = hio_read16b(f); } } D_(D_INFO "Stored patterns: %d ", mod->pat); pat_addr = hio_tell(f); for (i = 0; i < mod->pat; i++) { if (pattern_tracks_alloc(mod, i, 64) < 0) return -1; for (j = 0; j < 4; j++) { hio_seek(f, pat_addr + pat_table[i][j], SEEK_SET); hio_read(buf, 1, 1024, f); for (row = k = 0; k < 4; k++) { for (x = 0; x < 4; x++) { for (y = 0; y < 4; y++, row++) { event = &EVENT(i, j, row); memcpy(mod_event, &buf[buf[buf[buf[k] + x] + y] * 2], 4); decode_protracker_event(event, mod_event); } } } } } /* Read samples */ D_(D_INFO "Loading samples: %d", mod->ins); /* first check smp.filename */ if (strlen(m->basename) < 5 || m->basename[3] != '.') { fprintf(stderr, "libxmp: invalid filename %s\n", m->basename); goto err; } m->basename[0] = 's'; m->basename[1] = 'm'; m->basename[2] = 'p'; snprintf(smp_filename, sizeof(smp_filename), "%s%s", m->dirname, m->basename); if (stat(smp_filename, &st) < 0) { /* handle .set filenames like in Kid Chaos*/ char *x; if (strchr(m->basename, '-')) { if ((x = strrchr(smp_filename, '-'))) strcpy(x, ".set"); } if (stat(smp_filename, &st) < 0) { fprintf(stderr, "libxmp: missing file %s\n", smp_filename); goto err; } } if ((s = hio_open_file(smp_filename, "rb")) == NULL) { fprintf(stderr, "libxmp: can't open sample file %s\n", smp_filename); goto err; } for (i = 0; i < mod->ins; i++) { if (load_sample(m, s, SAMPLE_FLAG_FULLREP, &mod->xxs[mod->xxi[i].sub[0].sid], NULL) < 0) return -1; } hio_close(s); m->quirk |= QUIRK_MODRNG; return 0; err: for (i = 0; i < mod->ins; i++) { mod->xxi[i].nsm = 0; memset(&mod->xxs[i], 0, sizeof(struct xmp_sample)); } return 0; }
static int mod_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct mod_header mh; uint8 mod_event[4]; char magic[8]; int ptkloop = 0; /* Protracker loop */ LOAD_INIT(); mod->ins = 31; mod->smp = mod->ins; mod->chn = 0; m->quirk |= QUIRK_MODRNG; hio_read(&mh.name, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); /* Instrument name */ mh.ins[i].size = hio_read16b(f); /* Length in 16-bit words */ mh.ins[i].finetune = hio_read8(f); /* Finetune (signed nibble) */ mh.ins[i].volume = hio_read8(f); /* Linear playback volume */ mh.ins[i].loop_start = hio_read16b(f); /* Loop start in 16-bit words */ mh.ins[i].loop_size = hio_read16b(f); /* Loop size in 16-bit words */ } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); memset(magic, 0, 8); hio_read(magic, 4, 1, f); if (!memcmp(magic, "M.K.", 4)) { mod->chn = 4; } else if (!strncmp(magic + 2, "CH", 2) && isdigit((int)magic[0]) && isdigit((int)magic[1])) { mod->chn = (*magic - '0') * 10 + magic[1] - '0'; } else if (!strncmp(magic + 1, "CHN", 3) && isdigit((int)*magic)) { mod->chn = *magic - '0'; } else { return -1; } strncpy(mod->name, (char *) mh.name, 20); mod->len = mh.len; /* mod->rst = mh.restart; */ if (mod->rst >= mod->len) mod->rst = 0; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { /* This fixes dragnet.mod (garbage in the order list) */ if (mod->xxo[i] > 0x7f) break; if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; if (instrument_init(mod) < 0) return -1; for (i = 0; i < mod->ins; i++) { if (subinstrument_alloc(mod, i, 1) < 0) return -1; mod->xxs[i].len = 2 * mh.ins[i].size; mod->xxs[i].lps = 2 * mh.ins[i].loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * mh.ins[i].loop_size; if (mod->xxs[i].lpe > mod->xxs[i].len) mod->xxs[i].lpe = mod->xxs[i].len; mod->xxs[i].flg = (mh.ins[i].loop_size > 1 && mod->xxs[i].lpe >= 4) ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].fin = (int8)(mh.ins[i].finetune << 4); mod->xxi[i].sub[0].vol = mh.ins[i].volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; instrument_name(mod, i, mh.ins[i].name, 22); if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; } mod->trk = mod->chn * mod->pat; set_type(m, mod->chn == 4 ? "Protracker" : "Fasttracker"); MODULE_INFO(); for (i = 0; i < mod->ins; i++) { D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d %c\n", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, (mh.ins[i].loop_size > 1 && mod->xxs[i].lpe > 8) ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4, ptkloop && mod->xxs[i].lps == 0 && mh.ins[i].loop_size > 1 && mod->xxs[i].len > mod->xxs[i].lpe ? '!' : ' '); } if (pattern_init(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (pattern_tracks_alloc(mod, i, 64) < 0) return -1; for (j = 0; j < (64 * mod->chn); j++) { event = &EVENT (i, j % mod->chn, j / mod->chn); hio_read (mod_event, 1, 4, f); decode_protracker_event(event, mod_event); } } /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { int flags; if (!mod->xxs[i].len) continue; flags = ptkloop ? SAMPLE_FLAG_FULLREP : 0; if (load_sample(m, f, flags, &mod->xxs[i], NULL) < 0) return -1; } if (mod->chn > 4) { m->quirk &= ~QUIRK_MODRNG; m->quirk |= QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; } return 0; }
static int ptdt_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct mod_header mh; uint8 mod_event[4]; hio_read(&mh.name, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); hio_read(&mh.magic, 4, 1, f); mod->ins = 31; mod->smp = mod->ins; mod->chn = 4; mod->len = mh.len; mod->rst = mh.restart; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; mod->trk = mod->chn * mod->pat; if (instrument_init(mod) < 0) return -1; for (i = 0; i < mod->ins; i++) { if (subinstrument_alloc(mod, i, 1) < 0) return -1; mod->xxs[i].len = 2 * mh.ins[i].size; mod->xxs[i].lps = 2 * mh.ins[i].loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * mh.ins[i].loop_size; mod->xxs[i].flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; mod->xxi[i].sub[0].fin = (int8)(mh.ins[i].finetune << 4); mod->xxi[i].sub[0].vol = mh.ins[i].volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].rls = 0xfff; instrument_name(mod, i, mh.ins[i].name, 22); D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mh.ins[i].loop_size > 1 ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4); } if (pattern_init(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (pattern_tracks_alloc(mod, i, 64) < 0) return -1; for (j = 0; j < (64 * 4); j++) { event = &EVENT(i, j % 4, j / 4); hio_read(mod_event, 1, 4, f); decode_protracker_event(event, mod_event); } } m->quirk |= QUIRK_MODRNG; /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (!mod->xxs[i].len) continue; if (load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; }
static int hmn_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct mod_header mh; struct mupp mupp[31]; uint8 mod_event[4]; int mupp_index, num_mupp; LOAD_INIT(); /* * clr.b $1c(a6) ;prog on/off * CMP.L #'Mupp',-$16(a3,d4.l) * bne.s noprgo * move.l a0,-(a7) * move.b #1,$1c(a6) ;prog on * move.l l697,a0 * lea $43c(a0),a0 * moveq #0,d2 * move.b -$16+$4(a3,d4.l),d2 ;pattno * mulu #$400,d2 * lea (a0,d2.l),a0 * move.l a0,4(a6) ;proginstr data-start * moveq #0,d2 * MOVE.B $3C0(A0),$12(A6) * AND.B #$7F,$12(A6) * move.b $380(a0),d2 * mulu #$20,d2 * lea (a0,d2.w),a0 * move.l a0,$a(a6) ;loopstartmempoi = startmempoi * move.B $3(a3,d4.l),$13(a6) ;volume * move.b -$16+$5(a3,d4.l),8(a6) ;dataloopstart * move.b -$16+$6(a3,d4.l),9(a6) ;dataloopend * move.w #$10,$e(a6) ;looplen * move.l (a7)+,a0 * MOVE.W $12(A6),(A2) * AND.W #$FF,(A2) * BRA.S L505_LQ */ /* * Wavetable structure is 22 * 32 byte waveforms and 32 byte * wave control data with looping. */ memset(mupp, 0, 31 * sizeof (struct mupp)); hio_read(&mh.name, 20, 1, f); num_mupp = 0; for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); /* Instrument name */ if (memcmp(mh.ins[i].name, "Mupp", 4) == 0) { mupp[i].prgon = 1; mupp[i].pattno = mh.ins[i].name[4]; mupp[i].dataloopstart = mh.ins[i].name[5]; mupp[i].dataloopend = mh.ins[i].name[6]; num_mupp++; } mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); hio_read(&mh.magic, 4, 1, f); mod->chn = 4; mod->ins = 31; mod->smp = mod->ins + 28 * num_mupp; mod->len = mh.len; mod->rst = mh.restart; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; mod->trk = mod->chn * mod->pat; if (hmn_new_module_extras(m) != 0) return -1; strncpy(mod->name, (char *)mh.name, 20); set_type(m, "%s (%4.4s)", "His Master's Noise", mh.magic); MODULE_INFO(); if (instrument_init(mod) < 0) return -1; for (i = 0; i < mod->ins; i++) { if (mupp[i].prgon) { mod->xxi[i].nsm = 28; snprintf(mod->xxi[i].name, 32, "Mupp %02x %02x %02x", mupp[i].pattno, mupp[i].dataloopstart, mupp[i].dataloopend); if (hmn_new_instrument_extras(&mod->xxi[i]) != 0) return -1; } else { mod->xxi[i].nsm = 1; instrument_name(mod, i, mh.ins[i].name, 22); mod->xxs[i].len = 2 * mh.ins[i].size; mod->xxs[i].lps = 2 * mh.ins[i].loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * mh.ins[i].loop_size; mod->xxs[i].flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; } if (subinstrument_alloc(mod, i, mod->xxi[i].nsm) < 0) return -1; for (j = 0; j < mod->xxi[i].nsm; j++) { mod->xxi[i].sub[j].fin = -(int8)(mh.ins[i].finetune << 3); mod->xxi[i].sub[j].vol = mh.ins[i].volume; mod->xxi[i].sub[j].pan = 0x80; mod->xxi[i].sub[j].sid = i; } } if (pattern_init(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (pattern_tracks_alloc(mod, i, 64) < 0) return -1; for (j = 0; j < (64 * 4); j++) { event = &EVENT(i, j % 4, j / 4); hio_read(mod_event, 1, 4, f); decode_protracker_event(event, mod_event); switch (event->fxt) { case 0x07: event->fxt = FX_MEGAARP; break; case 0x08: case 0x09: case 0x0e: event->fxt = event->fxp = 0; break; } } } m->quirk |= QUIRK_MODRNG; /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < 31; i++) { if (load_sample(m, f, SAMPLE_FLAG_FULLREP, &mod->xxs[i], NULL) < 0) { return -1; } } /* Load Mupp samples */ mupp_index = 0; for (i = 0; i < 31; i ++) { struct hmn_instrument_extras *extra = (struct hmn_instrument_extras *)mod->xxi[i].extra; if (!mupp[i].prgon) continue; hio_seek(f, start + 1084 + 1024 * mupp[i].pattno, SEEK_SET); for (j = 0; j < 28; j++) { int k = 31 + 28 * mupp_index + j; mod->xxi[i].sub[j].sid = k; mod->xxs[k].len = 32; mod->xxs[k].lps = 0; mod->xxs[k].lpe = 32; mod->xxs[k].flg = XMP_SAMPLE_LOOP; if (load_sample(m, f, 0, &mod->xxs[k], NULL) < 0) return -1; } extra->dataloopstart = mupp[i].dataloopstart; extra->dataloopend = mupp[i].dataloopend; hio_read(extra->data, 1, 64, f); hio_read(extra->progvolume, 1, 64, f); mupp_index++; } return 0; }
static int mod_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; int smp_size, pat_size, wow, ptsong = 0; struct xmp_event *event; struct mod_header mh; uint8 mod_event[4]; char *x, pathname[PATH_MAX] = "", *tracker = ""; int detected = 0; char magic[8], idbuffer[32]; int ptkloop = 0; /* Protracker loop */ int tracker_id = TRACKER_PROTRACKER; LOAD_INIT(); mod->ins = 31; mod->smp = mod->ins; mod->chn = 0; smp_size = 0; pat_size = 0; m->quirk |= QUIRK_MODRNG; hio_read(&mh.name, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); /* Instrument name */ mh.ins[i].size = hio_read16b(f); /* Length in 16-bit words */ mh.ins[i].finetune = hio_read8(f); /* Finetune (signed nibble) */ mh.ins[i].volume = hio_read8(f); /* Linear playback volume */ mh.ins[i].loop_start = hio_read16b(f); /* Loop start in 16-bit words */ mh.ins[i].loop_size = hio_read16b(f); /* Loop size in 16-bit words */ smp_size += 2 * mh.ins[i].size; } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); memset(magic, 0, 8); hio_read(magic, 4, 1, f); for (i = 0; mod_magic[i].ch; i++) { if (!(strncmp (magic, mod_magic[i].magic, 4))) { mod->chn = mod_magic[i].ch; tracker_id = mod_magic[i].id; detected = mod_magic[i].flag; break; } } if (!mod->chn) { if (!strncmp(magic + 2, "CH", 2) && isdigit((int)magic[0]) && isdigit((int)magic[1])) { mod->chn = (*magic - '0') * 10 + magic[1] - '0'; } else if (!strncmp(magic + 1, "CHN", 3) && isdigit((int)*magic)) { mod->chn = *magic - '0'; } else { return -1; } tracker_id = mod->chn & 1 ? TRACKER_TAKETRACKER : TRACKER_FASTTRACKER2; detected = 1; m->quirk &= ~QUIRK_MODRNG; } strncpy(mod->name, (char *) mh.name, 20); mod->len = mh.len; /* mod->rst = mh.restart; */ if (mod->rst >= mod->len) mod->rst = 0; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { /* This fixes dragnet.mod (garbage in the order list) */ if (mod->xxo[i] > 0x7f) break; if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; pat_size = 256 * mod->chn * mod->pat; if (instrument_init(mod) < 0) return -1; for (i = 0; i < mod->ins; i++) { if (subinstrument_alloc(mod, i, 1) < 0) return -1; mod->xxs[i].len = 2 * mh.ins[i].size; mod->xxs[i].lps = 2 * mh.ins[i].loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * mh.ins[i].loop_size; if (mod->xxs[i].lpe > mod->xxs[i].len) mod->xxs[i].lpe = mod->xxs[i].len; mod->xxs[i].flg = (mh.ins[i].loop_size > 1 && mod->xxs[i].lpe >= 4) ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].fin = (int8)(mh.ins[i].finetune << 4); mod->xxi[i].sub[0].vol = mh.ins[i].volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; instrument_name(mod, i, mh.ins[i].name, 22); if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; } /* * Experimental tracker-detection routine */ if (detected) goto skip_test; /* Test for Flextrax modules * * FlexTrax is a soundtracker for Atari Falcon030 compatible computers. * FlexTrax supports the standard MOD file format (up to eight channels) * for compatibility reasons but also features a new enhanced module * format FLX. The FLX format is an extended version of the standard * MOD file format with support for real-time sound effects like reverb * and delay. */ if (0x43c + mod->pat * 4 * mod->chn * 0x40 + smp_size < m->size) { int pos = hio_tell(f); hio_seek(f, start + 0x43c + mod->pat * 4 * mod->chn * 0x40 + smp_size, SEEK_SET); hio_read(idbuffer, 1, 4, f); hio_seek(f, start + pos, SEEK_SET); if (!memcmp(idbuffer, "FLEX", 4)) { tracker_id = TRACKER_FLEXTRAX; goto skip_test; } } /* Test for Mod's Grave WOW modules * * Stefan Danes <*****@*****.**> said: * This weird format is identical to '8CHN' but still uses the 'M.K.' ID. * You can only test for WOW by calculating the size of the module for 8 * channels and comparing this to the actual module length. If it's equal, * the module is an 8 channel WOW. */ if ((wow = (!strncmp(magic, "M.K.", 4) && (0x43c + mod->pat * 32 * 0x40 + smp_size == m->size)))) { mod->chn = 8; tracker_id = TRACKER_MODSGRAVE; goto skip_test; } /* Test for Protracker song files */ else if ((ptsong = (!strncmp((char *)magic, "M.K.", 4) && (0x43c + mod->pat * 0x400 == m->size)))) { tracker_id = TRACKER_PROTRACKER; goto skip_test; } /* Test Protracker-like files */ if (mod->chn == 4 && mh.restart == mod->pat) { tracker_id = TRACKER_SOUNDTRACKER; } else if (mod->chn == 4 && mh.restart == 0x78) { tracker_id = TRACKER_NOISETRACKER; } else if (mh.restart < 0x7f) { if (mod->chn == 4) { tracker_id = TRACKER_NOISETRACKER; } else { tracker_id = TRACKER_UNKNOWN; } mod->rst = mh.restart; } if (mod->chn != 4 && mh.restart == 0x7f) { tracker_id = TRACKER_SCREAMTRACKER3; m->quirk &= ~QUIRK_MODRNG; m->read_event_type = READ_EVENT_ST3; } if (mod->chn == 4 && mh.restart == 0x7f) { for (i = 0; i < 31; i++) { if (mh.ins[i].loop_size == 0) break; } if (i < 31) { tracker_id = TRACKER_CLONE; } } if (mh.restart != 0x78 && mh.restart < 0x7f) { for (i = 0; i < 31; i++) { if (mh.ins[i].loop_size == 0) break; } if (i == 31) { /* All loops are size 2 or greater */ for (i = 0; i < 31; i++) { if (mh.ins[i].size == 1 && mh.ins[i].volume == 0) { tracker_id = TRACKER_CONVERTED; goto skip_test; } } for (i = 0; i < 31; i++) { if (is_st_ins((char *)mh.ins[i].name)) break; } if (i == 31) { /* No st- instruments */ for (i = 0; i < 31; i++) { if (mh.ins[i].size == 0 && mh.ins[i].loop_size == 1) { switch (mod->chn) { case 4: tracker_id = TRACKER_NOISETRACKER; /* or Octalyser */ break; case 6: case 8: tracker_id = TRACKER_OCTALYSER; break; default: tracker_id = TRACKER_UNKNOWN; } goto skip_test; } } if (mod->chn == 4) { tracker_id = TRACKER_PROTRACKER; } else if (mod->chn == 6 || mod->chn == 8) { tracker_id = TRACKER_FASTTRACKER; /* FastTracker 1.01? */ m->quirk &= ~QUIRK_MODRNG; } else { tracker_id = TRACKER_UNKNOWN; } } } else { /* Has loops with 0 size */ for (i = 15; i < 31; i++) { if (strlen((char *)mh.ins[i].name) || mh.ins[i].size > 0) break; } if (i == 31 && is_st_ins((char *)mh.ins[14].name)) { tracker_id = TRACKER_CONVERTEDST; goto skip_test; } /* Assume that Fast Tracker modules won't have ST- instruments */ for (i = 0; i < 31; i++) { if (is_st_ins((char *)mh.ins[i].name)) break; } if (i < 31) { tracker_id = TRACKER_UNKNOWN_CONV; goto skip_test; } if (mod->chn == 4 || mod->chn == 6 || mod->chn == 8) { tracker_id = TRACKER_FASTTRACKER; m->quirk &= ~QUIRK_MODRNG; goto skip_test; } tracker_id = TRACKER_UNKNOWN; /* ??!? */ } } skip_test: switch (tracker_id) { case TRACKER_PROTRACKER: tracker = "Protracker"; ptkloop = 1; break; case TRACKER_NOISETRACKER: tracker = "Noisetracker"; ptkloop = 1; break; case TRACKER_SOUNDTRACKER: tracker = "Soundtracker"; ptkloop = 1; break; case TRACKER_FASTTRACKER: tracker = "Fast Tracker"; break; case TRACKER_FASTTRACKER2: tracker = "FastTracker 2"; break; case TRACKER_OCTALYSER: tracker = "Octalyser"; break; case TRACKER_TAKETRACKER: tracker = "TakeTracker"; break; case TRACKER_DIGITALTRACKER: tracker = "Digital Tracker"; break; case TRACKER_FLEXTRAX: tracker = "Flextrax"; break; case TRACKER_MODSGRAVE: tracker = "Mod's Grave"; break; case TRACKER_SCREAMTRACKER3: tracker = "Scream Tracker III"; break; case TRACKER_UNKNOWN_CONV: tracker = "unknown or converted"; break; case TRACKER_CONVERTEDST: tracker = "converted ST2.2 or earlier"; break; case TRACKER_CONVERTED: tracker = "converted"; break; case TRACKER_CLONE: tracker = "Protracker clone"; break; default: case TRACKER_UNKNOWN: tracker = "unknown"; break; } mod->trk = mod->chn * mod->pat; snprintf(mod->type, XMP_NAME_SIZE, "%s (%s)", tracker, magic); MODULE_INFO(); for (i = 0; i < mod->ins; i++) { D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d %c\n", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, (mh.ins[i].loop_size > 1 && mod->xxs[i].lpe > 8) ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4, ptkloop && mod->xxs[i].lps == 0 && mh.ins[i].loop_size > 1 && mod->xxs[i].len > mod->xxs[i].lpe ? '!' : ' '); } if (pattern_init(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (pattern_tracks_alloc(mod, i, 64) < 0) return -1; for (j = 0; j < (64 * mod->chn); j++) { event = &EVENT (i, j % mod->chn, j / mod->chn); hio_read (mod_event, 1, 4, f); switch (tracker_id) { case TRACKER_NOISETRACKER: decode_noisetracker_event(event, mod_event); break; case TRACKER_PROTRACKER: default: decode_protracker_event(event, mod_event); break; } } } /* Load samples */ if (m->filename && (x = strrchr(m->filename, '/'))) strncpy(pathname, m->filename, x - m->filename); D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { int flags; if (!mod->xxs[i].len) continue; flags = ptkloop ? SAMPLE_FLAG_FULLREP : 0; if (ptsong) { HIO_HANDLE *s; char sn[256]; snprintf(sn, XMP_NAME_SIZE, "%s%s", pathname, mod->xxi[i].name); if ((s = hio_open_file(sn, "rb"))) { if (load_sample(m, s, flags, &mod->xxs[i], NULL) < 0) { hio_close(s); return -1; } hio_close(s); } } else { if (load_sample(m, f, flags, &mod->xxs[i], NULL) < 0) return -1; } } if (mod->chn > 4) { m->quirk &= ~QUIRK_MODRNG; m->quirk |= QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; } else if (strcmp(tracker, "Protracker") == 0) { m->quirk |= QUIRK_INVLOOP; } return 0; }