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_stm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
\r
25 Screamtracker 2 (STM) 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
51 /* sample information */
\r
52 typedef struct STMSAMPLE {
\r
54 UBYTE unused; /* 0x00 */
\r
55 UBYTE instdisk; /* Instrument disk */
\r
57 UWORD length; /* Sample length */
\r
58 UWORD loopbeg; /* Loop start point */
\r
59 UWORD loopend; /* Loop end point */
\r
60 UBYTE volume; /* Volume */
\r
62 UWORD c2spd; /* Good old c2spd */
\r
68 typedef struct STMHEADER {
\r
70 CHAR trackername[8]; /* !Scream! for ST 2.xx */
\r
71 UBYTE unused; /* 0x1A */
\r
72 UBYTE filetype; /* 1=song, 2=module */
\r
75 UBYTE inittempo; /* initspeed= stm inittempo>>4 */
\r
76 UBYTE numpat; /* number of patterns */
\r
79 STMSAMPLE sample[31]; /* STM sample data */
\r
80 UBYTE patorder[128]; /* Docs say 64 - actually 128 */
\r
83 typedef struct STMNOTE {
\r
84 UBYTE note,insvol,volcmd,cmdinf;
\r
87 /*========== Loader variables */
\r
89 static STMNOTE *stmbuf = NULL;
\r
90 static STMHEADER *mh = NULL;
\r
92 /* tracker identifiers */
\r
93 static CHAR* STM_Version[STM_NTRACKERS] = {
\r
95 "Converted by MOD2STM (STM format)",
\r
96 "Wuzamod (STM format)"
\r
99 /*========== Loader code */
\r
101 BOOL STM_Test(void)
\r
106 _mm_fseek(modreader,20,SEEK_SET);
\r
107 _mm_read_UBYTES(str,44,modreader);
\r
108 if(str[9]!=2) return 0; /* STM Module = filetype 2 */
\r
110 /* Prevent false positives for S3M files */
\r
111 if(!memcmp(str+40,"SCRM",4))
\r
114 for (t=0;t<STM_NTRACKERS;t++)
\r
115 if(!memcmp(str,STM_Signatures[t],8))
\r
121 BOOL STM_Init(void)
\r
123 if(!(mh=(STMHEADER*)_mm_malloc(sizeof(STMHEADER)))) return 0;
\r
124 if(!(stmbuf=(STMNOTE*)_mm_calloc(64U*4,sizeof(STMNOTE)))) return 0;
\r
129 static void STM_Cleanup(void)
\r
135 static void STM_ConvertNote(STMNOTE *n)
\r
137 UBYTE note,ins,vol,cmd,inf;
\r
139 /* extract the various information from the 4 bytes that make up a note */
\r
141 ins = n->insvol>>3;
\r
142 vol = (n->insvol&7)+((n->volcmd&0x70)>>1);
\r
143 cmd = n->volcmd&15;
\r
146 if((ins)&&(ins<32)) UniInstrument(ins-1);
\r
148 /* special values of [SBYTE0] are handled here
\r
149 we have no idea if these strange values will ever be encountered.
\r
150 but it appears as those stms sound correct. */
\r
151 if((note==254)||(note==252)) {
\r
152 UniPTEffect(0xc,0); /* note cut */
\r
155 /* if note < 251, then all three bytes are stored in the file */
\r
156 if(note<251) UniNote((((note>>4)+2)*OCTAVE)+(note&0xf));
\r
158 if((!(n->volcmd&0x80))&&(vol<65)) UniPTEffect(0xc,vol);
\r
161 case 1: /* Axx set speed to xx */
\r
162 UniPTEffect(0xf,inf>>4);
\r
164 case 2: /* Bxx position jump */
\r
165 UniPTEffect(0xb,inf);
\r
167 case 3: /* Cxx patternbreak to row xx */
\r
168 UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf));
\r
170 case 4: /* Dxy volumeslide */
\r
171 UniEffect(UNI_S3MEFFECTD,inf);
\r
173 case 5: /* Exy toneslide down */
\r
174 UniEffect(UNI_S3MEFFECTE,inf);
\r
176 case 6: /* Fxy toneslide up */
\r
177 UniEffect(UNI_S3MEFFECTF,inf);
\r
179 case 7: /* Gxx Tone portamento,speed xx */
\r
180 UniPTEffect(0x3,inf);
\r
182 case 8: /* Hxy vibrato */
\r
183 UniPTEffect(0x4,inf);
\r
185 case 9: /* Ixy tremor, ontime x, offtime y */
\r
186 UniEffect(UNI_S3MEFFECTI,inf);
\r
188 case 0: /* protracker arpeggio */
\r
191 case 0xa: /* Jxy arpeggio */
\r
192 UniPTEffect(0x0,inf);
\r
194 case 0xb: /* Kxy Dual command H00 & Dxy */
\r
195 UniPTEffect(0x4,0);
\r
196 UniEffect(UNI_S3MEFFECTD,inf);
\r
198 case 0xc: /* Lxy Dual command G00 & Dxy */
\r
199 UniPTEffect(0x3,0);
\r
200 UniEffect(UNI_S3MEFFECTD,inf);
\r
202 /* Support all these above, since ST2 can LOAD these values but can
\r
203 actually only play up to J - and J is only half-way implemented
\r
205 case 0x18: /* Xxx amiga panning command 8xx */
\r
206 UniPTEffect(0x8,inf);
\r
207 of.flags |= UF_PANNING;
\r
212 static UBYTE *STM_ConvertTrack(STMNOTE *n)
\r
217 for(t=0;t<64;t++) {
\r
218 STM_ConvertNote(n);
\r
225 static BOOL STM_LoadPatterns(void)
\r
229 if(!AllocPatterns()) return 0;
\r
230 if(!AllocTracks()) return 0;
\r
232 /* Allocate temporary buffer for loading and converting the patterns */
\r
233 for(t=0;t<of.numpat;t++) {
\r
234 for(s=0;s<(64U*of.numchn);s++) {
\r
235 stmbuf[s].note = _mm_read_UBYTE(modreader);
\r
236 stmbuf[s].insvol = _mm_read_UBYTE(modreader);
\r
237 stmbuf[s].volcmd = _mm_read_UBYTE(modreader);
\r
238 stmbuf[s].cmdinf = _mm_read_UBYTE(modreader);
\r
241 if(_mm_eof(modreader)) {
\r
242 _mm_errno = MMERR_LOADING_PATTERN;
\r
246 for(s=0;s<of.numchn;s++)
\r
247 if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
\r
252 BOOL STM_Load(BOOL curious)
\r
255 ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */
\r
259 /* try to read stm header */
\r
260 _mm_read_string(mh->songname,20,modreader);
\r
261 _mm_read_string(mh->trackername,8,modreader);
\r
262 mh->unused =_mm_read_UBYTE(modreader);
\r
263 mh->filetype =_mm_read_UBYTE(modreader);
\r
264 mh->ver_major =_mm_read_UBYTE(modreader);
\r
265 mh->ver_minor =_mm_read_UBYTE(modreader);
\r
266 mh->inittempo =_mm_read_UBYTE(modreader);
\r
267 if(!mh->inittempo) {
\r
268 _mm_errno=MMERR_NOT_A_MODULE;
\r
271 mh->numpat =_mm_read_UBYTE(modreader);
\r
272 mh->globalvol =_mm_read_UBYTE(modreader);
\r
273 _mm_read_UBYTES(mh->reserved,13,modreader);
\r
275 for(t=0;t<31;t++) {
\r
276 STMSAMPLE *s=&mh->sample[t]; /* STM sample data */
\r
278 _mm_read_string(s->filename,12,modreader);
\r
279 s->unused =_mm_read_UBYTE(modreader);
\r
280 s->instdisk =_mm_read_UBYTE(modreader);
\r
281 s->reserved =_mm_read_I_UWORD(modreader);
\r
282 s->length =_mm_read_I_UWORD(modreader);
\r
283 s->loopbeg =_mm_read_I_UWORD(modreader);
\r
284 s->loopend =_mm_read_I_UWORD(modreader);
\r
285 s->volume =_mm_read_UBYTE(modreader);
\r
286 s->reserved2=_mm_read_UBYTE(modreader);
\r
287 s->c2spd =_mm_read_I_UWORD(modreader);
\r
288 s->reserved3=_mm_read_I_ULONG(modreader);
\r
289 s->isa =_mm_read_I_UWORD(modreader);
\r
291 _mm_read_UBYTES(mh->patorder,128,modreader);
\r
293 if(_mm_eof(modreader)) {
\r
294 _mm_errno = MMERR_LOADING_HEADER;
\r
298 /* set module variables */
\r
299 for(t=0;t<STM_NTRACKERS;t++)
\r
300 if(!memcmp(mh->trackername,STM_Signatures[t],8)) break;
\r
301 of.modtype = strdup(STM_Version[t]);
\r
302 of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */
\r
303 of.numpat = mh->numpat;
\r
304 of.inittempo = 125; /* mh->inittempo+0x1c; */
\r
305 of.initspeed = mh->inittempo>>4;
\r
306 of.numchn = 4; /* get number of channels */
\r
308 of.flags |= UF_S3MSLIDES;
\r
312 if(!AllocPositions(0x80)) return 0;
\r
313 /* 99 terminates the patorder list */
\r
314 while((mh->patorder[t]<=99)&&(mh->patorder[t]<mh->numpat)) {
\r
315 of.positions[t]=mh->patorder[t];
\r
318 if(mh->patorder[t]<=99) t++;
\r
320 of.numtrk=of.numpat*of.numchn;
\r
321 of.numins=of.numsmp=31;
\r
323 if(!AllocSamples()) return 0;
\r
324 if(!STM_LoadPatterns()) return 0;
\r
325 MikMod_ISA=_mm_ftell(modreader);
\r
326 MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
\r
328 for(q=of.samples,t=0;t<of.numsmp;t++,q++) {
\r
329 /* load sample info */
\r
330 q->samplename = DupStr(mh->sample[t].filename,12,1);
\r
331 q->speed = (mh->sample[t].c2spd * 8363) / 8448;
\r
332 q->volume = mh->sample[t].volume;
\r
333 q->length = mh->sample[t].length;
\r
334 if (/*(!mh->sample[t].volume)||*/(q->length==1)) q->length=0;
\r
335 q->loopstart = mh->sample[t].loopbeg;
\r
336 q->loopend = mh->sample[t].loopend;
\r
337 q->seekpos = MikMod_ISA;
\r
339 MikMod_ISA+=q->length;
\r
340 MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
\r
342 /* contrary to the STM specs, sample data is signed */
\r
343 q->flags = SF_SIGNED;
\r
345 if(q->loopend && q->loopend != 0xffff)
\r
351 CHAR *STM_LoadTitle(void)
\r
355 _mm_fseek(modreader,0,SEEK_SET);
\r
356 if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
\r
358 return(DupStr(s,20,1));
\r
361 /*========== Loader information */
\r
363 MIKMODAPI MLOADER load_stm={
\r
366 "STM (Scream Tracker)",
\r