4
|
1 /*
|
|
2
|
|
3 Name: LOAD_STM.C
|
|
4
|
|
5 Description:
|
|
6 ScreamTracker 2 (STM) module Loader - Version 1.oOo Release 2
|
|
7 A Coding Nightmare by Rao and Air Richter of HaRDCoDE
|
|
8 You can now play all of those wonderful old C.C. Catch STM's!
|
|
9
|
|
10 Portability:
|
|
11 All systems - all compilers (hopefully)
|
|
12
|
|
13 If this module is found to not be portable to any particular platform,
|
|
14 please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for
|
|
15 more information on contacting the author).
|
|
16
|
|
17 */
|
|
18
|
|
19 #include <string.h>
|
|
20 #include <ctype.h>
|
|
21 #include "mikmod.h"
|
|
22
|
|
23
|
|
24 typedef struct STMNOTE
|
|
25 { UBYTE note,insvol,volcmd,cmdinf;
|
|
26 } STMNOTE;
|
|
27
|
|
28
|
|
29 // Raw STM sampleinfo struct:
|
|
30
|
|
31 typedef struct STMSAMPLE
|
|
32 { CHAR filename[12]; // Can't have long comments - just filename comments :)
|
|
33 UBYTE unused; // 0x00
|
|
34 UBYTE instdisk; // Instrument disk
|
|
35 UWORD reserved; // ISA in memory when in ST 2
|
|
36 UWORD length; // Sample length
|
|
37 UWORD loopbeg; // Loop start point
|
|
38 UWORD loopend; // Loop end point
|
|
39 UBYTE volume; // Volume
|
|
40 UBYTE reserved2; // More reserved crap
|
|
41 UWORD c2spd; // Good old c2spd
|
|
42 UBYTE reserved3[4]; // Yet more of PSi's reserved crap
|
|
43 UWORD isa; // Internal Segment Address ->
|
|
44 // contrary to the tech specs, this is NOT actually
|
|
45 // written to the stm file.
|
|
46 } STMSAMPLE;
|
|
47
|
|
48 // Raw STM header struct:
|
|
49
|
|
50 typedef struct STMHEADER
|
|
51 { CHAR songname[20];
|
|
52 CHAR trackername[8]; // !SCREAM! for ST 2.xx
|
|
53 UBYTE unused; // 0x1A
|
|
54 UBYTE filetype; // 1=song, 2=module (only 2 is supported, of course) :)
|
|
55 UBYTE ver_major; // Like 2
|
|
56 UBYTE ver_minor; // "ditto"
|
|
57 UBYTE inittempo; // initspeed= stm inittempo>>4
|
|
58 UBYTE numpat; // number of patterns
|
|
59 UBYTE globalvol; // <- WoW! a RiGHT TRiANGLE =8*)
|
|
60 UBYTE reserved[13]; // More of PSi's internal crap
|
|
61 STMSAMPLE sample[31]; // STM sample data
|
|
62 UBYTE patorder[128]; // Docs say 64 - actually 128
|
|
63 } STMHEADER;
|
|
64
|
|
65
|
|
66 static STMNOTE *stmbuf = NULL;
|
|
67 static STMHEADER *mh = NULL;
|
|
68
|
|
69 static CHAR STM_Version[] = "Screamtracker 2";
|
|
70
|
|
71
|
|
72 BOOL STM_Test(void)
|
|
73 {
|
|
74 UBYTE str[9],filetype;
|
|
75
|
|
76 _mm_fseek(modfp,21,SEEK_SET);
|
|
77 _mm_read_UBYTES(str,9,modfp);
|
|
78 filetype = _mm_read_UBYTE(modfp);
|
|
79 if(!memcmp(str,"!SCREAM!",8) || (filetype!=2)) // STM Module = filetype 2
|
|
80 return 0;
|
|
81 return 1;
|
|
82 }
|
|
83
|
|
84
|
|
85
|
|
86 BOOL STM_Init(void)
|
|
87 {
|
|
88 if(!(mh=(STMHEADER *)_mm_calloc(1,sizeof(STMHEADER)))) return 0;
|
|
89 if(!(stmbuf=(STMNOTE *)_mm_calloc(64U*of.numchn,sizeof(STMNOTE)))) return 0;
|
|
90
|
|
91 return 1;
|
|
92 }
|
|
93
|
|
94 void STM_Cleanup(void)
|
|
95 {
|
|
96 if(mh!=NULL) free(mh);
|
|
97 if(stmbuf!=NULL) free(stmbuf);
|
|
98
|
|
99 stmbuf = NULL;
|
|
100 mh = NULL;
|
|
101 }
|
|
102
|
|
103
|
|
104
|
|
105 void STM_ConvertNote(STMNOTE *n)
|
|
106 {
|
|
107 UBYTE note,ins,vol,cmd,inf;
|
|
108
|
|
109 // extract the various information from the 4 bytes that
|
|
110 // make up a single note
|
|
111
|
|
112 note = n->note;
|
|
113 ins = n->insvol>>3;
|
|
114 vol = (n->insvol&7)+(n->volcmd>>1);
|
|
115 cmd = n->volcmd&15;
|
|
116 inf = n->cmdinf;
|
|
117
|
|
118 if(ins!=0 && ins<32) UniInstrument(ins-1);
|
|
119
|
|
120 // special values of [SBYTE0] are handled here ->
|
|
121 // we have no idea if these strange values will ever be encountered.
|
|
122 // but it appears as though stms sound correct.
|
|
123 if(note==254 || note==252) UniPTEffect(0xc,0); // <- note off command (???)
|
|
124 else
|
|
125 // if note < 251, then all three bytes are stored in the file
|
|
126 if(note<251) UniNote((((note>>4)+2)*12)+(note&0xf)); // <- normal note and up the octave by two
|
|
127
|
|
128 if(vol<65)
|
|
129 UniPTEffect(0xc,vol);
|
|
130
|
|
131 if(cmd!=255){
|
|
132 switch(cmd){
|
|
133
|
|
134 case 1: // Axx set speed to xx and add 0x1c to fix StoOoPiD STM 2.x
|
|
135 UniPTEffect(0xf,inf>>4);
|
|
136 break;
|
|
137
|
|
138 case 2: // Bxx position jump
|
|
139 UniPTEffect(0xb,inf);
|
|
140 break;
|
|
141
|
|
142 case 3: // Cxx patternbreak to row xx
|
|
143 UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf));
|
|
144 break;
|
|
145
|
|
146 case 4: // Dxy volumeslide
|
|
147 UniWrite(UNI_S3MEFFECTD);
|
|
148 UniWrite(inf);
|
|
149 break;
|
|
150
|
|
151 case 5: // Exy toneslide down
|
|
152 UniWrite(UNI_S3MEFFECTE);
|
|
153 UniWrite(inf);
|
|
154 break;
|
|
155
|
|
156 case 6: // Fxy toneslide up
|
|
157 UniWrite(UNI_S3MEFFECTF);
|
|
158 UniWrite(inf);
|
|
159 break;
|
|
160
|
|
161 case 7: // Gxx Tone portamento,speed xx
|
|
162 UniPTEffect(0x3,inf);
|
|
163 break;
|
|
164
|
|
165 case 8: // Hxy vibrato
|
|
166 UniPTEffect(0x4,inf);
|
|
167 break;
|
|
168
|
|
169 case 9: // Ixy tremor, ontime x, offtime y
|
|
170 UniWrite(UNI_S3MEFFECTI);
|
|
171 UniWrite(inf);
|
|
172 break;
|
|
173
|
|
174 case 0xa: // Jxy arpeggio
|
|
175 UniPTEffect(0x0,inf);
|
|
176 break;
|
|
177
|
|
178 case 0xb: // Kxy Dual command H00 & Dxy
|
|
179 UniPTEffect(0x4,0);
|
|
180 UniWrite(UNI_S3MEFFECTD);
|
|
181 UniWrite(inf);
|
|
182 break;
|
|
183
|
|
184 case 0xc: // Lxy Dual command G00 & Dxy
|
|
185 UniPTEffect(0x3,0);
|
|
186 UniWrite(UNI_S3MEFFECTD);
|
|
187 UniWrite(inf);
|
|
188 break;
|
|
189
|
|
190 // Support all these above, since ST2 can LOAD these values
|
|
191 // but can actually only play up to J - and J is only
|
|
192 // half-way implemented in ST2
|
|
193
|
|
194 case 0x18: // Xxx amiga command 8xx - What the hell, support panning. :)
|
|
195 UniPTEffect(0x8,inf);
|
|
196 break;
|
|
197 }
|
|
198 }
|
|
199 }
|
|
200
|
|
201
|
|
202 UBYTE *STM_ConvertTrack(STMNOTE *n)
|
|
203 {
|
|
204 int t;
|
|
205
|
|
206 UniReset();
|
|
207 for(t=0; t<64; t++)
|
|
208 { STM_ConvertNote(n);
|
|
209 UniNewline();
|
|
210 n+=of.numchn;
|
|
211 }
|
|
212 return UniDup();
|
|
213 }
|
|
214
|
|
215
|
|
216 BOOL STM_LoadPatterns(void)
|
|
217 {
|
|
218 int t,s,tracks=0;
|
|
219
|
|
220 if(!AllocPatterns()) return 0;
|
|
221 if(!AllocTracks()) return 0;
|
|
222
|
|
223 // Allocate temporary buffer for loading
|
|
224 // and converting the patterns
|
|
225
|
|
226 for(t=0; t<of.numpat; t++)
|
|
227 { for(s=0; s<(64U*of.numchn); s++)
|
|
228 { stmbuf[s].note = _mm_read_UBYTE(modfp);
|
|
229 stmbuf[s].insvol = _mm_read_UBYTE(modfp);
|
|
230 stmbuf[s].volcmd = _mm_read_UBYTE(modfp);
|
|
231 stmbuf[s].cmdinf = _mm_read_UBYTE(modfp);
|
|
232 }
|
|
233
|
|
234 if(feof(modfp))
|
|
235 { _mm_errno = MMERR_LOADING_PATTERN;
|
|
236 return 0;
|
|
237 }
|
|
238
|
|
239 for(s=0;s<of.numchn;s++)
|
|
240 { if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
|
|
241 }
|
|
242 }
|
|
243
|
|
244 return 1;
|
|
245 }
|
|
246
|
|
247
|
|
248
|
|
249 BOOL STM_Load(void)
|
|
250 {
|
|
251 int t;
|
|
252 ULONG MikMod_ISA; // We MUST generate our own ISA - NOT stored in the stm
|
|
253 SAMPLE *q;
|
|
254
|
|
255 // try to read stm header
|
|
256
|
|
257 _mm_read_string(mh->songname,20,modfp);
|
|
258 _mm_read_string(mh->trackername,8,modfp);
|
|
259 mh->unused =_mm_read_UBYTE(modfp);
|
|
260 mh->filetype =_mm_read_UBYTE(modfp);
|
|
261 mh->ver_major =_mm_read_UBYTE(modfp);
|
|
262 mh->ver_minor =_mm_read_UBYTE(modfp);
|
|
263 mh->inittempo =_mm_read_UBYTE(modfp);
|
|
264 mh->numpat =_mm_read_UBYTE(modfp);
|
|
265 mh->globalvol =_mm_read_UBYTE(modfp);
|
|
266 _mm_read_UBYTES(mh->reserved,13,modfp);
|
|
267
|
|
268 for(t=0;t<31;t++)
|
|
269 { STMSAMPLE *s = &mh->sample[t]; // STM sample data
|
|
270
|
|
271 _mm_read_string(s->filename,12,modfp);
|
|
272 s->unused =_mm_read_UBYTE(modfp);
|
|
273 s->instdisk =_mm_read_UBYTE(modfp);
|
|
274 s->reserved =_mm_read_I_UWORD(modfp);
|
|
275 s->length =_mm_read_I_UWORD(modfp);
|
|
276 s->loopbeg =_mm_read_I_UWORD(modfp);
|
|
277 s->loopend =_mm_read_I_UWORD(modfp);
|
|
278 s->volume =_mm_read_UBYTE(modfp);
|
|
279 s->reserved2=_mm_read_UBYTE(modfp);
|
|
280 s->c2spd =_mm_read_I_UWORD(modfp);
|
|
281 _mm_read_UBYTES(s->reserved3,4,modfp);
|
|
282 s->isa =_mm_read_I_UWORD(modfp);
|
|
283 }
|
|
284 _mm_read_UBYTES(mh->patorder,128,modfp);
|
|
285
|
|
286 if(feof(modfp))
|
|
287 { _mm_errno = MMERR_LOADING_HEADER;
|
|
288 return 0;
|
|
289 }
|
|
290
|
|
291 // set module variables
|
|
292
|
|
293 of.modtype = strdup(STM_Version);
|
|
294 of.songname = DupStr(mh->songname,20); // make a cstr of songname
|
|
295 of.numpat = mh->numpat;
|
|
296 of.inittempo = 125; // mh->inittempo+0x1c;
|
|
297 of.initspeed = mh->inittempo>>4;
|
|
298 of.numchn = 4; // get number of channels
|
|
299
|
|
300 t=0;
|
|
301 if(!AllocPositions(0x80)) return 0;
|
|
302 while(mh->patorder[t]!=99) // 99 terminates the patorder list
|
|
303 { of.positions[t] = mh->patorder[t];
|
|
304 t++;
|
|
305 }
|
|
306 of.numpos = --t;
|
|
307 of.numtrk = of.numpat*of.numchn;
|
|
308
|
|
309 // Finally, init the sampleinfo structures
|
|
310 of.numins = of.numsmp = 31; // always this
|
|
311
|
|
312 if(!AllocSamples()) return 0;
|
|
313 if(!STM_LoadPatterns()) return 0;
|
|
314
|
|
315 q = of.samples;
|
|
316
|
|
317 MikMod_ISA = _mm_ftell(modfp);
|
|
318 MikMod_ISA = (MikMod_ISA+15)&0xfffffff0;
|
|
319
|
|
320 for(t=0; t<of.numins; t++)
|
|
321 { // load sample info
|
|
322
|
|
323 q->samplename = DupStr(mh->sample[t].filename,12);
|
|
324 q->speed = mh->sample[t].c2spd;
|
|
325 q->volume = mh->sample[t].volume;
|
|
326 q->length = mh->sample[t].length;
|
|
327 if (!mh->sample[t].volume || q->length==1 ) q->length = 0; // if vol = 0 or length = 1, then no sample
|
|
328 q->loopstart = mh->sample[t].loopbeg;
|
|
329 q->loopend = mh->sample[t].loopend;
|
|
330 q->seekpos = MikMod_ISA;
|
|
331
|
|
332 MikMod_ISA+=q->length;
|
|
333 MikMod_ISA = (MikMod_ISA+15)&0xfffffff0;
|
|
334
|
|
335 // Once again, contrary to the STM specs, all the sample data is
|
|
336 // actually SIGNED! Sheesh
|
|
337
|
|
338 q->flags = SF_SIGNED;
|
|
339
|
|
340 if(mh->sample[t].loopend>0 && mh->sample[t].loopend!=0xffff) q->flags|=SF_LOOP;
|
|
341
|
|
342 // fix replen if repend>length
|
|
343
|
|
344 if(q->loopend > q->length) q->loopend = q->length;
|
|
345
|
|
346 q++;
|
|
347 }
|
|
348
|
|
349 return 1;
|
|
350 }
|
|
351
|
|
352
|
|
353 CHAR *STM_LoadTitle(void)
|
|
354 {
|
|
355 CHAR s[20];
|
|
356
|
|
357 _mm_fseek(modfp,0,SEEK_SET);
|
|
358 if(!fread(s,20,1,modfp)) return NULL;
|
|
359
|
|
360 return(DupStr(s,20));
|
|
361 }
|
|
362
|
|
363
|
|
364 MLOADER load_stm =
|
|
365 { NULL,
|
|
366 "STM",
|
|
367 "Portable STM Loader - V 1.2",
|
|
368 STM_Init,
|
|
369 STM_Test,
|
|
370 STM_Load,
|
|
371 STM_Cleanup,
|
|
372 STM_LoadTitle
|
|
373 };
|
|
374
|