Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_med.c
1 /*      MikMod sound library\r
2         (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
3         AUTHORS for complete list.\r
4 \r
5         This library is free software; you can redistribute it and/or modify\r
6         it under the terms of the GNU Library General Public License as\r
7         published by the Free Software Foundation; either version 2 of\r
8         the License, or (at your option) any later version.\r
9  \r
10         This program is distributed in the hope that it will be useful,\r
11         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13         GNU Library General Public License for more details.\r
14  \r
15         You should have received a copy of the GNU Library General Public\r
16         License along with this library; if not, write to the Free Software\r
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
18         02111-1307, USA.\r
19 */\r
20 \r
21 /*==============================================================================\r
22 \r
23   $Id: load_med.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
24 \r
25   Amiga MED module loader\r
26 \r
27 ==============================================================================*/\r
28 \r
29 #ifdef HAVE_CONFIG_H\r
30 #include "config.h"\r
31 #endif\r
32 \r
33 #ifdef HAVE_UNISTD_H\r
34 #include <unistd.h>\r
35 #endif\r
36 \r
37 #include <stdio.h>\r
38 #ifdef HAVE_MEMORY_H\r
39 #include <memory.h>\r
40 #endif\r
41 #include <string.h>\r
42 \r
43 #include "mikmod_internals.h"\r
44 \r
45 #ifdef SUNOS\r
46 extern int fprintf(FILE *, const char *, ...);\r
47 #endif\r
48 \r
49 /*========== Module information */\r
50 \r
51 typedef struct MEDHEADER {\r
52         ULONG id;\r
53         ULONG modlen;\r
54         ULONG MEDSONGP;                         /* struct MEDSONG *song; */\r
55         UWORD psecnum;                          /* for the player routine, MMD2 only */\r
56         UWORD pseq;                                     /*  "   "   "   " */\r
57         ULONG MEDBlockPP;                       /* struct MEDBlock **blockarr; */\r
58         ULONG reserved1;\r
59         ULONG MEDINSTHEADERPP;          /* struct MEDINSTHEADER **smplarr; */\r
60         ULONG reserved2;\r
61         ULONG MEDEXPP;                          /* struct MEDEXP *expdata; */\r
62         ULONG reserved3;\r
63         UWORD pstate;                           /* some data for the player routine */\r
64         UWORD pblock;\r
65         UWORD pline;\r
66         UWORD pseqnum;\r
67         SWORD actplayline;\r
68         UBYTE counter;\r
69         UBYTE extra_songs;                      /* number of songs - 1 */\r
70 } MEDHEADER;\r
71 \r
72 typedef struct MEDSAMPLE {\r
73         UWORD rep, replen;                      /* offs: 0(s), 2(s) */\r
74         UBYTE midich;                           /* offs: 4(s) */\r
75         UBYTE midipreset;                       /* offs: 5(s) */\r
76         UBYTE svol;                                     /* offs: 6(s) */\r
77         SBYTE strans;                           /* offs: 7(s) */\r
78 } MEDSAMPLE;\r
79 \r
80 typedef struct MEDSONG {\r
81         MEDSAMPLE sample[63];           /* 63 * 8 bytes = 504 bytes */\r
82         UWORD numblocks;                        /* offs: 504 */\r
83         UWORD songlen;                          /* offs: 506 */\r
84         UBYTE playseq[256];                     /* offs: 508 */\r
85         UWORD deftempo;                         /* offs: 764 */\r
86         SBYTE playtransp;                       /* offs: 766 */\r
87         UBYTE flags;                            /* offs: 767 */\r
88         UBYTE flags2;                           /* offs: 768 */\r
89         UBYTE tempo2;                           /* offs: 769 */\r
90         UBYTE trkvol[16];                       /* offs: 770 */\r
91         UBYTE mastervol;                        /* offs: 786 */\r
92         UBYTE numsamples;                       /* offs: 787 */\r
93 } MEDSONG;\r
94 \r
95 typedef struct MEDEXP {\r
96         ULONG nextmod;                          /* pointer to next module */\r
97         ULONG exp_smp;                          /* pointer to MEDINSTEXT array */\r
98         UWORD s_ext_entries;\r
99         UWORD s_ext_entrsz;\r
100         ULONG annotxt;                          /* pointer to annotation text */\r
101         ULONG annolen;\r
102         ULONG iinfo;                            /* pointer to MEDINSTINFO array */\r
103         UWORD i_ext_entries;\r
104         UWORD i_ext_entrsz;\r
105         ULONG jumpmask;\r
106         ULONG rgbtable;\r
107         ULONG channelsplit;\r
108         ULONG n_info;\r
109         ULONG songname;                         /* pointer to songname */\r
110         ULONG songnamelen;\r
111         ULONG dumps;\r
112         ULONG reserved2[7];\r
113 } MEDEXP;\r
114 \r
115 typedef struct MMD0NOTE {\r
116         UBYTE a, b, c;\r
117 } MMD0NOTE;\r
118 \r
119 typedef struct MMD1NOTE {\r
120         UBYTE a, b, c, d;\r
121 } MMD1NOTE;\r
122 \r
123 typedef struct MEDINSTHEADER {\r
124         ULONG length;\r
125         SWORD type;\r
126         /* Followed by actual data */\r
127 } MEDINSTHEADER;\r
128 \r
129 typedef struct MEDINSTEXT {\r
130         UBYTE hold;\r
131         UBYTE decay;\r
132         UBYTE suppress_midi_off;\r
133         SBYTE finetune;\r
134 } MEDINSTEXT;\r
135 \r
136 typedef struct MEDINSTINFO {\r
137         UBYTE name[40];\r
138 } MEDINSTINFO;\r
139 \r
140 /*========== Loader variables */\r
141 \r
142 #define MMD0_string 0x4D4D4430\r
143 #define MMD1_string 0x4D4D4431\r
144 \r
145 static MEDHEADER *mh = NULL;\r
146 static MEDSONG *ms = NULL;\r
147 static MEDEXP *me = NULL;\r
148 static ULONG *ba = NULL;\r
149 static MMD0NOTE *mmd0pat = NULL;\r
150 static MMD1NOTE *mmd1pat = NULL;\r
151 \r
152 static BOOL decimalvolumes;\r
153 static BOOL bpmtempos;\r
154 \r
155 #define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]\r
156 #define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]\r
157 \r
158 static CHAR MED_Version[] = "OctaMED (MMDx)";\r
159 \r
160 /*========== Loader code */\r
161 \r
162 BOOL MED_Test(void)\r
163 {\r
164         UBYTE id[4];\r
165 \r
166         if (!_mm_read_UBYTES(id, 4, modreader))\r
167                 return 0;\r
168         if ((!memcmp(id, "MMD0", 4)) || (!memcmp(id, "MMD1", 4)))\r
169                 return 1;\r
170         return 0;\r
171 }\r
172 \r
173 BOOL MED_Init(void)\r
174 {\r
175         if (!(me = (MEDEXP *)_mm_malloc(sizeof(MEDEXP))))\r
176                 return 0;\r
177         if (!(mh = (MEDHEADER *)_mm_malloc(sizeof(MEDHEADER))))\r
178                 return 0;\r
179         if (!(ms = (MEDSONG *)_mm_malloc(sizeof(MEDSONG))))\r
180                 return 0;\r
181         return 1;\r
182 }\r
183 \r
184 void MED_Cleanup(void)\r
185 {\r
186         _mm_free(me);\r
187         _mm_free(mh);\r
188         _mm_free(ms);\r
189         _mm_free(ba);\r
190         _mm_free(mmd0pat);\r
191         _mm_free(mmd1pat);\r
192 }\r
193 \r
194 static void EffectCvt(UBYTE eff, UBYTE dat)\r
195 {\r
196         switch (eff) {\r
197                 /* 0x0 0x1 0x2 0x3 0x4 PT effects */\r
198           case 0x5:                             /* PT vibrato with speed/depth nibbles swapped */\r
199                 UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4));\r
200                 break;\r
201                 /* 0x6 0x7 not used */\r
202           case 0x6:\r
203           case 0x7:\r
204                 break;\r
205           case 0x8:                             /* midi hold/decay */\r
206                 break;\r
207           case 0x9:\r
208                 if (bpmtempos) {\r
209                         if (!dat)\r
210                                 dat = of.initspeed;\r
211                         UniEffect(UNI_S3MEFFECTA, dat);\r
212                 } else {\r
213                         if (dat <= 0x20) {\r
214                                 if (!dat)\r
215                                         dat = of.initspeed;\r
216                                 else\r
217                                         dat /= 4;\r
218                                 UniPTEffect(0xf, dat);\r
219                         } else\r
220                                 UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / (33 * 4));\r
221                 }\r
222                 break;\r
223                 /* 0xa 0xb PT effects */\r
224           case 0xc:\r
225                 if (decimalvolumes)\r
226                         dat = (dat >> 4) * 10 + (dat & 0xf);\r
227                 UniPTEffect(0xc, dat);\r
228                 break;\r
229           case 0xd:                             /* same as PT volslide */\r
230                 UniPTEffect(0xa, dat);\r
231                 break;\r
232           case 0xe:                             /* synth jmp - midi */\r
233                 break;\r
234           case 0xf:\r
235                 switch (dat) {\r
236                   case 0:                               /* patternbreak */\r
237                         UniPTEffect(0xd, 0);\r
238                         break;\r
239                   case 0xf1:                    /* play note twice */\r
240                         UniWriteByte(UNI_MEDEFFECTF1);\r
241                         break;\r
242                   case 0xf2:                    /* delay note */\r
243                         UniWriteByte(UNI_MEDEFFECTF2);\r
244                         break;\r
245                   case 0xf3:                    /* play note three times */\r
246                         UniWriteByte(UNI_MEDEFFECTF3);\r
247                         break;\r
248                   case 0xfe:                    /* stop playing */\r
249                         UniPTEffect(0xb, of.numpat);\r
250                         break;\r
251                   case 0xff:                    /* note cut */\r
252                         UniPTEffect(0xc, 0);\r
253                         break;\r
254                   default:\r
255                         if (dat <= 10)\r
256                                 UniPTEffect(0xf, dat);\r
257                         else if (dat <= 240) {\r
258                                 if (bpmtempos)\r
259                                         UniPTEffect(0xf, (dat < 32) ? 32 : dat);\r
260                                 else\r
261                                         UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33);\r
262                         }\r
263                 }\r
264                 break;\r
265           default:                                      /* all normal PT effects are handled here */\r
266                 UniPTEffect(eff, dat);\r
267                 break;\r
268         }\r
269 }\r
270 \r
271 static UBYTE *MED_Convert1(int count, int col)\r
272 {\r
273         int t;\r
274         UBYTE inst, note, eff, dat;\r
275         MMD1NOTE *n;\r
276 \r
277         UniReset();\r
278         for (t = 0; t < count; t++) {\r
279                 n = &d1note(t, col);\r
280 \r
281                 note = n->a & 0x7f;\r
282                 inst = n->b & 0x3f;\r
283                 eff = n->c & 0xf;\r
284                 dat = n->d;\r
285 \r
286                 if (inst)\r
287                         UniInstrument(inst - 1);\r
288                 if (note)\r
289                         UniNote(note + 3 * OCTAVE - 1);\r
290                 EffectCvt(eff, dat);\r
291                 UniNewline();\r
292         }\r
293         return UniDup();\r
294 }\r
295 \r
296 static UBYTE *MED_Convert0(int count, int col)\r
297 {\r
298         int t;\r
299         UBYTE a, b, inst, note, eff, dat;\r
300         MMD0NOTE *n;\r
301 \r
302         UniReset();\r
303         for (t = 0; t < count; t++) {\r
304                 n = &d0note(t, col);\r
305                 a = n->a;\r
306                 b = n->b;\r
307 \r
308                 note = a & 0x3f;\r
309                 a >>= 6;\r
310                 a = ((a & 1) << 1) | (a >> 1);\r
311                 inst = (b >> 4) | (a << 4);\r
312                 eff = b & 0xf;\r
313                 dat = n->c;\r
314 \r
315                 if (inst)\r
316                         UniInstrument(inst - 1);\r
317                 if (note)\r
318                         UniNote(note + 3 * OCTAVE - 1);\r
319                 EffectCvt(eff, dat);\r
320                 UniNewline();\r
321         }\r
322         return UniDup();\r
323 }\r
324 \r
325 static BOOL LoadMEDPatterns(void)\r
326 {\r
327         int t, row, col;\r
328         UWORD numtracks, numlines, maxlines = 0, track = 0;\r
329         MMD0NOTE *mmdp;\r
330 \r
331         /* first, scan patterns to see how many channels are used */\r
332         for (t = 0; t < of.numpat; t++) {\r
333                 _mm_fseek(modreader, ba[t], SEEK_SET);\r
334                 numtracks = _mm_read_UBYTE(modreader);\r
335                 numlines = _mm_read_UBYTE(modreader);\r
336 \r
337                 if (numtracks > of.numchn)\r
338                         of.numchn = numtracks;\r
339                 if (numlines > maxlines)\r
340                         maxlines = numlines;\r
341         }\r
342 \r
343         of.numtrk = of.numpat * of.numchn;\r
344         if (!AllocTracks())\r
345                 return 0;\r
346         if (!AllocPatterns())\r
347                 return 0;\r
348 \r
349         if (!\r
350                 (mmd0pat =\r
351                  (MMD0NOTE *)_mm_calloc(of.numchn * (maxlines + 1),\r
352                                                                 sizeof(MMD0NOTE)))) return 0;\r
353 \r
354         /* second read: read and convert patterns */\r
355         for (t = 0; t < of.numpat; t++) {\r
356                 _mm_fseek(modreader, ba[t], SEEK_SET);\r
357                 numtracks = _mm_read_UBYTE(modreader);\r
358                 numlines = _mm_read_UBYTE(modreader);\r
359 \r
360                 of.pattrows[t] = ++numlines;\r
361                 memset(mmdp = mmd0pat, 0, of.numchn * maxlines * sizeof(MMD0NOTE));\r
362                 for (row = numlines; row; row--) {\r
363                         for (col = numtracks; col; col--, mmdp++) {\r
364                                 mmdp->a = _mm_read_UBYTE(modreader);\r
365                                 mmdp->b = _mm_read_UBYTE(modreader);\r
366                                 mmdp->c = _mm_read_UBYTE(modreader);\r
367                         }\r
368                 }\r
369 \r
370                 for (col = 0; col < of.numchn; col++)\r
371                         of.tracks[track++] = MED_Convert0(numlines, col);\r
372         }\r
373         return 1;\r
374 }\r
375 \r
376 static BOOL LoadMMD1Patterns(void)\r
377 {\r
378         int t, row, col;\r
379         UWORD numtracks, numlines, maxlines = 0, track = 0;\r
380         MMD1NOTE *mmdp;\r
381 \r
382         /* first, scan patterns to see how many channels are used */\r
383         for (t = 0; t < of.numpat; t++) {\r
384                 _mm_fseek(modreader, ba[t], SEEK_SET);\r
385                 numtracks = _mm_read_M_UWORD(modreader);\r
386                 numlines = _mm_read_M_UWORD(modreader);\r
387                 if (numtracks > of.numchn)\r
388                         of.numchn = numtracks;\r
389                 if (numlines > maxlines)\r
390                         maxlines = numlines;\r
391         }\r
392 \r
393         of.numtrk = of.numpat * of.numchn;\r
394         if (!AllocTracks())\r
395                 return 0;\r
396         if (!AllocPatterns())\r
397                 return 0;\r
398 \r
399         if (!\r
400                 (mmd1pat =\r
401                  (MMD1NOTE *)_mm_calloc(of.numchn * (maxlines + 1),\r
402                                                                 sizeof(MMD1NOTE)))) return 0;\r
403 \r
404         /* second read: really read and convert patterns */\r
405         for (t = 0; t < of.numpat; t++) {\r
406                 _mm_fseek(modreader, ba[t], SEEK_SET);\r
407                 numtracks = _mm_read_M_UWORD(modreader);\r
408                 numlines = _mm_read_M_UWORD(modreader);\r
409 \r
410                 _mm_fseek(modreader, sizeof(ULONG), SEEK_CUR);\r
411                 of.pattrows[t] = ++numlines;\r
412                 memset(mmdp = mmd1pat, 0, of.numchn * maxlines * sizeof(MMD1NOTE));\r
413 \r
414                 for (row = numlines; row; row--) {\r
415                         for (col = numtracks; col; col--, mmdp++) {\r
416                                 mmdp->a = _mm_read_UBYTE(modreader);\r
417                                 mmdp->b = _mm_read_UBYTE(modreader);\r
418                                 mmdp->c = _mm_read_UBYTE(modreader);\r
419                                 mmdp->d = _mm_read_UBYTE(modreader);\r
420                         }\r
421                 }\r
422 \r
423                 for (col = 0; col < of.numchn; col++)\r
424                         of.tracks[track++] = MED_Convert1(numlines, col);\r
425         }\r
426         return 1;\r
427 }\r
428 \r
429 BOOL MED_Load(BOOL curious)\r
430 {\r
431         int t;\r
432         ULONG sa[64];\r
433         MEDINSTHEADER s;\r
434         SAMPLE *q;\r
435         MEDSAMPLE *mss;\r
436 \r
437         /* try to read module header */\r
438         mh->id = _mm_read_M_ULONG(modreader);\r
439         mh->modlen = _mm_read_M_ULONG(modreader);\r
440         mh->MEDSONGP = _mm_read_M_ULONG(modreader);\r
441         mh->psecnum = _mm_read_M_UWORD(modreader);\r
442         mh->pseq = _mm_read_M_UWORD(modreader);\r
443         mh->MEDBlockPP = _mm_read_M_ULONG(modreader);\r
444         mh->reserved1 = _mm_read_M_ULONG(modreader);\r
445         mh->MEDINSTHEADERPP = _mm_read_M_ULONG(modreader);\r
446         mh->reserved2 = _mm_read_M_ULONG(modreader);\r
447         mh->MEDEXPP = _mm_read_M_ULONG(modreader);\r
448         mh->reserved3 = _mm_read_M_ULONG(modreader);\r
449         mh->pstate = _mm_read_M_UWORD(modreader);\r
450         mh->pblock = _mm_read_M_UWORD(modreader);\r
451         mh->pline = _mm_read_M_UWORD(modreader);\r
452         mh->pseqnum = _mm_read_M_UWORD(modreader);\r
453         mh->actplayline = _mm_read_M_SWORD(modreader);\r
454         mh->counter = _mm_read_UBYTE(modreader);\r
455         mh->extra_songs = _mm_read_UBYTE(modreader);\r
456 \r
457         /* Seek to MEDSONG struct */\r
458         _mm_fseek(modreader, mh->MEDSONGP, SEEK_SET);\r
459 \r
460         /* Load the MED Song Header */\r
461         mss = ms->sample;                       /* load the sample data first */\r
462         for (t = 63; t; t--, mss++) {\r
463                 mss->rep = _mm_read_M_UWORD(modreader);\r
464                 mss->replen = _mm_read_M_UWORD(modreader);\r
465                 mss->midich = _mm_read_UBYTE(modreader);\r
466                 mss->midipreset = _mm_read_UBYTE(modreader);\r
467                 mss->svol = _mm_read_UBYTE(modreader);\r
468                 mss->strans = _mm_read_SBYTE(modreader);\r
469         }\r
470 \r
471         ms->numblocks = _mm_read_M_UWORD(modreader);\r
472         ms->songlen = _mm_read_M_UWORD(modreader);\r
473         _mm_read_UBYTES(ms->playseq, 256, modreader);\r
474         ms->deftempo = _mm_read_M_UWORD(modreader);\r
475         ms->playtransp = _mm_read_SBYTE(modreader);\r
476         ms->flags = _mm_read_UBYTE(modreader);\r
477         ms->flags2 = _mm_read_UBYTE(modreader);\r
478         ms->tempo2 = _mm_read_UBYTE(modreader);\r
479         _mm_read_UBYTES(ms->trkvol, 16, modreader);\r
480         ms->mastervol = _mm_read_UBYTE(modreader);\r
481         ms->numsamples = _mm_read_UBYTE(modreader);\r
482 \r
483         /* check for a bad header */\r
484         if (_mm_eof(modreader)) {\r
485                 _mm_errno = MMERR_LOADING_HEADER;\r
486                 return 0;\r
487         }\r
488 \r
489         /* load extension structure */\r
490         if (mh->MEDEXPP) {\r
491                 _mm_fseek(modreader, mh->MEDEXPP, SEEK_SET);\r
492                 me->nextmod = _mm_read_M_ULONG(modreader);\r
493                 me->exp_smp = _mm_read_M_ULONG(modreader);\r
494                 me->s_ext_entries = _mm_read_M_UWORD(modreader);\r
495                 me->s_ext_entrsz = _mm_read_M_UWORD(modreader);\r
496                 me->annotxt = _mm_read_M_ULONG(modreader);\r
497                 me->annolen = _mm_read_M_ULONG(modreader);\r
498                 me->iinfo = _mm_read_M_ULONG(modreader);\r
499                 me->i_ext_entries = _mm_read_M_UWORD(modreader);\r
500                 me->i_ext_entrsz = _mm_read_M_UWORD(modreader);\r
501                 me->jumpmask = _mm_read_M_ULONG(modreader);\r
502                 me->rgbtable = _mm_read_M_ULONG(modreader);\r
503                 me->channelsplit = _mm_read_M_ULONG(modreader);\r
504                 me->n_info = _mm_read_M_ULONG(modreader);\r
505                 me->songname = _mm_read_M_ULONG(modreader);\r
506                 me->songnamelen = _mm_read_M_ULONG(modreader);\r
507                 me->dumps = _mm_read_M_ULONG(modreader);\r
508         }\r
509 \r
510         /* seek to and read the samplepointer array */\r
511         _mm_fseek(modreader, mh->MEDINSTHEADERPP, SEEK_SET);\r
512         if (!_mm_read_M_ULONGS(sa, ms->numsamples, modreader)) {\r
513                 _mm_errno = MMERR_LOADING_HEADER;\r
514                 return 0;\r
515         }\r
516 \r
517         /* alloc and read the blockpointer array */\r
518         if (!(ba = (ULONG *)_mm_calloc(ms->numblocks, sizeof(ULONG))))\r
519                 return 0;\r
520         _mm_fseek(modreader, mh->MEDBlockPP, SEEK_SET);\r
521         if (!_mm_read_M_ULONGS(ba, ms->numblocks, modreader)) {\r
522                 _mm_errno = MMERR_LOADING_HEADER;\r
523                 return 0;\r
524         }\r
525 \r
526         /* copy song positions */\r
527         if (!AllocPositions(ms->songlen))\r
528                 return 0;\r
529         for (t = 0; t < ms->songlen; t++)\r
530                 of.positions[t] = ms->playseq[t];\r
531 \r
532         decimalvolumes = (ms->flags & 0x10) ? 0 : 1;\r
533         bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;\r
534 \r
535         if (bpmtempos) {\r
536                 int bpmlen = (ms->flags2 & 0x1f) + 1;\r
537                 of.initspeed = ms->tempo2;\r
538                 of.inittempo = ms->deftempo * bpmlen / 4;\r
539 \r
540                 if (bpmlen != 4) {\r
541                         /* Let's do some math : compute GCD of BPM beat length and speed */\r
542                         int a, b;\r
543 \r
544                         a = bpmlen;\r
545                         b = ms->tempo2;\r
546 \r
547                         if (a > b) {\r
548                                 t = b;\r
549                                 b = a;\r
550                                 a = t;\r
551                         }\r
552                         while ((a != b) && (a)) {\r
553                                 t = a;\r
554                                 a = b - a;\r
555                                 b = t;\r
556                                 if (a > b) {\r
557                                         t = b;\r
558                                         b = a;\r
559                                         a = t;\r
560                                 }\r
561                         }\r
562 \r
563                         of.initspeed /= b;\r
564                         of.inittempo = ms->deftempo * bpmlen / (4 * b);\r
565                 }\r
566         } else {\r
567                 of.initspeed = ms->tempo2;\r
568                 of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128;\r
569                 if ((ms->deftempo <= 10) && (ms->deftempo))\r
570                         of.inittempo = (of.inittempo * 33) / 6;\r
571                 of.flags |= UF_HIGHBPM;\r
572         }\r
573         MED_Version[12] = mh->id;\r
574         of.modtype = strdup(MED_Version);\r
575         of.numchn = 0;                          /* will be counted later */\r
576         of.numpat = ms->numblocks;\r
577         of.numpos = ms->songlen;\r
578         of.numins = ms->numsamples;\r
579         of.numsmp = of.numins;\r
580         of.reppos = 0;\r
581         if ((mh->MEDEXPP) && (me->songname) && (me->songnamelen)) {\r
582                 char *name;\r
583 \r
584                 _mm_fseek(modreader, me->songname, SEEK_SET);\r
585                 name = _mm_malloc(me->songnamelen);\r
586                 _mm_read_UBYTES(name, me->songnamelen, modreader);\r
587                 of.songname = DupStr(name, me->songnamelen, 1);\r
588                 free(name);\r
589         } else\r
590                 of.songname = DupStr(NULL, 0, 0);\r
591         if ((mh->MEDEXPP) && (me->annotxt) && (me->annolen)) {\r
592                 _mm_fseek(modreader, me->annotxt, SEEK_SET);\r
593                 ReadComment(me->annolen);\r
594         }\r
595 \r
596         if (!AllocSamples())\r
597                 return 0;\r
598         q = of.samples;\r
599         for (t = 0; t < of.numins; t++) {\r
600                 q->flags = SF_SIGNED;\r
601                 q->volume = 64;\r
602                 if (sa[t]) {\r
603                         _mm_fseek(modreader, sa[t], SEEK_SET);\r
604                         s.length = _mm_read_M_ULONG(modreader);\r
605                         s.type = _mm_read_M_SWORD(modreader);\r
606 \r
607                         if (s.type) {\r
608 #ifdef MIKMOD_DEBUG\r
609                                 fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");\r
610 #endif\r
611                                 if (!curious) {\r
612                                         _mm_errno = MMERR_MED_SYNTHSAMPLES;\r
613                                         return 0;\r
614                                 }\r
615                                 s.length = 0;\r
616                         }\r
617 \r
618                         if (_mm_eof(modreader)) {\r
619                                 _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
620                                 return 0;\r
621                         }\r
622 \r
623                         q->length = s.length;\r
624                         q->seekpos = _mm_ftell(modreader);\r
625                         q->loopstart = ms->sample[t].rep << 1;\r
626                         q->loopend = q->loopstart + (ms->sample[t].replen << 1);\r
627 \r
628                         if (ms->sample[t].replen > 1)\r
629                                 q->flags |= SF_LOOP;\r
630 \r
631                         /* don't load sample if length>='MMD0'...\r
632                            such kluges make libmikmod's code unique !!! */\r
633                         if (q->length >= MMD0_string)\r
634                                 q->length = 0;\r
635                 } else\r
636                         q->length = 0;\r
637 \r
638                 if ((mh->MEDEXPP) && (me->exp_smp) &&\r
639                         (t < me->s_ext_entries) && (me->s_ext_entrsz >= 4)) {\r
640                         MEDINSTEXT ie;\r
641 \r
642                         _mm_fseek(modreader, me->exp_smp + t * me->s_ext_entrsz,\r
643                                           SEEK_SET);\r
644                         ie.hold = _mm_read_UBYTE(modreader);\r
645                         ie.decay = _mm_read_UBYTE(modreader);\r
646                         ie.suppress_midi_off = _mm_read_UBYTE(modreader);\r
647                         ie.finetune = _mm_read_SBYTE(modreader);\r
648 \r
649                         q->speed = finetune[ie.finetune & 0xf];\r
650                 } else\r
651                         q->speed = 8363;\r
652 \r
653                 if ((mh->MEDEXPP) && (me->iinfo) &&\r
654                         (t < me->i_ext_entries) && (me->i_ext_entrsz >= 40)) {\r
655                         MEDINSTINFO ii;\r
656 \r
657                         _mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET);\r
658                         _mm_read_UBYTES(ii.name, 40, modreader);\r
659                         q->samplename = DupStr((char*)ii.name, 40, 1);\r
660                 } else\r
661                         q->samplename = NULL;\r
662 \r
663                 q++;\r
664         }\r
665 \r
666         if (mh->id == MMD0_string) {\r
667                 if (!LoadMEDPatterns()) {\r
668                         _mm_errno = MMERR_LOADING_PATTERN;\r
669                         return 0;\r
670                 }\r
671         } else if (mh->id == MMD1_string) {\r
672                 if (!LoadMMD1Patterns()) {\r
673                         _mm_errno = MMERR_LOADING_PATTERN;\r
674                         return 0;\r
675                 }\r
676         } else {\r
677                 _mm_errno = MMERR_NOT_A_MODULE;\r
678                 return 0;\r
679         }\r
680         return 1;\r
681 }\r
682 \r
683 CHAR *MED_LoadTitle(void)\r
684 {\r
685         ULONG posit, namelen;\r
686         CHAR *name, *retvalue = NULL;\r
687         \r
688         _mm_fseek(modreader, 0x20, SEEK_SET);\r
689         posit = _mm_read_M_ULONG(modreader);\r
690         \r
691         if (posit) {\r
692                 _mm_fseek(modreader, posit + 0x2C, SEEK_SET);\r
693                 posit = _mm_read_M_ULONG(modreader);\r
694                 namelen = _mm_read_M_ULONG(modreader);\r
695 \r
696                 _mm_fseek(modreader, posit, SEEK_SET);\r
697                 name = _mm_malloc(namelen);\r
698                 _mm_read_UBYTES(name, namelen, modreader);\r
699                 retvalue = DupStr(name, namelen, 1);\r
700                 free(name);\r
701         }\r
702 \r
703         return retvalue;\r
704 }\r
705 \r
706 /*========== Loader information */\r
707 \r
708 MIKMODAPI MLOADER load_med = {\r
709         NULL,\r
710         "MED",\r
711         "MED (OctaMED)",\r
712         MED_Init,\r
713         MED_Test,\r
714         MED_Load,\r
715         MED_Cleanup,\r
716         MED_LoadTitle\r
717 };\r
718 \r
719 /* ex:set ts=4: */\r