diff options
Diffstat (limited to 'apps/plugins/mikmod/load_xm.c')
-rw-r--r-- | apps/plugins/mikmod/load_xm.c | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_xm.c b/apps/plugins/mikmod/load_xm.c new file mode 100644 index 0000000000..54a95aa2e6 --- /dev/null +++ b/apps/plugins/mikmod/load_xm.c | |||
@@ -0,0 +1,829 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS for complete list. | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU Library General Public License as | ||
7 | published by the Free Software Foundation; either version 2 of | ||
8 | the License, or (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
18 | 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /*============================================================================== | ||
22 | |||
23 | $Id: load_xm.c,v 1.5 2008/02/29 18:49:03 denis111 Exp $ | ||
24 | |||
25 | Fasttracker (XM) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | typedef struct XMHEADER { | ||
52 | CHAR id[17]; /* ID text: 'Extended module: ' */ | ||
53 | CHAR songname[21]; /* Module name */ | ||
54 | CHAR trackername[20]; /* Tracker name */ | ||
55 | UWORD version; /* Version number */ | ||
56 | ULONG headersize; /* Header size */ | ||
57 | UWORD songlength; /* Song length (in patten order table) */ | ||
58 | UWORD restart; /* Restart position */ | ||
59 | UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */ | ||
60 | UWORD numpat; /* Number of patterns (max 256) */ | ||
61 | UWORD numins; /* Number of instruments (max 128) */ | ||
62 | UWORD flags; | ||
63 | UWORD tempo; /* Default tempo */ | ||
64 | UWORD bpm; /* Default BPM */ | ||
65 | UBYTE orders[256]; /* Pattern order table */ | ||
66 | } XMHEADER; | ||
67 | |||
68 | typedef struct XMINSTHEADER { | ||
69 | ULONG size; /* Instrument size */ | ||
70 | CHAR name[22]; /* Instrument name */ | ||
71 | UBYTE type; /* Instrument type (always 0) */ | ||
72 | UWORD numsmp; /* Number of samples in instrument */ | ||
73 | ULONG ssize; | ||
74 | } XMINSTHEADER; | ||
75 | |||
76 | #define XMENVCNT (12*2) | ||
77 | #define XMNOTECNT (8*OCTAVE) | ||
78 | typedef struct XMPATCHHEADER { | ||
79 | UBYTE what[XMNOTECNT]; /* Sample number for all notes */ | ||
80 | UWORD volenv[XMENVCNT]; /* Points for volume envelope */ | ||
81 | UWORD panenv[XMENVCNT]; /* Points for panning envelope */ | ||
82 | UBYTE volpts; /* Number of volume points */ | ||
83 | UBYTE panpts; /* Number of panning points */ | ||
84 | UBYTE volsus; /* Volume sustain point */ | ||
85 | UBYTE volbeg; /* Volume loop start point */ | ||
86 | UBYTE volend; /* Volume loop end point */ | ||
87 | UBYTE pansus; /* Panning sustain point */ | ||
88 | UBYTE panbeg; /* Panning loop start point */ | ||
89 | UBYTE panend; /* Panning loop end point */ | ||
90 | UBYTE volflg; /* Volume type: bit 0: On; 1: Sustain; 2: Loop */ | ||
91 | UBYTE panflg; /* Panning type: bit 0: On; 1: Sustain; 2: Loop */ | ||
92 | UBYTE vibflg; /* Vibrato type */ | ||
93 | UBYTE vibsweep; /* Vibrato sweep */ | ||
94 | UBYTE vibdepth; /* Vibrato depth */ | ||
95 | UBYTE vibrate; /* Vibrato rate */ | ||
96 | UWORD volfade; /* Volume fadeout */ | ||
97 | } XMPATCHHEADER; | ||
98 | |||
99 | typedef struct XMWAVHEADER { | ||
100 | ULONG length; /* Sample length */ | ||
101 | ULONG loopstart; /* Sample loop start */ | ||
102 | ULONG looplength; /* Sample loop length */ | ||
103 | UBYTE volume; /* Volume */ | ||
104 | SBYTE finetune; /* Finetune (signed byte -128..+127) */ | ||
105 | UBYTE type; /* Loop type */ | ||
106 | UBYTE panning; /* Panning (0-255) */ | ||
107 | SBYTE relnote; /* Relative note number (signed byte) */ | ||
108 | UBYTE reserved; | ||
109 | CHAR samplename[22]; /* Sample name */ | ||
110 | UBYTE vibtype; /* Vibrato type */ | ||
111 | UBYTE vibsweep; /* Vibrato sweep */ | ||
112 | UBYTE vibdepth; /* Vibrato depth */ | ||
113 | UBYTE vibrate; /* Vibrato rate */ | ||
114 | } XMWAVHEADER; | ||
115 | |||
116 | typedef struct XMPATHEADER { | ||
117 | ULONG size; /* Pattern header length */ | ||
118 | UBYTE packing; /* Packing type (always 0) */ | ||
119 | UWORD numrows; /* Number of rows in pattern (1..256) */ | ||
120 | SWORD packsize; /* Packed patterndata size */ | ||
121 | } XMPATHEADER; | ||
122 | |||
123 | typedef struct XMNOTE { | ||
124 | UBYTE note,ins,vol,eff,dat; | ||
125 | } XMNOTE; | ||
126 | |||
127 | /*========== Loader variables */ | ||
128 | |||
129 | static XMNOTE *xmpat=NULL; | ||
130 | static XMHEADER *mh=NULL; | ||
131 | |||
132 | /* increment unit for sample array MikMod_reallocation */ | ||
133 | #define XM_SMPINCR 64 | ||
134 | static ULONG *nextwav=NULL; | ||
135 | static XMWAVHEADER *wh=NULL,*s=NULL; | ||
136 | |||
137 | /*========== Loader code */ | ||
138 | |||
139 | int XM_Test(void) | ||
140 | { | ||
141 | UBYTE id[38]; | ||
142 | |||
143 | if(!_mm_read_UBYTES(id,38,modreader)) return 0; | ||
144 | if(memcmp(id,"Extended Module: ",17)) return 0; | ||
145 | if(id[37]==0x1a) return 1; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | int XM_Init(void) | ||
150 | { | ||
151 | if(!(mh=(XMHEADER *)MikMod_malloc(sizeof(XMHEADER)))) return 0; | ||
152 | return 1; | ||
153 | } | ||
154 | |||
155 | void XM_Cleanup(void) | ||
156 | { | ||
157 | MikMod_free(mh); | ||
158 | } | ||
159 | |||
160 | static int XM_ReadNote(XMNOTE* n) | ||
161 | { | ||
162 | UBYTE cmp,result=1; | ||
163 | |||
164 | memset(n,0,sizeof(XMNOTE)); | ||
165 | cmp=_mm_read_UBYTE(modreader); | ||
166 | |||
167 | if(cmp&0x80) { | ||
168 | if(cmp&1) { result++;n->note = _mm_read_UBYTE(modreader); } | ||
169 | if(cmp&2) { result++;n->ins = _mm_read_UBYTE(modreader); } | ||
170 | if(cmp&4) { result++;n->vol = _mm_read_UBYTE(modreader); } | ||
171 | if(cmp&8) { result++;n->eff = _mm_read_UBYTE(modreader); } | ||
172 | if(cmp&16) { result++;n->dat = _mm_read_UBYTE(modreader); } | ||
173 | } else { | ||
174 | n->note = cmp; | ||
175 | n->ins = _mm_read_UBYTE(modreader); | ||
176 | n->vol = _mm_read_UBYTE(modreader); | ||
177 | n->eff = _mm_read_UBYTE(modreader); | ||
178 | n->dat = _mm_read_UBYTE(modreader); | ||
179 | result += 4; | ||
180 | } | ||
181 | return result; | ||
182 | } | ||
183 | |||
184 | static UBYTE* XM_Convert(XMNOTE* xmtrack,UWORD rows) | ||
185 | { | ||
186 | int t; | ||
187 | UBYTE note,ins,vol,eff,dat; | ||
188 | |||
189 | UniReset(); | ||
190 | for(t=0;t<rows;t++) { | ||
191 | note = xmtrack->note; | ||
192 | ins = xmtrack->ins; | ||
193 | vol = xmtrack->vol; | ||
194 | eff = xmtrack->eff; | ||
195 | dat = xmtrack->dat; | ||
196 | |||
197 | if(note) { | ||
198 | if(note>XMNOTECNT) | ||
199 | UniEffect(UNI_KEYFADE,0); | ||
200 | else | ||
201 | UniNote(note-1); | ||
202 | } | ||
203 | if(ins) UniInstrument(ins-1); | ||
204 | |||
205 | switch(vol>>4) { | ||
206 | case 0x6: /* volslide down */ | ||
207 | if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol&0xf); | ||
208 | break; | ||
209 | case 0x7: /* volslide up */ | ||
210 | if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol<<4); | ||
211 | break; | ||
212 | |||
213 | /* volume-row fine volume slide is compatible with protracker | ||
214 | EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as | ||
215 | opposed to 'take the last sliding value'. */ | ||
216 | case 0x8: /* finevol down */ | ||
217 | UniPTEffect(0xe,0xb0|(vol&0xf)); | ||
218 | break; | ||
219 | case 0x9: /* finevol up */ | ||
220 | UniPTEffect(0xe,0xa0|(vol&0xf)); | ||
221 | break; | ||
222 | case 0xa: /* set vibrato speed */ | ||
223 | UniEffect(UNI_XMEFFECT4,vol<<4); | ||
224 | break; | ||
225 | case 0xb: /* vibrato */ | ||
226 | UniEffect(UNI_XMEFFECT4,vol&0xf); | ||
227 | break; | ||
228 | case 0xc: /* set panning */ | ||
229 | UniPTEffect(0x8,vol<<4); | ||
230 | break; | ||
231 | case 0xd: /* panning slide left (only slide when data not zero) */ | ||
232 | if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol&0xf); | ||
233 | break; | ||
234 | case 0xe: /* panning slide right (only slide when data not zero) */ | ||
235 | if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol<<4); | ||
236 | break; | ||
237 | case 0xf: /* tone porta */ | ||
238 | UniPTEffect(0x3,vol<<4); | ||
239 | break; | ||
240 | default: | ||
241 | if((vol>=0x10)&&(vol<=0x50)) | ||
242 | UniPTEffect(0xc,vol-0x10); | ||
243 | } | ||
244 | |||
245 | switch(eff) { | ||
246 | case 0x4: | ||
247 | UniEffect(UNI_XMEFFECT4,dat); | ||
248 | break; | ||
249 | case 0x6: | ||
250 | UniEffect(UNI_XMEFFECT6,dat); | ||
251 | break; | ||
252 | case 0xa: | ||
253 | UniEffect(UNI_XMEFFECTA,dat); | ||
254 | break; | ||
255 | case 0xe: /* Extended effects */ | ||
256 | switch(dat>>4) { | ||
257 | case 0x1: /* XM fine porta up */ | ||
258 | UniEffect(UNI_XMEFFECTE1,dat&0xf); | ||
259 | break; | ||
260 | case 0x2: /* XM fine porta down */ | ||
261 | UniEffect(UNI_XMEFFECTE2,dat&0xf); | ||
262 | break; | ||
263 | case 0xa: /* XM fine volume up */ | ||
264 | UniEffect(UNI_XMEFFECTEA,dat&0xf); | ||
265 | break; | ||
266 | case 0xb: /* XM fine volume down */ | ||
267 | UniEffect(UNI_XMEFFECTEB,dat&0xf); | ||
268 | break; | ||
269 | default: | ||
270 | UniPTEffect(eff,dat); | ||
271 | } | ||
272 | break; | ||
273 | case 'G'-55: /* G - set global volume */ | ||
274 | UniEffect(UNI_XMEFFECTG,dat>64?128:dat<<1); | ||
275 | break; | ||
276 | case 'H'-55: /* H - global volume slide */ | ||
277 | UniEffect(UNI_XMEFFECTH,dat); | ||
278 | break; | ||
279 | case 'K'-55: /* K - keyOff and KeyFade */ | ||
280 | UniEffect(UNI_KEYFADE,dat); | ||
281 | break; | ||
282 | case 'L'-55: /* L - set envelope position */ | ||
283 | UniEffect(UNI_XMEFFECTL,dat); | ||
284 | break; | ||
285 | case 'P'-55: /* P - panning slide */ | ||
286 | UniEffect(UNI_XMEFFECTP,dat); | ||
287 | break; | ||
288 | case 'R'-55: /* R - multi retrig note */ | ||
289 | UniEffect(UNI_S3MEFFECTQ,dat); | ||
290 | break; | ||
291 | case 'T'-55: /* T - Tremor */ | ||
292 | UniEffect(UNI_S3MEFFECTI,dat); | ||
293 | break; | ||
294 | case 'X'-55: | ||
295 | switch(dat>>4) { | ||
296 | case 1: /* X1 - Extra Fine Porta up */ | ||
297 | UniEffect(UNI_XMEFFECTX1,dat&0xf); | ||
298 | break; | ||
299 | case 2: /* X2 - Extra Fine Porta down */ | ||
300 | UniEffect(UNI_XMEFFECTX2,dat&0xf); | ||
301 | break; | ||
302 | } | ||
303 | break; | ||
304 | default: | ||
305 | if(eff<=0xf) { | ||
306 | /* the pattern jump destination is written in decimal, | ||
307 | but it seems some poor tracker software writes them | ||
308 | in hexadecimal... (sigh) */ | ||
309 | if (eff==0xd) | ||
310 | /* don't change anything if we're sure it's in hexa */ | ||
311 | if ((((dat&0xf0)>>4)<=9)&&((dat&0xf)<=9)) | ||
312 | /* otherwise, convert from dec to hex */ | ||
313 | dat=(((dat&0xf0)>>4)*10)+(dat&0xf); | ||
314 | UniPTEffect(eff,dat); | ||
315 | } | ||
316 | break; | ||
317 | } | ||
318 | UniNewline(); | ||
319 | xmtrack++; | ||
320 | } | ||
321 | return UniDup(); | ||
322 | } | ||
323 | |||
324 | static int LoadPatterns(int dummypat) | ||
325 | { | ||
326 | int t,u,v,numtrk; | ||
327 | |||
328 | if(!AllocTracks()) return 0; | ||
329 | if(!AllocPatterns()) return 0; | ||
330 | |||
331 | numtrk=0; | ||
332 | for(t=0;t<mh->numpat;t++) { | ||
333 | XMPATHEADER ph; | ||
334 | |||
335 | ph.size =_mm_read_I_ULONG(modreader); | ||
336 | if (ph.size<(mh->version==0x0102?8:9)) { | ||
337 | _mm_errno=MMERR_LOADING_PATTERN; | ||
338 | return 0; | ||
339 | } | ||
340 | ph.packing =_mm_read_UBYTE(modreader); | ||
341 | if(ph.packing) { | ||
342 | _mm_errno=MMERR_LOADING_PATTERN; | ||
343 | return 0; | ||
344 | } | ||
345 | if(mh->version==0x0102) | ||
346 | ph.numrows =_mm_read_UBYTE(modreader)+1; | ||
347 | else | ||
348 | ph.numrows =_mm_read_I_UWORD(modreader); | ||
349 | ph.packsize =_mm_read_I_UWORD(modreader); | ||
350 | |||
351 | ph.size-=(mh->version==0x0102?8:9); | ||
352 | if(ph.size) | ||
353 | _mm_fseek(modreader,ph.size,SEEK_CUR); | ||
354 | |||
355 | of.pattrows[t]=ph.numrows; | ||
356 | |||
357 | if(ph.numrows) { | ||
358 | if(!(xmpat=(XMNOTE*)MikMod_calloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) | ||
359 | return 0; | ||
360 | |||
361 | /* when packsize is 0, don't try to load a pattern.. it's empty. */ | ||
362 | if(ph.packsize) | ||
363 | for(u=0;u<ph.numrows;u++) | ||
364 | for(v=0;v<of.numchn;v++) { | ||
365 | if(!ph.packsize) break; | ||
366 | |||
367 | ph.packsize-=XM_ReadNote(&xmpat[(v*ph.numrows)+u]); | ||
368 | if(ph.packsize<0) { | ||
369 | MikMod_free(xmpat);xmpat=NULL; | ||
370 | _mm_errno=MMERR_LOADING_PATTERN; | ||
371 | return 0; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | if(ph.packsize) { | ||
376 | _mm_fseek(modreader,ph.packsize,SEEK_CUR); | ||
377 | } | ||
378 | |||
379 | if(_mm_eof(modreader)) { | ||
380 | MikMod_free(xmpat);xmpat=NULL; | ||
381 | _mm_errno=MMERR_LOADING_PATTERN; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | for(v=0;v<of.numchn;v++) | ||
386 | of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows); | ||
387 | |||
388 | MikMod_free(xmpat);xmpat=NULL; | ||
389 | } else { | ||
390 | for(v=0;v<of.numchn;v++) | ||
391 | of.tracks[numtrk++]=XM_Convert(NULL,ph.numrows); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | if(dummypat) { | ||
396 | of.pattrows[t]=64; | ||
397 | if(!(xmpat=(XMNOTE*)MikMod_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0; | ||
398 | for(v=0;v<of.numchn;v++) | ||
399 | of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64); | ||
400 | MikMod_free(xmpat);xmpat=NULL; | ||
401 | } | ||
402 | |||
403 | return 1; | ||
404 | } | ||
405 | |||
406 | static void FixEnvelope(ENVPT *cur, int pts) | ||
407 | { | ||
408 | int u, old, tmp; | ||
409 | ENVPT *prev; | ||
410 | |||
411 | /* Some broken XM editing program will only save the low byte | ||
412 | of the position value. Try to compensate by adding the | ||
413 | missing high byte. */ | ||
414 | |||
415 | prev = cur++; | ||
416 | old = prev->pos; | ||
417 | |||
418 | for (u = 1; u < pts; u++, prev++, cur++) { | ||
419 | if (cur->pos < prev->pos) { | ||
420 | if (cur->pos < 0x100) { | ||
421 | if (cur->pos > old) /* same hex century */ | ||
422 | tmp = cur->pos + (prev->pos - old); | ||
423 | else | ||
424 | tmp = cur->pos | ((prev->pos + 0x100) & 0xff00); | ||
425 | old = cur->pos; | ||
426 | cur->pos = tmp; | ||
427 | #ifdef MIKMOD_DEBUG | ||
428 | fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d -> %d\n", | ||
429 | u, pts, prev->pos, old, cur->pos); | ||
430 | #endif | ||
431 | } else { | ||
432 | #ifdef MIKMOD_DEBUG | ||
433 | /* different brokenness style... fix unknown */ | ||
434 | fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d\n", | ||
435 | u, pts, old, cur->pos); | ||
436 | #endif | ||
437 | old = cur->pos; | ||
438 | } | ||
439 | } else | ||
440 | old = cur->pos; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | static int LoadInstruments(void) | ||
445 | { | ||
446 | int t,u, ck; | ||
447 | INSTRUMENT *d; | ||
448 | ULONG next=0; | ||
449 | UWORD wavcnt=0; | ||
450 | |||
451 | if(!AllocInstruments()) return 0; | ||
452 | d=of.instruments; | ||
453 | for(t=0;t<of.numins;t++,d++) { | ||
454 | XMINSTHEADER ih; | ||
455 | long headend; | ||
456 | |||
457 | memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD)); | ||
458 | |||
459 | /* read instrument header */ | ||
460 | headend = _mm_ftell(modreader); | ||
461 | ih.size = _mm_read_I_ULONG(modreader); | ||
462 | headend += ih.size; | ||
463 | ck = _mm_ftell(modreader); | ||
464 | _mm_fseek(modreader,0,SEEK_END); | ||
465 | if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) { | ||
466 | _mm_fseek(modreader,ck,SEEK_SET); | ||
467 | break; | ||
468 | } | ||
469 | _mm_fseek(modreader,ck,SEEK_SET); | ||
470 | _mm_read_string(ih.name, 22, modreader); | ||
471 | ih.type = _mm_read_UBYTE(modreader); | ||
472 | ih.numsmp = _mm_read_I_UWORD(modreader); | ||
473 | |||
474 | d->insname = DupStr(ih.name,22,1); | ||
475 | |||
476 | if((SWORD)ih.size>29) { | ||
477 | ih.ssize = _mm_read_I_ULONG(modreader); | ||
478 | if(((SWORD)ih.numsmp>0)&&(ih.numsmp<=XMNOTECNT)) { | ||
479 | XMPATCHHEADER pth; | ||
480 | int p; | ||
481 | |||
482 | _mm_read_UBYTES (pth.what,XMNOTECNT,modreader); | ||
483 | _mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader); | ||
484 | _mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader); | ||
485 | pth.volpts = _mm_read_UBYTE(modreader); | ||
486 | pth.panpts = _mm_read_UBYTE(modreader); | ||
487 | pth.volsus = _mm_read_UBYTE(modreader); | ||
488 | pth.volbeg = _mm_read_UBYTE(modreader); | ||
489 | pth.volend = _mm_read_UBYTE(modreader); | ||
490 | pth.pansus = _mm_read_UBYTE(modreader); | ||
491 | pth.panbeg = _mm_read_UBYTE(modreader); | ||
492 | pth.panend = _mm_read_UBYTE(modreader); | ||
493 | pth.volflg = _mm_read_UBYTE(modreader); | ||
494 | pth.panflg = _mm_read_UBYTE(modreader); | ||
495 | pth.vibflg = _mm_read_UBYTE(modreader); | ||
496 | pth.vibsweep = _mm_read_UBYTE(modreader); | ||
497 | pth.vibdepth = _mm_read_UBYTE(modreader); | ||
498 | pth.vibrate = _mm_read_UBYTE(modreader); | ||
499 | pth.volfade = _mm_read_I_UWORD(modreader); | ||
500 | |||
501 | /* read the remainder of the header | ||
502 | (2 bytes for 1.03, 22 for 1.04) */ | ||
503 | if (headend>=_mm_ftell(modreader)) for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader); | ||
504 | |||
505 | /* we can't trust the envelope point count here, as some | ||
506 | modules have incorrect values (K_OSPACE.XM reports 32 volume | ||
507 | points, for example). */ | ||
508 | if(pth.volpts>XMENVCNT/2) pth.volpts=XMENVCNT/2; | ||
509 | if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2; | ||
510 | |||
511 | if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) { | ||
512 | if(nextwav) { MikMod_free(nextwav);nextwav=NULL; } | ||
513 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
514 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | for(u=0;u<XMNOTECNT;u++) | ||
519 | d->samplenumber[u]=pth.what[u]+of.numsmp; | ||
520 | d->volfade = pth.volfade; | ||
521 | |||
522 | #if defined __STDC__ || defined _MSC_VER || defined MPW_C | ||
523 | #define XM_ProcessEnvelope(name) \ | ||
524 | for (u = 0; u < (XMENVCNT >> 1); u++) { \ | ||
525 | d-> name##env[u].pos = pth. name##env[u << 1]; \ | ||
526 | d-> name##env[u].val = pth. name##env[(u << 1)+ 1]; \ | ||
527 | } \ | ||
528 | if (pth. name##flg&1) d-> name##flg|=EF_ON; \ | ||
529 | if (pth. name##flg&2) d-> name##flg|=EF_SUSTAIN; \ | ||
530 | if (pth. name##flg&4) d-> name##flg|=EF_LOOP; \ | ||
531 | d-> name##susbeg=d-> name##susend=pth. name##sus; \ | ||
532 | d-> name##beg=pth. name##beg; \ | ||
533 | d-> name##end=pth. name##end; \ | ||
534 | d-> name##pts=pth. name##pts; \ | ||
535 | \ | ||
536 | /* scale envelope */ \ | ||
537 | for (p=0;p<XMENVCNT/2;p++) \ | ||
538 | d-> name##env[p].val<<=2; \ | ||
539 | \ | ||
540 | if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \ | ||
541 | d-> name##flg&=~EF_ON | ||
542 | #else | ||
543 | #define XM_ProcessEnvelope(name) \ | ||
544 | for (u = 0; u < (XMENVCNT >> 1); u++) { \ | ||
545 | d-> name/**/env[u].pos = pth. name/**/env[u << 1]; \ | ||
546 | d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \ | ||
547 | } \ | ||
548 | if (pth. name/**/flg&1) d-> name/**/flg|=EF_ON; \ | ||
549 | if (pth. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \ | ||
550 | if (pth. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \ | ||
551 | d-> name/**/susbeg=d-> name/**/susend= \ | ||
552 | pth. name/**/sus; \ | ||
553 | d-> name/**/beg=pth. name/**/beg; \ | ||
554 | d-> name/**/end=pth. name/**/end; \ | ||
555 | d-> name/**/pts=pth. name/**/pts; \ | ||
556 | \ | ||
557 | /* scale envelope */ \ | ||
558 | for (p=0;p<XMENVCNT/2;p++) \ | ||
559 | d-> name/**/env[p].val<<=2; \ | ||
560 | \ | ||
561 | if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \ | ||
562 | d-> name/**/flg&=~EF_ON | ||
563 | #endif | ||
564 | |||
565 | XM_ProcessEnvelope(vol); | ||
566 | XM_ProcessEnvelope(pan); | ||
567 | #undef XM_ProcessEnvelope | ||
568 | |||
569 | if (d->volflg & EF_ON) | ||
570 | FixEnvelope(d->volenv, d->volpts); | ||
571 | if (d->panflg & EF_ON) | ||
572 | FixEnvelope(d->panenv, d->panpts); | ||
573 | |||
574 | /* Samples are stored outside the instrument struct now, so we | ||
575 | have to load them all into a temp area, count the of.numsmp | ||
576 | along the way and then do an AllocSamples() and move | ||
577 | everything over */ | ||
578 | if(mh->version>0x0103) next = 0; | ||
579 | for(u=0;u<ih.numsmp;u++,s++) { | ||
580 | /* Allocate more room for sample information if necessary */ | ||
581 | if(of.numsmp+u==wavcnt) { | ||
582 | wavcnt+=XM_SMPINCR; | ||
583 | if(!(nextwav=MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))){ | ||
584 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
585 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
586 | return 0; | ||
587 | } | ||
588 | if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) { | ||
589 | MikMod_free(nextwav);nextwav=NULL; | ||
590 | _mm_errno = MMERR_OUT_OF_MEMORY; | ||
591 | return 0; | ||
592 | } | ||
593 | s=wh+(wavcnt-XM_SMPINCR); | ||
594 | } | ||
595 | |||
596 | s->length =_mm_read_I_ULONG (modreader); | ||
597 | s->loopstart =_mm_read_I_ULONG (modreader); | ||
598 | s->looplength =_mm_read_I_ULONG (modreader); | ||
599 | s->volume =_mm_read_UBYTE (modreader); | ||
600 | s->finetune =_mm_read_SBYTE (modreader); | ||
601 | s->type =_mm_read_UBYTE (modreader); | ||
602 | s->panning =_mm_read_UBYTE (modreader); | ||
603 | s->relnote =_mm_read_SBYTE (modreader); | ||
604 | s->vibtype = pth.vibflg; | ||
605 | s->vibsweep = pth.vibsweep; | ||
606 | s->vibdepth = pth.vibdepth*4; | ||
607 | s->vibrate = pth.vibrate; | ||
608 | s->reserved =_mm_read_UBYTE (modreader); | ||
609 | _mm_read_string(s->samplename, 22, modreader); | ||
610 | |||
611 | nextwav[of.numsmp+u]=next; | ||
612 | next+=s->length; | ||
613 | |||
614 | if(_mm_eof(modreader)) { | ||
615 | MikMod_free(nextwav);MikMod_free(wh); | ||
616 | nextwav=NULL;wh=NULL; | ||
617 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
618 | return 0; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | if(mh->version>0x0103) { | ||
623 | for(u=0;u<ih.numsmp;u++) | ||
624 | nextwav[of.numsmp++]+=_mm_ftell(modreader); | ||
625 | _mm_fseek(modreader,next,SEEK_CUR); | ||
626 | } else | ||
627 | of.numsmp+=ih.numsmp; | ||
628 | } else { | ||
629 | /* read the remainder of the header */ | ||
630 | ck = _mm_ftell(modreader); | ||
631 | _mm_fseek(modreader,0,SEEK_END); | ||
632 | if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) { | ||
633 | _mm_fseek(modreader,ck,SEEK_SET); | ||
634 | break; | ||
635 | } | ||
636 | _mm_fseek(modreader,ck,SEEK_SET); | ||
637 | for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader); | ||
638 | |||
639 | if(_mm_eof(modreader)) { | ||
640 | MikMod_free(nextwav);MikMod_free(wh); | ||
641 | nextwav=NULL;wh=NULL; | ||
642 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
643 | return 0; | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | } | ||
648 | |||
649 | /* sanity check */ | ||
650 | if(!of.numsmp) { | ||
651 | if(nextwav) { MikMod_free(nextwav);nextwav=NULL; } | ||
652 | if(wh) { MikMod_free(wh);wh=NULL; } | ||
653 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | return 1; | ||
658 | } | ||
659 | |||
660 | int XM_Load(int curious) | ||
661 | { | ||
662 | INSTRUMENT *d; | ||
663 | SAMPLE *q; | ||
664 | int t,u; | ||
665 | int dummypat=0; | ||
666 | char tracker[21],modtype[60]; | ||
667 | |||
668 | /* try to read module header */ | ||
669 | _mm_read_string(mh->id,17,modreader); | ||
670 | _mm_read_string(mh->songname,21,modreader); | ||
671 | _mm_read_string(mh->trackername,20,modreader); | ||
672 | mh->version =_mm_read_I_UWORD(modreader); | ||
673 | if((mh->version<0x102)||(mh->version>0x104)) { | ||
674 | _mm_errno=MMERR_NOT_A_MODULE; | ||
675 | return 0; | ||
676 | } | ||
677 | mh->headersize =_mm_read_I_ULONG(modreader); | ||
678 | mh->songlength =_mm_read_I_UWORD(modreader); | ||
679 | mh->restart =_mm_read_I_UWORD(modreader); | ||
680 | mh->numchn =_mm_read_I_UWORD(modreader); | ||
681 | mh->numpat =_mm_read_I_UWORD(modreader); | ||
682 | mh->numins =_mm_read_I_UWORD(modreader); | ||
683 | mh->flags =_mm_read_I_UWORD(modreader); | ||
684 | mh->tempo =_mm_read_I_UWORD(modreader); | ||
685 | mh->bpm =_mm_read_I_UWORD(modreader); | ||
686 | if(!mh->bpm) { | ||
687 | _mm_errno=MMERR_NOT_A_MODULE; | ||
688 | return 0; | ||
689 | } | ||
690 | _mm_read_UBYTES(mh->orders,mh->headersize-20,modreader); | ||
691 | |||
692 | if(_mm_eof(modreader)) { | ||
693 | _mm_errno = MMERR_LOADING_HEADER; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /* set module variables */ | ||
698 | of.initspeed = mh->tempo; | ||
699 | of.inittempo = mh->bpm; | ||
700 | strncpy(tracker,mh->trackername,20);tracker[20]=0; | ||
701 | for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0; | ||
702 | |||
703 | /* some modules have the tracker name empty */ | ||
704 | if (!tracker[0]) | ||
705 | strcpy(tracker,"Unknown tracker"); | ||
706 | |||
707 | #ifdef HAVE_SNPRINTF | ||
708 | snprintf(modtype,60,"%s (XM format %d.%02d)", | ||
709 | tracker,mh->version>>8,mh->version&0xff); | ||
710 | #else | ||
711 | sprintf(modtype,"%s (XM format %d.%02d)", | ||
712 | tracker,mh->version>>8,mh->version&0xff); | ||
713 | #endif | ||
714 | of.modtype = StrDup(modtype); | ||
715 | of.numchn = mh->numchn; | ||
716 | of.numpat = mh->numpat; | ||
717 | of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */ | ||
718 | of.songname = DupStr(mh->songname,20,1); | ||
719 | of.numpos = mh->songlength; /* copy the songlength */ | ||
720 | of.reppos = mh->restart<mh->songlength?mh->restart:0; | ||
721 | of.numins = mh->numins; | ||
722 | of.flags |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS | | ||
723 | UF_PANNING; | ||
724 | if(mh->flags&1) of.flags |= UF_LINEAR; | ||
725 | of.bpmlimit = 32; | ||
726 | |||
727 | memset(of.chanvol,64,of.numchn); /* store channel volumes */ | ||
728 | |||
729 | if(!AllocPositions(of.numpos+1)) return 0; | ||
730 | for(t=0;t<of.numpos;t++) | ||
731 | of.positions[t]=mh->orders[t]; | ||
732 | |||
733 | /* We have to check for any pattern numbers in the order list greater than | ||
734 | the number of patterns total. If one or more is found, we set it equal to | ||
735 | the pattern total and make a dummy pattern to workaround the problem */ | ||
736 | for(t=0;t<of.numpos;t++) { | ||
737 | if(of.positions[t]>=of.numpat) { | ||
738 | of.positions[t]=of.numpat; | ||
739 | dummypat=1; | ||
740 | } | ||
741 | } | ||
742 | if(dummypat) { | ||
743 | of.numpat++;of.numtrk+=of.numchn; | ||
744 | } | ||
745 | |||
746 | if(mh->version<0x0104) { | ||
747 | if(!LoadInstruments()) return 0; | ||
748 | if(!LoadPatterns(dummypat)) return 0; | ||
749 | for(t=0;t<of.numsmp;t++) | ||
750 | nextwav[t]+=_mm_ftell(modreader); | ||
751 | } else { | ||
752 | if(!LoadPatterns(dummypat)) return 0; | ||
753 | if(!LoadInstruments()) return 0; | ||
754 | } | ||
755 | |||
756 | if(!AllocSamples()) { | ||
757 | MikMod_free(nextwav);MikMod_free(wh); | ||
758 | nextwav=NULL;wh=NULL; | ||
759 | return 0; | ||
760 | } | ||
761 | q = of.samples; | ||
762 | s = wh; | ||
763 | for(u=0;u<of.numsmp;u++,q++,s++) { | ||
764 | q->samplename = DupStr(s->samplename,22,1); | ||
765 | q->length = s->length; | ||
766 | q->loopstart = s->loopstart; | ||
767 | q->loopend = s->loopstart+s->looplength; | ||
768 | q->volume = s->volume; | ||
769 | q->speed = s->finetune+128; | ||
770 | q->panning = s->panning; | ||
771 | q->seekpos = nextwav[u]; | ||
772 | q->vibtype = s->vibtype; | ||
773 | q->vibsweep = s->vibsweep; | ||
774 | q->vibdepth = s->vibdepth; | ||
775 | q->vibrate = s->vibrate; | ||
776 | |||
777 | if(s->type & 0x10) { | ||
778 | q->length >>= 1; | ||
779 | q->loopstart >>= 1; | ||
780 | q->loopend >>= 1; | ||
781 | } | ||
782 | |||
783 | q->flags|=SF_OWNPAN|SF_DELTA|SF_SIGNED; | ||
784 | if(s->type&0x3) q->flags|=SF_LOOP; | ||
785 | if(s->type&0x2) q->flags|=SF_BIDI; | ||
786 | if(s->type&0x10) q->flags|=SF_16BITS; | ||
787 | } | ||
788 | |||
789 | d=of.instruments; | ||
790 | s=wh; | ||
791 | for(u=0;u<of.numins;u++,d++) | ||
792 | for(t=0;t<XMNOTECNT;t++) { | ||
793 | if (d->samplenumber[t]>=of.numsmp) | ||
794 | d->samplenote[t]=255; | ||
795 | else { | ||
796 | int note=t+s[d->samplenumber[t]].relnote; | ||
797 | d->samplenote[t]=(note<0)?0:note; | ||
798 | } | ||
799 | } | ||
800 | |||
801 | MikMod_free(wh);MikMod_free(nextwav); | ||
802 | wh=NULL;nextwav=NULL; | ||
803 | return 1; | ||
804 | } | ||
805 | |||
806 | CHAR *XM_LoadTitle(void) | ||
807 | { | ||
808 | CHAR s[21]; | ||
809 | |||
810 | _mm_fseek(modreader,17,SEEK_SET); | ||
811 | if(!_mm_read_UBYTES(s,21,modreader)) return NULL; | ||
812 | |||
813 | return(DupStr(s,21,1)); | ||
814 | } | ||
815 | |||
816 | /*========== Loader information */ | ||
817 | |||
818 | MIKMODAPI MLOADER load_xm={ | ||
819 | NULL, | ||
820 | "XM", | ||
821 | "XM (FastTracker 2)", | ||
822 | XM_Init, | ||
823 | XM_Test, | ||
824 | XM_Load, | ||
825 | XM_Cleanup, | ||
826 | XM_LoadTitle | ||
827 | }; | ||
828 | |||
829 | /* ex:set ts=4: */ | ||