Mercurial > ~darius > hgwebdir.cgi > mikmod
comparison playercode/load_m15.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_M15.C | |
4 | |
5 Description: | |
6 15 instrument MOD loader | |
7 Also supports Ultimate Sound Tracker (old M15 format) | |
8 | |
9 Portability: | |
10 All systems - all compilers (hopefully) | |
11 | |
12 If this module is found to not be portable to any particular platform, | |
13 please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for | |
14 more information on contacting the author). | |
15 | |
16 */ | |
17 | |
18 #include <string.h> | |
19 #include "mikmod.h" | |
20 | |
21 /************************************************************************* | |
22 *************************************************************************/ | |
23 | |
24 | |
25 typedef struct MSAMPINFO // sample header as it appears in a module | |
26 { CHAR samplename[22]; | |
27 UWORD length; | |
28 UBYTE finetune; | |
29 UBYTE volume; | |
30 UWORD reppos; | |
31 UWORD replen; | |
32 } MSAMPINFO; | |
33 | |
34 | |
35 typedef struct MODULEHEADER // verbatim module header | |
36 { CHAR songname[20]; // the songname.. | |
37 MSAMPINFO samples[15]; // all sampleinfo | |
38 UBYTE songlength; // number of patterns used | |
39 UBYTE magic1; // should be 127 | |
40 UBYTE positions[128]; // which pattern to play at pos | |
41 } MODULEHEADER; | |
42 | |
43 | |
44 typedef struct MODNOTE | |
45 { UBYTE a,b,c,d; | |
46 } MODNOTE; | |
47 | |
48 | |
49 /************************************************************************* | |
50 *************************************************************************/ | |
51 | |
52 static MODULEHEADER *mh = NULL; // raw as-is module header | |
53 static MODNOTE *patbuf = NULL; | |
54 static BOOL ust_loader = 0; // if TRUE, load as a ust module. | |
55 static CHAR nulls[3] = {0,0,0}; | |
56 | |
57 static BOOL LoadModuleHeader(MODULEHEADER *mh) | |
58 { | |
59 int t; | |
60 | |
61 _mm_read_string(mh->songname,20,modfp); | |
62 | |
63 for(t=0; t<15; t++) | |
64 { MSAMPINFO *s = &mh->samples[t]; | |
65 _mm_read_string(s->samplename,22,modfp); | |
66 s->length =_mm_read_M_UWORD(modfp); | |
67 s->finetune =_mm_read_UBYTE(modfp); | |
68 s->volume =_mm_read_UBYTE(modfp); | |
69 s->reppos =_mm_read_M_UWORD(modfp); | |
70 s->replen =_mm_read_M_UWORD(modfp); | |
71 } | |
72 | |
73 mh->songlength =_mm_read_UBYTE(modfp); | |
74 mh->magic1 =_mm_read_UBYTE(modfp); // should be 127 | |
75 _mm_read_UBYTES(mh->positions,128,modfp); | |
76 | |
77 return(!feof(modfp)); | |
78 } | |
79 | |
80 | |
81 static int CheckPatternType(int numpat) | |
82 | |
83 // Checks the patterns in the modfile for UST / 15-inst indications. | |
84 // For example, if an effect 3xx is found, it is assumed that the song | |
85 // is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST. | |
86 // Returns: 0 indecisive; 1 = UST; 2 = 15-inst | |
87 | |
88 { | |
89 int t; | |
90 UBYTE eff, dat; | |
91 | |
92 ust_loader = 1; | |
93 | |
94 for(t=0; t<numpat*(64U*4); t++) | |
95 { // Load the pattern into the temp buffer | |
96 // and convert it | |
97 | |
98 _mm_read_UBYTE(modfp); // read note | |
99 _mm_read_UBYTE(modfp); // read inst | |
100 eff = _mm_read_UBYTE(modfp); | |
101 dat = _mm_read_UBYTE(modfp); | |
102 | |
103 if((eff==3) && (dat!=0) || (eff >= 2)) return 2; | |
104 if(eff==1) | |
105 { if(dat > 0x1f) return 1; | |
106 if(dat < 0x3) return 2; | |
107 } | |
108 if((eff==2) && (dat > 0x1f)) return 1; | |
109 } | |
110 | |
111 return 0; | |
112 } | |
113 | |
114 | |
115 BOOL M15_Test(void) | |
116 { | |
117 int t, numpat; | |
118 MODULEHEADER mh; | |
119 | |
120 ust_loader = 0; | |
121 | |
122 if(!LoadModuleHeader(&mh)) return 0; | |
123 if(mh.magic1>127) return 0; | |
124 | |
125 for(t=0; t<15; t++) | |
126 { // all finetunes should be zero | |
127 if(mh.samples[t].finetune != 0) return 0; | |
128 | |
129 // all volumes should be <= 64 | |
130 if(mh.samples[t].volume > 64) return 0; | |
131 | |
132 // all instrument names should begin with s, st-, or a number | |
133 if(mh.samples[t].samplename[0] == 's') | |
134 { if((memcmp(mh.samples[t].samplename,"st-",3) != 0) && | |
135 (memcmp(mh.samples[t].samplename,"ST-",3) != 0) && | |
136 (memcmp(mh.samples[t].samplename,nulls,3) != 0)) | |
137 ust_loader = 1; | |
138 } else if((mh.samples[t].samplename[0] < '0') || (mh.samples[t].samplename[0] > '9')) | |
139 ust_loader = 1; | |
140 | |
141 if(mh.samples[t].length > 4999) | |
142 { ust_loader = 0; | |
143 if(mh.samples[t].length > 32768) return 0; | |
144 } | |
145 | |
146 if(!ust_loader) return 1; | |
147 | |
148 if(((mh.samples[t].reppos) + mh.samples[t].replen) > (mh.samples[t].length + 10)) | |
149 { ust_loader = 1; | |
150 return 1; | |
151 } | |
152 | |
153 } | |
154 | |
155 for(numpat=0, t=0; t<mh.songlength; t++) | |
156 { if(mh.positions[t] > numpat) | |
157 numpat = mh.positions[t]; | |
158 } | |
159 | |
160 numpat++; | |
161 switch(CheckPatternType(numpat)) | |
162 { case 0: // indecisive, so check more clues... | |
163 | |
164 break; | |
165 | |
166 case 1: ust_loader = 1; break; | |
167 case 2: ust_loader = 0; break; | |
168 } | |
169 | |
170 return 1; | |
171 } | |
172 | |
173 | |
174 BOOL M15_Init(void) | |
175 { | |
176 if(!(mh=(MODULEHEADER *)_mm_calloc(1,sizeof(MODULEHEADER)))) return 0; | |
177 return 1; | |
178 } | |
179 | |
180 | |
181 void M15_Cleanup(void) | |
182 { | |
183 if(mh!=NULL) free(mh); | |
184 if(patbuf!=NULL) free(patbuf); | |
185 | |
186 mh = NULL; | |
187 patbuf = NULL; | |
188 } | |
189 | |
190 | |
191 /* | |
192 Old (amiga) noteinfo: | |
193 | |
194 _____byte 1_____ byte2_ _____byte 3_____ byte4_ | |
195 / \ / \ / \ / \ | |
196 0000 0000-00000000 0000 0000-00000000 | |
197 | |
198 Upper four 12 bits for Lower four Effect command. | |
199 bits of sam- note period. bits of sam- | |
200 ple number. ple number. | |
201 | |
202 */ | |
203 | |
204 | |
205 static void M15_ConvertNote(MODNOTE *n) | |
206 { | |
207 UBYTE instrument,effect,effdat,note; | |
208 UWORD period; | |
209 | |
210 // extract the various information from the 4 bytes that | |
211 // make up a single note | |
212 | |
213 instrument = (n->a&0x10)|(n->c>>4); | |
214 period = (((UWORD)n->a&0xf)<<8)+n->b; | |
215 effect = n->c&0xf; | |
216 effdat = n->d; | |
217 | |
218 // Convert the period to a note number | |
219 | |
220 note=0; | |
221 if(period != 0) | |
222 { for(note=0; note<60; note++) | |
223 if(period >= npertab[note]) break; | |
224 note++; | |
225 if(note==61) note = 0; | |
226 } | |
227 | |
228 if(instrument!=0) UniInstrument(instrument-1); | |
229 if(note!=0) UniNote(note+23); | |
230 | |
231 // Convert pattern jump from Dec to Hex | |
232 if(effect == 0xd) | |
233 effdat = (((effdat&0xf0)>>4)*10)+(effdat&0xf); | |
234 | |
235 if(ust_loader) | |
236 { switch(effect) | |
237 { case 0: break; | |
238 case 1: | |
239 UniPTEffect(0,effdat); | |
240 break; | |
241 | |
242 case 2: | |
243 if(effdat&0xf) UniPTEffect(1,effdat&0xf); | |
244 if(effdat>>2) UniPTEffect(2,effdat>>2); | |
245 break; | |
246 | |
247 case 3: break; | |
248 | |
249 default: | |
250 UniPTEffect(effect,effdat); | |
251 break; | |
252 } | |
253 } else UniPTEffect(effect,effdat); | |
254 } | |
255 | |
256 | |
257 static UBYTE *M15_ConvertTrack(MODNOTE *n) | |
258 { | |
259 int t; | |
260 | |
261 UniReset(); | |
262 for(t=0; t<64; t++) | |
263 { M15_ConvertNote(n); | |
264 UniNewline(); | |
265 n += 4; | |
266 } | |
267 return UniDup(); | |
268 } | |
269 | |
270 | |
271 | |
272 static BOOL M15_LoadPatterns(void) | |
273 // Loads all patterns of a modfile and converts them into the | |
274 // 3 byte format. | |
275 { | |
276 int t,s,tracks=0; | |
277 | |
278 if(!AllocPatterns()) return 0; | |
279 if(!AllocTracks()) return 0; | |
280 | |
281 // Allocate temporary buffer for loading | |
282 // and converting the patterns | |
283 | |
284 if(!(patbuf=(MODNOTE *)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0; | |
285 | |
286 for(t=0; t<of.numpat; t++) | |
287 { // Load the pattern into the temp buffer | |
288 // and convert it | |
289 | |
290 for(s=0; s<(64U*4); s++) | |
291 { patbuf[s].a=_mm_read_UBYTE(modfp); | |
292 patbuf[s].b=_mm_read_UBYTE(modfp); | |
293 patbuf[s].c=_mm_read_UBYTE(modfp); | |
294 patbuf[s].d=_mm_read_UBYTE(modfp); | |
295 } | |
296 | |
297 for(s=0; s<4; s++) | |
298 if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0; | |
299 } | |
300 | |
301 return 1; | |
302 } | |
303 | |
304 | |
305 BOOL M15_Load(void) | |
306 { | |
307 int t; | |
308 SAMPLE *q; | |
309 MSAMPINFO *s; // old module sampleinfo | |
310 | |
311 // try to read module header | |
312 | |
313 if(!LoadModuleHeader(mh)) | |
314 { _mm_errno = MMERR_LOADING_HEADER; | |
315 return 0; | |
316 } | |
317 | |
318 | |
319 if(ust_loader) | |
320 of.modtype = strdup("Ultimate Soundtracker"); | |
321 else | |
322 of.modtype = strdup("Soundtracker"); | |
323 | |
324 // set module variables | |
325 | |
326 of.initspeed = 6; | |
327 of.inittempo = 125; | |
328 of.numchn = 4; // get number of channels | |
329 of.songname = DupStr(mh->songname,20); // make a cstr of songname | |
330 of.numpos = mh->songlength; // copy the songlength | |
331 | |
332 if(!AllocPositions(of.numpos)) return 0; | |
333 for(t=0; t<of.numpos; t++) | |
334 of.positions[t] = mh->positions[t]; | |
335 | |
336 | |
337 // Count the number of patterns | |
338 | |
339 of.numpat = 0; | |
340 | |
341 for(t=0; t<of.numpos; t++) | |
342 { if(of.positions[t] > of.numpat) | |
343 of.numpat = of.positions[t]; | |
344 } | |
345 of.numpat++; | |
346 of.numtrk = of.numpat*4; | |
347 | |
348 // Finally, init the sampleinfo structures | |
349 | |
350 of.numins = of.numsmp = 15; | |
351 if(!AllocSamples()) return 0; | |
352 | |
353 s = mh->samples; // init source pointer | |
354 q = of.samples; | |
355 | |
356 for(t=0; t<of.numins; t++) | |
357 { // convert the samplename | |
358 q->samplename = DupStr(s->samplename,22); | |
359 | |
360 // init the sampleinfo variables and | |
361 // convert the size pointers to longword format | |
362 | |
363 q->speed = finetune[s->finetune&0xf]; | |
364 q->volume = s->volume; | |
365 if(ust_loader) | |
366 q->loopstart = s->reppos; | |
367 else | |
368 q->loopstart = s->reppos<<1; | |
369 q->loopend = q->loopstart+(s->replen<<1); | |
370 q->length = s->length<<1; | |
371 | |
372 q->flags = SF_SIGNED | SF_UST_LOOP; | |
373 if(s->replen>1) q->flags |= SF_LOOP; | |
374 | |
375 // fix replen if repend>length | |
376 | |
377 if(q->loopend>q->length) q->loopend = q->length; | |
378 | |
379 s++; // point to next source sampleinfo | |
380 q++; | |
381 } | |
382 | |
383 if(!M15_LoadPatterns()) return 0; | |
384 | |
385 ust_loader = 0; | |
386 return 1; | |
387 } | |
388 | |
389 | |
390 CHAR *M15_LoadTitle(void) | |
391 { | |
392 CHAR s[20]; | |
393 | |
394 fseek(modfp,0,SEEK_SET); | |
395 if(!fread(s,22,1,modfp)) return NULL; | |
396 | |
397 return(DupStr(s,20)); | |
398 } | |
399 | |
400 | |
401 MLOADER load_m15 = | |
402 { NULL, | |
403 "15-instrument module", | |
404 "Portable MOD-15 loader v0.1", | |
405 M15_Init, | |
406 M15_Test, | |
407 M15_Load, | |
408 M15_Cleanup, | |
409 M15_LoadTitle | |
410 }; |