diff options
Diffstat (limited to 'apps/plugins/mikmod/load_669.c')
-rw-r--r-- | apps/plugins/mikmod/load_669.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_669.c b/apps/plugins/mikmod/load_669.c new file mode 100644 index 0000000000..95b04aa5b1 --- /dev/null +++ b/apps/plugins/mikmod/load_669.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS for complete list. | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU Library General Public License as | ||
7 | published by the Free Software Foundation; either version 2 of | ||
8 | the License, or (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
18 | 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /*============================================================================== | ||
22 | |||
23 | $Id: load_669.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | Composer 669 module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | /* header */ | ||
52 | typedef struct S69HEADER { | ||
53 | UBYTE marker[2]; | ||
54 | CHAR message[108]; | ||
55 | UBYTE nos; | ||
56 | UBYTE rbnop; | ||
57 | UBYTE looporder; | ||
58 | UBYTE orders[0x80]; | ||
59 | UBYTE tempos[0x80]; | ||
60 | UBYTE breaks[0x80]; | ||
61 | } S69HEADER; | ||
62 | |||
63 | /* sample information */ | ||
64 | typedef struct S69SAMPLE { | ||
65 | CHAR filename[13]; | ||
66 | SLONG length; | ||
67 | SLONG loopbeg; | ||
68 | SLONG loopend; | ||
69 | } S69SAMPLE; | ||
70 | |||
71 | /* encoded note */ | ||
72 | typedef struct S69NOTE { | ||
73 | UBYTE a,b,c; | ||
74 | } S69NOTE; | ||
75 | |||
76 | /*========== Loader variables */ | ||
77 | |||
78 | /* current pattern */ | ||
79 | static S69NOTE* s69pat=NULL; | ||
80 | /* Module header */ | ||
81 | static S69HEADER* mh=NULL; | ||
82 | |||
83 | /* file type identification */ | ||
84 | static CHAR* S69_Version[]={ | ||
85 | "Composer 669", | ||
86 | "Extended 669" | ||
87 | }; | ||
88 | |||
89 | /*========== Loader code */ | ||
90 | |||
91 | int S69_Test(void) | ||
92 | { | ||
93 | UBYTE buf[0x80]; | ||
94 | |||
95 | if(!_mm_read_UBYTES(buf,2,modreader)) | ||
96 | return 0; | ||
97 | /* look for id */ | ||
98 | if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) { | ||
99 | int i; | ||
100 | |||
101 | /* skip song message */ | ||
102 | _mm_fseek(modreader,108,SEEK_CUR); | ||
103 | /* sanity checks */ | ||
104 | if(_mm_read_UBYTE(modreader) > 64) return 0; | ||
105 | if(_mm_read_UBYTE(modreader) > 128) return 0; | ||
106 | if(_mm_read_UBYTE(modreader) > 127) return 0; | ||
107 | /* check order table */ | ||
108 | if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0; | ||
109 | for(i=0;i<0x80;i++) | ||
110 | if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0; | ||
111 | /* check tempos table */ | ||
112 | if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0; | ||
113 | for(i=0;i<0x80;i++) | ||
114 | if((!buf[i])||(buf[i]>32)) return 0; | ||
115 | /* check pattern length table */ | ||
116 | if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0; | ||
117 | for(i=0;i<0x80;i++) | ||
118 | if(buf[i]>0x3f) return 0; | ||
119 | } else | ||
120 | return 0; | ||
121 | |||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | int S69_Init(void) | ||
126 | { | ||
127 | if(!(s69pat=(S69NOTE *)MikMod_malloc(64*8*sizeof(S69NOTE)))) return 0; | ||
128 | if(!(mh=(S69HEADER *)MikMod_malloc(sizeof(S69HEADER)))) return 0; | ||
129 | |||
130 | return 1; | ||
131 | } | ||
132 | |||
133 | void S69_Cleanup(void) | ||
134 | { | ||
135 | MikMod_free(s69pat); | ||
136 | MikMod_free(mh); | ||
137 | } | ||
138 | |||
139 | static int S69_LoadPatterns(void) | ||
140 | { | ||
141 | int track,row,channel; | ||
142 | UBYTE note,inst,vol,effect,lastfx,lastval; | ||
143 | S69NOTE *cur; | ||
144 | int tracks=0; | ||
145 | |||
146 | if(!AllocPatterns()) return 0; | ||
147 | if(!AllocTracks()) return 0; | ||
148 | |||
149 | for(track=0;track<of.numpat;track++) { | ||
150 | /* set pattern break locations */ | ||
151 | of.pattrows[track]=mh->breaks[track]+1; | ||
152 | |||
153 | /* load the 669 pattern */ | ||
154 | cur=s69pat; | ||
155 | for(row=0;row<64;row++) { | ||
156 | for(channel=0;channel<8;channel++,cur++) { | ||
157 | cur->a = _mm_read_UBYTE(modreader); | ||
158 | cur->b = _mm_read_UBYTE(modreader); | ||
159 | cur->c = _mm_read_UBYTE(modreader); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | if(_mm_eof(modreader)) { | ||
164 | _mm_errno = MMERR_LOADING_PATTERN; | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | /* translate the pattern */ | ||
169 | for(channel=0;channel<8;channel++) { | ||
170 | UniReset(); | ||
171 | /* set pattern tempo */ | ||
172 | UniPTEffect(0xf,78); | ||
173 | UniPTEffect(0xf,mh->tempos[track]); | ||
174 | |||
175 | lastfx=0xff,lastval=0; | ||
176 | |||
177 | for(row=0;row<=mh->breaks[track];row++) { | ||
178 | int a,b,c; | ||
179 | |||
180 | /* fetch the encoded note */ | ||
181 | a=s69pat[(row*8)+channel].a; | ||
182 | b=s69pat[(row*8)+channel].b; | ||
183 | c=s69pat[(row*8)+channel].c; | ||
184 | |||
185 | /* decode it */ | ||
186 | note=a>>2; | ||
187 | inst=((a&0x3)<<4)|((b&0xf0)>>4); | ||
188 | vol=b&0xf; | ||
189 | |||
190 | if (a<0xff) { | ||
191 | if (a<0xfe) { | ||
192 | UniInstrument(inst); | ||
193 | UniNote(note+2*OCTAVE); | ||
194 | lastfx=0xff; /* reset background effect memory */ | ||
195 | } | ||
196 | UniPTEffect(0xc,vol<<2); | ||
197 | } | ||
198 | |||
199 | if ((c!=0xff)||(lastfx!=0xff)) { | ||
200 | if(c==0xff) | ||
201 | c=lastfx,effect=lastval; | ||
202 | else | ||
203 | effect=c&0xf; | ||
204 | |||
205 | switch(c>>4) { | ||
206 | case 0: /* porta up */ | ||
207 | UniPTEffect(0x1,effect); | ||
208 | lastfx=c,lastval=effect; | ||
209 | break; | ||
210 | case 1: /* porta down */ | ||
211 | UniPTEffect(0x2,effect); | ||
212 | lastfx=c,lastval=effect; | ||
213 | break; | ||
214 | case 2: /* porta to note */ | ||
215 | UniPTEffect(0x3,effect); | ||
216 | lastfx=c,lastval=effect; | ||
217 | break; | ||
218 | case 3: /* frequency adjust */ | ||
219 | /* DMP converts this effect to S3M FF1. Why not ? */ | ||
220 | UniEffect(UNI_S3MEFFECTF,0xf0|effect); | ||
221 | break; | ||
222 | case 4: /* vibrato */ | ||
223 | UniPTEffect(0x4,effect); | ||
224 | lastfx=c,lastval=effect; | ||
225 | break; | ||
226 | case 5: /* set speed */ | ||
227 | if (effect) | ||
228 | UniPTEffect(0xf,effect); | ||
229 | else | ||
230 | if(mh->marker[0]!=0x69) { | ||
231 | #ifdef MIKMOD_DEBUG | ||
232 | fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n", | ||
233 | track,row,channel); | ||
234 | #endif | ||
235 | } | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | UniNewline(); | ||
240 | } | ||
241 | if(!(of.tracks[tracks++]=UniDup())) return 0; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | return 1; | ||
246 | } | ||
247 | |||
248 | int S69_Load(int curious) | ||
249 | { | ||
250 | int i; | ||
251 | SAMPLE *current; | ||
252 | S69SAMPLE sample; | ||
253 | |||
254 | /* module header */ | ||
255 | _mm_read_UBYTES(mh->marker,2,modreader); | ||
256 | _mm_read_UBYTES(mh->message,108,modreader); | ||
257 | mh->nos=_mm_read_UBYTE(modreader); | ||
258 | mh->rbnop=_mm_read_UBYTE(modreader); | ||
259 | mh->looporder=_mm_read_UBYTE(modreader); | ||
260 | _mm_read_UBYTES(mh->orders,0x80,modreader); | ||
261 | for(i=0;i<0x80;i++) | ||
262 | if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) { | ||
263 | _mm_errno=MMERR_NOT_A_MODULE; | ||
264 | return 1; | ||
265 | } | ||
266 | _mm_read_UBYTES(mh->tempos,0x80,modreader); | ||
267 | for(i=0;i<0x80;i++) | ||
268 | if ((!mh->tempos[i])||(mh->tempos[i]>32)) { | ||
269 | _mm_errno=MMERR_NOT_A_MODULE; | ||
270 | return 1; | ||
271 | } | ||
272 | _mm_read_UBYTES(mh->breaks,0x80,modreader); | ||
273 | for(i=0;i<0x80;i++) | ||
274 | if (mh->breaks[i]>0x3f) { | ||
275 | _mm_errno=MMERR_NOT_A_MODULE; | ||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | /* set module variables */ | ||
280 | of.initspeed=4; | ||
281 | of.inittempo=78; | ||
282 | of.songname=DupStr(mh->message,36,1); | ||
283 | of.modtype=StrDup(S69_Version[memcmp(mh->marker,"JN",2)==0]); | ||
284 | of.numchn=8; | ||
285 | of.numpat=mh->rbnop; | ||
286 | of.numins=of.numsmp=mh->nos; | ||
287 | of.numtrk=of.numchn*of.numpat; | ||
288 | of.flags=UF_XMPERIODS|UF_LINEAR; | ||
289 | |||
290 | for(i= 35;(i>= 0)&&(mh->message[i]==' ');i--) mh->message[i]=0; | ||
291 | for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0; | ||
292 | for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0; | ||
293 | if((mh->message[0])||(mh->message[36])||(mh->message[72])) | ||
294 | if((of.comment=(CHAR*)MikMod_malloc(3*(36+1)+1))) { | ||
295 | strncpy(of.comment,mh->message,36); | ||
296 | strcat(of.comment,"\r"); | ||
297 | if (mh->message[36]) strncat(of.comment,mh->message+36,36); | ||
298 | strcat(of.comment,"\r"); | ||
299 | if (mh->message[72]) strncat(of.comment,mh->message+72,36); | ||
300 | strcat(of.comment,"\r"); | ||
301 | of.comment[3*(36+1)]=0; | ||
302 | } | ||
303 | |||
304 | if(!AllocPositions(0x80)) return 0; | ||
305 | for(i=0;i<0x80;i++) { | ||
306 | if(mh->orders[i]>=mh->rbnop) break; | ||
307 | of.positions[i]=mh->orders[i]; | ||
308 | } | ||
309 | of.numpos=i; | ||
310 | of.reppos=mh->looporder<of.numpos?mh->looporder:0; | ||
311 | |||
312 | if(!AllocSamples()) return 0; | ||
313 | current=of.samples; | ||
314 | |||
315 | for(i=0;i<of.numins;i++) { | ||
316 | /* sample information */ | ||
317 | _mm_read_UBYTES((UBYTE*)sample.filename,13,modreader); | ||
318 | sample.length=_mm_read_I_SLONG(modreader); | ||
319 | sample.loopbeg=_mm_read_I_SLONG(modreader); | ||
320 | sample.loopend=_mm_read_I_SLONG(modreader); | ||
321 | if (sample.loopend==0xfffff) sample.loopend=0; | ||
322 | |||
323 | if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) { | ||
324 | _mm_errno = MMERR_LOADING_HEADER; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | current->samplename=DupStr(sample.filename,13,1); | ||
329 | current->seekpos=0; | ||
330 | current->speed=0; | ||
331 | current->length=sample.length; | ||
332 | current->loopstart=sample.loopbeg; | ||
333 | current->loopend=sample.loopend; | ||
334 | current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0; | ||
335 | current->volume=64; | ||
336 | |||
337 | current++; | ||
338 | } | ||
339 | |||
340 | if(!S69_LoadPatterns()) return 0; | ||
341 | |||
342 | return 1; | ||
343 | } | ||
344 | |||
345 | CHAR *S69_LoadTitle(void) | ||
346 | { | ||
347 | CHAR s[36]; | ||
348 | |||
349 | _mm_fseek(modreader,2,SEEK_SET); | ||
350 | if(!_mm_read_UBYTES(s,36,modreader)) return NULL; | ||
351 | |||
352 | return(DupStr(s,36,1)); | ||
353 | } | ||
354 | |||
355 | /*========== Loader information */ | ||
356 | |||
357 | MIKMODAPI MLOADER load_669={ | ||
358 | NULL, | ||
359 | "669", | ||
360 | "669 (Composer 669, Unis 669)", | ||
361 | S69_Init, | ||
362 | S69_Test, | ||
363 | S69_Load, | ||
364 | S69_Cleanup, | ||
365 | S69_LoadTitle | ||
366 | }; | ||
367 | |||
368 | /* ex:set ts=4: */ | ||