Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_imf.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_imf.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
24 \r
25   Imago Orpheus (IMF) module 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 /* module header */\r
52 typedef struct IMFHEADER {\r
53         CHAR  songname[32];\r
54         UWORD ordnum;\r
55         UWORD patnum;\r
56         UWORD insnum;\r
57         UWORD flags;\r
58         UBYTE initspeed;\r
59         UBYTE inittempo;\r
60         UBYTE mastervol;\r
61         UBYTE mastermult;\r
62         UBYTE orders[256];\r
63 } IMFHEADER;\r
64 \r
65 /* channel settings */\r
66 typedef struct IMFCHANNEL {\r
67         CHAR  name[12];\r
68         UBYTE chorus;\r
69         UBYTE reverb;\r
70         UBYTE pan;\r
71         UBYTE status;\r
72 } IMFCHANNEL;\r
73 \r
74 /* instrument header */\r
75 #define IMFNOTECNT (10*OCTAVE)\r
76 #define IMFENVCNT (16*2)\r
77 typedef struct IMFINSTHEADER {\r
78         CHAR  name[32];\r
79         UBYTE what[IMFNOTECNT];\r
80         UWORD volenv[IMFENVCNT];\r
81         UWORD panenv[IMFENVCNT];\r
82         UWORD pitenv[IMFENVCNT];\r
83         UBYTE volpts;\r
84         UBYTE volsus;\r
85         UBYTE volbeg;\r
86         UBYTE volend;\r
87         UBYTE volflg;\r
88         UBYTE panpts;\r
89         UBYTE pansus;\r
90         UBYTE panbeg;\r
91         UBYTE panend;\r
92         UBYTE panflg;\r
93         UBYTE pitpts;\r
94         UBYTE pitsus;\r
95         UBYTE pitbeg;\r
96         UBYTE pitend;\r
97         UBYTE pitflg;\r
98         UWORD volfade;\r
99         UWORD numsmp;\r
100         ULONG signature;\r
101 } IMFINSTHEADER;\r
102 \r
103 /* sample header */\r
104 typedef struct IMFWAVHEADER {\r
105         CHAR  samplename[13];\r
106         ULONG length;\r
107         ULONG loopstart;\r
108         ULONG loopend;\r
109         ULONG samplerate;\r
110         UBYTE volume;\r
111         UBYTE pan;\r
112         UBYTE flags;\r
113 } IMFWAVHEADER;\r
114 \r
115 typedef struct IMFNOTE {\r
116         UBYTE note,ins,eff1,dat1,eff2,dat2;\r
117 } IMFNOTE;\r
118 \r
119 /*========== Loader variables */\r
120 \r
121 static  CHAR IMF_Version[]="Imago Orpheus";\r
122 \r
123 static  IMFNOTE *imfpat=NULL;\r
124 static  IMFHEADER *mh=NULL;\r
125 \r
126 /*========== Loader code */\r
127 \r
128 BOOL IMF_Test(void)\r
129 {\r
130         UBYTE id[4];\r
131 \r
132         _mm_fseek(modreader,0x3c,SEEK_SET);\r
133         if(!_mm_read_UBYTES(id,4,modreader)) return 0;\r
134         if(!memcmp(id,"IM10",4)) return 1;\r
135         return 0;\r
136 }\r
137 \r
138 BOOL IMF_Init(void)\r
139 {\r
140         if(!(imfpat=(IMFNOTE*)_mm_malloc(32*256*sizeof(IMFNOTE)))) return 0;\r
141         if(!(mh=(IMFHEADER*)_mm_malloc(sizeof(IMFHEADER)))) return 0;\r
142 \r
143         return 1;\r
144 }\r
145 \r
146 void IMF_Cleanup(void)\r
147 {\r
148         FreeLinear();\r
149 \r
150         _mm_free(imfpat);\r
151         _mm_free(mh);\r
152 }\r
153 \r
154 static BOOL IMF_ReadPattern(SLONG size,UWORD rows)\r
155 {\r
156         int row=0,flag,ch;\r
157         IMFNOTE *n,dummy;\r
158 \r
159         /* clear pattern data */\r
160         memset(imfpat,255,32*256*sizeof(IMFNOTE));\r
161 \r
162         while((size>0)&&(row<rows)) {\r
163                 flag=_mm_read_UBYTE(modreader);size--;\r
164 \r
165                 if(_mm_eof(modreader)) {\r
166                         _mm_errno=MMERR_LOADING_PATTERN;\r
167                         return 0;\r
168                 }\r
169 \r
170                 if(flag) {\r
171                         ch=remap[flag&31];\r
172 \r
173                         if(ch!=-1)\r
174                                 n=&imfpat[256*ch+row];\r
175                         else\r
176                                 n=&dummy;\r
177 \r
178                         if(flag&32) {\r
179                                 n->note=_mm_read_UBYTE(modreader);\r
180                                 if(n->note>=0xa0) n->note=0xa0; /* note off */\r
181                                 n->ins =_mm_read_UBYTE(modreader);\r
182                                 size-=2;\r
183                         }\r
184                         if(flag&64) {\r
185                                 size-=2;\r
186                                 n->eff2=_mm_read_UBYTE(modreader);\r
187                                 n->dat2=_mm_read_UBYTE(modreader);\r
188                         }\r
189                         if(flag&128) {\r
190                                 n->eff1=_mm_read_UBYTE(modreader);\r
191                                 n->dat1=_mm_read_UBYTE(modreader);\r
192                                 size-=2;\r
193                         }\r
194                 } else row++;\r
195         }\r
196         if((size)||(row!=rows)) {\r
197                 _mm_errno=MMERR_LOADING_PATTERN;\r
198                 return 0;\r
199         }\r
200         return 1;\r
201 }\r
202 \r
203 static void IMF_ProcessCmd(UBYTE eff,UBYTE inf)\r
204 {\r
205         if((eff)&&(eff!=255))\r
206                 switch (eff) {\r
207                         case 0x01:      /* set tempo */\r
208                                 UniEffect(UNI_S3MEFFECTA,inf);\r
209                                 break;\r
210                         case 0x02:      /* set BPM */\r
211                                 if(inf>=0x20) UniEffect(UNI_S3MEFFECTT,inf);\r
212                                 break;\r
213                         case 0x03:      /* tone portamento */\r
214                                 UniEffect(UNI_ITEFFECTG,inf);\r
215                                 break;\r
216                         case 0x04:      /* porta + volslide */\r
217                                 UniEffect(UNI_ITEFFECTG,inf);\r
218                                 UniEffect(UNI_S3MEFFECTD,0);\r
219                                 break;\r
220                         case 0x05:      /* vibrato */\r
221                                 UniEffect(UNI_XMEFFECT4,inf);\r
222                                 break;\r
223                         case 0x06:      /* vibrato + volslide */\r
224                                 UniEffect(UNI_XMEFFECT6,inf);\r
225                                 break;\r
226                         case 0x07:      /* fine vibrato */\r
227                                 UniEffect(UNI_ITEFFECTU,inf);\r
228                                 break;\r
229                         case 0x08:      /* tremolo */\r
230                                 UniEffect(UNI_S3MEFFECTR,inf);\r
231                                 break;\r
232                         case 0x09:      /* arpeggio */\r
233                                 UniPTEffect(0x0,inf);\r
234                                 break;\r
235                         case 0x0a:      /* panning */\r
236                                 UniPTEffect(0x8,(inf>=128)?255:(inf<<1));\r
237                                 break;\r
238                         case 0x0b:      /* pan slide */\r
239                                 UniEffect(UNI_XMEFFECTP,inf);\r
240                                 break;\r
241                         case 0x0c:      /* set channel volume */\r
242                                 if(inf<=64) UniPTEffect(0xc,inf);\r
243                                 break;\r
244                         case 0x0d:      /* volume slide */\r
245                                 UniEffect(UNI_S3MEFFECTD,inf);\r
246                                 break;\r
247                         case 0x0e:      /* fine volume slide */\r
248                                 if(inf) {\r
249                                         if(inf>>4)\r
250                                                 UniEffect(UNI_S3MEFFECTD,0x0f|inf);\r
251                                         else\r
252                                                 UniEffect(UNI_S3MEFFECTD,0xf0|inf);\r
253                                 } else\r
254                                         UniEffect(UNI_S3MEFFECTD,0);\r
255                                 break;\r
256                         case 0x0f:      /* set finetune */\r
257                                 UniPTEffect(0xe,0x50|(inf>>4));\r
258                                 break;\r
259 #ifdef MIKMOD_DEBUG\r
260                         case 0x10:      /* note slide up */\r
261                         case 0x11:      /* not slide down */\r
262                                 fprintf(stderr,"\rIMF effect 0x10/0x11 (note slide)"\r
263                                                " not implemented (eff=%2X inf=%2X)\n",eff,inf);\r
264                                 break;\r
265 #endif\r
266                         case 0x12:      /* slide up */\r
267                                 UniEffect(UNI_S3MEFFECTF,inf);\r
268                                 break;\r
269                         case 0x13:      /* slide down */\r
270                                 UniEffect(UNI_S3MEFFECTE,inf);\r
271                                 break;\r
272                         case 0x14:      /* fine slide up */\r
273                                 if (inf) {\r
274                                         if (inf<0x40)\r
275                                                 UniEffect(UNI_S3MEFFECTF,0xe0|(inf>>2));\r
276                                         else\r
277                                                 UniEffect(UNI_S3MEFFECTF,0xf0|(inf>>4));\r
278                                 } else\r
279                                         UniEffect(UNI_S3MEFFECTF,0);\r
280                                 break;\r
281                         case 0x15:      /* fine slide down */\r
282                                 if (inf) {\r
283                                         if (inf<0x40)\r
284                                                 UniEffect(UNI_S3MEFFECTE,0xe0|(inf>>2));\r
285                                         else\r
286                                                 UniEffect(UNI_S3MEFFECTE,0xf0|(inf>>4));\r
287                                 } else\r
288                                         UniEffect(UNI_S3MEFFECTE,0);\r
289                                 break;\r
290                         /* 0x16 set filter cutoff (awe32) */\r
291                         /* 0x17 filter side + resonance (awe32) */\r
292                         case 0x18:      /* sample offset */\r
293                                 UniPTEffect(0x9,inf);\r
294                                 break;\r
295 #ifdef MIKMOD_DEBUG\r
296                         case 0x19:      /* set fine sample offset */\r
297                                 fprintf(stderr,"\rIMF effect 0x19 (fine sample offset)"\r
298                                                " not implemented (inf=%2X)\n",inf);\r
299                                 break;\r
300 #endif\r
301                         case 0x1a:      /* keyoff */\r
302                                 UniWriteByte(UNI_KEYOFF);\r
303                                 break;\r
304                         case 0x1b:      /* retrig */\r
305                                 UniEffect(UNI_S3MEFFECTQ,inf);\r
306                                 break;\r
307                         case 0x1c:      /* tremor */\r
308                                 UniEffect(UNI_S3MEFFECTI,inf);\r
309                                 break;\r
310                         case 0x1d:      /* position jump */\r
311                                 UniPTEffect(0xb,inf);\r
312                                 break;\r
313                         case 0x1e:      /* pattern break */\r
314                                 UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));\r
315                                 break;\r
316                         case 0x1f:      /* set master volume */\r
317                                 if(inf<=64) UniEffect(UNI_XMEFFECTG,inf<<1);\r
318                                 break;\r
319                         case 0x20:      /* master volume slide */\r
320                                 UniEffect(UNI_XMEFFECTH,inf);\r
321                                 break;\r
322                         case 0x21:      /* extended effects */\r
323                                 switch(inf>>4) {\r
324                                         case 0x1:       /* set filter */\r
325                                         case 0x5:       /* vibrato waveform */\r
326                                         case 0x8:       /* tremolo waveform */\r
327                                                 UniPTEffect(0xe,inf-0x10);\r
328                                                 break;\r
329                                         case 0xa:       /* pattern loop */\r
330                                                 UniPTEffect(0xe,0x60|(inf&0xf));\r
331                                                 break;\r
332                                         case 0xb:       /* pattern delay */\r
333                                                 UniPTEffect(0xe,0xe0|(inf&0xf));\r
334                                                 break;\r
335                                         case 0x3:       /* glissando */\r
336                                         case 0xc:       /* note cut */\r
337                                         case 0xd:       /* note delay */\r
338                                         case 0xf:       /* invert loop */\r
339                                                 UniPTEffect(0xe,inf);\r
340                                                 break;\r
341                                         case 0xe:       /* ignore envelope */\r
342                                                 UniEffect(UNI_ITEFFECTS0, 0x77);    /* vol */\r
343                                                 UniEffect(UNI_ITEFFECTS0, 0x79);    /* pan */\r
344                                                 UniEffect(UNI_ITEFFECTS0, 0x7b);    /* pit */\r
345                                                 break;\r
346                                 }\r
347                                 break;\r
348                         /* 0x22 chorus (awe32) */\r
349                         /* 0x23 reverb (awe32) */\r
350                 }\r
351 }\r
352 \r
353 static UBYTE* IMF_ConvertTrack(IMFNOTE* tr,UWORD rows)\r
354 {\r
355         int t;\r
356         UBYTE note,ins;\r
357 \r
358         UniReset();\r
359         for(t=0;t<rows;t++) {\r
360                 note=tr[t].note;\r
361                 ins=tr[t].ins;\r
362 \r
363                 if((ins)&&(ins!=255)) UniInstrument(ins-1);\r
364                 if(note!=255) {\r
365                         if(note==0xa0) {\r
366                                 UniPTEffect(0xc,0); /* Note cut */\r
367                                 if(tr[t].eff1==0x0c) tr[t].eff1=0;\r
368                                 if(tr[t].eff2==0x0c) tr[t].eff2=0;\r
369                         } else\r
370                                 UniNote(((note>>4)*OCTAVE)+(note&0xf));\r
371                 }\r
372 \r
373                 IMF_ProcessCmd(tr[t].eff1,tr[t].dat1);\r
374                 IMF_ProcessCmd(tr[t].eff2,tr[t].dat2);\r
375                 UniNewline();\r
376         }\r
377         return UniDup();\r
378 }\r
379 \r
380 BOOL IMF_Load(BOOL curious)\r
381 {\r
382 #define IMF_SMPINCR 64\r
383         int t,u,track=0,oldnumsmp;\r
384         IMFCHANNEL channels[32];\r
385         INSTRUMENT *d;\r
386         SAMPLE *q;\r
387         IMFWAVHEADER *wh=NULL,*s=NULL;\r
388         ULONG *nextwav=NULL;\r
389         UWORD wavcnt=0;\r
390         UBYTE id[4];\r
391         (void)curious;\r
392 \r
393         /* try to read the module header */\r
394         _mm_read_string(mh->songname,32,modreader);\r
395         mh->ordnum=_mm_read_I_UWORD(modreader);\r
396         mh->patnum=_mm_read_I_UWORD(modreader);\r
397         mh->insnum=_mm_read_I_UWORD(modreader);\r
398         mh->flags =_mm_read_I_UWORD(modreader);\r
399         _mm_fseek(modreader,8,SEEK_CUR);\r
400         mh->initspeed =_mm_read_UBYTE(modreader);\r
401         mh->inittempo =_mm_read_UBYTE(modreader);\r
402         mh->mastervol =_mm_read_UBYTE(modreader);\r
403         mh->mastermult=_mm_read_UBYTE(modreader);\r
404         _mm_fseek(modreader,64,SEEK_SET);\r
405 \r
406         if(_mm_eof(modreader)) {\r
407                 _mm_errno = MMERR_LOADING_HEADER;\r
408                 return 0;\r
409         }\r
410 \r
411         /* set module variables */\r
412         of.songname=DupStr(mh->songname,31,1);\r
413         of.modtype=strdup(IMF_Version);\r
414         of.numpat=mh->patnum;\r
415         of.numins=mh->insnum;\r
416         of.reppos=0;\r
417         of.initspeed=mh->initspeed;\r
418         of.inittempo=mh->inittempo;\r
419         of.initvolume=mh->mastervol<<1;\r
420         of.flags |= UF_INST | UF_ARPMEM | UF_PANNING;\r
421         if(mh->flags&1) of.flags |= UF_LINEAR;\r
422         of.bpmlimit=32;\r
423 \r
424         /* read channel information */\r
425         of.numchn=0;\r
426         memset(remap,-1,32*sizeof(UBYTE));\r
427         for(t=0;t<32;t++) {\r
428                 _mm_read_string(channels[t].name,12,modreader);\r
429                 channels[t].chorus=_mm_read_UBYTE(modreader);\r
430                 channels[t].reverb=_mm_read_UBYTE(modreader);\r
431                 channels[t].pan   =_mm_read_UBYTE(modreader);\r
432                 channels[t].status=_mm_read_UBYTE(modreader);\r
433         }\r
434         /* bug in Imago Orpheus ? If only channel 1 is enabled, in fact we have to\r
435            enable 16 channels */\r
436         if(!channels[0].status) {\r
437                 for(t=1;t<16;t++) if(channels[t].status!=1) break;\r
438                 if(t==16) for(t=1;t<16;t++) channels[t].status=0;\r
439         }\r
440         for(t=0;t<32;t++) {\r
441                 if(channels[t].status!=2)\r
442                         remap[t]=of.numchn++;\r
443                 else\r
444                         remap[t]=-1;\r
445         }\r
446         for(t=0;t<32;t++)\r
447                 if(remap[t]!=-1) {\r
448                         of.panning[remap[t]]=channels[t].pan;\r
449                         of.chanvol[remap[t]]=channels[t].status?0:64;\r
450                 }\r
451 \r
452         if(_mm_eof(modreader)) {\r
453                 _mm_errno = MMERR_LOADING_HEADER;\r
454                 return 0;\r
455         }\r
456 \r
457         /* read order list */\r
458         _mm_read_UBYTES(mh->orders,256,modreader);\r
459         if(_mm_eof(modreader)) {\r
460                 _mm_errno = MMERR_LOADING_HEADER;\r
461                 return 0;\r
462         }\r
463 \r
464         of.numpos=0;\r
465         for(t=0;t<mh->ordnum;t++)\r
466                 if(mh->orders[t]!=0xff) of.numpos++;\r
467         if(!AllocPositions(of.numpos)) return 0;\r
468         for(t=u=0;t<mh->ordnum;t++)\r
469                 if(mh->orders[t]!=0xff) of.positions[u++]=mh->orders[t];\r
470 \r
471         /* load pattern info */\r
472         of.numtrk=of.numpat*of.numchn;\r
473         if(!AllocTracks()) return 0;\r
474         if(!AllocPatterns()) return 0;\r
475 \r
476         for(t=0;t<of.numpat;t++) {\r
477                 SLONG size;\r
478                 UWORD rows;\r
479 \r
480                 size=(SLONG)_mm_read_I_UWORD(modreader);\r
481                 rows=_mm_read_I_UWORD(modreader);\r
482                 if((rows>256)||(size<4)) {\r
483                         _mm_errno=MMERR_LOADING_PATTERN;\r
484                         return 0;\r
485                 }\r
486 \r
487                 of.pattrows[t]=rows;\r
488                 if(!IMF_ReadPattern(size-4,rows)) return 0;\r
489                 for(u=0;u<of.numchn;u++)\r
490                         if(!(of.tracks[track++]=IMF_ConvertTrack(&imfpat[u*256],rows)))\r
491                                 return 0;\r
492         }\r
493 \r
494         /* load instruments */\r
495         if(!AllocInstruments()) return 0;\r
496         d=of.instruments;\r
497 \r
498         for(oldnumsmp=t=0;t<of.numins;t++) {\r
499                 IMFINSTHEADER ih;\r
500 \r
501                 memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));\r
502 \r
503                 /* read instrument header */\r
504                 _mm_read_string(ih.name,32,modreader);\r
505                 d->insname=DupStr(ih.name,31,1);\r
506                 _mm_read_UBYTES(ih.what,IMFNOTECNT,modreader);\r
507                 _mm_fseek(modreader,8,SEEK_CUR);\r
508                 _mm_read_I_UWORDS(ih.volenv,IMFENVCNT,modreader);\r
509                 _mm_read_I_UWORDS(ih.panenv,IMFENVCNT,modreader);\r
510                 _mm_read_I_UWORDS(ih.pitenv,IMFENVCNT,modreader);\r
511 \r
512 #if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
513 #define IMF_FinishLoadingEnvelope(name)                                 \\r
514                 ih. name##pts=_mm_read_UBYTE(modreader);                \\r
515                 ih. name##sus=_mm_read_UBYTE(modreader);                \\r
516                 ih. name##beg=_mm_read_UBYTE(modreader);                \\r
517                 ih. name##end=_mm_read_UBYTE(modreader);                \\r
518                 ih. name##flg=_mm_read_UBYTE(modreader);                \\r
519                 _mm_read_UBYTE(modreader);                                              \\r
520                 _mm_read_UBYTE(modreader);                                              \\r
521                 _mm_read_UBYTE(modreader)\r
522 #else\r
523 #define IMF_FinishLoadingEnvelope(name)                         \\r
524                 ih. name/**/pts=_mm_read_UBYTE(modreader);      \\r
525                 ih. name/**/sus=_mm_read_UBYTE(modreader);      \\r
526                 ih. name/**/beg=_mm_read_UBYTE(modreader);      \\r
527                 ih. name/**/end=_mm_read_UBYTE(modreader);      \\r
528                 ih. name/**/flg=_mm_read_UBYTE(modreader);      \\r
529                 _mm_read_UBYTE(modreader);                                      \\r
530                 _mm_read_UBYTE(modreader);                                      \\r
531                 _mm_read_UBYTE(modreader)\r
532 #endif\r
533 \r
534                 IMF_FinishLoadingEnvelope(vol);\r
535                 IMF_FinishLoadingEnvelope(pan);\r
536                 IMF_FinishLoadingEnvelope(pit);\r
537 \r
538                 ih.volfade=_mm_read_I_UWORD(modreader);\r
539                 ih.numsmp =_mm_read_I_UWORD(modreader);\r
540 \r
541                 _mm_read_UBYTES(id,4,modreader);\r
542                 /* Looks like Imago Orpheus forgets the signature for empty\r
543                    instruments following a multi-sample instrument... */\r
544                 if(memcmp(id,"II10",4) && \r
545                    (oldnumsmp && memcmp(id,"\x0\x0\x0\x0",4))) {\r
546                         if(nextwav) free(nextwav);\r
547                         if(wh) free(wh);\r
548                         _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
549                         return 0;\r
550                 }\r
551                 oldnumsmp=ih.numsmp;\r
552 \r
553                 if((ih.numsmp>16)||(ih.volpts>IMFENVCNT/2)||(ih.panpts>IMFENVCNT/2)||\r
554                    (ih.pitpts>IMFENVCNT/2)||(_mm_eof(modreader))) {\r
555                         if(nextwav) free(nextwav);\r
556                         if(wh) free(wh);\r
557                         _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
558                         return 0;\r
559                 }\r
560 \r
561                 for(u=0;u<IMFNOTECNT;u++)\r
562                         d->samplenumber[u]=ih.what[u]>ih.numsmp?0xffff:ih.what[u]+of.numsmp;\r
563                 d->volfade=ih.volfade;\r
564 \r
565 #if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
566 #define IMF_ProcessEnvelope(name)                                                                       \\r
567                 for (u = 0; u < (IMFENVCNT >> 1); u++) {                                        \\r
568                         d-> name##env[u].pos = ih. name##env[u << 1];                   \\r
569                         d-> name##env[u].val = ih. name##env[(u << 1)+ 1];              \\r
570                 }                                                                                                                       \\r
571                 if (ih. name##flg&1) d-> name##flg|=EF_ON;                                      \\r
572                 if (ih. name##flg&2) d-> name##flg|=EF_SUSTAIN;                         \\r
573                 if (ih. name##flg&4) d-> name##flg|=EF_LOOP;                            \\r
574                 d-> name##susbeg=d-> name##susend=ih. name##sus;                        \\r
575                 d-> name##beg=ih. name##beg;                                                            \\r
576                 d-> name##end=ih. name##end;                                                            \\r
577                 d-> name##pts=ih. name##pts;                                                            \\r
578                                                                                                                                         \\r
579                 if ((d-> name##flg&EF_ON)&&(d-> name##pts<2))                           \\r
580                         d-> name##flg&=~EF_ON\r
581 #else\r
582 #define IMF_ProcessEnvelope(name)                                                                       \\r
583                 for (u = 0; u < (IMFENVCNT >> 1); u++) {                                        \\r
584                         d-> name/**/env[u].pos = ih. name/**/env[u << 1];               \\r
585                         d-> name/**/env[u].val = ih. name/**/env[(u << 1)+ 1];  \\r
586                 }                                                                                                                       \\r
587                 if (ih. name/**/flg&1) d-> name/**/flg|=EF_ON;                          \\r
588                 if (ih. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN;                     \\r
589                 if (ih. name/**/flg&4) d-> name/**/flg|=EF_LOOP;                        \\r
590                 d-> name/**/susbeg=d-> name/**/susend=ih. name/**/sus;          \\r
591                 d-> name/**/beg=ih. name/**/beg;                                                        \\r
592                 d-> name/**/end=ih. name/**/end;                                                        \\r
593                 d-> name/**/pts=ih. name/**/pts;                                                        \\r
594                                                                                                                                         \\r
595                 if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2))                       \\r
596                         d-> name/**/flg&=~EF_ON\r
597 #endif\r
598 \r
599                 IMF_ProcessEnvelope(vol);\r
600                 IMF_ProcessEnvelope(pan);\r
601                 IMF_ProcessEnvelope(pit);\r
602 #undef IMF_ProcessEnvelope\r
603 \r
604                 if(ih.pitflg&1) {\r
605                         d->pitflg&=~EF_ON;\r
606 #ifdef MIKMOD_DEBUG\r
607                         fprintf(stderr, "\rFilter envelopes not supported yet\n");\r
608 #endif\r
609                 }\r
610 \r
611                 /* gather sample information */\r
612                 for(u=0;u<ih.numsmp;u++,s++) {\r
613                         /* allocate more room for sample information if necessary */\r
614                         if(of.numsmp+u==wavcnt) {\r
615                                 wavcnt+=IMF_SMPINCR;\r
616                                 if(!(nextwav=realloc(nextwav,wavcnt*sizeof(ULONG)))) {\r
617                                         if(wh) free(wh);\r
618                                         _mm_errno=MMERR_OUT_OF_MEMORY;\r
619                                         return 0;\r
620                                 }\r
621                                 if(!(wh=realloc(wh,wavcnt*sizeof(IMFWAVHEADER)))) {\r
622                                         free(nextwav);\r
623                                         _mm_errno=MMERR_OUT_OF_MEMORY;\r
624                                         return 0;\r
625                                 }\r
626                                 s=wh+(wavcnt-IMF_SMPINCR);\r
627                         }\r
628 \r
629                         _mm_read_string(s->samplename,13,modreader);\r
630                         _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);\r
631                         s->length    =_mm_read_I_ULONG(modreader);\r
632                         s->loopstart =_mm_read_I_ULONG(modreader);\r
633                         s->loopend   =_mm_read_I_ULONG(modreader);\r
634                         s->samplerate=_mm_read_I_ULONG(modreader);\r
635                         s->volume    =_mm_read_UBYTE(modreader)&0x7f;\r
636                         s->pan       =_mm_read_UBYTE(modreader);\r
637                         _mm_fseek(modreader,14,SEEK_CUR);\r
638                         s->flags     =_mm_read_UBYTE(modreader);\r
639                         _mm_fseek(modreader,11,SEEK_CUR);\r
640                         _mm_read_UBYTES(id,4,modreader);\r
641                         if(((memcmp(id,"IS10",4))&&(memcmp(id,"IW10",4)))||\r
642                            (_mm_eof(modreader))) {\r
643                                 free(nextwav);free(wh);\r
644                                 _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
645                                 return 0;\r
646                         }\r
647                         nextwav[of.numsmp+u]=_mm_ftell(modreader);\r
648                         _mm_fseek(modreader,s->length,SEEK_CUR);\r
649                 }\r
650 \r
651                 of.numsmp+=ih.numsmp;\r
652                 d++;\r
653         }\r
654 \r
655         /* sanity check */\r
656         if(!of.numsmp) {\r
657                 if(nextwav) free(nextwav);\r
658                 if(wh) free(wh);\r
659                 _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
660                 return 0;\r
661         }\r
662 \r
663         /* load samples */\r
664         if(!AllocSamples()) {\r
665                 free(nextwav);free(wh);\r
666                 return 0;\r
667         }\r
668         if(!AllocLinear()) {\r
669                 free(nextwav);free(wh);\r
670                 return 0;\r
671         }\r
672         q=of.samples;\r
673         s=wh;\r
674         for(u=0;u<of.numsmp;u++,s++,q++) {\r
675                 q->samplename=DupStr(s->samplename,12,1);\r
676                 q->length   =s->length;\r
677                 q->loopstart=s->loopstart;\r
678                 q->loopend  =s->loopend;\r
679                 q->volume   =s->volume;\r
680                 q->speed    =s->samplerate;\r
681                 if(of.flags&UF_LINEAR)\r
682                         q->speed=speed_to_finetune(s->samplerate<<1,u);\r
683                 q->panning  =s->pan;\r
684                 q->seekpos  =nextwav[u];\r
685 \r
686                 q->flags|=SF_SIGNED;\r
687                 if(s->flags&0x1) q->flags|=SF_LOOP;\r
688                 if(s->flags&0x2) q->flags|=SF_BIDI;\r
689                 if(s->flags&0x8) q->flags|=SF_OWNPAN;\r
690                 if(s->flags&0x4) {\r
691                         q->flags|=SF_16BITS;\r
692                         q->length   >>=1;\r
693                         q->loopstart>>=1;\r
694                         q->loopend  >>=1;\r
695                 }\r
696         }\r
697 \r
698         d=of.instruments;\r
699         s=wh;\r
700         for(u=0;u<of.numins;u++,d++) {\r
701                 for(t=0;t<IMFNOTECNT;t++) {\r
702                         if(d->samplenumber[t]>=of.numsmp)\r
703                                 d->samplenote[t]=255;\r
704                         else if (of.flags&UF_LINEAR) {\r
705                                 int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];\r
706                                 d->samplenote[u]=(note<0)?0:(note>255?255:note);\r
707                         } else\r
708                                 d->samplenote[t]=t;\r
709                 }\r
710         }\r
711 \r
712         free(wh);free(nextwav);\r
713         return 1;\r
714 }\r
715 \r
716 CHAR *IMF_LoadTitle(void)\r
717 {\r
718         CHAR s[31];\r
719 \r
720         _mm_fseek(modreader,0,SEEK_SET);\r
721         if(!_mm_read_UBYTES(s,31,modreader)) return NULL;\r
722 \r
723         return(DupStr(s,31,1));\r
724 }\r
725 \r
726 /*========== Loader information */\r
727 \r
728 MIKMODAPI MLOADER load_imf={\r
729         NULL,\r
730         "IMF",\r
731         "IMF (Imago Orpheus)",\r
732         IMF_Init,\r
733         IMF_Test,\r
734         IMF_Load,\r
735         IMF_Cleanup,\r
736         IMF_LoadTitle\r
737 };\r
738 \r
739 /* ex:set ts=4: */\r