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