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