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_stx.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
25 STMIK 0.2 (STX) module loader
27 ==============================================================================*/
31 Written by Claudio Matsuoka <claudio@helllabs.org>
49 #include "mikmod_internals.h"
52 extern int fprintf(FILE *, const char *, ...);
55 /*========== Module structure */
58 typedef struct STXHEADER
{
65 UWORD chnptr
; /* not sure */
81 /* sample information */
82 typedef struct STXSAMPLE
{
100 typedef struct STXNOTE
{
101 UBYTE note
,ins
,vol
,cmd
,inf
;
104 /*========== Loader variables */
106 static STXNOTE
*stxbuf
= NULL
; /* pointer to a complete STX pattern */
107 static STXHEADER
*mh
= NULL
;
108 static UWORD
*paraptr
= NULL
; /* parapointer array (see STX docs) */
110 /*========== Loader code */
112 static int STX_Test(void)
117 _mm_fseek(modreader
,0x3C,SEEK_SET
);
118 if(!_mm_read_UBYTES(id
,4,modreader
)) return 0;
119 if(memcmp(id
,"SCRM",4)) return 0;
121 _mm_fseek(modreader
,0x14,SEEK_SET
);
122 if(!_mm_read_UBYTES(id
,8,modreader
)) return 0;
124 for(t
=0;t
<STM_NTRACKERS
;t
++)
125 if(!memcmp(id
,STM_Signatures
[t
],8)) return 1;
130 static int STX_Init(void)
132 if(!(stxbuf
=(STXNOTE
*)MikMod_malloc(4*64*sizeof(STXNOTE
)))) return 0;
133 if(!(mh
=(STXHEADER
*)MikMod_malloc(sizeof(STXHEADER
)))) return 0;
134 if(!(poslookup
=(UBYTE
*)MikMod_malloc(sizeof(UBYTE
)*256))) return 0;
135 memset(poslookup
,-1,256);
140 static void STX_Cleanup(void)
143 MikMod_free(paraptr
);
144 MikMod_free(poslookup
);
148 static int STX_ReadPattern(void)
153 /* clear pattern data */
154 memset(stxbuf
,255,4*64*sizeof(STXNOTE
));
157 flag
=_mm_read_UBYTE(modreader
);
159 if(_mm_eof(modreader
)) {
160 _mm_errno
= MMERR_LOADING_PATTERN
;
168 n
=&stxbuf
[(64U*ch
)+row
];
173 n
->note
=_mm_read_UBYTE(modreader
);
174 n
->ins
=_mm_read_UBYTE(modreader
);
177 n
->vol
=_mm_read_UBYTE(modreader
);
178 if(n
->vol
>64) n
->vol
=64;
181 n
->cmd
=_mm_read_UBYTE(modreader
);
182 n
->inf
=_mm_read_UBYTE(modreader
);
189 static UBYTE
* STX_ConvertTrack(STXNOTE
* tr
)
195 UBYTE note
,ins
,vol
,cmd
,inf
;
203 if((ins
)&&(ins
!=255)) UniInstrument(ins
-1);
204 if((note
)&&(note
!=255)) {
206 UniPTEffect(0xc,0); /* note cut command */
208 } else UniNote(24+((note
>>4)*OCTAVE
)+(note
&0xf)); /* normal note */
211 if(vol
<255) UniPTEffect(0xc,vol
);
213 if(cmd
<255) switch(cmd
) {
214 case 1: /* Axx set speed to xx */
215 UniPTEffect(0xf,inf
>>4);
217 case 2: /* Bxx position jump */
218 UniPTEffect(0xb,inf
);
220 case 3: /* Cxx patternbreak to row xx */
221 UniPTEffect(0xd,(((inf
&0xf0)>>4)*10)+(inf
&0xf));
223 case 4: /* Dxy volumeslide */
224 UniEffect(UNI_S3MEFFECTD
,inf
);
226 case 5: /* Exy toneslide down */
227 UniEffect(UNI_S3MEFFECTE
,inf
);
229 case 6: /* Fxy toneslide up */
230 UniEffect(UNI_S3MEFFECTF
,inf
);
232 case 7: /* Gxx Tone portamento,speed xx */
233 UniPTEffect(0x3,inf
);
235 case 8: /* Hxy vibrato */
236 UniPTEffect(0x4,inf
);
238 case 9: /* Ixy tremor, ontime x, offtime y */
239 UniEffect(UNI_S3MEFFECTI
,inf
);
241 case 0: /* protracker arpeggio */
244 case 0xa: /* Jxy arpeggio */
245 UniPTEffect(0x0,inf
);
247 case 0xb: /* Kxy Dual command H00 & Dxy */
249 UniEffect(UNI_S3MEFFECTD
,inf
);
251 case 0xc: /* Lxy Dual command G00 & Dxy */
253 UniEffect(UNI_S3MEFFECTD
,inf
);
255 /* Support all these above, since ST2 can LOAD these values but can
256 actually only play up to J - and J is only half-way implemented
258 case 0x18: /* Xxx amiga panning command 8xx */
259 UniPTEffect(0x8,inf
);
260 of
.flags
|= UF_PANNING
;
268 static int STX_Load(int curious
)
274 /* try to read module header */
275 _mm_read_string(mh
->songname
,20,modreader
);
276 _mm_read_string(mh
->trackername
,8,modreader
);
277 mh
->patsize
=_mm_read_I_UWORD(modreader
);
278 mh
->unknown1
=_mm_read_I_UWORD(modreader
);
279 mh
->patptr
=_mm_read_I_UWORD(modreader
);
280 mh
->insptr
=_mm_read_I_UWORD(modreader
);
281 mh
->chnptr
=_mm_read_I_UWORD(modreader
);
282 mh
->unknown2
=_mm_read_I_UWORD(modreader
);
283 mh
->unknown3
=_mm_read_I_UWORD(modreader
);
284 mh
->mastermult
=_mm_read_UBYTE(modreader
);
285 mh
->initspeed
=_mm_read_UBYTE(modreader
)>>4;
286 mh
->unknown4
=_mm_read_I_UWORD(modreader
);
287 mh
->unknown5
=_mm_read_I_UWORD(modreader
);
288 mh
->patnum
=_mm_read_I_UWORD(modreader
);
289 mh
->insnum
=_mm_read_I_UWORD(modreader
);
290 mh
->ordnum
=_mm_read_I_UWORD(modreader
);
291 mh
->unknown6
=_mm_read_I_UWORD(modreader
);
292 mh
->unknown7
=_mm_read_I_UWORD(modreader
);
293 mh
->unknown8
=_mm_read_I_UWORD(modreader
);
294 _mm_read_string(mh
->scrm
,4,modreader
);
296 if(_mm_eof(modreader
)) {
297 _mm_errno
= MMERR_LOADING_HEADER
;
301 /* set module variables */
302 of
.songname
= DupStr(mh
->songname
,20,1);
303 of
.numpat
= mh
->patnum
;
305 of
.numins
= of
.numsmp
= mh
->insnum
;
306 of
.initspeed
= mh
->initspeed
;
309 of
.flags
|= UF_S3MSLIDES
;
312 if(!(paraptr
=(UWORD
*)MikMod_malloc((of
.numins
+of
.numpat
)*sizeof(UWORD
))))
315 /* read the instrument+pattern parapointers */
316 _mm_fseek(modreader
,mh
->insptr
<<4,SEEK_SET
);
317 _mm_read_I_UWORDS(paraptr
,of
.numins
,modreader
);
318 _mm_fseek(modreader
,mh
->patptr
<<4,SEEK_SET
);
319 _mm_read_I_UWORDS(paraptr
+of
.numins
,of
.numpat
,modreader
);
321 /* check module version */
322 _mm_fseek(modreader
,paraptr
[of
.numins
]<<4,SEEK_SET
);
323 version
=_mm_read_I_UWORD(modreader
);
324 if(version
==mh
->patsize
) {
326 of
.modtype
= StrDup("STMIK 0.2 (STM2STX 1.0)");
329 of
.modtype
= StrDup("STMIK 0.2 (STM2STX 1.1)");
332 /* read the order data */
333 _mm_fseek(modreader
,(mh
->chnptr
<<4)+32,SEEK_SET
);
334 if(!AllocPositions(mh
->ordnum
)) return 0;
335 for(t
=0;t
<mh
->ordnum
;t
++) {
336 of
.positions
[t
]=_mm_read_UBYTE(modreader
);
337 _mm_fseek(modreader
,4,SEEK_CUR
);
340 of
.numpos
=0;poslookupcnt
=mh
->ordnum
;
341 for(t
=0;t
<mh
->ordnum
;t
++) {
342 int order
=of
.positions
[t
];
343 if(order
==255) order
=LAST_PATTERN
;
344 of
.positions
[of
.numpos
]=order
;
345 poslookup
[t
]=of
.numpos
; /* bug fix for freaky S3Ms */
346 if(of
.positions
[t
]<254) of
.numpos
++;
348 /* special end of song pattern */
349 if((order
==LAST_PATTERN
)&&(!curious
)) break;
352 if(_mm_eof(modreader
)) {
353 _mm_errno
= MMERR_LOADING_HEADER
;
358 if(!AllocSamples()) return 0;
359 for(q
=of
.samples
,t
=0;t
<of
.numins
;t
++,q
++) {
362 /* seek to instrument position */
363 _mm_fseek(modreader
,((long)paraptr
[t
])<<4,SEEK_SET
);
364 /* and load sample info */
365 s
.type
=_mm_read_UBYTE(modreader
);
366 _mm_read_string(s
.filename
,12,modreader
);
367 s
.memsegh
=_mm_read_UBYTE(modreader
);
368 s
.memsegl
=_mm_read_I_UWORD(modreader
);
369 s
.length
=_mm_read_I_ULONG(modreader
);
370 s
.loopbeg
=_mm_read_I_ULONG(modreader
);
371 s
.loopend
=_mm_read_I_ULONG(modreader
);
372 s
.volume
=_mm_read_UBYTE(modreader
);
373 s
.dsk
=_mm_read_UBYTE(modreader
);
374 s
.pack
=_mm_read_UBYTE(modreader
);
375 s
.flags
=_mm_read_UBYTE(modreader
);
376 s
.c2spd
=_mm_read_I_ULONG(modreader
);
377 _mm_read_UBYTES(s
.unused
,12,modreader
);
378 _mm_read_string(s
.sampname
,28,modreader
);
379 _mm_read_string(s
.scrs
,4,modreader
);
381 if(_mm_eof(modreader
)) {
382 _mm_errno
= MMERR_LOADING_SAMPLEINFO
;
386 q
->samplename
= DupStr(s
.sampname
,28,1);
387 q
->speed
= (s
.c2spd
* 8363) / 8448;
388 q
->length
= s
.length
;
389 q
->loopstart
= s
.loopbeg
;
390 q
->loopend
= s
.loopend
;
391 q
->volume
= s
.volume
;
392 q
->seekpos
= (((long)s
.memsegh
)<<16|s
.memsegl
)<<4;
393 q
->flags
|= SF_SIGNED
;
395 if(s
.flags
&1) q
->flags
|= SF_LOOP
;
396 if(s
.flags
&4) q
->flags
|= SF_16BITS
;
399 /* load pattern info */
400 of
.numtrk
=of
.numpat
*of
.numchn
;
401 if(!AllocTracks()) return 0;
402 if(!AllocPatterns()) return 0;
404 for(t
=0;t
<of
.numpat
;t
++) {
405 /* seek to pattern position (+2 skip pattern length) */
406 _mm_fseek(modreader
,(((long)paraptr
[of
.numins
+t
])<<4)+
407 (version
==0x10?2:0),SEEK_SET
);
408 if(!STX_ReadPattern()) return 0;
409 for(u
=0;u
<of
.numchn
;u
++)
410 if(!(of
.tracks
[track
++]=STX_ConvertTrack(&stxbuf
[u
*64]))) return 0;
416 static CHAR
*STX_LoadTitle(void)
420 _mm_fseek(modreader
,0,SEEK_SET
);
421 if(!_mm_read_UBYTES(s
,20,modreader
)) return NULL
;
423 return(DupStr(s
,28,1));
426 /*========== Loader information */
428 MIKMODAPI MLOADER load_stx
={
431 "STX (Scream Tracker Music Interface Kit)",