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
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
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
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
21 /*==============================================================================
\r
23 $Id: load_669.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
\r
25 Composer 669 module loader
\r
27 ==============================================================================*/
\r
29 #ifdef HAVE_CONFIG_H
\r
33 #ifdef HAVE_UNISTD_H
\r
38 #ifdef HAVE_MEMORY_H
\r
43 #include "mikmod_internals.h"
\r
46 extern int fprintf(FILE *, const char *, ...);
\r
49 /*========== Module structure */
\r
52 typedef struct S69HEADER {
\r
63 /* sample information */
\r
64 typedef struct S69SAMPLE {
\r
72 typedef struct S69NOTE {
\r
76 /*========== Loader variables */
\r
78 /* current pattern */
\r
79 static S69NOTE* s69pat=NULL;
\r
81 static S69HEADER* mh=NULL;
\r
83 /* file type identification */
\r
84 static CHAR* S69_Version[]={
\r
89 /*========== Loader code */
\r
95 if(!_mm_read_UBYTES(buf,2,modreader))
\r
98 if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) {
\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
125 BOOL S69_Init(void)
\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
133 void S69_Cleanup(void)
\r
139 static BOOL S69_LoadPatterns(void)
\r
141 int track,row,channel;
\r
142 UBYTE note,inst,vol,effect,lastfx,lastval;
\r
146 if(!AllocPatterns()) return 0;
\r
147 if(!AllocTracks()) return 0;
\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
153 /* load the 669 pattern */
\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
163 if(_mm_eof(modreader)) {
\r
164 _mm_errno = MMERR_LOADING_PATTERN;
\r
168 /* translate the pattern */
\r
169 for(channel=0;channel<8;channel++) {
\r
171 /* set pattern tempo */
\r
172 UniPTEffect(0xf,78);
\r
173 UniPTEffect(0xf,mh->tempos[track]);
\r
175 lastfx=0xff,lastval=0;
\r
177 for(row=0;row<=mh->breaks[track];row++) {
\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
187 inst=((a&0x3)<<4)|((b&0xf0)>>4);
\r
192 UniInstrument(inst);
\r
193 UniNote(note+2*OCTAVE);
\r
194 lastfx=0xff; /* reset background effect memory */
\r
196 UniPTEffect(0xc,vol<<2);
\r
199 if ((c!=0xff)||(lastfx!=0xff)) {
\r
201 c=lastfx,effect=lastval;
\r
206 case 0: /* porta up */
\r
207 UniPTEffect(0x1,effect);
\r
208 lastfx=c,lastval=effect;
\r
210 case 1: /* porta down */
\r
211 UniPTEffect(0x2,effect);
\r
212 lastfx=c,lastval=effect;
\r
214 case 2: /* porta to note */
\r
215 UniPTEffect(0x3,effect);
\r
216 lastfx=c,lastval=effect;
\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
222 case 4: /* vibrato */
\r
223 UniPTEffect(0x4,effect);
\r
224 lastfx=c,lastval=effect;
\r
226 case 5: /* set speed */
\r
228 UniPTEffect(0xf,effect);
\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
241 if(!(of.tracks[tracks++]=UniDup())) return 0;
\r
248 BOOL S69_Load(BOOL curious)
\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
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
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
280 /* set module variables */
\r
283 of.songname=DupStr(mh->message,36,1);
\r
284 of.modtype=strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]);
\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
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
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
311 of.reppos=mh->looporder<of.numpos?mh->looporder:0;
\r
313 if(!AllocSamples()) return 0;
\r
314 current=of.samples;
\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
324 if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {
\r
325 _mm_errno = MMERR_LOADING_HEADER;
\r
329 current->samplename=DupStr(sample.filename,13,1);
\r
330 current->seekpos=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
341 if(!S69_LoadPatterns()) return 0;
\r
346 CHAR *S69_LoadTitle(void)
\r
350 _mm_fseek(modreader,2,SEEK_SET);
\r
351 if(!_mm_read_UBYTES(s,36,modreader)) return NULL;
\r
353 return(DupStr(s,36,1));
\r
356 /*========== Loader information */
\r
358 MIKMODAPI MLOADER load_669={
\r
361 "669 (Composer 669, Unis 669)",
\r