Add AI to the pong plugin, to allow single-player operation.
[kugel-rb.git] / apps / plugins / mikmod / load_669.c
blob95b04aa5b1f707d485e881a0d35145af11e940c8
1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for complete list.
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.
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.
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.
21 /*==============================================================================
23 $Id: load_669.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
25 Composer 669 module loader
27 ==============================================================================*/
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
37 #include <stdio.h>
38 #ifdef HAVE_MEMORY_H
39 #include <memory.h>
40 #endif
41 #include <string.h>
43 #include "mikmod_internals.h"
45 #ifdef SUNOS
46 extern int fprintf(FILE *, const char *, ...);
47 #endif
49 /*========== Module structure */
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;
63 /* sample information */
64 typedef struct S69SAMPLE {
65 CHAR filename[13];
66 SLONG length;
67 SLONG loopbeg;
68 SLONG loopend;
69 } S69SAMPLE;
71 /* encoded note */
72 typedef struct S69NOTE {
73 UBYTE a,b,c;
74 } S69NOTE;
76 /*========== Loader variables */
78 /* current pattern */
79 static S69NOTE* s69pat=NULL;
80 /* Module header */
81 static S69HEADER* mh=NULL;
83 /* file type identification */
84 static CHAR* S69_Version[]={
85 "Composer 669",
86 "Extended 669"
89 /*========== Loader code */
91 int S69_Test(void)
93 UBYTE buf[0x80];
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;
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;
122 return 1;
125 int S69_Init(void)
127 if(!(s69pat=(S69NOTE *)MikMod_malloc(64*8*sizeof(S69NOTE)))) return 0;
128 if(!(mh=(S69HEADER *)MikMod_malloc(sizeof(S69HEADER)))) return 0;
130 return 1;
133 void S69_Cleanup(void)
135 MikMod_free(s69pat);
136 MikMod_free(mh);
139 static int S69_LoadPatterns(void)
141 int track,row,channel;
142 UBYTE note,inst,vol,effect,lastfx,lastval;
143 S69NOTE *cur;
144 int tracks=0;
146 if(!AllocPatterns()) return 0;
147 if(!AllocTracks()) return 0;
149 for(track=0;track<of.numpat;track++) {
150 /* set pattern break locations */
151 of.pattrows[track]=mh->breaks[track]+1;
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);
163 if(_mm_eof(modreader)) {
164 _mm_errno = MMERR_LOADING_PATTERN;
165 return 0;
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]);
175 lastfx=0xff,lastval=0;
177 for(row=0;row<=mh->breaks[track];row++) {
178 int a,b,c;
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;
185 /* decode it */
186 note=a>>2;
187 inst=((a&0x3)<<4)|((b&0xf0)>>4);
188 vol=b&0xf;
190 if (a<0xff) {
191 if (a<0xfe) {
192 UniInstrument(inst);
193 UniNote(note+2*OCTAVE);
194 lastfx=0xff; /* reset background effect memory */
196 UniPTEffect(0xc,vol<<2);
199 if ((c!=0xff)||(lastfx!=0xff)) {
200 if(c==0xff)
201 c=lastfx,effect=lastval;
202 else
203 effect=c&0xf;
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
236 break;
239 UniNewline();
241 if(!(of.tracks[tracks++]=UniDup())) return 0;
245 return 1;
248 int S69_Load(int curious)
250 int i;
251 SAMPLE *current;
252 S69SAMPLE sample;
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;
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;
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;
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;
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;
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];
309 of.numpos=i;
310 of.reppos=mh->looporder<of.numpos?mh->looporder:0;
312 if(!AllocSamples()) return 0;
313 current=of.samples;
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;
323 if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {
324 _mm_errno = MMERR_LOADING_HEADER;
325 return 0;
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;
337 current++;
340 if(!S69_LoadPatterns()) return 0;
342 return 1;
345 CHAR *S69_LoadTitle(void)
347 CHAR s[36];
349 _mm_fseek(modreader,2,SEEK_SET);
350 if(!_mm_read_UBYTES(s,36,modreader)) return NULL;
352 return(DupStr(s,36,1));
355 /*========== Loader information */
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
368 /* ex:set ts=4: */