added an old version of mikmod for dos
[dosdemo] / libs / oldmik / src / load_xm.c
1 /*\r
2 \r
3 Name:\r
4 LOAD_XM.C\r
5 \r
6 Description:\r
7 Fasttracker (XM) module loader\r
8 \r
9 Portability:\r
10 All systems - all compilers (hopefully)\r
11 \r
12 */\r
13 #include <stdio.h>\r
14 #include <stdlib.h>\r
15 #include <string.h>\r
16 #include <ctype.h>\r
17 #include <malloc.h>\r
18 #include "mikmod.h"\r
19 \r
20 /**************************************************************************\r
21 **************************************************************************/\r
22 \r
23 \r
24 typedef struct XMHEADER{\r
25         char  id[17];                   /* ID text: 'Extended module: ' */\r
26         char  songname[21];             /* Module name, padded with zeroes and 0x1a at the end */\r
27         char  trackername[20];  /* Tracker name */\r
28         UWORD version;                  /* (word) Version number, hi-byte major and low-byte minor */\r
29         ULONG headersize;               /* Header size */\r
30         UWORD songlength;               /* (word) Song length (in patten order table) */\r
31         UWORD restart;                  /* (word) Restart position */\r
32         UWORD numchn;                   /* (word) Number of channels (2,4,6,8,10,...,32) */\r
33         UWORD numpat;                   /* (word) Number of patterns (max 256) */\r
34         UWORD numins;                   /* (word) Number of instruments (max 128) */\r
35         UWORD flags;                    /* (word) Flags: bit 0: 0 = Amiga frequency table (see below) 1 = Linear frequency table */\r
36         UWORD tempo;                    /* (word) Default tempo */\r
37         UWORD bpm;                              /* (word) Default BPM */\r
38         UBYTE orders[256];              /* (byte) Pattern order table */\r
39 } XMHEADER;\r
40 \r
41 \r
42 typedef struct XMINSTHEADER{\r
43         ULONG size;                             /* (dword) Instrument size */\r
44         char  name[22];                 /* (char) Instrument name */\r
45         UBYTE type;                             /* (byte) Instrument type (always 0) */\r
46         UWORD numsmp;                   /* (word) Number of samples in instrument */\r
47         ULONG ssize;                    /* */\r
48 } XMINSTHEADER;\r
49 \r
50 \r
51 typedef struct XMPATCHHEADER{\r
52         UBYTE what[96];         /* (byte) Sample number for all notes */\r
53         UBYTE volenv[48];       /* (byte) Points for volume envelope */\r
54         UBYTE panenv[48];       /* (byte) Points for panning envelope */\r
55         UBYTE volpts;           /* (byte) Number of volume points */\r
56         UBYTE panpts;           /* (byte) Number of panning points */\r
57         UBYTE volsus;           /* (byte) Volume sustain point */\r
58         UBYTE volbeg;           /* (byte) Volume loop start point */\r
59         UBYTE volend;           /* (byte) Volume loop end point */\r
60         UBYTE pansus;           /* (byte) Panning sustain point */\r
61         UBYTE panbeg;           /* (byte) Panning loop start point */\r
62         UBYTE panend;           /* (byte) Panning loop end point */\r
63         UBYTE volflg;           /* (byte) Volume type: bit 0: On; 1: Sustain; 2: Loop */\r
64         UBYTE panflg;           /* (byte) Panning type: bit 0: On; 1: Sustain; 2: Loop */\r
65         UBYTE vibflg;           /* (byte) Vibrato type */\r
66         UBYTE vibsweep;         /* (byte) Vibrato sweep */\r
67         UBYTE vibdepth;         /* (byte) Vibrato depth */\r
68         UBYTE vibrate;          /* (byte) Vibrato rate */\r
69         UWORD volfade;          /* (word) Volume fadeout */\r
70         UWORD reserved[11];     /* (word) Reserved */\r
71 } XMPATCHHEADER;\r
72 \r
73 \r
74 typedef struct XMWAVHEADER{\r
75         ULONG length;           /* (dword) Sample length */\r
76         ULONG loopstart;        /* (dword) Sample loop start */\r
77         ULONG looplength;       /* (dword) Sample loop length */\r
78         UBYTE volume;           /* (byte) Volume */\r
79         SBYTE finetune;          /* (byte) Finetune (signed byte -128..+127) */\r
80         UBYTE type;                     /* (byte) Type: Bit 0-1: 0 = No loop, 1 = Forward loop, */\r
81 /*                                        2 = Ping-pong loop; */\r
82 /*                                        4: 16-bit sampledata */\r
83         UBYTE panning;          /* (byte) Panning (0-255) */\r
84         SBYTE  relnote;          /* (byte) Relative note number (signed byte) */\r
85         UBYTE reserved;         /* (byte) Reserved */\r
86         char  samplename[22];   /* (char) Sample name */\r
87 } XMWAVHEADER;\r
88 \r
89 \r
90 typedef struct XMPATHEADER{\r
91         ULONG size;                             /* (dword) Pattern header length */\r
92         UBYTE packing;                  /* (byte) Packing type (always 0) */\r
93         UWORD numrows;                  /* (word) Number of rows in pattern (1..256) */\r
94         UWORD packsize;                 /* (word) Packed patterndata size */\r
95 } XMPATHEADER;\r
96 \r
97 typedef struct MTMNOTE{\r
98         UBYTE a,b,c;\r
99 } MTMNOTE;\r
100 \r
101 \r
102 typedef struct XMNOTE{\r
103         UBYTE note,ins,vol,eff,dat;\r
104 }XMNOTE;\r
105 \r
106 XMNOTE *xmpat;\r
107 \r
108 /**************************************************************************\r
109 **************************************************************************/\r
110 \r
111 \r
112 \r
113 static XMHEADER *mh;\r
114 \r
115 char XM_Version[]="XM";\r
116 \r
117 \r
118 \r
119 BOOL XM_Test(void)\r
120 {\r
121         char id[17];\r
122         if(!fread(id,17,1,modfp)) return 0;\r
123         if(!memcmp(id,"Extended Module: ",17)) return 1;\r
124         return 0;\r
125 }\r
126 \r
127 \r
128 BOOL XM_Init(void)\r
129 {\r
130         mh=NULL;\r
131         if(!(mh=(XMHEADER *)MyCalloc(1,sizeof(XMHEADER)))) return 0;\r
132         return 1;\r
133 }\r
134 \r
135 \r
136 void XM_Cleanup(void)\r
137 {\r
138         if(mh!=NULL) free(mh);\r
139 }\r
140 \r
141 \r
142 void XM_ReadNote(XMNOTE *n)\r
143 {\r
144         UBYTE cmp;\r
145         memset(n,0,sizeof(XMNOTE));\r
146 \r
147         cmp=fgetc(modfp);\r
148 \r
149         if(cmp&0x80){\r
150                 if(cmp&1) n->note=fgetc(modfp);\r
151                 if(cmp&2) n->ins=fgetc(modfp);\r
152                 if(cmp&4) n->vol=fgetc(modfp);\r
153                 if(cmp&8) n->eff=fgetc(modfp);\r
154                 if(cmp&16) n->dat=fgetc(modfp);\r
155         }\r
156         else{\r
157                 n->note=cmp;\r
158                 n->ins=fgetc(modfp);\r
159                 n->vol=fgetc(modfp);\r
160                 n->eff=fgetc(modfp);\r
161                 n->dat=fgetc(modfp);\r
162         }\r
163 }\r
164 \r
165 \r
166 UBYTE *XM_Convert(XMNOTE *xmtrack,UWORD rows)\r
167 {\r
168         int t;\r
169         UBYTE note,ins,vol,eff,dat;\r
170 \r
171         UniReset();\r
172 \r
173         for(t=0;t<rows;t++){\r
174 \r
175                 note=xmtrack->note;\r
176                 ins=xmtrack->ins;\r
177                 vol=xmtrack->vol;\r
178                 eff=xmtrack->eff;\r
179                 dat=xmtrack->dat;\r
180 \r
181                 if(note!=0) UniNote(note-1);\r
182 \r
183                 if(ins!=0) UniInstrument(ins-1);\r
184 \r
185 /*              printf("Vol:%d\n",vol); */\r
186 \r
187                 switch(vol>>4){\r
188 \r
189                         case 0x6:                                       /* volslide down */\r
190                                 if(vol&0xf){\r
191                                         UniWrite(UNI_XMEFFECTA);\r
192                                         UniWrite(vol&0xf);\r
193                                 }\r
194                                 break;\r
195 \r
196                         case 0x7:                                       /* volslide up */\r
197                                 if(vol&0xf){\r
198                                         UniWrite(UNI_XMEFFECTA);\r
199                                         UniWrite(vol<<4);\r
200                                 }\r
201                                 break;\r
202 \r
203                         /* volume-row fine volume slide is compatible with protracker\r
204                            EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as\r
205                            opposed to 'take the last sliding value'.\r
206                         */\r
207 \r
208                         case 0x8:                                               /* finevol down */\r
209                                 UniPTEffect(0xe,0xb0 | (vol&0xf));\r
210                                 break;\r
211 \r
212                         case 0x9:                       /* finevol up */\r
213                                 UniPTEffect(0xe,0xa0 | (vol&0xf));\r
214                                 break;\r
215 \r
216                         case 0xa:                       /* set vibrato speed */\r
217                                 UniPTEffect(0x4,vol<<4);\r
218                                 break;\r
219 \r
220                         case 0xb:                       /* vibrato */\r
221                                 UniPTEffect(0x4,vol&0xf);\r
222                                 break;\r
223 \r
224                         case 0xc:                       /* set panning */\r
225                                 UniPTEffect(0x8,vol<<4);\r
226                                 break;\r
227 \r
228                         case 0xd:                       /* panning slide left */\r
229                                 /* only slide when data nibble not zero: */\r
230 \r
231                                 if(vol&0xf){\r
232                                         UniWrite(UNI_XMEFFECTP);\r
233                                         UniWrite(vol&0xf);\r
234                                 }\r
235                                 break;\r
236 \r
237                         case 0xe:                       /* panning slide right */\r
238                                 /* only slide when data nibble not zero: */\r
239 \r
240                                 if(vol&0xf){\r
241                                         UniWrite(UNI_XMEFFECTP);\r
242                                         UniWrite(vol<<4);\r
243                                 }\r
244                                 break;\r
245 \r
246                         case 0xf:                       /* tone porta */\r
247                                 UniPTEffect(0x3,vol<<4);\r
248                                 break;\r
249 \r
250                         default:\r
251                                 if(vol>=0x10 && vol<=0x50){\r
252                                         UniPTEffect(0xc,vol-0x10);\r
253                                 }\r
254                 }\r
255 \r
256 /*              if(eff>0xf) printf("Effect %d",eff); */\r
257 \r
258                 switch(eff){\r
259 \r
260                         case 'G'-55:                    /* G - set global volume */\r
261                                 if(dat>64) dat=64;\r
262                                 UniWrite(UNI_XMEFFECTG);\r
263                                 UniWrite(dat);\r
264                                 break;\r
265 \r
266                         case 'H'-55:                    /* H - global volume slide */\r
267                                 UniWrite(UNI_XMEFFECTH);\r
268                                 UniWrite(dat);\r
269                                 break;\r
270 \r
271                         case 'K'-55:                    /* K - keyoff */\r
272                                 UniNote(96);\r
273                                 break;\r
274 \r
275                         case 'L'-55:                    /* L - set envelope position */\r
276                                 break;\r
277 \r
278                         case 'P'-55:                    /* P - panning slide */\r
279                                 UniWrite(UNI_XMEFFECTP);\r
280                                 UniWrite(dat);\r
281                                 break;\r
282 \r
283                         case 'R'-55:                    /* R - multi retrig note */\r
284                                 UniWrite(UNI_S3MEFFECTQ);\r
285                                 UniWrite(dat);\r
286                                 break;\r
287 \r
288                         case 'T'-55:                            /* T - Tremor !! (== S3M effect I) */\r
289                                 UniWrite(UNI_S3MEFFECTI);\r
290                                 UniWrite(dat);\r
291                                 break;\r
292 \r
293                         case 'X'-55:\r
294                                 if((dat>>4)==1){                /* X1 extra fine porta up */\r
295 \r
296 \r
297                                 }\r
298                                 else{                                   /* X2 extra fine porta down */\r
299 \r
300                                 }\r
301                                 break;\r
302 \r
303                         default:\r
304                                 if(eff==0xa){\r
305                                         UniWrite(UNI_XMEFFECTA);\r
306                                         UniWrite(dat);\r
307                                 }\r
308                                 else if(eff<=0xf) UniPTEffect(eff,dat);\r
309                                 break;\r
310                 }\r
311 \r
312                 UniNewline();\r
313                 xmtrack++;\r
314         }\r
315         return UniDup();\r
316 }\r
317 \r
318 \r
319 \r
320 BOOL XM_Load(void)\r
321 {\r
322         INSTRUMENT *d;\r
323         SAMPLE *q;\r
324         int t,u,v,p,numtrk;\r
325         long next;\r
326 \r
327         /* try to read module header */\r
328 \r
329         _mm_read_str(mh->id,17,modfp);\r
330         _mm_read_str(mh->songname,21,modfp);\r
331         _mm_read_str(mh->trackername,20,modfp);\r
332         mh->version             =_mm_read_I_UWORD(modfp);\r
333         mh->headersize  =_mm_read_I_ULONG(modfp);\r
334         mh->songlength  =_mm_read_I_UWORD(modfp);\r
335         mh->restart             =_mm_read_I_UWORD(modfp);\r
336         mh->numchn              =_mm_read_I_UWORD(modfp);\r
337         mh->numpat              =_mm_read_I_UWORD(modfp);\r
338         mh->numins              =_mm_read_I_UWORD(modfp);\r
339         mh->flags               =_mm_read_I_UWORD(modfp);\r
340         mh->tempo               =_mm_read_I_UWORD(modfp);\r
341         mh->bpm                 =_mm_read_I_UWORD(modfp);\r
342         _mm_read_UBYTES(mh->orders,256,modfp);\r
343 \r
344         if(feof(modfp)){\r
345                 myerr = ERROR_LOADING_HEADER;\r
346                 return 0;\r
347         }\r
348 \r
349         /* set module variables */\r
350 \r
351         of.initspeed=mh->tempo;\r
352         of.inittempo=mh->bpm;\r
353         of.modtype=DupStr(mh->trackername,20);\r
354         of.numchn=mh->numchn;\r
355         of.numpat=mh->numpat;\r
356         of.numtrk=(UWORD)of.numpat*of.numchn;   /* get number of channels */\r
357         of.songname=DupStr(mh->songname,20);    /* make a cstr of songname */\r
358         of.numpos=mh->songlength;                       /* copy the songlength */\r
359         of.reppos=mh->restart;\r
360         of.numins=mh->numins;\r
361         of.flags|=UF_XMPERIODS;\r
362         if(mh->flags&1) of.flags|=UF_LINEAR;\r
363 \r
364         memcpy(of.positions,mh->orders,256);\r
365 \r
366 /*\r
367         WHY THIS CODE HERE?? I CAN'T REMEMBER!\r
368 \r
369         of.numpat=0;\r
370         for(t=0;t<of.numpos;t++){\r
371                 if(of.positions[t]>of.numpat) of.numpat=of.positions[t];\r
372         }\r
373         of.numpat++;\r
374 */\r
375 \r
376 /*      printf("Modtype :%s\n",of.modtype);\r
377         printf("Version :%x\n",mh->version);\r
378         printf("Song    :%s\n",of.songname);\r
379         printf("Speed   :%d,%d\n",of.initspeed,of.inittempo);\r
380         printf("Channels:%d\n",of.numchn);\r
381         printf("Numins  :%d\n",mh->numins);\r
382 */\r
383         if(!AllocTracks()) return 0;\r
384         if(!AllocPatterns()) return 0;\r
385 \r
386         numtrk=0;\r
387         for(t=0;t<mh->numpat;t++){\r
388                 XMPATHEADER ph;\r
389 \r
390 /*              printf("Reading pattern %d\n",t); */\r
391 \r
392                 ph.size         =_mm_read_I_ULONG(modfp);\r
393                 ph.packing      =_mm_read_UBYTE(modfp);\r
394                 ph.numrows      =_mm_read_I_UWORD(modfp);\r
395                 ph.packsize     =_mm_read_I_UWORD(modfp);\r
396 \r
397 /*              printf("headln:  %ld\n",ph.size); */\r
398 /*              printf("numrows: %d\n",ph.numrows); */\r
399 /*              printf("packsize:%d\n",ph.packsize); */\r
400 \r
401                 of.pattrows[t]=ph.numrows;\r
402 \r
403                 /*\r
404                         Gr8.. when packsize is 0, don't try to load a pattern.. it's empty.\r
405                         This bug was discovered thanks to Khyron's module..\r
406                 */\r
407 \r
408                 if(!(xmpat=(XMNOTE *)MyCalloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0;\r
409 \r
410                 if(ph.packsize>0){\r
411                         for(u=0;u<ph.numrows;u++){\r
412                                 for(v=0;v<of.numchn;v++){\r
413                                         XM_ReadNote(&xmpat[(v*ph.numrows)+u]);\r
414                                 }\r
415                         }\r
416                 }\r
417 \r
418                 for(v=0;v<of.numchn;v++){\r
419                         of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);\r
420                 }\r
421 \r
422                 free(xmpat);\r
423         }\r
424 \r
425         if(!AllocInstruments()) return 0;\r
426 \r
427         d=of.instruments;\r
428 \r
429         for(t=0;t<of.numins;t++){\r
430                 XMINSTHEADER ih;\r
431 \r
432                 /* read instrument header */\r
433 \r
434                 ih.size         =_mm_read_I_ULONG(modfp);\r
435                 _mm_read_str (ih.name, 22, modfp);\r
436                 ih.type         =_mm_read_UBYTE(modfp);\r
437                 ih.numsmp       =_mm_read_I_UWORD(modfp);\r
438                 ih.ssize        =_mm_read_I_ULONG(modfp);\r
439 \r
440 /*      printf("Size: %ld\n",ih.size);\r
441                 printf("Name:   %22.22s\n",ih.name);\r
442                 printf("Samples:%d\n",ih.numsmp);\r
443                 printf("sampleheadersize:%ld\n",ih.ssize);\r
444 */\r
445                 d->insname=DupStr(ih.name,22);\r
446                 d->numsmp=ih.numsmp;\r
447 \r
448                 if(!AllocSamples(d)) return 0;\r
449 \r
450                 if(ih.numsmp>0){\r
451                         XMPATCHHEADER pth;\r
452                         XMWAVHEADER wh;\r
453 \r
454                         _mm_read_UBYTES (pth.what, 96, modfp);\r
455                         _mm_read_UBYTES (pth.volenv, 48, modfp);\r
456                         _mm_read_UBYTES (pth.panenv, 48, modfp);\r
457                         pth.volpts              =_mm_read_UBYTE(modfp);\r
458                         pth.panpts              =_mm_read_UBYTE(modfp);\r
459                         pth.volsus              =_mm_read_UBYTE(modfp);\r
460                         pth.volbeg              =_mm_read_UBYTE(modfp);\r
461                         pth.volend              =_mm_read_UBYTE(modfp);\r
462                         pth.pansus              =_mm_read_UBYTE(modfp);\r
463                         pth.panbeg              =_mm_read_UBYTE(modfp);\r
464                         pth.panend              =_mm_read_UBYTE(modfp);\r
465                         pth.volflg              =_mm_read_UBYTE(modfp);\r
466                         pth.panflg              =_mm_read_UBYTE(modfp);\r
467                         pth.vibflg              =_mm_read_UBYTE(modfp);\r
468                         pth.vibsweep    =_mm_read_UBYTE(modfp);\r
469                         pth.vibdepth    =_mm_read_UBYTE(modfp);\r
470                         pth.vibrate             =_mm_read_UBYTE(modfp);\r
471                         pth.volfade             =_mm_read_I_UWORD(modfp);\r
472                         _mm_read_I_UWORDS(pth.reserved, 11, modfp);\r
473 \r
474                         memcpy(d->samplenumber,pth.what,96);\r
475 \r
476                         d->volfade=pth.volfade;\r
477 \r
478 /*                      printf("Volfade %x\n",d->volfade); */\r
479 \r
480                         memcpy(d->volenv,pth.volenv,24);\r
481                         d->volflg=pth.volflg;\r
482                         d->volsus=pth.volsus;\r
483                         d->volbeg=pth.volbeg;\r
484                         d->volend=pth.volend;\r
485                         d->volpts=pth.volpts;\r
486 \r
487 /*                      printf("volume points   : %d\n"\r
488                                    "volflg                      : %d\n"\r
489                                    "volbeg                      : %d\n"\r
490                                    "volend                      : %d\n"\r
491                                    "volsus                      : %d\n",\r
492                                    d->volpts,\r
493                                    d->volflg,\r
494                                    d->volbeg,\r
495                                    d->volend,\r
496                                    d->volsus);\r
497 */\r
498                         /* scale volume envelope: */\r
499 \r
500                         for(p=0;p<12;p++){\r
501                                 d->volenv[p].val<<=2;\r
502 /*                              printf("%d,%d,",d->volenv[p].pos,d->volenv[p].val); */\r
503                         }\r
504 \r
505                         memcpy(d->panenv,pth.panenv,24);\r
506                         d->panflg=pth.panflg;\r
507                         d->pansus=pth.pansus;\r
508                         d->panbeg=pth.panbeg;\r
509                         d->panend=pth.panend;\r
510                         d->panpts=pth.panpts;\r
511 \r
512 /*                                        printf("Panning points        : %d\n"\r
513                                    "panflg                      : %d\n"\r
514                                    "panbeg                      : %d\n"\r
515                                    "panend                      : %d\n"\r
516                                    "pansus                      : %d\n",\r
517                                    d->panpts,\r
518                                    d->panflg,\r
519                                    d->panbeg,\r
520                                    d->panend,\r
521                                    d->pansus);\r
522 */\r
523                         /* scale panning envelope: */\r
524 \r
525                         for(p=0;p<12;p++){\r
526                                 d->panenv[p].val<<=2;\r
527 /*                              printf("%d,%d,",d->panenv[p].pos,d->panenv[p].val); */\r
528                         }\r
529 \r
530 /*                      for(u=0;u<256;u++){ */\r
531 /*                              printf("%2.2x ",fgetc(modfp)); */\r
532 /*                      } */\r
533 \r
534                         next=0;\r
535 \r
536                         for(u=0;u<ih.numsmp;u++){\r
537                                 q=&d->samples[u];\r
538 \r
539                                 wh.length               =_mm_read_I_ULONG (modfp);\r
540                                 wh.loopstart    =_mm_read_I_ULONG (modfp);\r
541                                 wh.looplength   =_mm_read_I_ULONG (modfp);\r
542                                 wh.volume               =_mm_read_UBYTE (modfp);\r
543                                 wh.finetune             =_mm_read_SBYTE (modfp);\r
544                                 wh.type                 =_mm_read_UBYTE (modfp);\r
545                                 wh.panning              =_mm_read_UBYTE (modfp);\r
546                                 wh.relnote              =_mm_read_SBYTE (modfp);\r
547                                 wh.reserved             =_mm_read_UBYTE (modfp);\r
548                                 _mm_read_str(wh.samplename, 22, modfp);\r
549 \r
550 /*              printf("wav %d:%22.22s\n",u,wh.samplename); */\r
551 \r
552                                 q->samplename   =DupStr(wh.samplename,22);\r
553                                 q->length       =wh.length;\r
554                                 q->loopstart    =wh.loopstart;\r
555                                 q->loopend      =wh.loopstart+wh.looplength;\r
556                                 q->volume       =wh.volume;\r
557                                 q->c2spd                =wh.finetune+128;\r
558                                 q->transpose    =wh.relnote;\r
559                                 q->panning      =wh.panning;\r
560                                 q->seekpos              =next;\r
561 \r
562                                 if(wh.type&0x10){\r
563                                         q->length>>=1;\r
564                                         q->loopstart>>=1;\r
565                                         q->loopend>>=1;\r
566                                 }\r
567 \r
568                                 next+=wh.length;\r
569 \r
570 /*                              printf("Type %u\n",wh.type); */\r
571 /*                              printf("Trans %d\n",wh.relnote); */\r
572 \r
573                                 q->flags|=SF_OWNPAN;\r
574                                 if(wh.type&0x3) q->flags|=SF_LOOP;\r
575                                 if(wh.type&0x2) q->flags|=SF_BIDI;\r
576 \r
577                                 if(wh.type&0x10) q->flags|=SF_16BITS;\r
578                                 q->flags|=SF_DELTA;\r
579                                 q->flags|=SF_SIGNED;\r
580                         }\r
581 \r
582                         for(u=0;u<ih.numsmp;u++) d->samples[u].seekpos+=_mm_ftell(modfp);\r
583 \r
584                         _mm_fseek(modfp,next,SEEK_CUR);\r
585                 }\r
586 \r
587                 d++;\r
588         }\r
589 \r
590 \r
591         return 1;\r
592 }\r
593 \r
594 \r
595 LOADER load_xm={\r
596         NULL,\r
597         "XM",\r
598         "Portable XM loader v0.4 - for your ears only / MikMak",\r
599         XM_Init,\r
600         XM_Test,\r
601         XM_Load,\r
602         XM_Cleanup\r
603 };\r