comparison playercode/load_stm.c @ 4:5d614bcc4287

Initial entry of mikmod into the CVS tree.
author darius
date Fri, 23 Jan 1998 16:05:08 +0000
parents
children
comparison
equal deleted inserted replaced
3:71e20a32bd84 4:5d614bcc4287
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