diff options
Diffstat (limited to 'apps/plugins/mikmod/load_stx.c')
-rw-r--r-- | apps/plugins/mikmod/load_stx.c | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_stx.c b/apps/plugins/mikmod/load_stx.c new file mode 100644 index 0000000000..ac6e51f4c7 --- /dev/null +++ b/apps/plugins/mikmod/load_stx.c | |||
@@ -0,0 +1,439 @@ | |||
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_stx.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | STMIK 0.2 (STX) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | /* | ||
30 | |||
31 | Written by Claudio Matsuoka <claudio@helllabs.org> | ||
32 | |||
33 | */ | ||
34 | |||
35 | #ifdef HAVE_CONFIG_H | ||
36 | #include "config.h" | ||
37 | #endif | ||
38 | |||
39 | #ifdef HAVE_UNISTD_H | ||
40 | #include <unistd.h> | ||
41 | #endif | ||
42 | |||
43 | #include <stdio.h> | ||
44 | #ifdef HAVE_MEMORY_H | ||
45 | #include <memory.h> | ||
46 | #endif | ||
47 | #include <string.h> | ||
48 | |||
49 | #include "mikmod_internals.h" | ||
50 | |||
51 | #ifdef SUNOS | ||
52 | extern int fprintf(FILE *, const char *, ...); | ||
53 | #endif | ||
54 | |||
55 | /*========== Module structure */ | ||
56 | |||
57 | /* header */ | ||
58 | typedef struct STXHEADER { | ||
59 | CHAR songname[20]; | ||
60 | CHAR trackername[8]; | ||
61 | UWORD patsize; | ||
62 | UWORD unknown1; | ||
63 | UWORD patptr; | ||
64 | UWORD insptr; | ||
65 | UWORD chnptr; /* not sure */ | ||
66 | UWORD unknown2; | ||
67 | UWORD unknown3; | ||
68 | UBYTE mastermult; | ||
69 | UBYTE initspeed; | ||
70 | UWORD unknown4; | ||
71 | UWORD unknown5; | ||
72 | UWORD patnum; | ||
73 | UWORD insnum; | ||
74 | UWORD ordnum; | ||
75 | UWORD unknown6; | ||
76 | UWORD unknown7; | ||
77 | UWORD unknown8; | ||
78 | CHAR scrm[4]; | ||
79 | } STXHEADER; | ||
80 | |||
81 | /* sample information */ | ||
82 | typedef struct STXSAMPLE { | ||
83 | UBYTE type; | ||
84 | CHAR filename[12]; | ||
85 | UBYTE memsegh; | ||
86 | UWORD memsegl; | ||
87 | ULONG length; | ||
88 | ULONG loopbeg; | ||
89 | ULONG loopend; | ||
90 | UBYTE volume; | ||
91 | UBYTE dsk; | ||
92 | UBYTE pack; | ||
93 | UBYTE flags; | ||
94 | ULONG c2spd; | ||
95 | UBYTE unused[12]; | ||
96 | CHAR sampname[28]; | ||
97 | CHAR scrs[4]; | ||
98 | } STXSAMPLE; | ||
99 | |||
100 | typedef struct STXNOTE { | ||
101 | UBYTE note,ins,vol,cmd,inf; | ||
102 | } STXNOTE; | ||
103 | |||
104 | /*========== Loader variables */ | ||
105 | |||
106 | static STXNOTE *stxbuf = NULL; /* pointer to a complete STX pattern */ | ||
107 | static STXHEADER *mh = NULL; | ||
108 | static UWORD *paraptr = NULL; /* parapointer array (see STX docs) */ | ||
109 | |||
110 | /*========== Loader code */ | ||
111 | |||
112 | static int STX_Test(void) | ||
113 | { | ||
114 | UBYTE id[8]; | ||
115 | int t; | ||
116 | |||
117 | _mm_fseek(modreader,0x3C,SEEK_SET); | ||
118 | if(!_mm_read_UBYTES(id,4,modreader)) return 0; | ||
119 | if(memcmp(id,"SCRM",4)) return 0; | ||
120 | |||
121 | _mm_fseek(modreader,0x14,SEEK_SET); | ||
122 | if(!_mm_read_UBYTES(id,8,modreader)) return 0; | ||
123 | |||
124 | for(t=0;t<STM_NTRACKERS;t++) | ||
125 | if(!memcmp(id,STM_Signatures[t],8)) return 1; | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int STX_Init(void) | ||
131 | { | ||
132 | if(!(stxbuf=(STXNOTE*)MikMod_malloc(4*64*sizeof(STXNOTE)))) return 0; | ||
133 | if(!(mh=(STXHEADER*)MikMod_malloc(sizeof(STXHEADER)))) return 0; | ||
134 | if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0; | ||
135 | memset(poslookup,-1,256); | ||
136 | |||
137 | return 1; | ||
138 | } | ||
139 | |||
140 | static void STX_Cleanup(void) | ||
141 | { | ||
142 | MikMod_free(stxbuf); | ||
143 | MikMod_free(paraptr); | ||
144 | MikMod_free(poslookup); | ||
145 | MikMod_free(mh); | ||
146 | } | ||
147 | |||
148 | static int STX_ReadPattern(void) | ||
149 | { | ||
150 | int row=0,flag,ch; | ||
151 | STXNOTE *n,dummy; | ||
152 | |||
153 | /* clear pattern data */ | ||
154 | memset(stxbuf,255,4*64*sizeof(STXNOTE)); | ||
155 | |||
156 | while(row<64) { | ||
157 | flag=_mm_read_UBYTE(modreader); | ||
158 | |||
159 | if(_mm_eof(modreader)) { | ||
160 | _mm_errno = MMERR_LOADING_PATTERN; | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | if(flag) { | ||
165 | ch=flag&31; | ||
166 | |||
167 | if((ch>=0)&&(ch<4)) | ||
168 | n=&stxbuf[(64U*ch)+row]; | ||
169 | else | ||
170 | n=&dummy; | ||
171 | |||
172 | if(flag&32) { | ||
173 | n->note=_mm_read_UBYTE(modreader); | ||
174 | n->ins=_mm_read_UBYTE(modreader); | ||
175 | } | ||
176 | if(flag&64) { | ||
177 | n->vol=_mm_read_UBYTE(modreader); | ||
178 | if(n->vol>64) n->vol=64; | ||
179 | } | ||
180 | if(flag&128) { | ||
181 | n->cmd=_mm_read_UBYTE(modreader); | ||
182 | n->inf=_mm_read_UBYTE(modreader); | ||
183 | } | ||
184 | } else row++; | ||
185 | } | ||
186 | return 1; | ||
187 | } | ||
188 | |||
189 | static UBYTE* STX_ConvertTrack(STXNOTE* tr) | ||
190 | { | ||
191 | int t; | ||
192 | |||
193 | UniReset(); | ||
194 | for(t=0;t<64;t++) { | ||
195 | UBYTE note,ins,vol,cmd,inf; | ||
196 | |||
197 | note=tr[t].note; | ||
198 | ins=tr[t].ins; | ||
199 | vol=tr[t].vol; | ||
200 | cmd=tr[t].cmd; | ||
201 | inf=tr[t].inf; | ||
202 | |||
203 | if((ins)&&(ins!=255)) UniInstrument(ins-1); | ||
204 | if((note)&&(note!=255)) { | ||
205 | if(note==254) { | ||
206 | UniPTEffect(0xc,0); /* note cut command */ | ||
207 | vol=255; | ||
208 | } else UniNote(24+((note>>4)*OCTAVE)+(note&0xf)); /* normal note */ | ||
209 | } | ||
210 | |||
211 | if(vol<255) UniPTEffect(0xc,vol); | ||
212 | |||
213 | if(cmd<255) switch(cmd) { | ||
214 | case 1: /* Axx set speed to xx */ | ||
215 | UniPTEffect(0xf,inf>>4); | ||
216 | break; | ||
217 | case 2: /* Bxx position jump */ | ||
218 | UniPTEffect(0xb,inf); | ||
219 | break; | ||
220 | case 3: /* Cxx patternbreak to row xx */ | ||
221 | UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf)); | ||
222 | break; | ||
223 | case 4: /* Dxy volumeslide */ | ||
224 | UniEffect(UNI_S3MEFFECTD,inf); | ||
225 | break; | ||
226 | case 5: /* Exy toneslide down */ | ||
227 | UniEffect(UNI_S3MEFFECTE,inf); | ||
228 | break; | ||
229 | case 6: /* Fxy toneslide up */ | ||
230 | UniEffect(UNI_S3MEFFECTF,inf); | ||
231 | break; | ||
232 | case 7: /* Gxx Tone portamento,speed xx */ | ||
233 | UniPTEffect(0x3,inf); | ||
234 | break; | ||
235 | case 8: /* Hxy vibrato */ | ||
236 | UniPTEffect(0x4,inf); | ||
237 | break; | ||
238 | case 9: /* Ixy tremor, ontime x, offtime y */ | ||
239 | UniEffect(UNI_S3MEFFECTI,inf); | ||
240 | break; | ||
241 | case 0: /* protracker arpeggio */ | ||
242 | if(!inf) break; | ||
243 | /* fall through */ | ||
244 | case 0xa: /* Jxy arpeggio */ | ||
245 | UniPTEffect(0x0,inf); | ||
246 | break; | ||
247 | case 0xb: /* Kxy Dual command H00 & Dxy */ | ||
248 | UniPTEffect(0x4,0); | ||
249 | UniEffect(UNI_S3MEFFECTD,inf); | ||
250 | break; | ||
251 | case 0xc: /* Lxy Dual command G00 & Dxy */ | ||
252 | UniPTEffect(0x3,0); | ||
253 | UniEffect(UNI_S3MEFFECTD,inf); | ||
254 | break; | ||
255 | /* Support all these above, since ST2 can LOAD these values but can | ||
256 | actually only play up to J - and J is only half-way implemented | ||
257 | in ST2 */ | ||
258 | case 0x18: /* Xxx amiga panning command 8xx */ | ||
259 | UniPTEffect(0x8,inf); | ||
260 | of.flags |= UF_PANNING; | ||
261 | break; | ||
262 | } | ||
263 | UniNewline(); | ||
264 | } | ||
265 | return UniDup(); | ||
266 | } | ||
267 | |||
268 | static int STX_Load(int curious) | ||
269 | { | ||
270 | int t,u,track = 0; | ||
271 | int version = 0; | ||
272 | SAMPLE *q; | ||
273 | |||
274 | /* try to read module header */ | ||
275 | _mm_read_string(mh->songname,20,modreader); | ||
276 | _mm_read_string(mh->trackername,8,modreader); | ||
277 | mh->patsize =_mm_read_I_UWORD(modreader); | ||
278 | mh->unknown1 =_mm_read_I_UWORD(modreader); | ||
279 | mh->patptr =_mm_read_I_UWORD(modreader); | ||
280 | mh->insptr =_mm_read_I_UWORD(modreader); | ||
281 | mh->chnptr =_mm_read_I_UWORD(modreader); | ||
282 | mh->unknown2 =_mm_read_I_UWORD(modreader); | ||
283 | mh->unknown3 =_mm_read_I_UWORD(modreader); | ||
284 | mh->mastermult =_mm_read_UBYTE(modreader); | ||
285 | mh->initspeed =_mm_read_UBYTE(modreader)>>4; | ||
286 | mh->unknown4 =_mm_read_I_UWORD(modreader); | ||
287 | mh->unknown5 =_mm_read_I_UWORD(modreader); | ||
288 | mh->patnum =_mm_read_I_UWORD(modreader); | ||
289 | mh->insnum =_mm_read_I_UWORD(modreader); | ||
290 | mh->ordnum =_mm_read_I_UWORD(modreader); | ||
291 | mh->unknown6 =_mm_read_I_UWORD(modreader); | ||
292 | mh->unknown7 =_mm_read_I_UWORD(modreader); | ||
293 | mh->unknown8 =_mm_read_I_UWORD(modreader); | ||
294 | _mm_read_string(mh->scrm,4,modreader); | ||
295 | |||
296 | if(_mm_eof(modreader)) { | ||
297 | _mm_errno = MMERR_LOADING_HEADER; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | /* set module variables */ | ||
302 | of.songname = DupStr(mh->songname,20,1); | ||
303 | of.numpat = mh->patnum; | ||
304 | of.reppos = 0; | ||
305 | of.numins = of.numsmp = mh->insnum; | ||
306 | of.initspeed = mh->initspeed; | ||
307 | of.inittempo = 125; | ||
308 | of.numchn = 4; | ||
309 | of.flags |= UF_S3MSLIDES; | ||
310 | of.bpmlimit = 32; | ||
311 | |||
312 | if(!(paraptr=(UWORD*)MikMod_malloc((of.numins+of.numpat)*sizeof(UWORD)))) | ||
313 | return 0; | ||
314 | |||
315 | /* read the instrument+pattern parapointers */ | ||
316 | _mm_fseek(modreader,mh->insptr<<4,SEEK_SET); | ||
317 | _mm_read_I_UWORDS(paraptr,of.numins,modreader); | ||
318 | _mm_fseek(modreader,mh->patptr<<4,SEEK_SET); | ||
319 | _mm_read_I_UWORDS(paraptr+of.numins,of.numpat,modreader); | ||
320 | |||
321 | /* check module version */ | ||
322 | _mm_fseek(modreader,paraptr[of.numins]<<4,SEEK_SET); | ||
323 | version=_mm_read_I_UWORD(modreader); | ||
324 | if(version==mh->patsize) { | ||
325 | version = 0x10; | ||
326 | of.modtype = StrDup("STMIK 0.2 (STM2STX 1.0)"); | ||
327 | } else { | ||
328 | version = 0x11; | ||
329 | of.modtype = StrDup("STMIK 0.2 (STM2STX 1.1)"); | ||
330 | } | ||
331 | |||
332 | /* read the order data */ | ||
333 | _mm_fseek(modreader,(mh->chnptr<<4)+32,SEEK_SET); | ||
334 | if(!AllocPositions(mh->ordnum)) return 0; | ||
335 | for(t=0;t<mh->ordnum;t++) { | ||
336 | of.positions[t]=_mm_read_UBYTE(modreader); | ||
337 | _mm_fseek(modreader,4,SEEK_CUR); | ||
338 | } | ||
339 | |||
340 | of.numpos=0;poslookupcnt=mh->ordnum; | ||
341 | for(t=0;t<mh->ordnum;t++) { | ||
342 | int order=of.positions[t]; | ||
343 | if(order==255) order=LAST_PATTERN; | ||
344 | of.positions[of.numpos]=order; | ||
345 | poslookup[t]=of.numpos; /* bug fix for freaky S3Ms */ | ||
346 | if(of.positions[t]<254) of.numpos++; | ||
347 | else | ||
348 | /* special end of song pattern */ | ||
349 | if((order==LAST_PATTERN)&&(!curious)) break; | ||
350 | } | ||
351 | |||
352 | if(_mm_eof(modreader)) { | ||
353 | _mm_errno = MMERR_LOADING_HEADER; | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* load samples */ | ||
358 | if(!AllocSamples()) return 0; | ||
359 | for(q=of.samples,t=0;t<of.numins;t++,q++) { | ||
360 | STXSAMPLE s; | ||
361 | |||
362 | /* seek to instrument position */ | ||
363 | _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET); | ||
364 | /* and load sample info */ | ||
365 | s.type =_mm_read_UBYTE(modreader); | ||
366 | _mm_read_string(s.filename,12,modreader); | ||
367 | s.memsegh =_mm_read_UBYTE(modreader); | ||
368 | s.memsegl =_mm_read_I_UWORD(modreader); | ||
369 | s.length =_mm_read_I_ULONG(modreader); | ||
370 | s.loopbeg =_mm_read_I_ULONG(modreader); | ||
371 | s.loopend =_mm_read_I_ULONG(modreader); | ||
372 | s.volume =_mm_read_UBYTE(modreader); | ||
373 | s.dsk =_mm_read_UBYTE(modreader); | ||
374 | s.pack =_mm_read_UBYTE(modreader); | ||
375 | s.flags =_mm_read_UBYTE(modreader); | ||
376 | s.c2spd =_mm_read_I_ULONG(modreader); | ||
377 | _mm_read_UBYTES(s.unused,12,modreader); | ||
378 | _mm_read_string(s.sampname,28,modreader); | ||
379 | _mm_read_string(s.scrs,4,modreader); | ||
380 | |||
381 | if(_mm_eof(modreader)) { | ||
382 | _mm_errno = MMERR_LOADING_SAMPLEINFO; | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | q->samplename = DupStr(s.sampname,28,1); | ||
387 | q->speed = (s.c2spd * 8363) / 8448; | ||
388 | q->length = s.length; | ||
389 | q->loopstart = s.loopbeg; | ||
390 | q->loopend = s.loopend; | ||
391 | q->volume = s.volume; | ||
392 | q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4; | ||
393 | q->flags |= SF_SIGNED; | ||
394 | |||
395 | if(s.flags&1) q->flags |= SF_LOOP; | ||
396 | if(s.flags&4) q->flags |= SF_16BITS; | ||
397 | } | ||
398 | |||
399 | /* load pattern info */ | ||
400 | of.numtrk=of.numpat*of.numchn; | ||
401 | if(!AllocTracks()) return 0; | ||
402 | if(!AllocPatterns()) return 0; | ||
403 | |||
404 | for(t=0;t<of.numpat;t++) { | ||
405 | /* seek to pattern position (+2 skip pattern length) */ | ||
406 | _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+ | ||
407 | (version==0x10?2:0),SEEK_SET); | ||
408 | if(!STX_ReadPattern()) return 0; | ||
409 | for(u=0;u<of.numchn;u++) | ||
410 | if(!(of.tracks[track++]=STX_ConvertTrack(&stxbuf[u*64]))) return 0; | ||
411 | } | ||
412 | |||
413 | return 1; | ||
414 | } | ||
415 | |||
416 | static CHAR *STX_LoadTitle(void) | ||
417 | { | ||
418 | CHAR s[28]; | ||
419 | |||
420 | _mm_fseek(modreader,0,SEEK_SET); | ||
421 | if(!_mm_read_UBYTES(s,20,modreader)) return NULL; | ||
422 | |||
423 | return(DupStr(s,28,1)); | ||
424 | } | ||
425 | |||
426 | /*========== Loader information */ | ||
427 | |||
428 | MIKMODAPI MLOADER load_stx={ | ||
429 | NULL, | ||
430 | "STX", | ||
431 | "STX (Scream Tracker Music Interface Kit)", | ||
432 | STX_Init, | ||
433 | STX_Test, | ||
434 | STX_Load, | ||
435 | STX_Cleanup, | ||
436 | STX_LoadTitle | ||
437 | }; | ||
438 | |||
439 | /* ex:set ts=4: */ | ||