1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for complete list.
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.
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.
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
21 /*==============================================================================
23 $Id: load_uni.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
25 UNIMOD (libmikmod's and APlayer's internal module format) loader
27 ==============================================================================*/
43 #include "mikmod_internals.h"
46 extern int fprintf(FILE *, const char *, ...);
49 /*========== Module structure */
51 typedef struct UNIHEADER
{
71 typedef struct UNISMP05
{
87 /*========== Loader variables */
89 static UWORD universion
;
92 #define UNI_SMPINCR 64
93 static UNISMP05
*wh
=NULL
,*s
=NULL
;
95 /*========== Loader code */
97 static char* readstring(void)
102 len
=_mm_read_I_UWORD(modreader
);
104 s
=MikMod_malloc(len
+1);
105 _mm_read_UBYTES(s
,len
,modreader
);
115 if(!_mm_read_UBYTES(id
,6,modreader
)) return 0;
117 /* UNIMod created by MikCvt */
118 if(!(memcmp(id
,"UN0",3))) {
119 if((id
[3]>='4')&&(id
[3]<='6')) return 1;
121 /* UNIMod created by APlayer */
122 if(!(memcmp(id
,"APUN\01",5))) {
123 if((id
[5]>=1)&&(id
[5]<=6)) return 1;
133 void UNI_Cleanup(void)
139 static UBYTE
* readtrack(void)
146 len
=_mm_read_M_UWORD(modreader
);
148 len
=_mm_read_I_UWORD(modreader
);
150 if(!len
) return NULL
;
151 if(!(t
=MikMod_malloc(len
))) return NULL
;
152 _mm_read_UBYTES(t
,len
,modreader
);
154 /* Check if the track is correct */
158 chunk
=(chunk
&0x1f)-1;
169 if (universion
<= 5) {
175 /* UNI_NOTE .. UNI_S3MEFFECTQ are the same */
177 opcode
= UNI_S3MEFFECTT
;
180 opcode
= UNI_XMEFFECTA
;
183 opcode
= UNI_XMEFFECTG
;
186 opcode
= UNI_XMEFFECTH
;
189 opcode
= UNI_XMEFFECTP
;
193 /* APlayer < 1.05 does not have XMEFFECT6 */
194 if (opcode
>= UNI_XMEFFECT6
&& universion
< 0x105)
196 /* APlayer < 1.03 does not have ITEFFECTT */
197 if (opcode
>= UNI_ITEFFECTT
&& universion
< 0x103)
199 /* APlayer < 1.02 does not have ITEFFECTZ */
200 if (opcode
>= UNI_ITEFFECTZ
&& universion
< 0x102)
204 if((!opcode
)||(opcode
>=UNI_LAST
)) {
209 oplen
=unioperands
[opcode
]+1;
213 if((chunk
<0)||(cur
>=len
)) {
221 static int loadsmp6(void)
227 for(t
=0;t
<of
.numsmp
;t
++,s
++) {
230 flags
= _mm_read_M_UWORD(modreader
);
232 if(flags
&0x0004) s
->flags
|=SF_STEREO
;
233 if(flags
&0x0002) s
->flags
|=SF_SIGNED
;
234 if(flags
&0x0001) s
->flags
|=SF_16BITS
;
236 if(universion
>=0x104) {
237 if(flags
&0x2000) s
->flags
|=SF_UST_LOOP
;
238 if(flags
&0x1000) s
->flags
|=SF_OWNPAN
;
239 if(flags
&0x0800) s
->flags
|=SF_SUSTAIN
;
240 if(flags
&0x0400) s
->flags
|=SF_REVERSE
;
241 if(flags
&0x0200) s
->flags
|=SF_BIDI
;
242 if(flags
&0x0100) s
->flags
|=SF_LOOP
;
243 if(flags
&0x0020) s
->flags
|=SF_ITPACKED
;
244 if(flags
&0x0010) s
->flags
|=SF_DELTA
;
245 if(flags
&0x0008) s
->flags
|=SF_BIG_ENDIAN
;
246 } else if(universion
>=0x102) {
247 if(flags
&0x0800) s
->flags
|=SF_UST_LOOP
;
248 if(flags
&0x0400) s
->flags
|=SF_OWNPAN
;
249 if(flags
&0x0200) s
->flags
|=SF_SUSTAIN
;
250 if(flags
&0x0100) s
->flags
|=SF_REVERSE
;
251 if(flags
&0x0080) s
->flags
|=SF_BIDI
;
252 if(flags
&0x0040) s
->flags
|=SF_LOOP
;
253 if(flags
&0x0020) s
->flags
|=SF_ITPACKED
;
254 if(flags
&0x0010) s
->flags
|=SF_DELTA
;
255 if(flags
&0x0008) s
->flags
|=SF_BIG_ENDIAN
;
257 if(flags
&0x400) s
->flags
|=SF_UST_LOOP
;
258 if(flags
&0x200) s
->flags
|=SF_OWNPAN
;
259 if(flags
&0x100) s
->flags
|=SF_REVERSE
;
260 if(flags
&0x080) s
->flags
|=SF_SUSTAIN
;
261 if(flags
&0x040) s
->flags
|=SF_BIDI
;
262 if(flags
&0x020) s
->flags
|=SF_LOOP
;
263 if(flags
&0x010) s
->flags
|=SF_BIG_ENDIAN
;
264 if(flags
&0x008) s
->flags
|=SF_DELTA
;
267 s
->speed
= _mm_read_M_ULONG(modreader
);
268 s
->volume
= _mm_read_UBYTE(modreader
);
269 s
->panning
= _mm_read_M_UWORD(modreader
);
270 s
->length
= _mm_read_M_ULONG(modreader
);
271 s
->loopstart
= _mm_read_M_ULONG(modreader
);
272 s
->loopend
= _mm_read_M_ULONG(modreader
);
273 s
->susbegin
= _mm_read_M_ULONG(modreader
);
274 s
->susend
= _mm_read_M_ULONG(modreader
);
275 s
->globvol
= _mm_read_UBYTE(modreader
);
276 s
->vibflags
= _mm_read_UBYTE(modreader
);
277 s
->vibtype
= _mm_read_UBYTE(modreader
);
278 s
->vibsweep
= _mm_read_UBYTE(modreader
);
279 s
->vibdepth
= _mm_read_UBYTE(modreader
);
280 s
->vibrate
= _mm_read_UBYTE(modreader
);
282 s
->samplename
=readstring();
284 if(_mm_eof(modreader
)) {
285 _mm_errno
= MMERR_LOADING_SAMPLEINFO
;
292 static int loadinstr6(void)
298 for(t
=0;t
<of
.numins
;t
++,i
++) {
299 i
->flags
= _mm_read_UBYTE(modreader
);
300 i
->nnatype
= _mm_read_UBYTE(modreader
);
301 i
->dca
= _mm_read_UBYTE(modreader
);
302 i
->dct
= _mm_read_UBYTE(modreader
);
303 i
->globvol
= _mm_read_UBYTE(modreader
);
304 i
->panning
= _mm_read_M_UWORD(modreader
);
305 i
->pitpansep
= _mm_read_UBYTE(modreader
);
306 i
->pitpancenter
= _mm_read_UBYTE(modreader
);
307 i
->rvolvar
= _mm_read_UBYTE(modreader
);
308 i
->rpanvar
= _mm_read_UBYTE(modreader
);
309 i
->volfade
= _mm_read_M_UWORD(modreader
);
311 #if defined __STDC__ || defined _MSC_VER || defined MPW_C
312 #define UNI_LoadEnvelope6(name) \
313 i-> name##flg=_mm_read_UBYTE(modreader); \
314 i-> name##pts=_mm_read_UBYTE(modreader); \
315 i-> name##susbeg=_mm_read_UBYTE(modreader); \
316 i-> name##susend=_mm_read_UBYTE(modreader); \
317 i-> name##beg=_mm_read_UBYTE(modreader); \
318 i-> name##end=_mm_read_UBYTE(modreader); \
319 for(w=0;w<(universion>=0x100?32:i-> name##pts);w++) { \
320 i-> name##env[w].pos=_mm_read_M_SWORD(modreader); \
321 i-> name##env[w].val=_mm_read_M_SWORD(modreader); \
324 #define UNI_LoadEnvelope6(name) \
325 i-> name/**/flg=_mm_read_UBYTE(modreader); \
326 i-> name/**/pts=_mm_read_UBYTE(modreader); \
327 i-> name/**/susbeg=_mm_read_UBYTE(modreader); \
328 i-> name/**/susend=_mm_read_UBYTE(modreader); \
329 i-> name/**/beg=_mm_read_UBYTE(modreader); \
330 i-> name/**/end=_mm_read_UBYTE(modreader); \
331 for (w=0;w<(universion>=0x100?32:i-> name/**/pts);w++) { \
332 i-> name/**/env[w].pos=_mm_read_M_SWORD(modreader); \
333 i-> name/**/env[w].val=_mm_read_M_SWORD(modreader); \
337 UNI_LoadEnvelope6(vol
);
338 UNI_LoadEnvelope6(pan
);
339 UNI_LoadEnvelope6(pit
);
340 #undef UNI_LoadEnvelope6
342 if(universion
>=0x103)
343 _mm_read_M_UWORDS(i
->samplenumber
,120,modreader
);
346 i
->samplenumber
[w
]=_mm_read_UBYTE(modreader
);
347 _mm_read_UBYTES(i
->samplenote
,120,modreader
);
349 i
->insname
=readstring();
351 if(_mm_eof(modreader
)) {
352 _mm_errno
= MMERR_LOADING_SAMPLEINFO
;
359 static int loadinstr5(void)
364 UBYTE vibtype
,vibsweep
,vibdepth
,vibrate
;
367 for(of
.numsmp
=t
=0;t
<of
.numins
;t
++,i
++) {
370 numsmp
=_mm_read_UBYTE(modreader
);
372 memset(i
->samplenumber
,0xff,INSTNOTES
*sizeof(UWORD
));
374 i
->samplenumber
[u
]=of
.numsmp
+_mm_read_UBYTE(modreader
);
376 #if defined __STDC__ || defined _MSC_VER || defined MPW_C
377 #define UNI_LoadEnvelope5(name) \
378 i-> name##flg=_mm_read_UBYTE(modreader); \
379 i-> name##pts=_mm_read_UBYTE(modreader); \
380 i-> name##susbeg=_mm_read_UBYTE(modreader); \
381 i-> name##susend=i-> name##susbeg; \
382 i-> name##beg=_mm_read_UBYTE(modreader); \
383 i-> name##end=_mm_read_UBYTE(modreader); \
384 for(u=0;u<12;u++) { \
385 i-> name##env[u].pos=_mm_read_I_SWORD(modreader); \
386 i-> name##env[u].val=_mm_read_I_SWORD(modreader); \
389 #define UNI_LoadEnvelope5(name) \
390 i-> name/**/flg=_mm_read_UBYTE(modreader); \
391 i-> name/**/pts=_mm_read_UBYTE(modreader); \
392 i-> name/**/susbeg=_mm_read_UBYTE(modreader); \
393 i-> name/**/susend=i-> name/**/susbeg; \
394 i-> name/**/beg=_mm_read_UBYTE(modreader); \
395 i-> name/**/end=_mm_read_UBYTE(modreader); \
396 for(u=0;u<12;u++) { \
397 i-> name/**/env[u].pos=_mm_read_I_SWORD(modreader); \
398 i-> name/**/env[u].val=_mm_read_I_SWORD(modreader); \
402 UNI_LoadEnvelope5(vol
);
403 UNI_LoadEnvelope5(pan
);
404 #undef UNI_LoadEnvelope5
406 vibtype
=_mm_read_UBYTE(modreader
);
407 vibsweep
=_mm_read_UBYTE(modreader
);
408 vibdepth
=_mm_read_UBYTE(modreader
);
409 vibrate
=_mm_read_UBYTE(modreader
);
411 i
->volfade
=_mm_read_I_UWORD(modreader
);
412 i
->insname
=readstring();
414 for(u
=0;u
<numsmp
;u
++,s
++,of
.numsmp
++) {
415 /* Allocate more room for sample information if necessary */
416 if(of
.numsmp
+u
==wavcnt
) {
418 if(!(wh
=MikMod_realloc(wh
,wavcnt
*sizeof(UNISMP05
)))) {
419 _mm_errno
=MMERR_OUT_OF_MEMORY
;
422 s
=wh
+(wavcnt
-UNI_SMPINCR
);
425 s
->c2spd
=_mm_read_I_UWORD(modreader
);
426 s
->transpose
=_mm_read_SBYTE(modreader
);
427 s
->volume
=_mm_read_UBYTE(modreader
);
428 s
->panning
=_mm_read_UBYTE(modreader
);
429 s
->length
=_mm_read_I_ULONG(modreader
);
430 s
->loopstart
=_mm_read_I_ULONG(modreader
);
431 s
->loopend
=_mm_read_I_ULONG(modreader
);
432 s
->flags
=_mm_read_I_UWORD(modreader
);
433 s
->samplename
=readstring();
436 s
->vibsweep
=vibsweep
;
437 s
->vibdepth
=vibdepth
;
440 if(_mm_eof(modreader
)) {
441 MikMod_free(wh
);wh
=NULL
;
442 _mm_errno
=MMERR_LOADING_SAMPLEINFO
;
450 if(wh
) { MikMod_free(wh
);wh
=NULL
; }
451 _mm_errno
=MMERR_LOADING_SAMPLEINFO
;
457 static int loadsmp5(void)
464 for(u
=0;u
<of
.numsmp
;u
++,q
++,s
++) {
465 q
->samplename
=s
->samplename
;
467 q
->length
=s
->length
;
468 q
->loopstart
=s
->loopstart
;
469 q
->loopend
=s
->loopend
;
470 q
->volume
=s
->volume
;
472 q
->panning
=s
->panning
;
473 q
->vibtype
=s
->vibtype
;
474 q
->vibsweep
=s
->vibsweep
;
475 q
->vibdepth
=s
->vibdepth
;
476 q
->vibrate
=s
->vibrate
;
480 if(s
->flags
&128) q
->flags
|=SF_REVERSE
;
481 if(s
->flags
& 64) q
->flags
|=SF_SUSTAIN
;
482 if(s
->flags
& 32) q
->flags
|=SF_BIDI
;
483 if(s
->flags
& 16) q
->flags
|=SF_LOOP
;
484 if(s
->flags
& 8) q
->flags
|=SF_BIG_ENDIAN
;
485 if(s
->flags
& 4) q
->flags
|=SF_DELTA
;
486 if(s
->flags
& 2) q
->flags
|=SF_SIGNED
;
487 if(s
->flags
& 1) q
->flags
|=SF_16BITS
;
490 d
=of
.instruments
;s
=wh
;
491 for(u
=0;u
<of
.numins
;u
++,d
++)
492 for(t
=0;t
<INSTNOTES
;t
++)
493 d
->samplenote
[t
]=(d
->samplenumber
[t
]>=of
.numsmp
)?
494 255:(t
+s
[d
->samplenumber
[t
]].transpose
);
496 MikMod_free(wh
);wh
=NULL
;
501 int UNI_Load(int curious
)
504 char *modtype
,*oldtype
=NULL
;
508 /* read module header */
509 _mm_read_UBYTES(mh
.id
,4,modreader
);
511 universion
=mh
.id
[3]-'0';
517 _mm_read_UBYTE(modreader
);
519 universion
=_mm_read_M_UWORD(modreader
);
521 mh
.flags
=_mm_read_M_UWORD(modreader
);
522 mh
.numchn
=_mm_read_UBYTE(modreader
);
523 mh
.numvoices
=_mm_read_UBYTE(modreader
);
524 mh
.numpos
=_mm_read_M_UWORD(modreader
);
525 mh
.numpat
=_mm_read_M_UWORD(modreader
);
526 mh
.numtrk
=_mm_read_M_UWORD(modreader
);
527 mh
.numins
=_mm_read_M_UWORD(modreader
);
528 mh
.numsmp
=_mm_read_M_UWORD(modreader
);
529 mh
.reppos
=_mm_read_M_UWORD(modreader
);
530 mh
.initspeed
=_mm_read_UBYTE(modreader
);
531 mh
.inittempo
=_mm_read_UBYTE(modreader
);
532 mh
.initvolume
=_mm_read_UBYTE(modreader
);
533 /* I expect this to show up soon in APlayer 1.06 format */
534 if (universion
>= 0x106)
535 mh
.bpmlimit
=_mm_read_M_UWORD(modreader
);
539 mh
.flags
&= UF_XMPERIODS
| UF_LINEAR
| UF_INST
| UF_NNA
;
540 mh
.flags
|= UF_PANNING
;
542 mh
.numchn
=_mm_read_UBYTE(modreader
);
543 mh
.numpos
=_mm_read_I_UWORD(modreader
);
544 mh
.reppos
=(universion
==5)?_mm_read_I_UWORD(modreader
):0;
545 mh
.numpat
=_mm_read_I_UWORD(modreader
);
546 mh
.numtrk
=_mm_read_I_UWORD(modreader
);
547 mh
.numins
=_mm_read_I_UWORD(modreader
);
548 mh
.initspeed
=_mm_read_UBYTE(modreader
);
549 mh
.inittempo
=_mm_read_UBYTE(modreader
);
550 _mm_read_UBYTES(mh
.positions
,256,modreader
);
551 _mm_read_UBYTES(mh
.panning
,32,modreader
);
552 mh
.flags
=_mm_read_UBYTE(modreader
);
555 mh
.flags
&= UF_XMPERIODS
| UF_LINEAR
;
556 mh
.flags
|= UF_INST
| UF_NOWRAP
| UF_PANNING
;
559 /* set module parameters */
561 of
.numchn
=mh
.numchn
;
562 of
.numpos
=mh
.numpos
;
563 of
.numpat
=mh
.numpat
;
564 of
.numtrk
=mh
.numtrk
;
565 of
.numins
=mh
.numins
;
566 of
.reppos
=mh
.reppos
;
567 of
.initspeed
=mh
.initspeed
;
568 of
.inittempo
=mh
.inittempo
;
570 of
.bpmlimit
=mh
.bpmlimit
;
572 /* be bug-compatible with older releases */
575 of
.songname
=readstring();
577 oldtype
=readstring();
579 size_t len
=strlen(oldtype
)+20;
580 if(!(modtype
=MikMod_malloc(len
))) return 0;
582 snprintf(modtype
,len
,"%s (was %s)",(universion
>=0x100)?"APlayer":"MikCvt2",oldtype
);
584 sprintf(modtype
,"%s (was %s)",(universion
>=0x100)?"APlayer":"MikCvt2",oldtype
);
587 if(!(modtype
=MikMod_malloc(10))) return 0;
589 snprintf(modtype
,10,"%s",(universion
>=0x100)?"APlayer":"MikCvt3");
591 sprintf(modtype
,"%s",(universion
>=0x100)?"APlayer":"MikCvt3");
594 of
.modtype
=StrDup(modtype
);
595 MikMod_free(modtype
);MikMod_free(oldtype
);
596 of
.comment
=readstring();
599 of
.numvoices
=mh
.numvoices
;
600 of
.initvolume
=mh
.initvolume
;
603 if(_mm_eof(modreader
)) {
604 _mm_errno
=MMERR_LOADING_HEADER
;
609 if(!AllocPositions(of
.numpos
)) return 0;
611 if(universion
>=0x100)
612 _mm_read_M_UWORDS(of
.positions
,of
.numpos
,modreader
);
614 for(t
=0;t
<of
.numpos
;t
++) of
.positions
[t
]=_mm_read_UBYTE(modreader
);
615 _mm_read_M_UWORDS(of
.panning
,of
.numchn
,modreader
);
616 _mm_read_UBYTES(of
.chanvol
,of
.numchn
,modreader
);
618 if((mh
.numpos
>256)||(mh
.numchn
>32)) {
619 _mm_errno
=MMERR_LOADING_HEADER
;
622 for(t
=0;t
<of
.numpos
;t
++) of
.positions
[t
]=mh
.positions
[t
];
623 for(t
=0;t
<of
.numchn
;t
++) of
.panning
[t
]=mh
.panning
[t
];
625 /* convert the ``end of song'' pattern code if necessary */
627 for(t
=0;t
<of
.numpos
;t
++)
628 if(of
.positions
[t
]==255) of
.positions
[t
]=LAST_PATTERN
;
630 /* instruments and samples */
633 if(!AllocSamples()) return 0;
634 if(!loadsmp6()) return 0;
636 if(of
.flags
&UF_INST
) {
637 if(!AllocInstruments()) return 0;
638 if(!loadinstr6()) return 0;
641 if(!AllocInstruments()) return 0;
642 if(!loadinstr5()) return 0;
643 if(!AllocSamples()) {
644 if(wh
) { MikMod_free(wh
);wh
=NULL
; }
647 if(!loadsmp5()) return 0;
649 /* check if the original file had no instruments */
650 if(of
.numsmp
==of
.numins
) {
651 for(t
=0,d
=of
.instruments
;t
<of
.numins
;t
++,d
++) {
654 if((d
->volpts
)||(d
->panpts
)||(d
->globvol
!=64)) break;
656 if((d
->samplenumber
[u
]!=t
)||(d
->samplenote
[u
]!=u
)) break;
661 of
.flags
&=~UF_NOWRAP
;
662 for(t
=0,d
=of
.instruments
,q
=of
.samples
;t
<of
.numins
;t
++,d
++,q
++) {
663 q
->samplename
=d
->insname
;
671 if(!AllocPatterns()) return 0;
673 _mm_read_M_UWORDS(of
.pattrows
,of
.numpat
,modreader
);
674 _mm_read_M_UWORDS(of
.patterns
,of
.numpat
*of
.numchn
,modreader
);
676 _mm_read_I_UWORDS(of
.pattrows
,of
.numpat
,modreader
);
677 _mm_read_I_UWORDS(of
.patterns
,of
.numpat
*of
.numchn
,modreader
);
681 if(!AllocTracks()) return 0;
682 for(t
=0;t
<of
.numtrk
;t
++)
683 if(!(of
.tracks
[t
]=readtrack())) {
684 _mm_errno
=MMERR_LOADING_TRACK
;
691 CHAR
*UNI_LoadTitle(void)
694 int posit
[3]={304,306,26};
696 _mm_fseek(modreader
,3,SEEK_SET
);
697 ver
=_mm_read_UBYTE(modreader
);
698 if(ver
=='N') ver
='6';
700 _mm_fseek(modreader
,posit
[ver
-'4'],SEEK_SET
);
704 /*========== Loader information */
706 MIKMODAPI MLOADER load_uni
={
709 "APUN (APlayer) and UNI (MikMod)",