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$
24 
25   Screamtracker 2 (STM) 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
46 extern int fprintf(FILE *, const char *, ...);
47 #endif
48 
49 /*========== Module structure */
50 
51 /* sample information */
52 typedef struct STMSAMPLE {
53 	CHAR  filename[12];
54 	UBYTE unused;       /* 0x00 */
55 	UBYTE instdisk;     /* Instrument disk */
56 	UWORD reserved;
57 	UWORD length;       /* Sample length */
58 	UWORD loopbeg;      /* Loop start point */
59 	UWORD loopend;      /* Loop end point */
60 	UBYTE volume;       /* Volume */
61 	UBYTE reserved2;
62 	UWORD c2spd;        /* Good old c2spd */
63 	ULONG reserved3;
64 	UWORD isa;
65 } STMSAMPLE;
66 
67 /* header */
68 typedef struct STMHEADER {
69 	CHAR  songname[20];
70 	CHAR  trackername[8]; /* !Scream! for ST 2.xx  */
71 	UBYTE unused;         /* 0x1A  */
72 	UBYTE filetype;       /* 1=song, 2=module */
73 	UBYTE ver_major;
74 	UBYTE ver_minor;
75 	UBYTE inittempo;      /* initspeed= stm inittempo>>4  */
76 	UBYTE numpat;         /* number of patterns  */
77 	UBYTE globalvol;
78 	UBYTE reserved[13];
79 	STMSAMPLE sample[31]; /* STM sample data */
80 	UBYTE patorder[128];  /* Docs say 64 - actually 128 */
81 } STMHEADER;
82 
83 typedef struct STMNOTE {
84 	UBYTE note,insvol,volcmd,cmdinf;
85 } STMNOTE;
86 
87 /*========== Loader variables */
88 
89 static STMNOTE *stmbuf = NULL;
90 static STMHEADER *mh = NULL;
91 
92 /* tracker identifiers */
93 static const CHAR * STM_Version[STM_NTRACKERS] = {
94 	"Screamtracker 2",
95 	"Converted by MOD2STM (STM format)",
96 	"Wuzamod (STM format)"
97 };
98 
99 /*========== Loader code */
100 
STM_Test(void)101 static BOOL STM_Test(void)
102 {
103 	UBYTE str[44];
104 	int t;
105 
106 	_mm_fseek(modreader,20,SEEK_SET);
107 	_mm_read_UBYTES(str,44,modreader);
108 	if(str[9]!=2) return 0;	/* STM Module = filetype 2 */
109 
110 	/* Prevent false positives for S3M files */
111 	if(!memcmp(str+40,"SCRM",4))
112 		return 0;
113 
114 	for (t=0;t<STM_NTRACKERS;t++)
115 		if(!memcmp(str,STM_Signatures[t],8))
116 			return 1;
117 
118 	return 0;
119 }
120 
STM_Init(void)121 static BOOL STM_Init(void)
122 {
123 	if(!(mh=(STMHEADER*)MikMod_malloc(sizeof(STMHEADER)))) return 0;
124 	if(!(stmbuf=(STMNOTE*)MikMod_calloc(64U*4,sizeof(STMNOTE)))) return 0;
125 
126 	return 1;
127 }
128 
STM_Cleanup(void)129 static void STM_Cleanup(void)
130 {
131 	MikMod_free(mh);
132 	MikMod_free(stmbuf);
133 	mh=NULL;
134 	stmbuf=NULL;
135 }
136 
STM_ConvertNote(STMNOTE * n)137 static void STM_ConvertNote(STMNOTE *n)
138 {
139 	UBYTE note,ins,vol,cmd,inf;
140 
141 	/* extract the various information from the 4 bytes that make up a note */
142 	note = n->note;
143 	ins  = n->insvol>>3;
144 	vol  = (n->insvol&7)+((n->volcmd&0x70)>>1);
145 	cmd  = n->volcmd&15;
146 	inf  = n->cmdinf;
147 
148 	if((ins)&&(ins<32)) UniInstrument(ins-1);
149 
150 	/* special values of [SBYTE0] are handled here
151 	   we have no idea if these strange values will ever be encountered.
152 	   but it appears as those stms sound correct. */
153 	if((note==254)||(note==252)) {
154 		UniPTEffect(0xc,0); /* note cut */
155 		n->volcmd|=0x80;
156 	} else
157 		/* if note < 251, then all three bytes are stored in the file */
158 	  if(note<251) UniNote((((note>>4)+2)*OCTAVE)+(note&0xf));
159 
160 	if((!(n->volcmd&0x80))&&(vol<65)) UniPTEffect(0xc,vol);
161 	if(cmd!=255)
162 		switch(cmd) {
163 			case 1:	/* Axx set speed to xx */
164 				UniPTEffect(0xf,inf>>4);
165 				break;
166 			case 2:	/* Bxx position jump */
167 				UniPTEffect(0xb,inf);
168 				break;
169 			case 3:	/* Cxx patternbreak to row xx */
170 				UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf));
171 				break;
172 			case 4:	/* Dxy volumeslide */
173 				UniEffect(UNI_S3MEFFECTD,inf);
174 				break;
175 			case 5:	/* Exy toneslide down */
176 				UniEffect(UNI_S3MEFFECTE,inf);
177 				break;
178 			case 6:	/* Fxy toneslide up */
179 				UniEffect(UNI_S3MEFFECTF,inf);
180 				break;
181 			case 7:	/* Gxx Tone portamento,speed xx */
182 				UniPTEffect(0x3,inf);
183 				break;
184 			case 8:	/* Hxy vibrato */
185 				UniPTEffect(0x4,inf);
186 				break;
187 			case 9:	/* Ixy tremor, ontime x, offtime y */
188 				UniEffect(UNI_S3MEFFECTI,inf);
189 			break;
190 			case 0:		/* protracker arpeggio */
191 				if(!inf) break;
192 				/* fall through */
193 			case 0xa:	/* Jxy arpeggio */
194 				UniPTEffect(0x0,inf);
195 				break;
196 			case 0xb:	/* Kxy Dual command H00 & Dxy */
197 				UniPTEffect(0x4,0);
198 				UniEffect(UNI_S3MEFFECTD,inf);
199 				break;
200 			case 0xc:	/* Lxy Dual command G00 & Dxy */
201 				UniPTEffect(0x3,0);
202 				UniEffect(UNI_S3MEFFECTD,inf);
203 				break;
204 			/* Support all these above, since ST2 can LOAD these values but can
205 			   actually only play up to J - and J is only half-way implemented
206 			   in ST2 */
207 			case 0x18:	/* Xxx amiga panning command 8xx */
208 				UniPTEffect(0x8,inf);
209 				of.flags |= UF_PANNING;
210 				break;
211 		}
212 }
213 
STM_ConvertTrack(STMNOTE * n)214 static UBYTE *STM_ConvertTrack(STMNOTE *n)
215 {
216 	int t;
217 
218 	UniReset();
219 	for(t=0;t<64;t++) {
220 		STM_ConvertNote(n);
221 		UniNewline();
222 		n+=of.numchn;
223 	}
224 	return UniDup();
225 }
226 
STM_LoadPatterns(void)227 static BOOL STM_LoadPatterns(void)
228 {
229 	int t,s,tracks=0;
230 
231 	if(!AllocPatterns()) return 0;
232 	if(!AllocTracks()) return 0;
233 
234 	/* Allocate temporary buffer for loading and converting the patterns */
235 	for(t=0;t<of.numpat;t++) {
236 		for(s=0;s<(64U*of.numchn);s++) {
237 			stmbuf[s].note   = _mm_read_UBYTE(modreader);
238 			stmbuf[s].insvol = _mm_read_UBYTE(modreader);
239 			stmbuf[s].volcmd = _mm_read_UBYTE(modreader);
240 			stmbuf[s].cmdinf = _mm_read_UBYTE(modreader);
241 		}
242 
243 		if(_mm_eof(modreader)) {
244 			_mm_errno = MMERR_LOADING_PATTERN;
245 			return 0;
246 		}
247 
248 		for(s=0;s<of.numchn;s++)
249 			if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
250 	}
251 	return 1;
252 }
253 
STM_Load(BOOL curious)254 static BOOL STM_Load(BOOL curious)
255 {
256 	int t;
257 	ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */
258 	SAMPLE *q;
259 
260 	/* try to read stm header */
261 	_mm_read_string(mh->songname,20,modreader);
262 	_mm_read_string(mh->trackername,8,modreader);
263 	mh->unused      =_mm_read_UBYTE(modreader);
264 	mh->filetype    =_mm_read_UBYTE(modreader);
265 	mh->ver_major   =_mm_read_UBYTE(modreader);
266 	mh->ver_minor   =_mm_read_UBYTE(modreader);
267 	mh->inittempo   =_mm_read_UBYTE(modreader);
268 	if(!mh->inittempo) {
269 		_mm_errno=MMERR_NOT_A_MODULE;
270 		return 0;
271 	}
272 	mh->numpat      =_mm_read_UBYTE(modreader);
273 	mh->globalvol   =_mm_read_UBYTE(modreader);
274 	_mm_read_UBYTES(mh->reserved,13,modreader);
275 	if(mh->numpat > 128) {
276 		_mm_errno = MMERR_NOT_A_MODULE;
277 		return 0;
278 	}
279 
280 	for(t=0;t<31;t++) {
281 		STMSAMPLE *s=&mh->sample[t];	/* STM sample data */
282 
283 		_mm_read_string(s->filename,12,modreader);
284 		s->unused   =_mm_read_UBYTE(modreader);
285 		s->instdisk =_mm_read_UBYTE(modreader);
286 		s->reserved =_mm_read_I_UWORD(modreader);
287 		s->length   =_mm_read_I_UWORD(modreader);
288 		s->loopbeg  =_mm_read_I_UWORD(modreader);
289 		s->loopend  =_mm_read_I_UWORD(modreader);
290 		s->volume   =_mm_read_UBYTE(modreader);
291 		s->reserved2=_mm_read_UBYTE(modreader);
292 		s->c2spd    =_mm_read_I_UWORD(modreader);
293 		s->reserved3=_mm_read_I_ULONG(modreader);
294 		s->isa      =_mm_read_I_UWORD(modreader);
295 	}
296 	_mm_read_UBYTES(mh->patorder,128,modreader);
297 
298 	if(_mm_eof(modreader)) {
299 		_mm_errno = MMERR_LOADING_HEADER;
300 		return 0;
301 	}
302 
303 	/* set module variables */
304 	for(t=0;t<STM_NTRACKERS;t++)
305 		if(!memcmp(mh->trackername,STM_Signatures[t],8)) break;
306 	of.modtype   = MikMod_strdup(STM_Version[t]);
307 	of.songname  = DupStr(mh->songname,20,1); /* make a cstr of songname */
308 	of.numpat    = mh->numpat;
309 	of.inittempo = 125;                     /* mh->inittempo+0x1c; */
310 	of.initspeed = mh->inittempo>>4;
311 	of.numchn    = 4;                       /* get number of channels */
312 	of.reppos    = 0;
313 	of.flags    |= UF_S3MSLIDES;
314 	of.bpmlimit  = 32;
315 
316 	t=0;
317 	if(!AllocPositions(0x80)) return 0;
318 	/* 99 terminates the patorder list */
319 	while((mh->patorder[t]<=99)&&(mh->patorder[t]<mh->numpat)) {
320 		of.positions[t]=mh->patorder[t];
321 		if(++t == 0x80) {
322 			_mm_errno = MMERR_NOT_A_MODULE;
323 			return 0;
324 		}
325 	}
326 	if(mh->patorder[t]<=99) t++;
327 	of.numpos=t;
328 	of.numtrk=of.numpat*of.numchn;
329 	of.numins=of.numsmp=31;
330 
331 	if(!AllocSamples()) return 0;
332 	if(!STM_LoadPatterns()) return 0;
333 	MikMod_ISA=_mm_ftell(modreader);
334 	MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;	/* normalize */
335 
336 	for(q=of.samples,t=0;t<of.numsmp;t++,q++) {
337 		/* load sample info */
338 		q->samplename = DupStr(mh->sample[t].filename,12,1);
339 		q->speed      = (mh->sample[t].c2spd * 8363) / 8448;
340 		q->volume     = mh->sample[t].volume;
341 		q->length     = mh->sample[t].length;
342 		if (/*!mh->sample[t].volume || */q->length==1) q->length=0;
343 		q->loopstart  = mh->sample[t].loopbeg;
344 		q->loopend    = mh->sample[t].loopend;
345 		q->seekpos    = MikMod_ISA;
346 
347 		MikMod_ISA+=q->length;
348 		MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;	/* normalize */
349 
350 		/* contrary to the STM specs, sample data is signed */
351 		q->flags = SF_SIGNED;
352 
353 		if(q->loopend && q->loopend != 0xffff)
354 				q->flags|=SF_LOOP;
355 	}
356 	return 1;
357 }
358 
STM_LoadTitle(void)359 static CHAR *STM_LoadTitle(void)
360 {
361 	CHAR s[20];
362 
363 	_mm_fseek(modreader,0,SEEK_SET);
364 	if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
365 
366 	return(DupStr(s,20,1));
367 }
368 
369 /*========== Loader information */
370 
371 MIKMODAPI MLOADER load_stm={
372 	NULL,
373 	"STM",
374 	"STM (Scream Tracker)",
375 	STM_Init,
376 	STM_Test,
377 	STM_Load,
378 	STM_Cleanup,
379 	STM_LoadTitle
380 };
381 
382 /* ex:set ts=4: */
383