Mercurial > ~darius > hgwebdir.cgi > mikmod
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 |