예제 #1
0
static int get_emic(struct module_data *m, int size, HIO_HANDLE * f, void *parm)
{
	struct xmp_module *mod = &m->mod;
	int i, ver;
	uint8 reorder[256];

	ver = hio_read16b(f);
	hio_read(mod->name, 1, 20, f);
	hio_seek(f, 20, SEEK_CUR);
	mod->bpm = hio_read8(f);
	mod->ins = hio_read8(f);
	mod->smp = mod->ins;

	m->quirk |= QUIRK_MODRNG;

	snprintf(mod->type, XMP_NAME_SIZE, "Quadra Composer EMOD v%d", ver);
	MODULE_INFO();

	if (instrument_init(mod) < 0)
		return -1;

	for (i = 0; i < mod->ins; i++) {
		struct xmp_instrument *xxi = &mod->xxi[i];
		struct xmp_sample *xxs = &mod->xxs[i];
		struct xmp_subinstrument *sub;

		if (subinstrument_alloc(mod, i, 1) < 0)
			return -1;

		sub = &xxi->sub[0];

		hio_read8(f);	/* num */
		sub->vol = hio_read8(f);
		xxs->len = 2 * hio_read16b(f);
		hio_read(xxi->name, 1, 20, f);
		xxs->flg = hio_read8(f) & 1 ? XMP_SAMPLE_LOOP : 0;
		sub->fin = hio_read8s(f) << 4;
		xxs->lps = 2 * hio_read16b(f);
		xxs->lpe = xxs->lps + 2 * hio_read16b(f);
		hio_read32b(f);	/* ptr */

		xxi->nsm = 1;
		sub->pan = 0x80;
		sub->sid = i;

		D_(D_INFO "[%2X] %-20.20s %05x %05x %05x %c V%02x %+d",
			i, xxi->name, xxs->len, xxs->lps, xxs->lpe,
			xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
			sub->vol, sub->fin >> 4);
	}

	hio_read8(f);		/* pad */
	mod->pat = hio_read8(f);
	mod->trk = mod->pat * mod->chn;

	if (pattern_init(mod) < 0)
		return -1;

	memset(reorder, 0, 256);

	for (i = 0; i < mod->pat; i++) {
		reorder[hio_read8(f)] = i;

		if (pattern_tracks_alloc(mod, i, hio_read8(f) + 1) < 0)
			return -1;

		hio_seek(f, 20, SEEK_CUR);	/* skip name */
		hio_read32b(f);	/* ptr */
	}

	mod->len = hio_read8(f);

	D_(D_INFO "Module length: %d", mod->len);

	for (i = 0; i < mod->len; i++)
		mod->xxo[i] = reorder[hio_read8(f)];

	return 0;
}
예제 #2
0
파일: stc_load.c 프로젝트: rikolous/gideros
static int stc_load(struct module_data *m, HIO_HANDLE * f, const int start)
{
    struct xmp_module *mod = &m->mod;
    struct xmp_event *event /*, *noise*/;
    int i, j;
    uint8 buf[100];
    int pos_ptr, orn_ptr, pat_ptr;
    struct stc_ord stc_ord[256];
    struct stc_pat stc_pat[MAX_PAT];
    int num, flag, orn;
    int *decoded;
    struct spectrum_extra *se;

    LOAD_INIT();

    mod->spd = hio_read8(f);		/* Speed */
    pos_ptr = hio_read16l(f);		/* Positions pointer */
    orn_ptr = hio_read16l(f);		/* Ornaments pointer */
    pat_ptr = hio_read16l(f);		/* Patterns pointer */

    hio_read(buf, 18, 1, f);		/* Title */
    copy_adjust(mod->name, (uint8 *)buf, 18);
    set_type(m, "ZX Spectrum Sound Tracker");

    hio_read16l(f);			/* Size */

    /* Read orders */

    hio_seek(f, pos_ptr, SEEK_SET);
    mod->len = hio_read8(f) + 1;

    for (num = i = 0; i < mod->len; i++) {
        stc_ord[i].pattern = hio_read8(f);
        stc_ord[i].height = hio_read8s(f);
        //printf("%d %d -- ", stc_ord[i].pattern, stc_ord[i].height);

        for (flag = j = 0; j < i; j++) {
            if (stc_ord[i].pattern == stc_ord[j].pattern &&
                    stc_ord[i].height == stc_ord[j].height)
            {
                mod->xxo[i] = mod->xxo[j];
                flag = 1;
                break;
            }
        }
        if (!flag) {
            mod->xxo[i] = num++;
        }
        //printf("%d\n", mod->xxo[i]);
    }

    mod->chn = 3;
    mod->pat = num;
    mod->trk = mod->pat * mod->chn;
    mod->ins = 15;
    mod->smp = mod->ins;
    orn = (pat_ptr - orn_ptr) / 33;

    MODULE_INFO();

    /* Read patterns */

    if (pattern_init(mod) < 0)
        return -1;

    hio_seek(f, pat_ptr, SEEK_SET);
    decoded = calloc(mod->pat, sizeof(int));
    D_(D_INFO "Stored patterns: %d ", mod->pat);

    for (i = 0; i < MAX_PAT; i++) {
        if (hio_read8(f) == 0xff)
            break;
        stc_pat[i].ch[0] = hio_read16l(f);
        stc_pat[i].ch[1] = hio_read16l(f);
        stc_pat[i].ch[2] = hio_read16l(f);
    }

    for (i = 0; i < mod->len; i++) {		/* pattern */
        int src = stc_ord[i].pattern - 1;
        int dest = mod->xxo[i];
        int trans = stc_ord[i].height;

        if (decoded[dest])
            continue;

        //printf("%d/%d) Read pattern %d -> %d\n", i, mod->len, src, dest);

        if (pattern_tracks_alloc(mod, dest, 64) < 0)
            return -1;

        for (j = 0; j < 3; j++) {		/* row */
            int row = 0;
            int x;
            int rowinc = 0;

            hio_seek(f, stc_pat[src].ch[j], SEEK_SET);

            do {
                for (;;) {
                    x = hio_read8(f);

                    if (x == 0xff)
                        break;

//printf("pat %d, channel %d, row %d, x = %02x\n", dest, j, row, x);
                    event = &EVENT(dest, j, row);

                    if (x <= 0x5f) {
                        event->note = x + 18 + trans;
                        row += 1 + rowinc;
                        break;
                    }

                    if (x <= 0x6f) {
                        event->ins = x - 0x5f - 1;
                    } else if (x <= 0x7f) {
                        /* ornament*/
                        event->fxt = FX_SYNTH_0;
                        event->fxp = x - 0x70;
                    } else if (x == 0x80) {
                        event->note = XMP_KEY_OFF;
                        row += 1 + rowinc;
                        break;
                    } else if (x == 0x81) {
                        /* ? */
                        row += 1 + rowinc;
                    } else if (x == 0x82) {
                        /* disable ornament/envelope */
                        event->fxt = FX_SYNTH_0;
                        event->fxp = 0;
                        event->f2t = FX_SYNTH_2;
                        event->f2p = 0;
                    } else if (x <= 0x8e) {
                        /* envelope */
                        event->fxt = FX_SYNTH_0 +
                                     x - 0x80;      /* R13 */
                        event->fxp = hio_read8(f); /* R11 */
                        event->f2t = FX_SYNTH_1;
                        event->f2p = hio_read8(f); /* R12 */
                    } else {
                        rowinc = x - 0xa1;
                    }
                }
            } while (x != 0xff);
        }

        decoded[dest] = 1;
    }

    free(decoded);

    /* Read instruments */

    if (instrument_init(mod) < 0)
        return -1;

    hio_seek(f, 27, SEEK_SET);

    D_(D_INFO "Instruments: %d", mod->ins);
    for (i = 0; i < mod->ins; i++) {
        struct spectrum_sample ss;

        memset(&ss, 0, sizeof (struct spectrum_sample));
        if (subinstrument_alloc(mod, i, 1) < 0)
            return -1;
        mod->xxi[i].nsm = 1;
        mod->xxi[i].sub[0].vol = 0x40;
        mod->xxi[i].sub[0].pan = 0x80;
        mod->xxi[i].sub[0].xpo = -1;
        mod->xxi[i].sub[0].sid = i;

        hio_read(buf, 1, 99, f);

        if (buf[97] == 0) {
            ss.loop = 32;
            ss.length = 33;
        } else {
            ss.loop = buf[97] - 1;
            if (ss.loop > 31)
                ss.loop = 31;
            ss.length = buf[97] + buf[98];
            if (ss.length > 32)
                ss.length = 32;
            if (ss.length == 0)
                ss.length = 1;
            if (ss.loop >= ss.length)
                ss.loop = ss.length - 1;

            if (ss.length < 32) {
                ss.length += 33 - (ss.loop + 1);
                ss.loop = 32;
            }
        }

        /* Read sample ticks */

        for (j = 0; j < 31; j++) {
            struct spectrum_stick *sst = &ss.stick[j];
            uint8 *chdata = &buf[1 + j * 3];

            memset(sst, 0, sizeof (struct spectrum_stick));

            if (~chdata[1] & 0x80) {
                sst->flags |= SPECTRUM_FLAG_MIXNOISE;
                sst->noise_env_inc = chdata[1] & 0x1f;

                if (sst->noise_env_inc & 0x10)
                    sst->noise_env_inc |= 0xf0;
            }

            if (~chdata[1] & 0x40)
                sst->flags |= SPECTRUM_FLAG_MIXTONE;

            sst->vol = chdata[0] & 0x0f;

            sst->tone_inc = (((int)(chdata[0] & 0xf0)) << 4) |
                            chdata[2];

            if (~chdata[1] & 0x20)
                sst->tone_inc = -sst->tone_inc;

            sst->flags |= SPECTRUM_FLAG_ENVELOPE;

            /*if (j != 0) {
            	reportv(ctx, 1, "               ");
            }
            reportv(ctx, 1, "%02X %c%c%c %c%03x %x\n", j,
            	sst->flags & SPECTRUM_FLAG_MIXTONE ? 'T' : 't',
            	sst->flags & SPECTRUM_FLAG_MIXNOISE ? 'N' : 'n',
            	sst->flags & SPECTRUM_FLAG_ENVELOPE ? 'E' : 'e',
            	sst->tone_inc >= 0 ? '+' : '-',
            	sst->tone_inc >= 0 ?
            		sst->tone_inc : -sst->tone_inc,
            	sst->vol);*/

        }

        if (load_sample(m, f, SAMPLE_FLAG_SPECTRUM, &mod->xxs[i],
                        (char *)&ss) < 0) {
            return -1;
        }
    }

    /* Read ornaments */

    hio_seek(f, orn_ptr, SEEK_SET);
    m->extra = calloc(1, sizeof (struct spectrum_extra));
    se = m->extra;

    D_(D_INFO "Ornaments: %d", orn);
    for (i = 0; i < orn; i++) {
        int index;
        struct spectrum_ornament *so;

        index = hio_read8(f);

        so = &se->ornament[index];
        so->length = 32;
        so->loop = 31;

        for (j = 0; j < 32; j++) {
            so->val[j] = hio_read8s(f);
        }
    }

    for (i = 0; i < 4; i++) {
        mod->xxc[i].pan = 0x80;
        mod->xxc[i].flg = XMP_CHANNEL_SYNTH;
    }

    m->synth = &synth_spectrum;

    return 0;
}
예제 #3
0
파일: gtk_load.c 프로젝트: visy/turha
static int gtk_load(struct module_data *m, HIO_HANDLE *f, const int start)
{
	struct xmp_module *mod = &m->mod;
	struct xmp_event *event;
	int i, j, k;
	uint8 buffer[40];
	int rows, bits, c2spd, size;
	int ver, patmax;

	LOAD_INIT();

	hio_read(buffer, 4, 1, f);
	ver = buffer[3];
	hio_read(mod->name, 32, 1, f);
	set_type(m, "Graoumf Tracker GTK v%d", ver);
	hio_seek(f, 160, SEEK_CUR);	/* skip comments */

	mod->ins = hio_read16b(f);
	mod->smp = mod->ins;
	rows = hio_read16b(f);
	mod->chn = hio_read16b(f);
	mod->len = hio_read16b(f);
	mod->rst = hio_read16b(f);
	m->volbase = 0x100;

	MODULE_INFO();

	D_(D_INFO "Instruments    : %d ", mod->ins);

	if (instrument_init(mod) < 0)
		return -1;

	for (i = 0; i < mod->ins; i++) {
		if (subinstrument_alloc(mod, i, 1) < 0)
			return -1;

		hio_read(buffer, 28, 1, f);
		instrument_name(mod, i, buffer, 28);

		if (ver == 1) {
			hio_read32b(f);
			mod->xxs[i].len = hio_read32b(f);
			mod->xxs[i].lps = hio_read32b(f);
			size = hio_read32b(f);
			mod->xxs[i].lpe = mod->xxs[i].lps + size - 1;
			hio_read16b(f);
			hio_read16b(f);
			mod->xxi[i].sub[0].vol = 0xff;
			mod->xxi[i].sub[0].pan = 0x80;
			bits = 1;
			c2spd = 8363;
		} else {
			hio_seek(f, 14, SEEK_CUR);
			hio_read16b(f);		/* autobal */
			bits = hio_read16b(f);	/* 1 = 8 bits, 2 = 16 bits */
			c2spd = hio_read16b(f);
			c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin);
			mod->xxs[i].len = hio_read32b(f);
			mod->xxs[i].lps = hio_read32b(f);
			size = hio_read32b(f);
			mod->xxs[i].lpe = mod->xxs[i].lps + size - 1;
			mod->xxi[i].sub[0].vol = hio_read16b(f);
			hio_read8(f);
			mod->xxi[i].sub[0].fin = hio_read8s(f);
		}

		if (mod->xxs[i].len > 0)
			mod->xxi[i].nsm = 1;

		mod->xxi[i].sub[0].sid = i;
		mod->xxs[i].flg = size > 2 ? XMP_SAMPLE_LOOP : 0;

		if (bits > 1) {
			mod->xxs[i].flg |= XMP_SAMPLE_16BIT;
			mod->xxs[i].len >>= 1;
			mod->xxs[i].lps >>= 1;
			mod->xxs[i].lpe >>= 1;
		}

		D_(D_INFO "[%2X] %-28.28s  %05x%c%05x %05x %c "
						"V%02x F%+03d %5d", i,
			 	mod->xxi[i].name,
				mod->xxs[i].len,
				bits > 1 ? '+' : ' ',
				mod->xxs[i].lps,
				size,
				mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
				mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin,
				c2spd);
	}
예제 #4
0
파일: dt_load.c 프로젝트: GCrean/libxmp
static int get_inst(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
{
	struct xmp_module *mod = &m->mod;
	int i, c2spd;
	uint8 name[30];

	mod->ins = mod->smp = hio_read16b(f);

	D_(D_INFO "Instruments    : %d ", mod->ins);

	if (instrument_init(mod) < 0)
		return -1;

	for (i = 0; i < mod->ins; i++) {
		int fine, replen, flag;

		if (subinstrument_alloc(mod, i, 1) < 0)
			return -1;

		hio_read32b(f);		/* reserved */
		mod->xxs[i].len = hio_read32b(f);
		mod->xxi[i].nsm = !!mod->xxs[i].len;
		fine = hio_read8s(f);	/* finetune */
		mod->xxi[i].sub[0].vol = hio_read8(f);
		mod->xxi[i].sub[0].pan = 0x80;
		mod->xxs[i].lps = hio_read32b(f);
		replen = hio_read32b(f);
		mod->xxs[i].lpe = mod->xxs[i].lps + replen - 1;
		mod->xxs[i].flg = replen > 2 ?  XMP_SAMPLE_LOOP : 0;

		hio_read(name, 22, 1, f);
		instrument_name(mod, i, name, 22);

		flag = hio_read16b(f);	/* bit 0-7:resol 8:stereo */
		if ((flag & 0xff) > 8) {
			mod->xxs[i].flg |= XMP_SAMPLE_16BIT;
			mod->xxs[i].len >>= 1;
			mod->xxs[i].lps >>= 1;
			mod->xxs[i].lpe >>= 1;
		}

		hio_read32b(f);		/* midi note (0x00300000) */
		c2spd = hio_read32b(f);	/* frequency */
		c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin);

		/* It's strange that we have both c2spd and finetune */
		mod->xxi[i].sub[0].fin += fine;

		mod->xxi[i].sub[0].sid = i;

		D_(D_INFO "[%2X] %-22.22s %05x%c%05x %05x %c%c %2db V%02x F%+03d %5d",
			i, mod->xxi[i].name,
			mod->xxs[i].len,
			mod->xxs[i].flg & XMP_SAMPLE_16BIT ? '+' : ' ',
			mod->xxs[i].lps,
			replen,
			mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
			flag & 0x100 ? 'S' : ' ',
			flag & 0xff,
			mod->xxi[i].sub[0].vol,
			fine,
			c2spd);
	}
예제 #5
0
파일: med3_load.c 프로젝트: GCrean/libxmp
static int med3_load(struct module_data *m, HIO_HANDLE *f, const int start)
{
	struct xmp_module *mod = &m->mod;
	int i, j;
	uint32 mask;
	int transp, sliding;

	LOAD_INIT();

	hio_read32b(f);

	set_type(m, "MED 2.00 MED3");

	mod->ins = mod->smp = 32;

	if (instrument_init(mod) < 0)
		return -1;

	/* read instrument names */
	for (i = 0; i < 32; i++) {
		uint8 c, buf[40];
		for (j = 0; j < 40; j++) {
			c = hio_read8(f);
			buf[j] = c;
			if (c == 0)
				break;
		}
		instrument_name(mod, i, buf, 32);
		if (subinstrument_alloc(mod, i, 1) < 0)
			return -1;
	}

	/* read instrument volumes */
	mask = hio_read32b(f);
	for (i = 0; i < 32; i++, mask <<= 1) {
		mod->xxi[i].sub[0].vol = mask & MASK ? hio_read8(f) : 0;
		mod->xxi[i].sub[0].pan = 0x80;
		mod->xxi[i].sub[0].fin = 0;
		mod->xxi[i].sub[0].sid = i;
	}

	/* read instrument loops */
	mask = hio_read32b(f);
	for (i = 0; i < 32; i++, mask <<= 1) {
		mod->xxs[i].lps = mask & MASK ? hio_read16b(f) : 0;
	}

	/* read instrument loop length */
	mask = hio_read32b(f);
	for (i = 0; i < 32; i++, mask <<= 1) {
		uint32 lsiz = mask & MASK ? hio_read16b(f) : 0;
		mod->xxs[i].len = mod->xxs[i].lps + lsiz;
		mod->xxs[i].lpe = mod->xxs[i].lps + lsiz;
		mod->xxs[i].flg = lsiz > 1 ? XMP_SAMPLE_LOOP : 0;
	}

	mod->chn = 4;
	mod->pat = hio_read16b(f);
	mod->trk = mod->chn * mod->pat;

	mod->len = hio_read16b(f);
	hio_read(mod->xxo, 1, mod->len, f);
	mod->spd = hio_read16b(f);
	if (mod->spd > 10) {
		mod->bpm = 125 * mod->spd / 33;
		mod->spd = 6;
	}
	transp = hio_read8s(f);
	hio_read8(f);			/* flags */
	sliding = hio_read16b(f);	/* sliding */
	hio_read32b(f);			/* jumping mask */
	hio_seek(f, 16, SEEK_CUR);	/* rgb */

	/* read midi channels */
	mask = hio_read32b(f);
	for (i = 0; i < 32; i++, mask <<= 1) {
		if (mask & MASK)
			hio_read8(f);
	}

	/* read midi programs */
	mask = hio_read32b(f);
	for (i = 0; i < 32; i++, mask <<= 1) {
		if (mask & MASK)
			hio_read8(f);
	}
	
	MODULE_INFO();

	D_(D_INFO "Sliding: %d", sliding);
	D_(D_INFO "Play transpose: %d", transp);

	if (sliding == 6)
		m->quirk |= QUIRK_VSALL | QUIRK_PBALL;

	for (i = 0; i < 32; i++)
		mod->xxi[i].sub[0].xpo = transp;

	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++) {
		uint32 *conv;
		uint8 b, tracks;
		uint16 convsz;

		if (pattern_tracks_alloc(mod, i, 64) < 0)
			return -1;

		tracks = hio_read8(f);

		b = hio_read8(f);
		convsz = hio_read16b(f);
		conv = calloc(1, convsz + 16);
		if (conv == NULL)
			return -1;

                if (b & M0F_LINEMSK00)
			*conv = 0L;
                else if (b & M0F_LINEMSK0F)
			*conv = 0xffffffff;
                else
			*conv = hio_read32b(f);

                if (b & M0F_LINEMSK10)
			*(conv + 1) = 0L;
                else if (b & M0F_LINEMSK1F)
			*(conv + 1) = 0xffffffff;
                else
			*(conv + 1) = hio_read32b(f);

                if (b & M0F_FXMSK00)
			*(conv + 2) = 0L;
                else if (b & M0F_FXMSK0F)
			*(conv + 2) = 0xffffffff;
                else
			*(conv + 2) = hio_read32b(f);

                if (b & M0F_FXMSK10)
			*(conv + 3) = 0L;
                else if (b & M0F_FXMSK1F)
			*(conv + 3) = 0xffffffff;
                else
			*(conv + 3) = hio_read32b(f);

		hio_read(conv + 4, 1, convsz, f);

                if (unpack_block(m, i, (uint8 *)conv) < 0) {
			free(conv);
			return -1;
		}

		free(conv);
	}

	/* Load samples */

	D_(D_INFO "Instruments: %d", mod->ins);

	mask = hio_read32b(f);
	for (i = 0; i < 32; i++, mask <<= 1) {
		if (~mask & MASK)
			continue;

		mod->xxi[i].nsm = 1;
		mod->xxs[i].len = hio_read32b(f);

		if (mod->xxs[i].len == 0)
			mod->xxi[i].nsm = 0;

		if (hio_read16b(f))		/* type */
			continue;

		D_(D_INFO "[%2X] %-32.32s %04x %04x %04x %c V%02x ",
			i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps,
			mod->xxs[i].lpe,
			mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
			mod->xxi[i].sub[0].vol);

		if (load_sample(m, f, 0, &mod->xxs[i], NULL) < 0)
			return -1;
	}

	return 0;
}
예제 #6
0
static int mmd3_load(struct module_data *m, HIO_HANDLE *f, const int start)
{
	struct xmp_module *mod = &m->mod;
	int i, j, k;
	struct MMD0 header;
	struct MMD2song song;
	struct MMD1Block block;
	struct InstrHdr instr;
	struct SynthInstr synth;
	struct InstrExt exp_smp;
	struct MMD0exp expdata;
	struct xmp_event *event;
	int ver = 0;
	int smp_idx = 0;
	uint8 e[4];
	int song_offset;
	int seqtable_offset;
	int trackvols_offset;
	int trackpans_offset;
	int blockarr_offset;
	int smplarr_offset;
	int expdata_offset;
	int expsmp_offset;
	int songname_offset;
	int iinfo_offset;
	int playseq_offset;
	int pos;
	int bpm_on, bpmlen, med_8ch;

	LOAD_INIT();

	hio_read(&header.id, 4, 1, f);

	ver = *((char *)&header.id + 3) - '1' + 1;

	D_(D_WARN "load header");
	header.modlen = hio_read32b(f);
	song_offset = hio_read32b(f);
	D_(D_INFO "song_offset = 0x%08x", song_offset);
	hio_read16b(f);
	hio_read16b(f);
	blockarr_offset = hio_read32b(f);
	D_(D_INFO "blockarr_offset = 0x%08x", blockarr_offset);
	hio_read32b(f);
	smplarr_offset = hio_read32b(f);
	D_(D_INFO "smplarr_offset = 0x%08x", smplarr_offset);
	hio_read32b(f);
	expdata_offset = hio_read32b(f);
	D_(D_INFO "expdata_offset = 0x%08x", expdata_offset);
	hio_read32b(f);
	header.pstate = hio_read16b(f);
	header.pblock = hio_read16b(f);
	header.pline = hio_read16b(f);
	header.pseqnum = hio_read16b(f);
	header.actplayline = hio_read16b(f);
	header.counter = hio_read8(f);
	header.extra_songs = hio_read8(f);

	/*
	 * song structure
	 */
	D_(D_WARN "load song");
	hio_seek(f, start + song_offset, SEEK_SET);
	for (i = 0; i < 63; i++) {
		song.sample[i].rep = hio_read16b(f);
		song.sample[i].replen = hio_read16b(f);
		song.sample[i].midich = hio_read8(f);
		song.sample[i].midipreset = hio_read8(f);
		song.sample[i].svol = hio_read8(f);
		song.sample[i].strans = hio_read8s(f);
	}
	song.numblocks = hio_read16b(f);
	song.songlen = hio_read16b(f);
	D_(D_INFO "song.songlen = %d", song.songlen);
	seqtable_offset = hio_read32b(f);
	hio_read32b(f);
	trackvols_offset = hio_read32b(f);
	song.numtracks = hio_read16b(f);
	song.numpseqs = hio_read16b(f);
	trackpans_offset = hio_read32b(f);
	song.flags3 = hio_read32b(f);
	song.voladj = hio_read16b(f);
	song.channels = hio_read16b(f);
	song.mix_echotype = hio_read8(f);
	song.mix_echodepth = hio_read8(f);
	song.mix_echolen = hio_read16b(f);
	song.mix_stereosep = hio_read8(f);

	hio_seek(f, 223, SEEK_CUR);

	song.deftempo = hio_read16b(f);
	song.playtransp = hio_read8(f);
	song.flags = hio_read8(f);
	song.flags2 = hio_read8(f);
	song.tempo2 = hio_read8(f);
	for (i = 0; i < 16; i++)
		hio_read8(f);		/* reserved */
	song.mastervol = hio_read8(f);
	song.numsamples = hio_read8(f);

	/*
	 * read sequence
	 */
	hio_seek(f, start + seqtable_offset, SEEK_SET);
	playseq_offset = hio_read32b(f);
	hio_seek(f, start + playseq_offset, SEEK_SET);
	hio_seek(f, 32, SEEK_CUR);	/* skip name */
	hio_read32b(f);
	hio_read32b(f);
	mod->len = hio_read16b(f);
	for (i = 0; i < mod->len; i++)
		mod->xxo[i] = hio_read16b(f);

	/*
	 * convert header
	 */
	m->c4rate = C4_NTSC_RATE;
	m->quirk |= song.flags & FLAG_STSLIDE ? 0 : QUIRK_VSALL | QUIRK_PBALL;
	med_8ch = song.flags & FLAG_8CHANNEL;
	bpm_on = song.flags2 & FLAG2_BPM;
	bpmlen = 1 + (song.flags2 & FLAG2_BMASK);
	m->time_factor = MED_TIME_FACTOR;

	mmd_set_bpm(m, med_8ch, song.deftempo, bpm_on, bpmlen);

	mod->spd = song.tempo2;
	mod->pat = song.numblocks;
	mod->ins = song.numsamples;
	mod->rst = 0;
	mod->chn = 0;
	mod->name[0] = 0;

	/*
	 * Obtain number of samples from each instrument
	 */
	mod->smp = 0;
	for (i = 0; i < mod->ins; i++) {
		uint32 smpl_offset;
		int16 type;
		hio_seek(f, start + smplarr_offset + i * 4, SEEK_SET);
		smpl_offset = hio_read32b(f);
		if (smpl_offset == 0)
			continue;
		hio_seek(f, start + smpl_offset, SEEK_SET);
		hio_read32b(f);				/* length */
		type = hio_read16b(f);
		if (type == -1) {			/* type is synth? */
			hio_seek(f, 14, SEEK_CUR);
			mod->smp += hio_read16b(f);		/* wforms */
		} else {
			mod->smp++;
		}
	}

	/*
	 * expdata
	 */
	D_(D_WARN "load expdata");
	expdata.s_ext_entries = 0;
	expdata.s_ext_entrsz = 0;
	expdata.i_ext_entries = 0;
	expdata.i_ext_entrsz = 0;
	expsmp_offset = 0;
	iinfo_offset = 0;
	if (expdata_offset) {
		hio_seek(f, start + expdata_offset, SEEK_SET);
		hio_read32b(f);
		expsmp_offset = hio_read32b(f);
		D_(D_INFO "expsmp_offset = 0x%08x", expsmp_offset);
		expdata.s_ext_entries = hio_read16b(f);
		expdata.s_ext_entrsz = hio_read16b(f);
		hio_read32b(f);
		hio_read32b(f);
		iinfo_offset = hio_read32b(f);
		D_(D_INFO "iinfo_offset = 0x%08x", iinfo_offset);
		expdata.i_ext_entries = hio_read16b(f);
		expdata.i_ext_entrsz = hio_read16b(f);
		hio_read32b(f);
		hio_read32b(f);
		hio_read32b(f);
		hio_read32b(f);
		songname_offset = hio_read32b(f);
		D_(D_INFO "songname_offset = 0x%08x", songname_offset);
		expdata.songnamelen = hio_read32b(f);
		hio_seek(f, start + songname_offset, SEEK_SET);
		D_(D_INFO "expdata.songnamelen = %d", expdata.songnamelen);
		for (i = 0; i < expdata.songnamelen; i++) {
			if (i >= XMP_NAME_SIZE)
				break;
			mod->name[i] = hio_read8(f);
		}
	}

	/*
	 * Quickly scan patterns to check the number of channels
	 */
	D_(D_WARN "find number of channels");

	for (i = 0; i < mod->pat; i++) {
		int block_offset;

		hio_seek(f, start + blockarr_offset + i * 4, SEEK_SET);
		block_offset = hio_read32b(f);
		D_(D_INFO "block %d block_offset = 0x%08x", i, block_offset);
		if (block_offset == 0)
			continue;
		hio_seek(f, start + block_offset, SEEK_SET);

		block.numtracks = hio_read16b(f);
		block.lines = hio_read16b(f);

		if (block.numtracks > mod->chn)
			mod->chn = block.numtracks;
	}

	mod->trk = mod->pat * mod->chn;

	if (ver == 2)
	    set_type(m, "OctaMED v5 MMD2");
	else
	    set_type(m, "OctaMED Soundstudio MMD%c", '0' + ver);

	MODULE_INFO();

	D_(D_INFO "BPM mode: %s (length = %d)", bpm_on ? "on" : "off", bpmlen);
	D_(D_INFO "Song transpose : %d", song.playtransp);
	D_(D_INFO "Stored patterns: %d", mod->pat);

	/*
	 * Read and convert patterns
	 */
	D_(D_WARN "read patterns");

	if (pattern_init(mod) < 0)
		return -1;

	for (i = 0; i < mod->pat; i++) {
		int block_offset;

		hio_seek(f, start + blockarr_offset + i * 4, SEEK_SET);
		block_offset = hio_read32b(f);
		if (block_offset == 0)
			continue;
		hio_seek(f, start + block_offset, SEEK_SET);

		block.numtracks = hio_read16b(f);
		block.lines = hio_read16b(f);
		hio_read32b(f);

		if (pattern_tracks_alloc(mod, i, block.lines + 1) < 0)
			return -1;

		for (j = 0; j < mod->xxp[i]->rows; j++) {
			for (k = 0; k < block.numtracks; k++) {
				e[0] = hio_read8(f);
				e[1] = hio_read8(f);
				e[2] = hio_read8(f);
				e[3] = hio_read8(f);

				event = &EVENT(i, k, j);
				event->note = e[0] & 0x7f;
				if (event->note) {
					event->note += song.playtransp;
					if (ver == 2)
						event->note += 12;
					else
						event->note -= 12;
				};

				if (event->note < 0 || event->note >=
								XMP_MAX_KEYS)
					event->note = 0;

				event->ins = e[1] & 0x3f;

				/* Decay */
				if (event->ins && !event->note) {
					event->f2t = FX_MED_HOLD;
				}

				event->fxt = e[2];
				event->fxp = e[3];
				mmd_xlat_fx(event, bpm_on, bpmlen, med_8ch);
			}
		}
	}

	if (med_new_module_extras(m) != 0)
		return -1;

	/*
	 * Read and convert instruments and samples
	 */
	D_(D_WARN "read instruments");

	if (instrument_init(mod) < 0)
		return -1;

	D_(D_INFO "Instruments: %d", mod->ins);

	for (smp_idx = i = 0; i < mod->ins; i++) {
		int smpl_offset;
		char name[40] = "";

		hio_seek(f, start + smplarr_offset + i * 4, SEEK_SET);
		smpl_offset = hio_read32b(f);

		D_(D_INFO "sample %d smpl_offset = 0x%08x", i, smpl_offset);

		if (smpl_offset == 0)
			continue;

		hio_seek(f, start + smpl_offset, SEEK_SET);
		instr.length = hio_read32b(f);
		instr.type = hio_read16b(f);

		pos = hio_tell(f);

		if (expdata_offset && i < expdata.i_ext_entries) {
			hio_seek(f, iinfo_offset + i * expdata.i_ext_entrsz,
								SEEK_SET);
			hio_read(name, 40, 1, f);
			D_(D_INFO "[%2x] %-40.40s %d", i, name, instr.type);
		}

		exp_smp.finetune = 0;
		if (expdata_offset && i < expdata.s_ext_entries) {
			hio_seek(f, expsmp_offset + i * expdata.s_ext_entrsz,
							SEEK_SET);
			exp_smp.hold = hio_read8(f);
			exp_smp.decay = hio_read8(f);
			exp_smp.suppress_midi_off = hio_read8(f);
			exp_smp.finetune = hio_read8(f);

			if (expdata.s_ext_entrsz > 4) {	/* Octamed V5 */
				exp_smp.default_pitch = hio_read8(f);
				exp_smp.instr_flags = hio_read8(f);
			}
		}

		hio_seek(f, pos, SEEK_SET);

		if (instr.type == -2) {			/* Hybrid */
			int ret = mmd_load_hybrid_instrument(f, m, i,
				smp_idx, &synth, &exp_smp, &song.sample[i]);

			if (ret < 0)
				return -1;

			smp_idx++;

			if (mmd_alloc_tables(m, i, &synth) != 0)
				return -1;

			continue;
		}

		if (instr.type == -1) {			/* Synthetic */
			int ret = mmd_load_synth_instrument(f, m, i, smp_idx,
				&synth, &exp_smp, &song.sample[i]);

			if (ret > 0)
				continue;

			if (ret < 0)
				return -1;

			smp_idx += synth.wforms;

			if (mmd_alloc_tables(m, i, &synth) != 0)
				return -1;

			continue;
		}

		if (instr.type >= 1 && instr.type <= 6) {	/* IFFOCT */
			int ret;
			const int oct = num_oct[instr.type - 1];

			hio_seek(f, start + smpl_offset + 6, SEEK_SET);

			ret = mmd_load_iffoct_instrument(f, m, i, smp_idx,
				&instr, oct, &exp_smp, &song.sample[i]);

			if (ret < 0)
				return -1;

			smp_idx += oct;

			continue;
		}

		/* Filter out stereo samples */
		if ((instr.type & ~(S_16 | STEREO)) != 0)
			continue;

		if (instr.type == 0) {			/* Sample */
			int ret;

			hio_seek(f, start + smpl_offset + 6, SEEK_SET);

			ret = mmd_load_sampled_instrument(f, m, i, smp_idx,
				&instr, &expdata, &exp_smp, &song.sample[i],
				ver);

			if (ret < 0)
				return -1;

			smp_idx++;

			continue;
		}
	}

	hio_seek(f, start + trackvols_offset, SEEK_SET);
	for (i = 0; i < mod->chn; i++)
		mod->xxc[i].vol = hio_read8(f);;

	if (trackpans_offset) {
		hio_seek(f, start + trackpans_offset, SEEK_SET);
		for (i = 0; i < mod->chn; i++) {
			int p = 8 * hio_read8s(f);
			mod->xxc[i].pan = 0x80 + (p > 127 ? 127 : p);
		}
	} else {
		for (i = 0; i < mod->chn; i++)
			mod->xxc[i].pan = 0x80;
	}

	m->read_event_type = READ_EVENT_MED;

	return 0;
}