1 /* Extended Module Player
2 * Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 /*
24 * Originally based on the PSM loader from Modplug by Olivier Lapicque and
25 * fixed comparing the One Must Fall! PSMs with Kenny Chou's MTM files.
26 */
27
28 /*
29 * From EPICTEST Readme.1st:
30 *
31 * The Music And Sound Interface, MASI, is the basis behind all new Epic
32 * games. MASI uses its own proprietary file format, PSM, for storing
33 * its music.
34 */
35
36 /*
37 * kode54's comment on Sinaria PSMs in the foo_dumb hydrogenaudio forum:
38 *
39 * "The Sinaria variant uses eight character pattern and instrument IDs,
40 * the sample headers are laid out slightly different, and the patterns
41 * use a different format for the note values, and also different effect
42 * scales for certain commands.
43 *
44 * [Epic] PSM uses high nibble for octave and low nibble for note, for
45 * a valid range up to 0x7F, for a range of D-1 through D#9 compared to
46 * IT. (...) Sinaria PSM uses plain note values, from 1 - 83, for a
47 * range of C-3 through B-9.
48 *
49 * [Epic] PSM also uses an effect scale for portamento, volume slides,
50 * and vibrato that is about four times as sensitive as the IT equivalents.
51 * Sinaria does not. This seems to coincide with the MOD/S3M to PSM
52 * converter that Joshua Jensen released in the EPICTEST.ZIP file which
53 * can still be found on a few FTP sites. It converted effects literally,
54 * even though the bundled players behaved as the libraries used with
55 * Epic's games did and made the effects sound too strong."
56 */
57
58 /*
59 * Claudio's note: Sinaria seems to have a finetune byte just before
60 * volume and some kind of (stereo?) interleaved sample, with 16-byte
61 * frames (see Sinaria songs 5 and 8). Sinaria song 10 still sounds
62 * ugly, maybe caused by finetune issues?
63 */
64
65 #include <limits.h>
66 #include "loader.h"
67 #include "iff.h"
68 #include "period.h"
69
70 #define MAGIC_PSM_ MAGIC4('P','S','M',' ')
71 #define MAGIC_FILE MAGIC4('F','I','L','E')
72 #define MAGIC_TITL MAGIC4('T','I','T','L')
73 #define MAGIC_OPLH MAGIC4('O','P','L','H')
74 #define MAGIC_PPAN MAGIC4('P','P','A','N')
75
76
77 static int masi_test (HIO_HANDLE *, char *, const int);
78 static int masi_load (struct module_data *, HIO_HANDLE *, const int);
79
80 const struct format_loader libxmp_loader_masi = {
81 "Epic MegaGames MASI",
82 masi_test,
83 masi_load
84 };
85
masi_test(HIO_HANDLE * f,char * t,const int start)86 static int masi_test(HIO_HANDLE *f, char *t, const int start)
87 {
88 int val;
89
90 if (hio_read32b(f) != MAGIC_PSM_)
91 return -1;
92
93 hio_read8(f);
94 hio_read8(f);
95 hio_read8(f);
96 if (hio_read8(f) != 0)
97 return -1;
98
99 if (hio_read32b(f) != MAGIC_FILE)
100 return -1;
101
102 hio_read32b(f);
103 val = hio_read32l(f);
104 hio_seek(f, val, SEEK_CUR);
105
106 if (hio_read32b(f) == MAGIC_TITL) {
107 val = hio_read32l(f);
108 libxmp_read_title(f, t, val);
109 } else {
110 libxmp_read_title(f, t, 0);
111 }
112
113 return 0;
114 }
115
116 struct local_data {
117 int sinaria;
118 int cur_pat;
119 int cur_ins;
120 uint8 *pnam;
121 uint8 *pord;
122 };
123
get_sdft(struct module_data * m,int size,HIO_HANDLE * f,void * parm)124 static int get_sdft(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
125 {
126 return 0;
127 }
128
get_titl(struct module_data * m,int size,HIO_HANDLE * f,void * parm)129 static int get_titl(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
130 {
131 struct xmp_module *mod = &m->mod;
132 char buf[40];
133
134 hio_read(buf, 1, 40, f);
135 size = size > 32 ? 32 : size;
136 strncpy(mod->name, buf, size);
137 mod->name[size] = '\0';
138
139 return 0;
140 }
141
get_dsmp_cnt(struct module_data * m,int size,HIO_HANDLE * f,void * parm)142 static int get_dsmp_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
143 {
144 struct xmp_module *mod = &m->mod;
145
146 mod->ins++;
147 mod->smp = mod->ins;
148
149 return 0;
150 }
151
get_pbod_cnt(struct module_data * m,int size,HIO_HANDLE * f,void * parm)152 static int get_pbod_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
153 {
154 struct xmp_module *mod = &m->mod;
155 struct local_data *data = (struct local_data *)parm;
156 char buf[20];
157
158 mod->pat++;
159 if (hio_read(buf, 1, 20, f) < 20) {
160 D_(D_CRIT "read error at pat %d", mod->pat - 1);
161 return -1;
162 }
163 if (buf[9] != 0 && buf[13] == 0)
164 data->sinaria = 1;
165
166 return 0;
167 }
168
169
get_dsmp(struct module_data * m,int size,HIO_HANDLE * f,void * parm)170 static int get_dsmp(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
171 {
172 struct xmp_module *mod = &m->mod;
173 struct xmp_instrument *xxi;
174 struct xmp_subinstrument *sub;
175 struct xmp_sample *xxs;
176 struct local_data *data = (struct local_data *)parm;
177 int i, srate, flags;
178 int finetune;
179
180 flags = hio_read8(f); /* flags */
181 hio_seek(f, 8, SEEK_CUR); /* songname */
182 hio_seek(f, data->sinaria ? 8 : 4, SEEK_CUR); /* smpid */
183
184 i = data->cur_ins;
185 if (libxmp_alloc_subinstrument(mod, i, 1) < 0)
186 return -1;
187
188 xxi = &mod->xxi[i];
189 sub = &xxi->sub[0];
190 xxs = &mod->xxs[i];
191
192 hio_read(xxi->name, 1, 31, f);
193 hio_seek(f, 8, SEEK_CUR);
194 hio_read8(f); /* insno */
195 hio_read8(f);
196 xxs->len = hio_read32l(f);
197 xxs->lps = hio_read32l(f);
198 xxs->lpe = hio_read32l(f);
199 xxs->flg = flags & 0x80 ? XMP_SAMPLE_LOOP : 0;
200 hio_read16l(f);
201
202 if ((int32)xxs->lpe < 0)
203 xxs->lpe = 0;
204
205 if (xxs->len > 0)
206 xxi->nsm = 1;
207
208 finetune = 0;
209 if (data->sinaria) {
210 finetune = (int8)(hio_read8s(f) << 4);
211 }
212
213 sub->vol = hio_read8(f) / 2 + 1;
214 hio_read32l(f);
215 sub->pan = 0x80;
216 sub->sid = i;
217 srate = hio_read16l(f);
218
219 D_(D_INFO "[%2X] %-32.32s %05x %05x %05x %c V%02x %+04d %5d", i,
220 xxi->name, xxs->len, xxs->lps, xxs->lpe,
221 xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
222 sub->vol, finetune, srate);
223
224 libxmp_c2spd_to_note(srate, &sub->xpo, &sub->fin);
225 sub->fin += finetune;
226
227 hio_seek(f, 16, SEEK_CUR);
228 if (libxmp_load_sample(m, f, SAMPLE_FLAG_8BDIFF, xxs, NULL) < 0)
229 return -1;
230
231 data->cur_ins++;
232
233 return 0;
234 }
235
236
convert_porta(uint8 param,int sinaria)237 static uint8 convert_porta(uint8 param, int sinaria)
238 {
239 if (sinaria) {
240 return param;
241 }
242
243 if (param < 4) {
244 return param | 0xf0;
245 } else {
246 return param >> 2;
247 }
248 }
249
get_pbod(struct module_data * m,int size,HIO_HANDLE * f,void * parm)250 static int get_pbod(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
251 {
252 struct xmp_module *mod = &m->mod;
253 struct local_data *data = (struct local_data *)parm;
254 int i, r;
255 struct xmp_event *event, dummy;
256 uint8 flag, chan;
257 /* uint32 len; */
258 int rows, rowlen;
259
260 i = data->cur_pat;
261
262 /*len =*/ hio_read32l(f);
263 hio_read(data->pnam + i * 8, 1, data->sinaria ? 8 : 4, f);
264
265 rows = hio_read16l(f);
266 if (hio_error(f)) {
267 return -1;
268 }
269
270 if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0)
271 return -1;
272
273 r = 0;
274
275 do {
276 rowlen = hio_read16l(f) - 2;
277 if (hio_error(f)) {
278 return -1;
279 }
280 while (rowlen > 0) {
281 flag = hio_read8(f);
282
283 if (rowlen == 1)
284 break;
285
286 chan = hio_read8(f);
287 rowlen -= 2;
288
289 event = chan < mod->chn ? &EVENT(i, chan, r) : &dummy;
290
291 if (flag & 0x80) {
292 uint8 note = hio_read8(f);
293 rowlen--;
294 if (data->sinaria)
295 note += 36;
296 else
297 note = (note >> 4) * 12 + (note & 0x0f) + 1 + 12;
298 event->note = note;
299 }
300
301 if (flag & 0x40) {
302 event->ins = hio_read8(f) + 1;
303 rowlen--;
304 }
305
306 if (flag & 0x20) {
307 event->vol = hio_read8(f) / 2 + 1;
308 rowlen--;
309 }
310
311 if (flag & 0x10) {
312 uint8 fxt = hio_read8(f);
313 uint8 fxp = hio_read8(f);
314 rowlen -= 2;
315
316 #if 0
317 /* compressed events */
318 if (fxt >= 0x40) {
319 switch (fxp >> 4) {
320 case 0x0: {
321 uint8 note;
322 note = (fxt>>4)*12 +
323 (fxt & 0x0f) + 1;
324 event->note = note;
325 fxt = FX_TONEPORTA;
326 fxp = (fxp + 1) * 2;
327 break; }
328 default:
329 D_(D_CRIT "p%d r%d c%d: compressed event %02x %02x\n", i, r, chan, fxt, fxp);
330 return -1;
331 }
332 } else
333 #endif
334
335 switch (fxt) {
336
337 /* Volume slide */
338 case 0x01: /* fine volslide up */
339 fxt = FX_EXTENDED;
340 fxp = (EX_F_VSLIDE_UP << 4) |
341 ((fxp / 2) & 0x0f);
342 break;
343 case 0x02: /* volslide up */
344 fxt = FX_VOLSLIDE;
345 fxp = (fxp / 2) << 4;
346 break;
347 case 0x03: /* fine volslide down */
348 fxt = FX_EXTENDED;
349 fxp = (EX_F_VSLIDE_DN << 4) |
350 ((fxp / 2) & 0x0f);
351 break;
352 case 0x04: /* volslide down */
353 fxt = FX_VOLSLIDE;
354 fxp /= 2;
355 break;
356
357 /* Portamento */
358 case 0x0b: /* fine portamento up */
359 fxt = FX_PORTA_UP;
360 fxp = (EX_F_PORTA_UP << 4) |
361 convert_porta(fxp, data->sinaria);
362 break;
363 case 0x0c: /* portamento up */
364 fxt = FX_PORTA_UP;
365 fxp = convert_porta(fxp, data->sinaria);
366 break;
367 case 0x0d: /* fine portamento up */
368 fxt = FX_PORTA_DN;
369 fxp = (EX_F_PORTA_DN << 4) |
370 convert_porta(fxp, data->sinaria);
371 break;
372 case 0x0e: /* portamento down */
373 fxt = FX_PORTA_DN;
374 fxp = convert_porta(fxp, data->sinaria);
375 break;
376 case 0x0f: /* tone portamento */
377 fxt = FX_TONEPORTA;
378 fxp >>= 2;
379 break;
380 case 0x10: /* toneporta + vslide up */
381 fxt = FX_TONE_VSLIDE;
382 fxp = fxt & 0xf0;
383 break;
384 case 0x11: /* glissando */
385 fxt = FX_EXTENDED;
386 fxp = (EX_GLISS << 4) | (fxp & 0x0f);
387 break;
388 case 0x12: /* toneporta + vslide down */
389 fxt = FX_TONE_VSLIDE;
390 fxp >>= 4;
391 break;
392
393 /* 0x13: S3M S: crashes MASI */
394
395 /* Vibrato */
396 case 0x15: /* vibrato */
397 fxt = data->sinaria ?
398 FX_VIBRATO : FX_FINE_VIBRATO;
399 /* fxp remains the same */
400 break;
401 case 0x16: /* vibrato waveform */
402 fxt = FX_EXTENDED;
403 fxp = (EX_VIBRATO_WF << 4) | (fxp & 0x0f);
404 break;
405 case 0x17: /* vibrato + vslide up */
406 fxt = FX_VIBRA_VSLIDE;
407 fxp >>= 4;
408 break;
409 case 0x18: /* vibrato + vslide down */
410 fxt = FX_VIBRA_VSLIDE;
411 fxp = fxp & 0x0f;
412 break;
413
414 /* Tremolo */
415 case 0x1f: /* tremolo */
416 fxt = FX_TREMOLO;
417 /* fxp remains the same */
418 break;
419 case 0x20: /* tremolo waveform */
420 fxt = FX_EXTENDED;
421 fxp = (EX_TREMOLO_WF << 4) | (fxp & 0x0f);
422 break;
423
424 /* Sample commands */
425 case 0x29: /* 3-byte offset */
426 fxt = FX_OFFSET;
427 /* use only the middle byte */
428 fxp = hio_read8(f);
429 hio_read8(f);
430 rowlen -= 2;
431 break;
432 case 0x2a: /* retrig note */
433 fxt = FX_EXTENDED;
434 fxp = (EX_RETRIG << 4) | (fxp & 0x0f);
435 break;
436 case 0x2b: /* note cut */
437 fxt = FX_EXTENDED;
438 fxp = (EX_CUT << 4) | (fxp & 0x0f);
439 break;
440 case 0x2c: /* note delay */
441 fxt = FX_EXTENDED;
442 fxp = (EX_DELAY << 4) | (fxp & 0x0f);
443 break;
444
445 /* Position change */
446 case 0x33: /* position jump */
447 /* not used in MASI */
448 fxt = FX_JUMP;
449 fxp >>= 1;
450 hio_read8(f);
451 rowlen--;
452 break;
453 case 0x34: /* pattern break */
454 /* not used in MASI */
455 fxt = FX_BREAK;
456 break;
457 case 0x35: /* pattern loop */
458 fxt = FX_EXTENDED;
459 fxp = (EX_PATTERN_LOOP << 4) | (fxp & 0x0f);
460 break;
461 case 0x36: /* pattern delay */
462 fxt = FX_EXTENDED;
463 fxp = (EX_PATT_DELAY << 4) | (fxp & 0x0f);
464 break;
465
466 /* Speed change */
467 case 0x3d: /* speed */
468 fxt = FX_SPEED;
469 break;
470 case 0x3e: /* tempo */
471 fxt = FX_SPEED;
472 break;
473
474 /* Other */
475 case 0x47: /* arpeggio */
476 fxt = FX_S3M_ARPEGGIO;
477 break;
478 case 0x48: /* set finetune */
479 fxt = FX_EXTENDED;
480 fxp = (EX_FINETUNE << 4) | (fxp & 0x0f);
481 break;
482 case 0x49: /* set pan */
483 fxt = FX_SETPAN;
484 fxp <<= 4;
485 break;
486
487 default:
488 D_(D_CRIT "p%d r%d c%d: unknown effect %02x %02x\n", i, r, chan, fxt, fxp);
489 fxt = fxp = 0;
490 }
491
492 event->fxt = fxt;
493 event->fxp = fxp;
494 }
495 }
496 r++;
497 } while (r < rows);
498
499 data->cur_pat++;
500
501 return 0;
502 }
503
get_song(struct module_data * m,int size,HIO_HANDLE * f,void * parm)504 static int get_song(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
505 {
506 struct xmp_module *mod = &m->mod;
507
508 hio_seek(f, 10, SEEK_CUR);
509 mod->chn = hio_read8(f);
510
511 return 0;
512 }
513
subchunk_oplh(struct module_data * m,int size,HIO_HANDLE * f,void * parm)514 static int subchunk_oplh(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
515 {
516 struct xmp_module *mod = &m->mod;
517 struct local_data *data = (struct local_data *)parm;
518 int first_order_chunk = INT_MAX;
519 int num_chunk, i;
520
521 /* First two bytes = Number of chunks that follow */
522 num_chunk = hio_read16l(f);
523
524 /* Sub sub chunks */
525 for (i = 0; i < num_chunk && size > 0; i++) {
526 int opcode = hio_read8(f);
527
528 size--;
529
530 if (opcode == 0) { /* last sub sub chunk */
531 break;
532 }
533
534 /* Saga Musix's note in OpenMPT:
535 *
536 * "This is more like a playlist than a collection of global
537 * values. In theory, a tempo item inbetween two order items
538 * should modify the tempo when switching patterns. No module
539 * uses this feature in practice though, so we can keep our
540 * loader simple. Unimplemented opcodes do nothing or freeze
541 * MASI."
542 */
543 switch (opcode) {
544 case 0x01: /* Play order list item */
545 if (mod->len >= XMP_MAX_MOD_LENGTH) {
546 return -1;
547 }
548 hio_read(data->pord + mod->len * 8, 1, data->sinaria ? 8 : 4, f);
549 size -= data->sinaria ? 8 : 4;
550 mod->len++;
551 if (first_order_chunk == INT_MAX) {
552 first_order_chunk = i;
553 }
554 break;
555
556 /* 0x02: Play range */
557 /* 0x03: Jump loop */
558
559 case 0x04: { /* Jump line (restart position) */
560 int restart_chunk = hio_read16l(f);
561 size -= 2;
562
563 /* This jumps to the command line, but since we're converting
564 * play order list items to our order list, only change the
565 * restart position if it's after the first order chunk.
566 */
567
568 if (restart_chunk >= first_order_chunk) {
569 mod->rst = restart_chunk - first_order_chunk;
570 }
571
572 break; }
573
574 /* 0x05: Channel flip */
575 /* 0x06: Transpose */
576
577 case 0x07: /* Default speed */
578 mod->spd = hio_read8(f);
579 size--;
580 break;
581 case 0x08: /* Default tempo */
582 mod->bpm = hio_read8(f);
583 size--;
584 break;
585 case 0x0c: /* Sample map table */
586 hio_read16l(f);
587 hio_read16l(f);
588 hio_read16l(f);
589 size -= 6;
590 break;
591 case 0x0d: { /* Channel panning table */
592 int chn = hio_read8(f);
593 int pan = hio_read8(f);
594 int type = hio_read8(f);
595 struct xmp_channel *xxc;
596
597 if (chn >= XMP_MAX_CHANNELS) {
598 break;
599 }
600
601 xxc = &mod->xxc[chn];
602
603 size -= 3;
604
605 switch (type) {
606 case 0: /* use panning */
607 xxc->pan = pan ^ 0x80;
608 break;
609 case 2: /* surround */
610 xxc->pan = 0x80;
611 xxc->flg |= XMP_CHANNEL_SURROUND;
612 break;
613 case 4: /* center */
614 xxc->pan = 0x80;
615 break;
616 }
617 break; }
618 case 0x0e: { /* Channel volume table */
619 int chn = hio_read8(f);
620 int vol = hio_read8(f);
621 struct xmp_channel *xxc;
622
623 if (chn >= XMP_MAX_CHANNELS) {
624 break;
625 }
626
627 xxc = &mod->xxc[chn];
628
629 size -= 2;
630
631 xxc->vol = (vol >> 2) + 1;
632 break; }
633 default:
634 /*printf("channel %d: %02x %02x\n", i, c, hio_read8(f));*/
635 return -1;
636 }
637 }
638
639 return 0;
640 }
641
642 /* Sinaria channel panning table */
subchunk_ppan(struct module_data * m,int size,HIO_HANDLE * f,void * parm)643 static int subchunk_ppan(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
644 {
645 struct xmp_module *mod = &m->mod;
646 int i;
647
648 for (i = 0; i < XMP_MAX_CHANNELS && size > 0; i++) {
649 struct xmp_channel *xxc = &mod->xxc[i];
650 int type = hio_read8(f);
651 int pan = hio_read8(f);
652
653 size -= 2;
654
655 switch (type) {
656 case 0: /* use panning */
657 xxc->pan = pan ^ 0x80;
658 break;
659 case 2: /* surround */
660 xxc->pan = 0x80;
661 xxc->flg |= XMP_CHANNEL_SURROUND;
662 break;
663 case 4: /* center */
664 xxc->pan = 0x80;
665 break;
666 }
667 }
668
669 return 0;
670 }
671
672 /* Subchunk loader based on OpenMPT LoadPSM.cpp */
get_song_2(struct module_data * m,int size,HIO_HANDLE * f,void * parm)673 static int get_song_2(struct module_data *m, int size, HIO_HANDLE *f, void *parm)
674 {
675 uint32 magic;
676 char buf[20];
677
678 hio_read(buf, 1, 9, f);
679 hio_read16l(f);
680 size -= 11;
681
682 D_(D_INFO "Subsong title: %-9.9s", buf);
683
684 /* Iterate over subchunks. We want OPLH and PPAN */
685 while (size > 0) {
686 int subchunk_size;
687
688 magic = hio_read32b(f);
689 subchunk_size = hio_read32l(f);
690 if (subchunk_size <= 0 || hio_error(f)) {
691 return -1;
692 }
693
694 size -= subchunk_size;
695
696 switch (magic) {
697 case MAGIC_OPLH:
698 if (subchunk_oplh(m, size, f, parm) < 0) {
699 return -1;
700 }
701 break;
702
703 case MAGIC_PPAN:
704 if (subchunk_ppan(m, size, f, parm) < 0) {
705 return -1;
706 }
707 break;
708
709 default:
710 hio_seek(f, subchunk_size, SEEK_CUR);
711 }
712 }
713
714 return 0;
715 }
716
masi_load(struct module_data * m,HIO_HANDLE * f,const int start)717 static int masi_load(struct module_data *m, HIO_HANDLE *f, const int start)
718 {
719 struct xmp_module *mod = &m->mod;
720 iff_handle handle;
721 int ret, offset;
722 int i, j;
723 struct local_data data;
724
725 LOAD_INIT();
726
727 hio_read32b(f);
728
729 data.sinaria = 0;
730 mod->name[0] = 0;
731
732 hio_seek(f, 8, SEEK_CUR); /* skip file size and FILE */
733 mod->smp = mod->ins = 0;
734 data.cur_pat = 0;
735 data.cur_ins = 0;
736 offset = hio_tell(f);
737
738 handle = libxmp_iff_new();
739 if (handle == NULL)
740 goto err;
741
742 /* IFF chunk IDs */
743 ret = libxmp_iff_register(handle, "TITL", get_titl);
744 ret |= libxmp_iff_register(handle, "SDFT", get_sdft);
745 ret |= libxmp_iff_register(handle, "SONG", get_song);
746 ret |= libxmp_iff_register(handle, "DSMP", get_dsmp_cnt);
747 ret |= libxmp_iff_register(handle, "PBOD", get_pbod_cnt);
748
749 if (ret != 0)
750 goto err;
751
752 libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN);
753
754 /* Load IFF chunks */
755 if (libxmp_iff_load(handle, m, f, &data) < 0) {
756 libxmp_iff_release(handle);
757 goto err;
758 }
759
760 libxmp_iff_release(handle);
761
762 mod->trk = mod->pat * mod->chn;
763 data.pnam = malloc(mod->pat * 8); /* pattern names */
764 if (data.pnam == NULL)
765 goto err;
766
767 data.pord = malloc(XMP_MAX_MOD_LENGTH * 8); /* pattern orders */
768 if (data.pord == NULL)
769 goto err2;
770
771 libxmp_set_type(m, data.sinaria ?
772 "Sinaria PSM" : "Epic MegaGames MASI PSM");
773
774 m->c4rate = C4_NTSC_RATE;
775
776 MODULE_INFO();
777
778 if (libxmp_init_instrument(m) < 0)
779 goto err3;
780
781 if (libxmp_init_pattern(mod) < 0)
782 goto err3;
783
784 D_(D_INFO "Stored patterns: %d", mod->pat);
785 D_(D_INFO "Stored samples : %d", mod->smp);
786
787 hio_seek(f, start + offset, SEEK_SET);
788
789 mod->len = 0;
790
791 handle = libxmp_iff_new();
792 if (handle == NULL)
793 goto err3;
794
795 /* IFF chunk IDs */
796 ret = libxmp_iff_register(handle, "SONG", get_song_2);
797 ret |= libxmp_iff_register(handle, "DSMP", get_dsmp);
798 ret |= libxmp_iff_register(handle, "PBOD", get_pbod);
799
800 if (ret != 0)
801 goto err3;
802
803 libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN);
804
805 /* Load IFF chunks */
806 if (libxmp_iff_load(handle, m, f, &data) < 0) {
807 libxmp_iff_release(handle);
808 goto err3;
809 }
810
811 libxmp_iff_release(handle);
812
813 for (i = 0; i < mod->len; i++) {
814 for (j = 0; j < mod->pat; j++) {
815 if (!memcmp(data.pord + i * 8, data.pnam + j * 8, data.sinaria ? 8 : 4)) {
816 mod->xxo[i] = j;
817 break;
818 }
819 }
820
821 if (j == mod->pat)
822 break;
823 }
824
825 free(data.pord);
826 free(data.pnam);
827
828 return 0;
829
830 err3:
831 free(data.pord);
832 err2:
833 free(data.pnam);
834 err:
835 return -1;
836 }
837