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
21 /*==============================================================================
23 $Id: load_669.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
25 Composer 669 module loader
27 ==============================================================================*/
43 #include "mikmod_internals.h"
46 extern int fprintf(FILE *, const char *, ...);
49 /*========== Module structure */
52 typedef struct S69HEADER
{
63 /* sample information */
64 typedef struct S69SAMPLE
{
72 typedef struct S69NOTE
{
76 /*========== Loader variables */
79 static S69NOTE
* s69pat
=NULL
;
81 static S69HEADER
* mh
=NULL
;
83 /* file type identification */
84 static CHAR
* S69_Version
[]={
89 /*========== Loader code */
95 if(!_mm_read_UBYTES(buf
,2,modreader
))
98 if(!memcmp(buf
,"if",2) || !memcmp(buf
,"JN",2)) {
101 /* skip song message */
102 _mm_fseek(modreader
,108,SEEK_CUR
);
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;
110 if((buf
[i
]>=0x80)&&(buf
[i
]!=0xff)) return 0;
111 /* check tempos table */
112 if(!_mm_read_UBYTES(buf
,0x80,modreader
)) return 0;
114 if((!buf
[i
])||(buf
[i
]>32)) return 0;
115 /* check pattern length table */
116 if(!_mm_read_UBYTES(buf
,0x80,modreader
)) return 0;
118 if(buf
[i
]>0x3f) return 0;
127 if(!(s69pat
=(S69NOTE
*)MikMod_malloc(64*8*sizeof(S69NOTE
)))) return 0;
128 if(!(mh
=(S69HEADER
*)MikMod_malloc(sizeof(S69HEADER
)))) return 0;
133 void S69_Cleanup(void)
139 static int S69_LoadPatterns(void)
141 int track
,row
,channel
;
142 UBYTE note
,inst
,vol
,effect
,lastfx
,lastval
;
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 */
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
;
168 /* translate the pattern */
169 for(channel
=0;channel
<8;channel
++) {
171 /* set pattern tempo */
173 UniPTEffect(0xf,mh
->tempos
[track
]);
175 lastfx
=0xff,lastval
=0;
177 for(row
=0;row
<=mh
->breaks
[track
];row
++) {
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
;
187 inst
=((a
&0x3)<<4)|((b
&0xf0)>>4);
193 UniNote(note
+2*OCTAVE
);
194 lastfx
=0xff; /* reset background effect memory */
196 UniPTEffect(0xc,vol
<<2);
199 if ((c
!=0xff)||(lastfx
!=0xff)) {
201 c
=lastfx
,effect
=lastval
;
206 case 0: /* porta up */
207 UniPTEffect(0x1,effect
);
208 lastfx
=c
,lastval
=effect
;
210 case 1: /* porta down */
211 UniPTEffect(0x2,effect
);
212 lastfx
=c
,lastval
=effect
;
214 case 2: /* porta to note */
215 UniPTEffect(0x3,effect
);
216 lastfx
=c
,lastval
=effect
;
218 case 3: /* frequency adjust */
219 /* DMP converts this effect to S3M FF1. Why not ? */
220 UniEffect(UNI_S3MEFFECTF
,0xf0|effect
);
222 case 4: /* vibrato */
223 UniPTEffect(0x4,effect
);
224 lastfx
=c
,lastval
=effect
;
226 case 5: /* set speed */
228 UniPTEffect(0xf,effect
);
230 if(mh
->marker
[0]!=0x69) {
232 fprintf(stderr
,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",
241 if(!(of
.tracks
[tracks
++]=UniDup())) return 0;
248 int S69_Load(int curious
)
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
);
262 if ((mh
->orders
[i
]>=0x80)&&(mh
->orders
[i
]!=0xff)) {
263 _mm_errno
=MMERR_NOT_A_MODULE
;
266 _mm_read_UBYTES(mh
->tempos
,0x80,modreader
);
268 if ((!mh
->tempos
[i
])||(mh
->tempos
[i
]>32)) {
269 _mm_errno
=MMERR_NOT_A_MODULE
;
272 _mm_read_UBYTES(mh
->breaks
,0x80,modreader
);
274 if (mh
->breaks
[i
]>0x3f) {
275 _mm_errno
=MMERR_NOT_A_MODULE
;
279 /* set module variables */
282 of
.songname
=DupStr(mh
->message
,36,1);
283 of
.modtype
=StrDup(S69_Version
[memcmp(mh
->marker
,"JN",2)==0]);
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
];
310 of
.reppos
=mh
->looporder
<of
.numpos
?mh
->looporder
:0;
312 if(!AllocSamples()) return 0;
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
;
328 current
->samplename
=DupStr(sample
.filename
,13,1);
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;
340 if(!S69_LoadPatterns()) return 0;
345 CHAR
*S69_LoadTitle(void)
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
={
360 "669 (Composer 669, Unis 669)",