Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_uni.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_uni.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
24 \r
25   UNIMOD (libmikmod's and APlayer's internal module format) 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 structure */\r
50 \r
51 typedef struct UNIHEADER {\r
52         CHAR  id[4];\r
53         UBYTE numchn;\r
54         UWORD numpos;\r
55         UWORD reppos;\r
56         UWORD numpat;\r
57         UWORD numtrk;\r
58         UWORD numins;\r
59         UWORD numsmp;\r
60         UBYTE initspeed;\r
61         UBYTE inittempo;\r
62         UBYTE initvolume;\r
63         UWORD flags;\r
64         UBYTE numvoices;\r
65         UWORD bpmlimit;\r
66 \r
67         UBYTE positions[256];\r
68         UBYTE panning[32];\r
69 } UNIHEADER;\r
70 \r
71 typedef struct UNISMP05 {\r
72         UWORD c2spd;\r
73         UWORD transpose;\r
74         UBYTE volume;\r
75         UBYTE panning;\r
76         ULONG length;\r
77         ULONG loopstart;\r
78         ULONG loopend;\r
79         UWORD flags;\r
80         CHAR* samplename;\r
81         UBYTE vibtype;\r
82         UBYTE vibsweep;\r
83         UBYTE vibdepth;\r
84         UBYTE vibrate;\r
85 } UNISMP05;\r
86 \r
87 /*========== Loader variables */\r
88 \r
89 static UWORD universion;\r
90 static UNIHEADER mh;\r
91 \r
92 #define UNI_SMPINCR 64\r
93 static UNISMP05 *wh=NULL,*s=NULL;\r
94 \r
95 /*========== Loader code */\r
96 \r
97 static char* readstring(void)\r
98 {\r
99         char *s=NULL;\r
100         UWORD len;\r
101         \r
102         len=_mm_read_I_UWORD(modreader);\r
103         if(len) {\r
104                 s=_mm_malloc(len+1);\r
105                 _mm_read_UBYTES(s,len,modreader);\r
106                 s[len]=0;\r
107         }\r
108         return s;\r
109 }\r
110 \r
111 BOOL UNI_Test(void)\r
112 {\r
113         char id[6];\r
114 \r
115         if(!_mm_read_UBYTES(id,6,modreader)) return 0;\r
116 \r
117         /* UNIMod created by MikCvt */\r
118         if(!(memcmp(id,"UN0",3))) {\r
119                 if((id[3]>='4')&&(id[3]<='6')) return 1;\r
120         }\r
121         /* UNIMod created by APlayer */\r
122         if(!(memcmp(id,"APUN\01",5))) {\r
123                 if((id[5]>=1)&&(id[5]<=6)) return 1;\r
124         }\r
125         return 0;\r
126 }\r
127 \r
128 BOOL UNI_Init(void)\r
129 {\r
130         return 1;\r
131 }\r
132 \r
133 void UNI_Cleanup(void)\r
134 {\r
135         _mm_free(wh);\r
136         s=NULL;\r
137 }\r
138 \r
139 static UBYTE* readtrack(void)\r
140 {\r
141         UBYTE *t;\r
142         UWORD len;\r
143         int cur=0,chunk;\r
144 \r
145         if(universion>=6)\r
146                 len=_mm_read_M_UWORD(modreader);\r
147         else\r
148                 len=_mm_read_I_UWORD(modreader);\r
149 \r
150         if(!len) return NULL;\r
151         if(!(t=_mm_malloc(len))) return NULL;\r
152         _mm_read_UBYTES(t,len,modreader);\r
153 \r
154         /* Check if the track is correct */\r
155         while(1) {\r
156                 chunk=t[cur++];\r
157                 if(!chunk) break;\r
158                 chunk=(chunk&0x1f)-1;\r
159                 while(chunk>0) {\r
160                         int opcode,oplen;\r
161 \r
162                         if(cur>=len) {\r
163                                 free(t);\r
164                                 return NULL;\r
165                         }\r
166                         opcode=t[cur];\r
167 \r
168                         /* Remap opcodes */\r
169                         if (universion <= 5) {\r
170                                 if (opcode > 29) {\r
171                                         free(t);\r
172                                         return NULL;\r
173                                 }\r
174                                 switch (opcode) {\r
175                                         /* UNI_NOTE .. UNI_S3MEFFECTQ are the same */\r
176                                         case 25:\r
177                                                 opcode = UNI_S3MEFFECTT;\r
178                                                 break;\r
179                                         case 26:\r
180                                                 opcode = UNI_XMEFFECTA;\r
181                                                 break;\r
182                                         case 27:\r
183                                                 opcode = UNI_XMEFFECTG;\r
184                                                 break;\r
185                                         case 28:\r
186                                                 opcode = UNI_XMEFFECTH;\r
187                                                 break;\r
188                                         case 29:\r
189                                                 opcode = UNI_XMEFFECTP;\r
190                                                 break;\r
191                                 }\r
192                         } else {\r
193                                 /* APlayer < 1.05 does not have XMEFFECT6 */\r
194                                 if (opcode >= UNI_XMEFFECT6 && universion < 0x105)\r
195                                         opcode++;\r
196                                 /* APlayer < 1.03 does not have ITEFFECTT */\r
197                                 if (opcode >= UNI_ITEFFECTT && universion < 0x103)\r
198                                         opcode++;\r
199                                 /* APlayer < 1.02 does not have ITEFFECTZ */\r
200                                 if (opcode >= UNI_ITEFFECTZ && universion < 0x102)\r
201                                         opcode++;\r
202                         }\r
203 \r
204                         if((!opcode)||(opcode>=UNI_LAST)) {\r
205                                 free(t);\r
206                                 return NULL;\r
207                         }\r
208                         t[cur]=opcode;\r
209                         oplen=unioperands[opcode]+1;\r
210                         cur+=oplen;\r
211                         chunk-=oplen;\r
212                 }\r
213                 if((chunk<0)||(cur>=len)) {\r
214                         free(t);\r
215                         return NULL;\r
216                 }\r
217         }\r
218         return t;\r
219 }\r
220 \r
221 static BOOL loadsmp6(void)\r
222 {\r
223         int t;\r
224         SAMPLE *s;\r
225 \r
226         s=of.samples;\r
227         for(t=0;t<of.numsmp;t++,s++) {\r
228                 int flags;\r
229 \r
230                 flags         = _mm_read_M_UWORD(modreader);\r
231                 s->flags=0;\r
232                 if(flags&0x0004) s->flags|=SF_STEREO;\r
233                 if(flags&0x0002) s->flags|=SF_SIGNED;\r
234                 if(flags&0x0001) s->flags|=SF_16BITS;\r
235                 /* convert flags */\r
236                 if(universion>=0x104) {\r
237                         if(flags&0x2000) s->flags|=SF_UST_LOOP;\r
238                         if(flags&0x1000) s->flags|=SF_OWNPAN;\r
239                         if(flags&0x0800) s->flags|=SF_SUSTAIN;\r
240                         if(flags&0x0400) s->flags|=SF_REVERSE;\r
241                         if(flags&0x0200) s->flags|=SF_BIDI;\r
242                         if(flags&0x0100) s->flags|=SF_LOOP;\r
243                         if(flags&0x0020) s->flags|=SF_ITPACKED;\r
244                         if(flags&0x0010) s->flags|=SF_DELTA;\r
245                         if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;\r
246                 } else if(universion>=0x102) {\r
247                         if(flags&0x0800) s->flags|=SF_UST_LOOP;\r
248                         if(flags&0x0400) s->flags|=SF_OWNPAN;\r
249                         if(flags&0x0200) s->flags|=SF_SUSTAIN;\r
250                         if(flags&0x0100) s->flags|=SF_REVERSE;\r
251                         if(flags&0x0080) s->flags|=SF_BIDI;\r
252                         if(flags&0x0040) s->flags|=SF_LOOP;\r
253                         if(flags&0x0020) s->flags|=SF_ITPACKED;\r
254                         if(flags&0x0010) s->flags|=SF_DELTA;\r
255                         if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;\r
256                 } else {\r
257                         if(flags&0x400) s->flags|=SF_UST_LOOP;\r
258                         if(flags&0x200) s->flags|=SF_OWNPAN;\r
259                         if(flags&0x100) s->flags|=SF_REVERSE;\r
260                         if(flags&0x080) s->flags|=SF_SUSTAIN;\r
261                         if(flags&0x040) s->flags|=SF_BIDI;\r
262                         if(flags&0x020) s->flags|=SF_LOOP;\r
263                         if(flags&0x010) s->flags|=SF_BIG_ENDIAN;\r
264                         if(flags&0x008) s->flags|=SF_DELTA;\r
265                 }\r
266 \r
267                 s->speed      = _mm_read_M_ULONG(modreader);\r
268                 s->volume     = _mm_read_UBYTE(modreader);\r
269                 s->panning    = _mm_read_M_UWORD(modreader);\r
270                 s->length     = _mm_read_M_ULONG(modreader);\r
271                 s->loopstart  = _mm_read_M_ULONG(modreader);\r
272                 s->loopend    = _mm_read_M_ULONG(modreader);\r
273                 s->susbegin   = _mm_read_M_ULONG(modreader);\r
274                 s->susend     = _mm_read_M_ULONG(modreader);\r
275                 s->globvol    = _mm_read_UBYTE(modreader);\r
276                 s->vibflags   = _mm_read_UBYTE(modreader);\r
277                 s->vibtype    = _mm_read_UBYTE(modreader);\r
278                 s->vibsweep   = _mm_read_UBYTE(modreader);\r
279                 s->vibdepth   = _mm_read_UBYTE(modreader);\r
280                 s->vibrate    = _mm_read_UBYTE(modreader);\r
281 \r
282                 s->samplename=readstring();\r
283 \r
284                 if(_mm_eof(modreader)) {\r
285                         _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
286                         return 0;\r
287                 }\r
288         }\r
289         return 1;\r
290 }\r
291 \r
292 static BOOL loadinstr6(void)\r
293 {\r
294         int t,w;\r
295         INSTRUMENT *i;\r
296 \r
297         i=of.instruments;\r
298         for(t=0;t<of.numins;t++,i++) {\r
299                 i->flags        = _mm_read_UBYTE(modreader);\r
300                 i->nnatype      = _mm_read_UBYTE(modreader);\r
301                 i->dca          = _mm_read_UBYTE(modreader);\r
302                 i->dct          = _mm_read_UBYTE(modreader);\r
303                 i->globvol      = _mm_read_UBYTE(modreader);\r
304                 i->panning      = _mm_read_M_UWORD(modreader);\r
305                 i->pitpansep    = _mm_read_UBYTE(modreader);\r
306                 i->pitpancenter = _mm_read_UBYTE(modreader);\r
307                 i->rvolvar      = _mm_read_UBYTE(modreader);\r
308                 i->rpanvar      = _mm_read_UBYTE(modreader);\r
309                 i->volfade      = _mm_read_M_UWORD(modreader);\r
310 \r
311 #if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
312 #define UNI_LoadEnvelope6(name)                                                                                 \\r
313                 i-> name##flg=_mm_read_UBYTE(modreader);                                                \\r
314                 i-> name##pts=_mm_read_UBYTE(modreader);                                                \\r
315                 i-> name##susbeg=_mm_read_UBYTE(modreader);                                             \\r
316                 i-> name##susend=_mm_read_UBYTE(modreader);                                             \\r
317                 i-> name##beg=_mm_read_UBYTE(modreader);                                                \\r
318                 i-> name##end=_mm_read_UBYTE(modreader);                                                \\r
319                 for(w=0;w<(universion>=0x100?32:i-> name##pts);w++) {                   \\r
320                         i-> name##env[w].pos=_mm_read_M_SWORD(modreader);                       \\r
321                         i-> name##env[w].val=_mm_read_M_SWORD(modreader);                       \\r
322                 }\r
323 #else\r
324 #define UNI_LoadEnvelope6(name)                                                                                 \\r
325                 i-> name/**/flg=_mm_read_UBYTE(modreader);                                              \\r
326                 i-> name/**/pts=_mm_read_UBYTE(modreader);                                              \\r
327                 i-> name/**/susbeg=_mm_read_UBYTE(modreader);                                   \\r
328                 i-> name/**/susend=_mm_read_UBYTE(modreader);                                   \\r
329                 i-> name/**/beg=_mm_read_UBYTE(modreader);                                              \\r
330                 i-> name/**/end=_mm_read_UBYTE(modreader);                                              \\r
331                 for (w=0;w<(universion>=0x100?32:i-> name/**/pts);w++) {                \\r
332                         i-> name/**/env[w].pos=_mm_read_M_SWORD(modreader);                     \\r
333                         i-> name/**/env[w].val=_mm_read_M_SWORD(modreader);                     \\r
334                 }\r
335 #endif\r
336 \r
337                 UNI_LoadEnvelope6(vol);\r
338                 UNI_LoadEnvelope6(pan);\r
339                 UNI_LoadEnvelope6(pit);\r
340 #undef UNI_LoadEnvelope6\r
341 \r
342                 if(universion>=0x103)\r
343                         _mm_read_M_UWORDS(i->samplenumber,120,modreader);\r
344                 else\r
345                         for(w=0;w<120;w++)\r
346                                 i->samplenumber[w]=_mm_read_UBYTE(modreader);\r
347                 _mm_read_UBYTES(i->samplenote,120,modreader);\r
348 \r
349                 i->insname=readstring();\r
350 \r
351                 if(_mm_eof(modreader)) {\r
352                         _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
353                         return 0;\r
354                 }\r
355         }\r
356         return 1;\r
357 }\r
358 \r
359 static BOOL loadinstr5(void)\r
360 {\r
361         INSTRUMENT *i;\r
362         int t;\r
363         UWORD wavcnt=0;\r
364         UBYTE vibtype,vibsweep,vibdepth,vibrate;\r
365 \r
366         i=of.instruments;\r
367         for(of.numsmp=t=0;t<of.numins;t++,i++) {\r
368                 int u,numsmp;\r
369 \r
370                 numsmp=_mm_read_UBYTE(modreader);\r
371 \r
372                 memset(i->samplenumber,0xff,INSTNOTES*sizeof(UWORD));\r
373                 for(u=0;u<96;u++)\r
374                         i->samplenumber[u]=of.numsmp+_mm_read_UBYTE(modreader);\r
375 \r
376 #if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
377 #define UNI_LoadEnvelope5(name)                                                                         \\r
378                 i-> name##flg=_mm_read_UBYTE(modreader);                                        \\r
379                 i-> name##pts=_mm_read_UBYTE(modreader);                                        \\r
380                 i-> name##susbeg=_mm_read_UBYTE(modreader);                                     \\r
381                 i-> name##susend=i-> name##susbeg;                                                      \\r
382                 i-> name##beg=_mm_read_UBYTE(modreader);                                        \\r
383                 i-> name##end=_mm_read_UBYTE(modreader);                                        \\r
384                 for(u=0;u<12;u++) {                                                                                     \\r
385                         i-> name##env[u].pos=_mm_read_I_SWORD(modreader);               \\r
386                         i-> name##env[u].val=_mm_read_I_SWORD(modreader);               \\r
387                 }\r
388 #else\r
389 #define UNI_LoadEnvelope5(name)                                                                         \\r
390                 i-> name/**/flg=_mm_read_UBYTE(modreader);                                      \\r
391                 i-> name/**/pts=_mm_read_UBYTE(modreader);                                      \\r
392                 i-> name/**/susbeg=_mm_read_UBYTE(modreader);                           \\r
393                 i-> name/**/susend=i-> name/**/susbeg;                                          \\r
394                 i-> name/**/beg=_mm_read_UBYTE(modreader);                                      \\r
395                 i-> name/**/end=_mm_read_UBYTE(modreader);                                      \\r
396                 for(u=0;u<12;u++) {                                                                                     \\r
397                         i-> name/**/env[u].pos=_mm_read_I_SWORD(modreader);             \\r
398                         i-> name/**/env[u].val=_mm_read_I_SWORD(modreader);             \\r
399                 }\r
400 #endif\r
401 \r
402                 UNI_LoadEnvelope5(vol);\r
403                 UNI_LoadEnvelope5(pan);\r
404 #undef UNI_LoadEnvelope5\r
405 \r
406                 vibtype      =_mm_read_UBYTE(modreader);\r
407                 vibsweep     =_mm_read_UBYTE(modreader);\r
408                 vibdepth     =_mm_read_UBYTE(modreader);\r
409                 vibrate      =_mm_read_UBYTE(modreader);\r
410 \r
411                 i->volfade=_mm_read_I_UWORD(modreader);\r
412                 i->insname=readstring();\r
413 \r
414                 for(u=0;u<numsmp;u++,s++,of.numsmp++) {\r
415                         /* Allocate more room for sample information if necessary */\r
416                         if(of.numsmp+u==wavcnt) {\r
417                                 wavcnt+=UNI_SMPINCR;\r
418                                 if(!(wh=realloc(wh,wavcnt*sizeof(UNISMP05)))) {\r
419                                         _mm_errno=MMERR_OUT_OF_MEMORY;\r
420                                         return 0;\r
421                                 }\r
422                                 s=wh+(wavcnt-UNI_SMPINCR);\r
423                         }\r
424 \r
425                         s->c2spd    =_mm_read_I_UWORD(modreader);\r
426                         s->transpose=_mm_read_SBYTE(modreader);\r
427                         s->volume   =_mm_read_UBYTE(modreader);\r
428                         s->panning  =_mm_read_UBYTE(modreader);\r
429                         s->length   =_mm_read_I_ULONG(modreader);\r
430                         s->loopstart=_mm_read_I_ULONG(modreader);\r
431                         s->loopend  =_mm_read_I_ULONG(modreader);\r
432                         s->flags    =_mm_read_I_UWORD(modreader);\r
433                         s->samplename=readstring();\r
434 \r
435                         s->vibtype =vibtype;\r
436                         s->vibsweep=vibsweep;\r
437                         s->vibdepth=vibdepth;\r
438                         s->vibrate =vibrate;\r
439 \r
440                         if(_mm_eof(modreader)) {\r
441                                 free(wh);wh=NULL;\r
442                                 _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
443                                 return 0;\r
444                         }\r
445                 }\r
446         }\r
447 \r
448         /* sanity check */\r
449         if(!of.numsmp) {\r
450                 if(wh) { free(wh);wh=NULL; }\r
451                 _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
452                 return 0;\r
453         }\r
454         return 1;\r
455 }\r
456 \r
457 static BOOL loadsmp5(void)\r
458 {\r
459         int t,u;\r
460         SAMPLE *q;\r
461         INSTRUMENT *d;\r
462 \r
463         q=of.samples;s=wh;\r
464         for(u=0;u<of.numsmp;u++,q++,s++) {\r
465                 q->samplename=s->samplename;\r
466 \r
467                 q->length   =s->length;\r
468                 q->loopstart=s->loopstart;\r
469                 q->loopend  =s->loopend;\r
470                 q->volume   =s->volume;\r
471                 q->speed    =s->c2spd;\r
472                 q->panning  =s->panning;\r
473                 q->vibtype  =s->vibtype;\r
474                 q->vibsweep =s->vibsweep;\r
475                 q->vibdepth =s->vibdepth;\r
476                 q->vibrate  =s->vibrate;\r
477 \r
478                 /* convert flags */\r
479                 q->flags=0;\r
480                 if(s->flags&128) q->flags|=SF_REVERSE;\r
481                 if(s->flags& 64) q->flags|=SF_SUSTAIN;\r
482                 if(s->flags& 32) q->flags|=SF_BIDI;\r
483                 if(s->flags& 16) q->flags|=SF_LOOP;\r
484                 if(s->flags&  8) q->flags|=SF_BIG_ENDIAN;\r
485                 if(s->flags&  4) q->flags|=SF_DELTA;\r
486                 if(s->flags&  2) q->flags|=SF_SIGNED;\r
487                 if(s->flags&  1) q->flags|=SF_16BITS;\r
488         }\r
489 \r
490         d=of.instruments;s=wh;\r
491         for(u=0;u<of.numins;u++,d++)\r
492                 for(t=0;t<INSTNOTES;t++)\r
493                         d->samplenote[t]=(d->samplenumber[t]>=of.numsmp)?\r
494                           255:(t+s[d->samplenumber[t]].transpose);\r
495 \r
496         free(wh);wh=NULL;\r
497 \r
498         return 1;\r
499 }\r
500 \r
501 BOOL UNI_Load(BOOL curious)\r
502 {\r
503         int t;\r
504         char *modtype,*oldtype=NULL;\r
505         INSTRUMENT *d;\r
506         SAMPLE *q;\r
507         (void)curious;\r
508         \r
509         /* read module header */\r
510         _mm_read_UBYTES(mh.id,4,modreader);\r
511         if(mh.id[3]!='N')\r
512                 universion=mh.id[3]-'0';\r
513         else\r
514                 universion=0x100;\r
515 \r
516         if(universion>=6) {\r
517                 if (universion==6)\r
518                         _mm_read_UBYTE(modreader);\r
519                 else\r
520                         universion=_mm_read_M_UWORD(modreader);\r
521 \r
522                 mh.flags     =_mm_read_M_UWORD(modreader);\r
523                 mh.numchn    =_mm_read_UBYTE(modreader);\r
524                 mh.numvoices =_mm_read_UBYTE(modreader);\r
525                 mh.numpos    =_mm_read_M_UWORD(modreader);\r
526                 mh.numpat    =_mm_read_M_UWORD(modreader);\r
527                 mh.numtrk    =_mm_read_M_UWORD(modreader);\r
528                 mh.numins    =_mm_read_M_UWORD(modreader);\r
529                 mh.numsmp    =_mm_read_M_UWORD(modreader);\r
530                 mh.reppos    =_mm_read_M_UWORD(modreader);\r
531                 mh.initspeed =_mm_read_UBYTE(modreader);\r
532                 mh.inittempo =_mm_read_UBYTE(modreader);\r
533                 mh.initvolume=_mm_read_UBYTE(modreader);\r
534                 /* I expect this to show up soon in APlayer 1.06 format */\r
535                 if (universion >= 0x106)\r
536                         mh.bpmlimit=_mm_read_M_UWORD(modreader);\r
537                 else\r
538                         mh.bpmlimit=32;\r
539 \r
540                 mh.flags &= UF_XMPERIODS | UF_LINEAR | UF_INST | UF_NNA;\r
541                 mh.flags |= UF_PANNING;\r
542         } else {\r
543                 mh.numchn    =_mm_read_UBYTE(modreader);\r
544                 mh.numpos    =_mm_read_I_UWORD(modreader);\r
545                 mh.reppos    =(universion==5)?_mm_read_I_UWORD(modreader):0;\r
546                 mh.numpat    =_mm_read_I_UWORD(modreader);\r
547                 mh.numtrk    =_mm_read_I_UWORD(modreader);\r
548                 mh.numins    =_mm_read_I_UWORD(modreader);\r
549                 mh.initspeed =_mm_read_UBYTE(modreader);\r
550                 mh.inittempo =_mm_read_UBYTE(modreader);\r
551                 _mm_read_UBYTES(mh.positions,256,modreader);\r
552                 _mm_read_UBYTES(mh.panning,32,modreader);\r
553                 mh.flags     =_mm_read_UBYTE(modreader);\r
554                 mh.bpmlimit  =32;\r
555 \r
556                 mh.flags &= UF_XMPERIODS | UF_LINEAR;\r
557                 mh.flags |= UF_INST | UF_NOWRAP | UF_PANNING;\r
558         }\r
559         \r
560         /* set module parameters */\r
561         of.flags     =mh.flags;\r
562         of.numchn    =mh.numchn;\r
563         of.numpos    =mh.numpos;\r
564         of.numpat    =mh.numpat;\r
565         of.numtrk    =mh.numtrk;\r
566         of.numins    =mh.numins;\r
567         of.reppos    =mh.reppos;\r
568         of.initspeed =mh.initspeed;\r
569         of.inittempo =mh.inittempo;\r
570         if(mh.bpmlimit)\r
571                 of.bpmlimit=mh.bpmlimit;\r
572         else\r
573                 /* be bug-compatible with older releases */\r
574                 of.bpmlimit=32;\r
575 \r
576         of.songname=readstring();\r
577         if(universion<0x102)\r
578                 oldtype=readstring();\r
579         if(oldtype) {\r
580                 int len=strlen(oldtype)+20;\r
581                 if(!(modtype=_mm_malloc(len))) return 0;\r
582 #ifdef HAVE_SNPRINTF\r
583                 snprintf(modtype,len,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);\r
584 #else\r
585                 sprintf(modtype,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);\r
586 #endif\r
587         } else {\r
588                 if(!(modtype=_mm_malloc(10))) return 0;\r
589 #ifdef HAVE_SNPRINTF\r
590                 snprintf(modtype,10,"%s",(universion>=0x100)?"APlayer":"MikCvt3");\r
591 #else\r
592                 sprintf(modtype,"%s",(universion>=0x100)?"APlayer":"MikCvt3");\r
593 #endif\r
594         }\r
595         of.modtype=strdup(modtype);\r
596         free(modtype);free(oldtype);\r
597         of.comment=readstring();\r
598 \r
599         if(universion>=6) {\r
600                 of.numvoices=mh.numvoices;\r
601                 of.initvolume=mh.initvolume;\r
602         }\r
603 \r
604         if(_mm_eof(modreader)) {\r
605                 _mm_errno=MMERR_LOADING_HEADER;\r
606                 return 0;\r
607         }\r
608 \r
609         /* positions */\r
610         if(!AllocPositions(of.numpos)) return 0;\r
611         if(universion>=6) {\r
612                 if(universion>=0x100)\r
613                         _mm_read_M_UWORDS(of.positions,of.numpos,modreader);\r
614                 else\r
615                         for(t=0;t<of.numpos;t++) of.positions[t]=_mm_read_UBYTE(modreader);\r
616                 _mm_read_M_UWORDS(of.panning,of.numchn,modreader);\r
617                 _mm_read_UBYTES(of.chanvol,of.numchn,modreader);\r
618         } else {\r
619                 if((mh.numpos>256)||(mh.numchn>32)) {\r
620                         _mm_errno=MMERR_LOADING_HEADER;\r
621                         return 0;\r
622                 }\r
623                 for(t=0;t<of.numpos;t++) of.positions[t]=mh.positions[t];\r
624                 for(t=0;t<of.numchn;t++) of.panning[t]=mh.panning[t];\r
625         }\r
626         /* convert the ``end of song'' pattern code if necessary */\r
627         if(universion<0x106)\r
628                 for(t=0;t<of.numpos;t++)\r
629                         if(of.positions[t]==255) of.positions[t]=LAST_PATTERN;\r
630 \r
631         /* instruments and samples */\r
632         if(universion>=6) {\r
633                 of.numsmp=mh.numsmp;\r
634                 if(!AllocSamples()) return 0;\r
635                 if(!loadsmp6()) return 0;\r
636 \r
637                 if(of.flags&UF_INST) {\r
638                         if(!AllocInstruments()) return 0;\r
639                         if(!loadinstr6()) return 0;\r
640                 }\r
641         } else {\r
642                 if(!AllocInstruments()) return 0;\r
643                 if(!loadinstr5()) return 0;\r
644                 if(!AllocSamples()) {\r
645                         if(wh) { free(wh);wh=NULL; }\r
646                         return 0;\r
647                 }\r
648                 if(!loadsmp5()) return 0;\r
649 \r
650                 /* check if the original file had no instruments */\r
651                 if(of.numsmp==of.numins) {\r
652                         for(t=0,d=of.instruments;t<of.numins;t++,d++) {\r
653                                 int u;\r
654 \r
655                                 if((d->volpts)||(d->panpts)||(d->globvol!=64)) break;\r
656                                 for(u=0;u<96;u++)\r
657                                         if((d->samplenumber[u]!=t)||(d->samplenote[u]!=u)) break;\r
658                                 if(u!=96) break;\r
659                         }\r
660                         if(t==of.numins) {\r
661                                 of.flags&=~UF_INST;\r
662                                 of.flags&=~UF_NOWRAP;\r
663                                 for(t=0,d=of.instruments,q=of.samples;t<of.numins;t++,d++,q++) {\r
664                                         q->samplename=d->insname;\r
665                                         d->insname=NULL;\r
666                                 }\r
667                         }\r
668                 }\r
669         }\r
670 \r
671         /* patterns */\r
672         if(!AllocPatterns()) return 0;\r
673         if(universion>=6) {\r
674                 _mm_read_M_UWORDS(of.pattrows,of.numpat,modreader);\r
675                 _mm_read_M_UWORDS(of.patterns,of.numpat*of.numchn,modreader);\r
676         } else {\r
677                 _mm_read_I_UWORDS(of.pattrows,of.numpat,modreader);\r
678                 _mm_read_I_UWORDS(of.patterns,of.numpat*of.numchn,modreader);\r
679         }\r
680 \r
681         /* tracks */\r
682         if(!AllocTracks()) return 0;\r
683         for(t=0;t<of.numtrk;t++)\r
684                 if(!(of.tracks[t]=readtrack())) {\r
685                         _mm_errno=MMERR_LOADING_TRACK;\r
686                         return 0;\r
687                 }\r
688 \r
689         return 1;\r
690 }\r
691 \r
692 CHAR *UNI_LoadTitle(void)\r
693 {\r
694         UBYTE ver;\r
695         int posit[3]={304,306,26};\r
696 \r
697         _mm_fseek(modreader,3,SEEK_SET);\r
698         ver=_mm_read_UBYTE(modreader);\r
699         if(ver=='N') ver='6';\r
700 \r
701         _mm_fseek(modreader,posit[ver-'4'],SEEK_SET);\r
702         return readstring();\r
703 }\r
704 \r
705 /*========== Loader information */\r
706 \r
707 MIKMODAPI MLOADER load_uni={\r
708         NULL,\r
709         "UNI",\r
710         "APUN (APlayer) and UNI (MikMod)",\r
711         UNI_Init,\r
712         UNI_Test,\r
713         UNI_Load,\r
714         UNI_Cleanup,\r
715         UNI_LoadTitle\r
716 };\r
717 \r
718 /* ex:set ts=4: */\r