Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_669.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_669.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
24 \r
25   Composer 669 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 /* header */\r
52 typedef struct S69HEADER {   \r
53         UBYTE   marker[2];\r
54         CHAR    message[108];\r
55         UBYTE   nos;\r
56         UBYTE   nopa;\r
57         UBYTE   looporder;\r
58         UBYTE   orders[0x80];\r
59         UBYTE   tempos[0x80];\r
60         UBYTE   breaks[0x80];\r
61 } S69HEADER;\r
62 \r
63 /* sample information */\r
64 typedef struct S69SAMPLE {\r
65         CHAR    filename[13];\r
66         SLONG   length;\r
67         SLONG   loopbeg;\r
68         SLONG   loopend;\r
69 } S69SAMPLE;\r
70 \r
71 /* encoded note */\r
72 typedef struct S69NOTE {\r
73         UBYTE   a,b,c;\r
74 } S69NOTE;\r
75 \r
76 /*========== Loader variables */\r
77 \r
78 /* current pattern */\r
79 static  S69NOTE* s69pat=NULL;\r
80 /* Module header */\r
81 static  S69HEADER* mh=NULL;\r
82 \r
83 /* file type identification */\r
84 static  CHAR* S69_Version[]={\r
85         "Composer 669",\r
86         "Extended 669"\r
87 };\r
88 \r
89 /*========== Loader code */\r
90 \r
91 BOOL S69_Test(void)\r
92 {\r
93         UBYTE buf[0x80];\r
94 \r
95         if(!_mm_read_UBYTES(buf,2,modreader))\r
96                 return 0;\r
97         /* look for id */\r
98         if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) {\r
99                 int i;\r
100 \r
101                 /* skip song message */\r
102                 _mm_fseek(modreader,108,SEEK_CUR);\r
103                 /* sanity checks */\r
104                 if(_mm_read_UBYTE(modreader) > 64) return 0;\r
105                 if(_mm_read_UBYTE(modreader) > 128) return 0;\r
106                 if(_mm_read_UBYTE(modreader) > 127) return 0;\r
107                 /* check order table */\r
108                 if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
109                 for(i=0;i<0x80;i++)\r
110                         if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0;\r
111                 /* check tempos table */\r
112                 if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
113                 for(i=0;i<0x80;i++)\r
114                         if((!buf[i])||(buf[i]>32)) return 0;\r
115                 /* check pattern length table */\r
116                 if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
117                 for(i=0;i<0x80;i++)\r
118                         if(buf[i]>0x3f) return 0;\r
119         } else\r
120                 return 0;\r
121 \r
122         return 1;\r
123 }\r
124 \r
125 BOOL S69_Init(void)\r
126 {\r
127         if(!(s69pat=(S69NOTE *)_mm_malloc(64*8*sizeof(S69NOTE)))) return 0;\r
128         if(!(mh=(S69HEADER *)_mm_malloc(sizeof(S69HEADER)))) return 0;\r
129 \r
130         return 1;\r
131 }\r
132 \r
133 void S69_Cleanup(void)\r
134 {\r
135         _mm_free(s69pat);\r
136         _mm_free(mh);\r
137 }\r
138 \r
139 static BOOL S69_LoadPatterns(void)\r
140 {\r
141         int track,row,channel;\r
142         UBYTE note,inst,vol,effect,lastfx,lastval;\r
143         S69NOTE *cur;\r
144         int tracks=0;\r
145         \r
146         if(!AllocPatterns()) return 0;\r
147         if(!AllocTracks()) return 0;\r
148 \r
149         for(track=0;track<of.numpat;track++) {\r
150                 /* set pattern break locations */\r
151                 of.pattrows[track]=mh->breaks[track]+1;\r
152 \r
153                 /* load the 669 pattern */\r
154                 cur=s69pat;\r
155                 for(row=0;row<64;row++) {\r
156                         for(channel=0;channel<8;channel++,cur++) {\r
157                                 cur->a = _mm_read_UBYTE(modreader);\r
158                                 cur->b = _mm_read_UBYTE(modreader);\r
159                                 cur->c = _mm_read_UBYTE(modreader);\r
160                         }\r
161                 }\r
162 \r
163                 if(_mm_eof(modreader)) {\r
164                         _mm_errno = MMERR_LOADING_PATTERN;\r
165                         return 0;\r
166                 }\r
167 \r
168                 /* translate the pattern */\r
169                 for(channel=0;channel<8;channel++) {\r
170                         UniReset();\r
171                         /* set pattern tempo */\r
172                         UniPTEffect(0xf,78);\r
173                         UniPTEffect(0xf,mh->tempos[track]);\r
174 \r
175                         lastfx=0xff,lastval=0;\r
176 \r
177                         for(row=0;row<=mh->breaks[track];row++) {\r
178                                 int a,b,c;\r
179 \r
180                                 /* fetch the encoded note */\r
181                                 a=s69pat[(row*8)+channel].a;\r
182                                 b=s69pat[(row*8)+channel].b;\r
183                                 c=s69pat[(row*8)+channel].c;\r
184 \r
185                                 /* decode it */\r
186                                 note=a>>2;\r
187                                 inst=((a&0x3)<<4)|((b&0xf0)>>4);\r
188                                 vol=b&0xf;\r
189 \r
190                                 if (a<0xff) {\r
191                                         if (a<0xfe) {\r
192                                                 UniInstrument(inst);\r
193                                                 UniNote(note+2*OCTAVE);\r
194                                                 lastfx=0xff; /* reset background effect memory */\r
195                                         }\r
196                                         UniPTEffect(0xc,vol<<2);\r
197                                 }\r
198 \r
199                                 if ((c!=0xff)||(lastfx!=0xff)) {\r
200                                         if(c==0xff)\r
201                                                 c=lastfx,effect=lastval;\r
202                                         else\r
203                                                 effect=c&0xf;\r
204 \r
205                                         switch(c>>4) {\r
206                                                 case 0: /* porta up */\r
207                                                         UniPTEffect(0x1,effect);\r
208                                                         lastfx=c,lastval=effect;\r
209                                                         break;\r
210                                                 case 1: /* porta down */\r
211                                                         UniPTEffect(0x2,effect);\r
212                                                         lastfx=c,lastval=effect;\r
213                                                         break;\r
214                                                 case 2: /* porta to note */\r
215                                                         UniPTEffect(0x3,effect);\r
216                                                         lastfx=c,lastval=effect;\r
217                                                         break;\r
218                                                 case 3: /* frequency adjust */\r
219                                                         /* DMP converts this effect to S3M FF1. Why not ? */\r
220                                                         UniEffect(UNI_S3MEFFECTF,0xf0|effect);\r
221                                                         break;\r
222                                                 case 4: /* vibrato */\r
223                                                         UniPTEffect(0x4,effect);\r
224                                                         lastfx=c,lastval=effect;\r
225                                                         break;\r
226                                                 case 5: /* set speed */\r
227                                                         if (effect)\r
228                                                                 UniPTEffect(0xf,effect);\r
229                                                         else \r
230                                                           if(mh->marker[0]!=0x69) {\r
231 #ifdef MIKMOD_DEBUG\r
232                                                                 fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",\r
233                                                                        track,row,channel);\r
234 #endif\r
235                                                         }\r
236                                                         break;\r
237                                         }\r
238                                 }\r
239                                 UniNewline();\r
240                         }\r
241                         if(!(of.tracks[tracks++]=UniDup())) return 0;\r
242                 }\r
243         }\r
244 \r
245         return 1;\r
246 }\r
247 \r
248 BOOL S69_Load(BOOL curious)\r
249 {\r
250         int i;\r
251         SAMPLE *current;\r
252         S69SAMPLE sample;\r
253         (void)curious;\r
254 \r
255         /* module header */\r
256         _mm_read_UBYTES(mh->marker,2,modreader);\r
257         _mm_read_UBYTES(mh->message,108,modreader);\r
258         mh->nos=_mm_read_UBYTE(modreader);\r
259         mh->nopa=_mm_read_UBYTE(modreader);\r
260         mh->looporder=_mm_read_UBYTE(modreader);\r
261         _mm_read_UBYTES(mh->orders,0x80,modreader);\r
262         for(i=0;i<0x80;i++)\r
263                 if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) {\r
264                         _mm_errno=MMERR_NOT_A_MODULE;\r
265                         return 1;\r
266                 }\r
267         _mm_read_UBYTES(mh->tempos,0x80,modreader);\r
268         for(i=0;i<0x80;i++)\r
269                 if ((!mh->tempos[i])||(mh->tempos[i]>32)) {\r
270                         _mm_errno=MMERR_NOT_A_MODULE;\r
271                         return 1;\r
272                 }\r
273         _mm_read_UBYTES(mh->breaks,0x80,modreader);\r
274         for(i=0;i<0x80;i++)\r
275                 if (mh->breaks[i]>0x3f) {\r
276                         _mm_errno=MMERR_NOT_A_MODULE;\r
277                         return 1;\r
278                 }\r
279 \r
280         /* set module variables */\r
281         of.initspeed=4;\r
282         of.inittempo=78;\r
283         of.songname=DupStr(mh->message,36,1);\r
284         of.modtype=strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]);\r
285         of.numchn=8;\r
286         of.numpat=mh->nopa;\r
287         of.numins=of.numsmp=mh->nos;\r
288         of.numtrk=of.numchn*of.numpat;\r
289         of.flags=UF_XMPERIODS|UF_LINEAR;\r
290 \r
291         for(i=   35;(i>=   0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
292         for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
293         for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
294         if((mh->message[0])||(mh->message[36])||(mh->message[72]))\r
295                 if((of.comment=(CHAR*)_mm_malloc(3*(36+1)+1))) {\r
296                         strncpy(of.comment,mh->message,36);\r
297                         strcat(of.comment,"\r");\r
298                         if (mh->message[36]) strncat(of.comment,mh->message+36,36);\r
299                         strcat(of.comment,"\r");\r
300                         if (mh->message[72]) strncat(of.comment,mh->message+72,36);\r
301                         strcat(of.comment,"\r");\r
302                         of.comment[3*(36+1)]=0;\r
303                 }\r
304 \r
305         if(!AllocPositions(0x80)) return 0;\r
306         for(i=0;i<0x80;i++) {\r
307                 if(mh->orders[i]>=mh->nopa) break;\r
308                 of.positions[i]=mh->orders[i];\r
309         }\r
310         of.numpos=i;\r
311         of.reppos=mh->looporder<of.numpos?mh->looporder:0;\r
312 \r
313         if(!AllocSamples()) return 0;\r
314         current=of.samples;\r
315 \r
316         for(i=0;i<of.numins;i++) {\r
317                 /* sample information */\r
318                 _mm_read_UBYTES((UBYTE*)sample.filename,13,modreader);\r
319                 sample.length=_mm_read_I_SLONG(modreader);\r
320                 sample.loopbeg=_mm_read_I_SLONG(modreader);\r
321                 sample.loopend=_mm_read_I_SLONG(modreader);\r
322                 if (sample.loopend==0xfffff) sample.loopend=0;\r
323 \r
324                 if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {\r
325                         _mm_errno = MMERR_LOADING_HEADER;\r
326                         return 0;\r
327                 }\r
328 \r
329                 current->samplename=DupStr(sample.filename,13,1);\r
330                 current->seekpos=0;\r
331                 current->speed=0;\r
332                 current->length=sample.length;\r
333                 current->loopstart=sample.loopbeg;\r
334                 current->loopend=sample.loopend;\r
335                 current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0;\r
336                 current->volume=64;\r
337 \r
338                 current++;\r
339         }\r
340 \r
341         if(!S69_LoadPatterns()) return 0;\r
342 \r
343         return 1;\r
344 }\r
345 \r
346 CHAR *S69_LoadTitle(void)\r
347 {\r
348         CHAR s[36];\r
349 \r
350         _mm_fseek(modreader,2,SEEK_SET);\r
351         if(!_mm_read_UBYTES(s,36,modreader)) return NULL;\r
352 \r
353         return(DupStr(s,36,1));\r
354 }\r
355 \r
356 /*========== Loader information */\r
357 \r
358 MIKMODAPI MLOADER load_669={\r
359         NULL,\r
360         "669",\r
361         "669 (Composer 669, Unis 669)",\r
362         S69_Init,\r
363         S69_Test,\r
364         S69_Load,\r
365         S69_Cleanup,\r
366         S69_LoadTitle\r
367 };\r
368 \r
369 /* ex:set ts=4: */\r