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