summaryrefslogtreecommitdiffstats
path: root/apps/plugins/mikmod/load_med.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/load_med.c')
-rw-r--r--apps/plugins/mikmod/load_med.c719
1 files changed, 719 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_med.c b/apps/plugins/mikmod/load_med.c
new file mode 100644
index 0000000000..21a85b39a0
--- /dev/null
+++ b/apps/plugins/mikmod/load_med.c
@@ -0,0 +1,719 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
+ AUTHORS for complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ $Id: load_med.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Amiga MED module loader
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <string.h>
+
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+#endif
+
+/*========== Module information */
+
+typedef struct MEDHEADER {
+ ULONG id;
+ ULONG modlen;
+ ULONG MEDSONGP; /* struct MEDSONG *song; */
+ UWORD psecnum; /* for the player routine, MMD2 only */
+ UWORD pseq; /* " " " " */
+ ULONG MEDBlockPP; /* struct MEDBlock **blockarr; */
+ ULONG reserved1;
+ ULONG MEDINSTHEADERPP; /* struct MEDINSTHEADER **smplarr; */
+ ULONG reserved2;
+ ULONG MEDEXPP; /* struct MEDEXP *expdata; */
+ ULONG reserved3;
+ UWORD pstate; /* some data for the player routine */
+ UWORD pblock;
+ UWORD pline;
+ UWORD pseqnum;
+ SWORD actplayline;
+ UBYTE counter;
+ UBYTE extra_songs; /* number of songs - 1 */
+} MEDHEADER;
+
+typedef struct MEDSAMPLE {
+ UWORD rep, replen; /* offs: 0(s), 2(s) */
+ UBYTE midich; /* offs: 4(s) */
+ UBYTE midipreset; /* offs: 5(s) */
+ UBYTE svol; /* offs: 6(s) */
+ SBYTE strans; /* offs: 7(s) */
+} MEDSAMPLE;
+
+typedef struct MEDSONG {
+ MEDSAMPLE sample[63]; /* 63 * 8 bytes = 504 bytes */
+ UWORD numblocks; /* offs: 504 */
+ UWORD songlen; /* offs: 506 */
+ UBYTE playseq[256]; /* offs: 508 */
+ UWORD deftempo; /* offs: 764 */
+ SBYTE playtransp; /* offs: 766 */
+ UBYTE flags; /* offs: 767 */
+ UBYTE flags2; /* offs: 768 */
+ UBYTE tempo2; /* offs: 769 */
+ UBYTE trkvol[16]; /* offs: 770 */
+ UBYTE mastervol; /* offs: 786 */
+ UBYTE numsamples; /* offs: 787 */
+} MEDSONG;
+
+typedef struct MEDEXP {
+ ULONG nextmod; /* pointer to next module */
+ ULONG exp_smp; /* pointer to MEDINSTEXT array */
+ UWORD s_ext_entries;
+ UWORD s_ext_entrsz;
+ ULONG annotxt; /* pointer to annotation text */
+ ULONG annolen;
+ ULONG iinfo; /* pointer to MEDINSTINFO array */
+ UWORD i_ext_entries;
+ UWORD i_ext_entrsz;
+ ULONG jumpmask;
+ ULONG rgbtable;
+ ULONG channelsplit;
+ ULONG n_info;
+ ULONG songname; /* pointer to songname */
+ ULONG songnamelen;
+ ULONG dumps;
+ ULONG reserved2[7];
+} MEDEXP;
+
+typedef struct MMD0NOTE {
+ UBYTE a, b, c;
+} MMD0NOTE;
+
+typedef struct MMD1NOTE {
+ UBYTE a, b, c, d;
+} MMD1NOTE;
+
+typedef struct MEDINSTHEADER {
+ ULONG length;
+ SWORD type;
+ /* Followed by actual data */
+} MEDINSTHEADER;
+
+typedef struct MEDINSTEXT {
+ UBYTE hold;
+ UBYTE decay;
+ UBYTE suppress_midi_off;
+ SBYTE finetune;
+} MEDINSTEXT;
+
+typedef struct MEDINSTINFO {
+ UBYTE name[40];
+} MEDINSTINFO;
+
+/*========== Loader variables */
+
+#define MMD0_string 0x4D4D4430
+#define MMD1_string 0x4D4D4431
+
+static MEDHEADER *mh = NULL;
+static MEDSONG *ms = NULL;
+static MEDEXP *me = NULL;
+static ULONG *ba = NULL;
+static MMD0NOTE *mmd0pat = NULL;
+static MMD1NOTE *mmd1pat = NULL;
+
+static int decimalvolumes;
+static int bpmtempos;
+
+#define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]
+#define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]
+
+static CHAR MED_Version[] = "OctaMED (MMDx)";
+
+/*========== Loader code */
+
+int MED_Test(void)
+{
+ UBYTE id[4];
+
+ if (!_mm_read_UBYTES(id, 4, modreader))
+ return 0;
+ if ((!memcmp(id, "MMD0", 4)) || (!memcmp(id, "MMD1", 4)))
+ return 1;
+ return 0;
+}
+
+int MED_Init(void)
+{
+ if (!(me = (MEDEXP *)MikMod_malloc(sizeof(MEDEXP))))
+ return 0;
+ if (!(mh = (MEDHEADER *)MikMod_malloc(sizeof(MEDHEADER))))
+ return 0;
+ if (!(ms = (MEDSONG *)MikMod_malloc(sizeof(MEDSONG))))
+ return 0;
+ return 1;
+}
+
+void MED_Cleanup(void)
+{
+ MikMod_free(me);
+ MikMod_free(mh);
+ MikMod_free(ms);
+ MikMod_free(ba);
+ MikMod_free(mmd0pat);
+ MikMod_free(mmd1pat);
+}
+
+static void EffectCvt(UBYTE eff, UBYTE dat)
+{
+ switch (eff) {
+ /* 0x0 0x1 0x2 0x3 0x4 PT effects */
+ case 0x5: /* PT vibrato with speed/depth nibbles swapped */
+ UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4));
+ break;
+ /* 0x6 0x7 not used */
+ case 0x6:
+ case 0x7:
+ break;
+ case 0x8: /* midi hold/decay */
+ break;
+ case 0x9:
+ if (bpmtempos) {
+ if (!dat)
+ dat = of.initspeed;
+ UniEffect(UNI_S3MEFFECTA, dat);
+ } else {
+ if (dat <= 0x20) {
+ if (!dat)
+ dat = of.initspeed;
+ else
+ dat /= 4;
+ UniPTEffect(0xf, dat);
+ } else
+ UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / (33 * 4));
+ }
+ break;
+ /* 0xa 0xb PT effects */
+ case 0xc:
+ if (decimalvolumes)
+ dat = (dat >> 4) * 10 + (dat & 0xf);
+ UniPTEffect(0xc, dat);
+ break;
+ case 0xd: /* same as PT volslide */
+ UniPTEffect(0xa, dat);
+ break;
+ case 0xe: /* synth jmp - midi */
+ break;
+ case 0xf:
+ switch (dat) {
+ case 0: /* patternbreak */
+ UniPTEffect(0xd, 0);
+ break;
+ case 0xf1: /* play note twice */
+ UniWriteByte(UNI_MEDEFFECTF1);
+ break;
+ case 0xf2: /* delay note */
+ UniWriteByte(UNI_MEDEFFECTF2);
+ break;
+ case 0xf3: /* play note three times */
+ UniWriteByte(UNI_MEDEFFECTF3);
+ break;
+ case 0xfe: /* stop playing */
+ UniPTEffect(0xb, of.numpat);
+ break;
+ case 0xff: /* note cut */
+ UniPTEffect(0xc, 0);
+ break;
+ default:
+ if (dat <= 10)
+ UniPTEffect(0xf, dat);
+ else if (dat <= 240) {
+ if (bpmtempos)
+ UniPTEffect(0xf, (dat < 32) ? 32 : dat);
+ else
+ UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33);
+ }
+ }
+ break;
+ default: /* all normal PT effects are handled here */
+ UniPTEffect(eff, dat);
+ break;
+ }
+}
+
+static UBYTE *MED_Convert1(int count, int col)
+{
+ int t;
+ UBYTE inst, note, eff, dat;
+ MMD1NOTE *n;
+
+ UniReset();
+ for (t = 0; t < count; t++) {
+ n = &d1note(t, col);
+
+ note = n->a & 0x7f;
+ inst = n->b & 0x3f;
+ eff = n->c & 0xf;
+ dat = n->d;
+
+ if (inst)
+ UniInstrument(inst - 1);
+ if (note)
+ UniNote(note + 3 * OCTAVE - 1);
+ EffectCvt(eff, dat);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+static UBYTE *MED_Convert0(int count, int col)
+{
+ int t;
+ UBYTE a, b, inst, note, eff, dat;
+ MMD0NOTE *n;
+
+ UniReset();
+ for (t = 0; t < count; t++) {
+ n = &d0note(t, col);
+ a = n->a;
+ b = n->b;
+
+ note = a & 0x3f;
+ a >>= 6;
+ a = ((a & 1) << 1) | (a >> 1);
+ inst = (b >> 4) | (a << 4);
+ eff = b & 0xf;
+ dat = n->c;
+
+ if (inst)
+ UniInstrument(inst - 1);
+ if (note)
+ UniNote(note + 3 * OCTAVE - 1);
+ EffectCvt(eff, dat);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+static int LoadMEDPatterns(void)
+{
+ int t, row, col;
+ UWORD numtracks, numlines, maxlines = 0, track = 0;
+ MMD0NOTE *mmdp;
+
+ /* first, scan patterns to see how many channels are used */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_UBYTE(modreader);
+ numlines = _mm_read_UBYTE(modreader);
+
+ if (numtracks > of.numchn)
+ of.numchn = numtracks;
+ if (numlines > maxlines)
+ maxlines = numlines;
+ }
+
+ of.numtrk = of.numpat * of.numchn;
+ if (!AllocTracks())
+ return 0;
+ if (!AllocPatterns())
+ return 0;
+
+ if (!
+ (mmd0pat =
+ (MMD0NOTE *)MikMod_calloc(of.numchn * (maxlines + 1),
+ sizeof(MMD0NOTE)))) return 0;
+
+ /* second read: read and convert patterns */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_UBYTE(modreader);
+ numlines = _mm_read_UBYTE(modreader);
+
+ of.pattrows[t] = ++numlines;
+ memset(mmdp = mmd0pat, 0, of.numchn * maxlines * sizeof(MMD0NOTE));
+ for (row = numlines; row; row--) {
+ for (col = numtracks; col; col--, mmdp++) {
+ mmdp->a = _mm_read_UBYTE(modreader);
+ mmdp->b = _mm_read_UBYTE(modreader);
+ mmdp->c = _mm_read_UBYTE(modreader);
+ }
+ }
+
+ for (col = 0; col < of.numchn; col++)
+ of.tracks[track++] = MED_Convert0(numlines, col);
+ }
+ return 1;
+}
+
+static int LoadMMD1Patterns(void)
+{
+ int t, row, col;
+ UWORD numtracks, numlines, maxlines = 0, track = 0;
+ MMD1NOTE *mmdp;
+
+ /* first, scan patterns to see how many channels are used */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_M_UWORD(modreader);
+ numlines = _mm_read_M_UWORD(modreader);
+ if (numtracks > of.numchn)
+ of.numchn = numtracks;
+ if (numlines > maxlines)
+ maxlines = numlines;
+ }
+
+ of.numtrk = of.numpat * of.numchn;
+ if (!AllocTracks())
+ return 0;
+ if (!AllocPatterns())
+ return 0;
+
+ if (!
+ (mmd1pat =
+ (MMD1NOTE *)MikMod_calloc(of.numchn * (maxlines + 1),
+ sizeof(MMD1NOTE)))) return 0;
+
+ /* second read: really read and convert patterns */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_M_UWORD(modreader);
+ numlines = _mm_read_M_UWORD(modreader);
+
+ _mm_fseek(modreader, sizeof(ULONG), SEEK_CUR);
+ of.pattrows[t] = ++numlines;
+ memset(mmdp = mmd1pat, 0, of.numchn * maxlines * sizeof(MMD1NOTE));
+
+ for (row = numlines; row; row--) {
+ for (col = numtracks; col; col--, mmdp++) {
+ mmdp->a = _mm_read_UBYTE(modreader);
+ mmdp->b = _mm_read_UBYTE(modreader);
+ mmdp->c = _mm_read_UBYTE(modreader);
+ mmdp->d = _mm_read_UBYTE(modreader);
+ }
+ }
+
+ for (col = 0; col < of.numchn; col++)
+ of.tracks[track++] = MED_Convert1(numlines, col);
+ }
+ return 1;
+}
+
+int MED_Load(int curious)
+{
+ int t;
+ ULONG sa[64];
+ MEDINSTHEADER s;
+ SAMPLE *q;
+ MEDSAMPLE *mss;
+
+ /* try to read module header */
+ mh->id = _mm_read_M_ULONG(modreader);
+ mh->modlen = _mm_read_M_ULONG(modreader);
+ mh->MEDSONGP = _mm_read_M_ULONG(modreader);
+ mh->psecnum = _mm_read_M_UWORD(modreader);
+ mh->pseq = _mm_read_M_UWORD(modreader);
+ mh->MEDBlockPP = _mm_read_M_ULONG(modreader);
+ mh->reserved1 = _mm_read_M_ULONG(modreader);
+ mh->MEDINSTHEADERPP = _mm_read_M_ULONG(modreader);
+ mh->reserved2 = _mm_read_M_ULONG(modreader);
+ mh->MEDEXPP = _mm_read_M_ULONG(modreader);
+ mh->reserved3 = _mm_read_M_ULONG(modreader);
+ mh->pstate = _mm_read_M_UWORD(modreader);
+ mh->pblock = _mm_read_M_UWORD(modreader);
+ mh->pline = _mm_read_M_UWORD(modreader);
+ mh->pseqnum = _mm_read_M_UWORD(modreader);
+ mh->actplayline = _mm_read_M_SWORD(modreader);
+ mh->counter = _mm_read_UBYTE(modreader);
+ mh->extra_songs = _mm_read_UBYTE(modreader);
+
+ /* Seek to MEDSONG struct */
+ _mm_fseek(modreader, mh->MEDSONGP, SEEK_SET);
+
+ /* Load the MED Song Header */
+ mss = ms->sample; /* load the sample data first */
+ for (t = 63; t; t--, mss++) {
+ mss->rep = _mm_read_M_UWORD(modreader);
+ mss->replen = _mm_read_M_UWORD(modreader);
+ mss->midich = _mm_read_UBYTE(modreader);
+ mss->midipreset = _mm_read_UBYTE(modreader);
+ mss->svol = _mm_read_UBYTE(modreader);
+ mss->strans = _mm_read_SBYTE(modreader);
+ }
+
+ ms->numblocks = _mm_read_M_UWORD(modreader);
+ ms->songlen = _mm_read_M_UWORD(modreader);
+ _mm_read_UBYTES(ms->playseq, 256, modreader);
+ ms->deftempo = _mm_read_M_UWORD(modreader);
+ ms->playtransp = _mm_read_SBYTE(modreader);
+ ms->flags = _mm_read_UBYTE(modreader);
+ ms->flags2 = _mm_read_UBYTE(modreader);
+ ms->tempo2 = _mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(ms->trkvol, 16, modreader);
+ ms->mastervol = _mm_read_UBYTE(modreader);
+ ms->numsamples = _mm_read_UBYTE(modreader);
+
+ /* check for a bad header */
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* load extension structure */
+ if (mh->MEDEXPP) {
+ _mm_fseek(modreader, mh->MEDEXPP, SEEK_SET);
+ me->nextmod = _mm_read_M_ULONG(modreader);
+ me->exp_smp = _mm_read_M_ULONG(modreader);
+ me->s_ext_entries = _mm_read_M_UWORD(modreader);
+ me->s_ext_entrsz = _mm_read_M_UWORD(modreader);
+ me->annotxt = _mm_read_M_ULONG(modreader);
+ me->annolen = _mm_read_M_ULONG(modreader);
+ me->iinfo = _mm_read_M_ULONG(modreader);
+ me->i_ext_entries = _mm_read_M_UWORD(modreader);
+ me->i_ext_entrsz = _mm_read_M_UWORD(modreader);
+ me->jumpmask = _mm_read_M_ULONG(modreader);
+ me->rgbtable = _mm_read_M_ULONG(modreader);
+ me->channelsplit = _mm_read_M_ULONG(modreader);
+ me->n_info = _mm_read_M_ULONG(modreader);
+ me->songname = _mm_read_M_ULONG(modreader);
+ me->songnamelen = _mm_read_M_ULONG(modreader);
+ me->dumps = _mm_read_M_ULONG(modreader);
+ }
+
+ /* seek to and read the samplepointer array */
+ _mm_fseek(modreader, mh->MEDINSTHEADERPP, SEEK_SET);
+ if (!_mm_read_M_ULONGS(sa, ms->numsamples, modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* alloc and read the blockpointer array */
+ if (!(ba = (ULONG *)MikMod_calloc(ms->numblocks, sizeof(ULONG))))
+ return 0;
+ _mm_fseek(modreader, mh->MEDBlockPP, SEEK_SET);
+ if (!_mm_read_M_ULONGS(ba, ms->numblocks, modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* copy song positions */
+ if (!AllocPositions(ms->songlen))
+ return 0;
+ for (t = 0; t < ms->songlen; t++)
+ of.positions[t] = ms->playseq[t];
+
+ decimalvolumes = (ms->flags & 0x10) ? 0 : 1;
+ bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;
+
+ if (bpmtempos) {
+ int bpmlen = (ms->flags2 & 0x1f) + 1;
+ of.initspeed = ms->tempo2;
+ of.inittempo = ms->deftempo * bpmlen / 4;
+
+ if (bpmlen != 4) {
+ /* Let's do some math : compute GCD of BPM beat length and speed */
+ int a, b;
+
+ a = bpmlen;
+ b = ms->tempo2;
+
+ if (a > b) {
+ t = b;
+ b = a;
+ a = t;
+ }
+ while ((a != b) && (a)) {
+ t = a;
+ a = b - a;
+ b = t;
+ if (a > b) {
+ t = b;
+ b = a;
+ a = t;
+ }
+ }
+
+ of.initspeed /= b;
+ of.inittempo = ms->deftempo * bpmlen / (4 * b);
+ }
+ } else {
+ of.initspeed = ms->tempo2;
+ of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128;
+ if ((ms->deftempo <= 10) && (ms->deftempo))
+ of.inittempo = (of.inittempo * 33) / 6;
+ of.flags |= UF_HIGHBPM;
+ }
+ MED_Version[12] = mh->id;
+ of.modtype = StrDup(MED_Version);
+ of.numchn = 0; /* will be counted later */
+ of.numpat = ms->numblocks;
+ of.numpos = ms->songlen;
+ of.numins = ms->numsamples;
+ of.numsmp = of.numins;
+ of.reppos = 0;
+ if ((mh->MEDEXPP) && (me->songname) && (me->songnamelen)) {
+ char *name;
+
+ _mm_fseek(modreader, me->songname, SEEK_SET);
+ name = MikMod_malloc(me->songnamelen);
+ _mm_read_UBYTES(name, me->songnamelen, modreader);
+ of.songname = DupStr(name, me->songnamelen, 1);
+ MikMod_free(name);
+ } else
+ of.songname = DupStr(NULL, 0, 0);
+ if ((mh->MEDEXPP) && (me->annotxt) && (me->annolen)) {
+ _mm_fseek(modreader, me->annotxt, SEEK_SET);
+ ReadComment(me->annolen);
+ }
+
+ if (!AllocSamples())
+ return 0;
+ q = of.samples;
+ for (t = 0; t < of.numins; t++) {
+ q->flags = SF_SIGNED;
+ q->volume = 64;
+ if (sa[t]) {
+ _mm_fseek(modreader, sa[t], SEEK_SET);
+ s.length = _mm_read_M_ULONG(modreader);
+ s.type = _mm_read_M_SWORD(modreader);
+
+ if (s.type) {
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");
+#endif
+ if (!curious) {
+ _mm_errno = MMERR_MED_SYNTHSAMPLES;
+ return 0;
+ }
+ s.length = 0;
+ }
+
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->length = s.length;
+ q->seekpos = _mm_ftell(modreader);
+ q->loopstart = ms->sample[t].rep << 1;
+ q->loopend = q->loopstart + (ms->sample[t].replen << 1);
+
+ if (ms->sample[t].replen > 1)
+ q->flags |= SF_LOOP;
+
+ /* don't load sample if length>='MMD0'...
+ such kluges make libmikmod's code unique !!! */
+ if (q->length >= MMD0_string)
+ q->length = 0;
+ } else
+ q->length = 0;
+
+ if ((mh->MEDEXPP) && (me->exp_smp) &&
+ (t < me->s_ext_entries) && (me->s_ext_entrsz >= 4)) {
+ MEDINSTEXT ie;
+
+ _mm_fseek(modreader, me->exp_smp + t * me->s_ext_entrsz,
+ SEEK_SET);
+ ie.hold = _mm_read_UBYTE(modreader);
+ ie.decay = _mm_read_UBYTE(modreader);
+ ie.suppress_midi_off = _mm_read_UBYTE(modreader);
+ ie.finetune = _mm_read_SBYTE(modreader);
+
+ q->speed = finetune[ie.finetune & 0xf];
+ } else
+ q->speed = 8363;
+
+ if ((mh->MEDEXPP) && (me->iinfo) &&
+ (t < me->i_ext_entries) && (me->i_ext_entrsz >= 40)) {
+ MEDINSTINFO ii;
+
+ _mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET);
+ _mm_read_UBYTES(ii.name, 40, modreader);
+ q->samplename = DupStr((char*)ii.name, 40, 1);
+ } else
+ q->samplename = NULL;
+
+ q++;
+ }
+
+ if (mh->id == MMD0_string) {
+ if (!LoadMEDPatterns()) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ } else if (mh->id == MMD1_string) {
+ if (!LoadMMD1Patterns()) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ } else {
+ _mm_errno = MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ return 1;
+}
+
+CHAR *MED_LoadTitle(void)
+{
+ ULONG posit, namelen;
+ CHAR *name, *retvalue = NULL;
+
+ _mm_fseek(modreader, 0x20, SEEK_SET);
+ posit = _mm_read_M_ULONG(modreader);
+
+ if (posit) {
+ _mm_fseek(modreader, posit + 0x2C, SEEK_SET);
+ posit = _mm_read_M_ULONG(modreader);
+ namelen = _mm_read_M_ULONG(modreader);
+
+ _mm_fseek(modreader, posit, SEEK_SET);
+ name = MikMod_malloc(namelen);
+ _mm_read_UBYTES(name, namelen, modreader);
+ retvalue = DupStr(name, namelen, 1);
+ MikMod_free(name);
+ }
+
+ return retvalue;
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_med = {
+ NULL,
+ "MED",
+ "MED (OctaMED)",
+ MED_Init,
+ MED_Test,
+ MED_Load,
+ MED_Cleanup,
+ MED_LoadTitle
+};
+
+/* ex:set ts=4: */