Mercurial > ~darius > hgwebdir.cgi > mikmod
comparison playercode/load_med.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_MED.C | |
4 | |
5 Description: | |
6 Amiga MED module loader | |
7 | |
8 Portability: | |
9 All systems - all compilers (hopefully) | |
10 | |
11 If this module is found to not be portable to any particular platform, | |
12 please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for | |
13 more information on contacting the author). | |
14 | |
15 */ | |
16 | |
17 #include <string.h> | |
18 #include "mikmod.h" | |
19 | |
20 #define MMD0_string 0x4D4D4430 | |
21 #define MMD1_string 0x4D4D4431 | |
22 | |
23 typedef struct MMD0 | |
24 { ULONG id; | |
25 ULONG modlen; | |
26 ULONG MMD0songP; // struct MMD0song *song; | |
27 UWORD psecnum; // for the player routine, MMD2 only | |
28 UWORD pseq; // " " " " | |
29 ULONG MMD0BlockPP; // struct MMD0Block **blockarr; | |
30 ULONG reserved1; | |
31 ULONG InstrHdrPP; // struct InstrHdr **smplarr; | |
32 ULONG reserved2; | |
33 ULONG MMD0expP; // struct MMD0exp *expdata; | |
34 ULONG reserved3; | |
35 UWORD pstate; // some data for the player routine | |
36 UWORD pblock; | |
37 UWORD pline; | |
38 UWORD pseqnum; | |
39 SWORD actplayline; | |
40 UBYTE counter; | |
41 UBYTE extra_songs; // number of songs - 1 | |
42 } MMD0; | |
43 | |
44 | |
45 typedef struct MMD0sample | |
46 { UWORD rep,replen; // offs: 0(s), 2(s) | |
47 UBYTE midich; // offs: 4(s) | |
48 UBYTE midipreset; // offs: 5(s) | |
49 UBYTE svol; // offs: 6(s) | |
50 SBYTE strans; // offs: 7(s) | |
51 } MMD0sample; | |
52 | |
53 | |
54 typedef struct MMD0song | |
55 { MMD0sample sample[63]; // 63 * 8 bytes = 504 bytes | |
56 UWORD numblocks; // offs: 504 | |
57 UWORD songlen; // offs: 506 | |
58 UBYTE playseq[256]; // offs: 508 | |
59 UWORD deftempo; // offs: 764 | |
60 SBYTE playtransp; // offs: 766 | |
61 UBYTE flags; // offs: 767 | |
62 UBYTE flags2; // offs: 768 | |
63 UBYTE tempo2; // offs: 769 | |
64 UBYTE trkvol[16]; // offs: 770 | |
65 UBYTE mastervol; // offs: 786 | |
66 UBYTE numsamples; // offs: 787 | |
67 } MMD0song; | |
68 | |
69 | |
70 typedef struct MMD0NOTE | |
71 { UBYTE a,b,c; | |
72 } MMD0NOTE; | |
73 | |
74 | |
75 typedef struct MMD1NOTE | |
76 { UBYTE a,b,c,d; | |
77 } MMD1NOTE; | |
78 | |
79 | |
80 typedef struct InstrHdr | |
81 { ULONG length; | |
82 SWORD type; | |
83 // Followed by actual data | |
84 } InstrHdr; | |
85 | |
86 | |
87 static MMD0 *mh = NULL; | |
88 static MMD0song *ms = NULL; | |
89 static ULONG *ba = NULL; | |
90 static MMD0NOTE *mmd0pat = NULL; | |
91 static MMD1NOTE *mmd1pat = NULL; | |
92 | |
93 #define d0note(row,col) mmd0pat[(row*(UWORD)of.numchn)+col] | |
94 #define d1note(row,col) mmd1pat[(row*(UWORD)of.numchn)+col] | |
95 | |
96 | |
97 static CHAR MED_Version[] = "MED"; | |
98 | |
99 | |
100 BOOL MED_Test(void) | |
101 { | |
102 UBYTE id[4]; | |
103 | |
104 if(!_mm_read_UBYTES(id,4,modfp)) return 0; | |
105 if(!memcmp(id,"MMD0",4)) return 1; | |
106 if(!memcmp(id,"MMD1",4)) return 1; | |
107 return 0; | |
108 } | |
109 | |
110 | |
111 BOOL MED_Init(void) | |
112 { | |
113 if(!(mh=(MMD0 *)_mm_calloc(1,sizeof(MMD0)))) return 0; | |
114 if(!(ms=(MMD0song *)_mm_calloc(1,sizeof(MMD0song)))) return 0; | |
115 return 1; | |
116 } | |
117 | |
118 | |
119 void MED_Cleanup(void) | |
120 { | |
121 if(mh!=NULL) free(mh); | |
122 if(ms!=NULL) free(ms); | |
123 if(ba!=NULL) free(ba); | |
124 if(mmd0pat!=NULL) free(mmd0pat); | |
125 if(mmd1pat!=NULL) free(mmd1pat); | |
126 | |
127 mh = NULL; | |
128 ms = NULL; | |
129 ba = NULL; // blockarr | |
130 mmd0pat = NULL; | |
131 mmd1pat = NULL; | |
132 } | |
133 | |
134 | |
135 void EffectCvt(UBYTE eff,UBYTE dat) | |
136 { | |
137 switch(eff) | |
138 { // 0x0 0x1 0x2 0x3 0x4 // PT effects | |
139 case 0x5: // PT vibrato with speed/depth nibbles swapped | |
140 UniPTEffect(0x4,(dat>>4) | ((dat&0xf)<<4) ); | |
141 break; | |
142 | |
143 case 0x6: // not used | |
144 case 0x7: // not used | |
145 case 0x8: // midi hold/decay | |
146 break; | |
147 | |
148 case 0x9: | |
149 if(dat<=0x20) UniPTEffect(0xf,dat); | |
150 break; | |
151 | |
152 // 0xa 0xb 0xc all PT effects | |
153 | |
154 case 0xd: // same as PT volslide | |
155 UniPTEffect(0xa,dat); | |
156 break; | |
157 | |
158 case 0xe: // synth jmp - midi | |
159 break; | |
160 | |
161 case 0xf: | |
162 // F00 does patternbreak with med | |
163 if(dat==0) UniPTEffect(0xd,0); | |
164 else if(dat<=0xa) UniPTEffect(0xf,dat); | |
165 else if(dat<0xf1) UniPTEffect(0xf,((UWORD)dat*125)/33); | |
166 else if(dat==0xff) UniPTEffect(0xc,0); // stop note | |
167 break; | |
168 | |
169 default: // all normal PT effects are handled here :) | |
170 // Convert pattern jump from Dec to Hex | |
171 if(eff == 0xd) | |
172 dat = (((dat&0xf0)>>4)*10)+(dat&0xf); | |
173 UniPTEffect(eff,dat); | |
174 break; | |
175 } | |
176 } | |
177 | |
178 | |
179 | |
180 UBYTE *MED_Convert1(int col) | |
181 { | |
182 int t; | |
183 UBYTE a,b,c,d,inst,note,eff,dat; | |
184 MMD1NOTE *n; | |
185 | |
186 UniReset(); | |
187 for(t=0; t<64; t++) | |
188 { n = &d1note(t,col); | |
189 a = n->a; | |
190 b = n->b; | |
191 c = n->c; | |
192 d = n->d; | |
193 | |
194 note = a&0x7f; | |
195 inst = b&0x3f; | |
196 eff = c&0xf; | |
197 dat = d; | |
198 | |
199 if(inst!=0) UniInstrument(inst-1); | |
200 if(note!=0) UniNote(note+23); | |
201 | |
202 EffectCvt(eff,dat); | |
203 UniNewline(); | |
204 } | |
205 | |
206 return UniDup(); | |
207 } | |
208 | |
209 | |
210 UBYTE *MED_Convert0(int col) | |
211 { | |
212 int t; | |
213 UBYTE a,b,c,inst,note,eff,dat; | |
214 MMD0NOTE *n; | |
215 | |
216 UniReset(); | |
217 for(t=0;t<64;t++) | |
218 { n = &d0note(t,col); | |
219 a = n->a; | |
220 b = n->b; | |
221 c = n->c; | |
222 | |
223 note = a & 0x3f; | |
224 a >>= 6; | |
225 a = ((a & 1) << 1) | (a >> 1); | |
226 | |
227 inst = (b >> 4) | (a << 4); | |
228 eff = b & 0xf; | |
229 dat = c; | |
230 | |
231 if(inst!=0) UniInstrument(inst-1); | |
232 if(note!=0) UniNote(note+35); | |
233 | |
234 EffectCvt(eff,dat); | |
235 UniNewline(); | |
236 } | |
237 return UniDup(); | |
238 } | |
239 | |
240 | |
241 BOOL LoadMMD0Patterns(void) | |
242 { | |
243 int t,row,col; | |
244 UWORD numtracks,numlines,maxlines=0,track=0; | |
245 MMD0NOTE *mmdp; | |
246 | |
247 // first, scan patterns to see how many channels are used | |
248 for(t=0; t<of.numpat; t++) | |
249 { _mm_fseek(modfp,ba[t],SEEK_SET); | |
250 numtracks = _mm_read_UBYTE(modfp); | |
251 numlines = _mm_read_UBYTE(modfp); | |
252 | |
253 if(numtracks>of.numchn) of.numchn = numtracks; | |
254 if(numlines>maxlines) maxlines = numlines; | |
255 } | |
256 | |
257 of.numtrk = of.numpat*of.numchn; | |
258 if(!AllocTracks()) return 0; | |
259 if(!AllocPatterns()) return 0; | |
260 | |
261 if(!(mmd0pat=(MMD0NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD0NOTE)))) return 0; | |
262 | |
263 // second read: no more mr. nice guy, | |
264 // really read and convert patterns | |
265 | |
266 for(t=0; t<of.numpat; t++) | |
267 { _mm_fseek(modfp,ba[t],SEEK_SET); | |
268 numtracks = _mm_read_UBYTE(modfp); | |
269 numlines = _mm_read_UBYTE(modfp); | |
270 | |
271 of.pattrows[t] = numlines+1; | |
272 memset(mmdp=mmd0pat,0,of.numchn*maxlines*sizeof(MMD0NOTE)); | |
273 for(row=numlines+1; row; row--) | |
274 { for(col=numtracks; col; col--,mmdp++) | |
275 { mmdp->a = _mm_read_UBYTE(modfp); | |
276 mmdp->b = _mm_read_UBYTE(modfp); | |
277 mmdp->c = _mm_read_UBYTE(modfp); | |
278 } | |
279 } | |
280 | |
281 for(col=0; col<of.numchn; col++) | |
282 { of.tracks[track] = MED_Convert0(col); | |
283 track++; | |
284 } | |
285 } | |
286 return 1; | |
287 } | |
288 | |
289 | |
290 BOOL LoadMMD1Patterns(void) | |
291 { | |
292 int t,row,col; | |
293 UWORD numtracks,numlines,maxlines=0,track=0; | |
294 MMD1NOTE *mmdp; | |
295 | |
296 // first, scan patterns to see how many channels are used | |
297 for(t=0; t<of.numpat; t++) | |
298 { _mm_fseek(modfp,ba[t],SEEK_SET); | |
299 numtracks = _mm_read_M_UWORD(modfp); | |
300 numlines = _mm_read_M_UWORD(modfp); | |
301 | |
302 _mm_fseek(modfp,sizeof(ULONG),SEEK_CUR); | |
303 if(numtracks>of.numchn) of.numchn = numtracks; | |
304 if(numlines>maxlines) maxlines = numlines; | |
305 } | |
306 | |
307 of.numtrk = of.numpat*of.numchn; | |
308 if(!AllocTracks()) return 0; | |
309 if(!AllocPatterns()) return 0; | |
310 | |
311 if(!(mmd1pat=(MMD1NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD1NOTE)))) return 0; | |
312 | |
313 // second read: no more mr. nice guy, really read and convert patterns | |
314 for(t=0; t<of.numpat; t++) | |
315 { _mm_fseek(modfp,ba[t],SEEK_SET); | |
316 numtracks = _mm_read_M_UWORD(modfp); | |
317 numlines = _mm_read_M_UWORD(modfp); | |
318 | |
319 _mm_fseek(modfp,sizeof(ULONG),SEEK_CUR); | |
320 of.pattrows[t] = numlines; | |
321 memset(mmdp=mmd1pat,0,of.numchn*maxlines*sizeof(MMD1NOTE)); | |
322 | |
323 for(row=numlines+1; row; row--) | |
324 { for(col=numtracks; col; col--,mmdp++) | |
325 { mmdp->a = _mm_read_UBYTE(modfp); | |
326 mmdp->b = _mm_read_UBYTE(modfp); | |
327 mmdp->c = _mm_read_UBYTE(modfp); | |
328 mmdp->d = _mm_read_UBYTE(modfp); | |
329 } | |
330 } | |
331 | |
332 for(col=0;col<of.numchn;col++) | |
333 { of.tracks[track]=MED_Convert1(col); | |
334 track++; | |
335 } | |
336 } | |
337 return 1; | |
338 } | |
339 | |
340 | |
341 | |
342 BOOL MED_Load(void) | |
343 { | |
344 int t; | |
345 ULONG sa[64]; | |
346 InstrHdr s; | |
347 SAMPLE *q; | |
348 MMD0sample *mss; | |
349 | |
350 // try to read module header | |
351 | |
352 mh->id = _mm_read_M_ULONG(modfp); | |
353 mh->modlen = _mm_read_M_ULONG(modfp); | |
354 mh->MMD0songP = _mm_read_M_ULONG(modfp); | |
355 mh->psecnum = _mm_read_M_UWORD(modfp); | |
356 mh->pseq = _mm_read_M_UWORD(modfp); | |
357 mh->MMD0BlockPP = _mm_read_M_ULONG(modfp); | |
358 mh->reserved1 = _mm_read_M_ULONG(modfp); | |
359 mh->InstrHdrPP = _mm_read_M_ULONG(modfp); | |
360 mh->reserved2 = _mm_read_M_ULONG(modfp); | |
361 mh->MMD0expP = _mm_read_M_ULONG(modfp); | |
362 mh->reserved3 = _mm_read_M_ULONG(modfp); | |
363 mh->pstate = _mm_read_M_UWORD(modfp); | |
364 mh->pblock = _mm_read_M_UWORD(modfp); | |
365 mh->pline = _mm_read_M_UWORD(modfp); | |
366 mh->pseqnum = _mm_read_M_UWORD(modfp); | |
367 mh->actplayline = _mm_read_M_SWORD(modfp); | |
368 mh->counter = _mm_read_UBYTE(modfp); | |
369 mh->extra_songs = _mm_read_UBYTE(modfp); | |
370 | |
371 // Seek to MMD0song struct | |
372 _mm_fseek(modfp,mh->MMD0songP,SEEK_SET); | |
373 | |
374 | |
375 // Load the MMD0 Song Header | |
376 | |
377 mss = ms->sample; // load the sample data first | |
378 for(t=63; t; t--, mss++) | |
379 { mss->rep = _mm_read_M_UWORD(modfp); | |
380 mss->replen = _mm_read_M_UWORD(modfp); | |
381 mss->midich = _mm_read_UBYTE(modfp); | |
382 mss->midipreset = _mm_read_UBYTE(modfp); | |
383 mss->svol = _mm_read_UBYTE(modfp); | |
384 mss->strans = _mm_read_SBYTE(modfp); | |
385 } | |
386 | |
387 ms->numblocks = _mm_read_M_UWORD(modfp); | |
388 ms->songlen = _mm_read_M_UWORD(modfp); | |
389 _mm_read_UBYTES(ms->playseq,256,modfp); | |
390 ms->deftempo = _mm_read_M_UWORD(modfp); | |
391 ms->playtransp = _mm_read_SBYTE(modfp); | |
392 ms->flags = _mm_read_UBYTE(modfp); | |
393 ms->flags2 = _mm_read_UBYTE(modfp); | |
394 ms->tempo2 = _mm_read_UBYTE(modfp); | |
395 _mm_read_UBYTES(ms->trkvol,16,modfp); | |
396 ms->mastervol = _mm_read_UBYTE(modfp); | |
397 ms->numsamples = _mm_read_UBYTE(modfp); | |
398 | |
399 // check for a bad header | |
400 if(feof(modfp)) | |
401 { _mm_errno = MMERR_LOADING_HEADER; | |
402 return 0; | |
403 } | |
404 | |
405 // seek to and read the samplepointer array | |
406 _mm_fseek(modfp,mh->InstrHdrPP,SEEK_SET); | |
407 if(!_mm_read_M_ULONGS(sa,ms->numsamples,modfp)) | |
408 { _mm_errno = MMERR_LOADING_HEADER; | |
409 return 0; | |
410 } | |
411 | |
412 // alloc and read the blockpointer array | |
413 if(!(ba=(ULONG *)_mm_calloc(ms->numblocks, sizeof(ULONG)))) return 0; | |
414 _mm_fseek(modfp,mh->MMD0BlockPP,SEEK_SET); | |
415 if(!_mm_read_M_ULONGS(ba,ms->numblocks,modfp)) | |
416 { _mm_errno = MMERR_LOADING_HEADER; | |
417 return 0; | |
418 } | |
419 | |
420 | |
421 // copy song positions | |
422 if(!AllocPositions(ms->songlen)) return 0; | |
423 for(t=0; t<ms->songlen; t++) | |
424 of.positions[t] = ms->playseq[t]; | |
425 | |
426 of.initspeed = 6; | |
427 of.inittempo = ((UWORD)ms->deftempo*125)/33; | |
428 of.modtype = strdup(MED_Version); | |
429 of.numchn = 0; // will be counted later | |
430 of.numpat = ms->numblocks; | |
431 of.numpos = ms->songlen; | |
432 of.numins = ms->numsamples; | |
433 | |
434 of.numsmp = of.numins; | |
435 if(!AllocSamples()) return 0; | |
436 q = of.samples; | |
437 | |
438 for(t=0; t<of.numins; t++) | |
439 { _mm_fseek(modfp,sa[t],SEEK_SET); | |
440 s.length = _mm_read_M_ULONG(modfp); | |
441 s.type = _mm_read_M_SWORD(modfp); | |
442 | |
443 if(feof(modfp)) | |
444 { _mm_errno = MMERR_LOADING_SAMPLEINFO; | |
445 return 0; | |
446 } | |
447 | |
448 q->samplename = NULL; | |
449 q->length = s.length; | |
450 q->seekpos = _mm_ftell(modfp); | |
451 q->loopstart = ms->sample[t].rep<<1; | |
452 q->loopend = q->loopstart+(ms->sample[t].replen<<1); | |
453 q->flags = SF_SIGNED; | |
454 q->speed = 8363; | |
455 q->volume = 64; | |
456 | |
457 if(ms->sample[t].replen>1) q->flags|=SF_LOOP; | |
458 | |
459 // don't load sample if length>='MMD0' hah.. hah.. very funny.. NOT! | |
460 if(q->length >= MMD0_string) q->length = 0; | |
461 | |
462 q++; | |
463 } | |
464 | |
465 | |
466 if(mh->id==MMD0_string) | |
467 { if(!LoadMMD0Patterns()) return 0; | |
468 } else if(mh->id==MMD1_string) | |
469 { if(!LoadMMD1Patterns()) return 0; | |
470 } else | |
471 { _mm_errno = MMERR_NOT_A_MODULE; | |
472 return 0; | |
473 } | |
474 | |
475 return 1; | |
476 } | |
477 | |
478 | |
479 MLOADER load_med = | |
480 { NULL, | |
481 "MED", | |
482 "MED loader v0.1", | |
483 MED_Init, | |
484 MED_Test, | |
485 MED_Load, | |
486 MED_Cleanup, | |
487 NULL | |
488 }; | |
489 | |
490 |