summaryrefslogtreecommitdiff
path: root/apps/plugins/mikmod/load_669.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/load_669.c')
-rw-r--r--apps/plugins/mikmod/load_669.c368
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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51/* header */
52typedef 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 */
64typedef struct S69SAMPLE {
65 CHAR filename[13];
66 SLONG length;
67 SLONG loopbeg;
68 SLONG loopend;
69} S69SAMPLE;
70
71/* encoded note */
72typedef struct S69NOTE {
73 UBYTE a,b,c;
74} S69NOTE;
75
76/*========== Loader variables */
77
78/* current pattern */
79static S69NOTE* s69pat=NULL;
80/* Module header */
81static S69HEADER* mh=NULL;
82
83/* file type identification */
84static CHAR* S69_Version[]={
85 "Composer 669",
86 "Extended 669"
87};
88
89/*========== Loader code */
90
91int 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
125int 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
133void S69_Cleanup(void)
134{
135 MikMod_free(s69pat);
136 MikMod_free(mh);
137}
138
139static 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
248int 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
345CHAR *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
357MIKMODAPI 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: */