summaryrefslogtreecommitdiff
path: root/apps/plugins/mikmod/load_s3m.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/load_s3m.c')
-rw-r--r--apps/plugins/mikmod/load_s3m.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_s3m.c b/apps/plugins/mikmod/load_s3m.c
new file mode 100644
index 0000000000..4ecb5bdd1f
--- /dev/null
+++ b/apps/plugins/mikmod/load_s3m.c
@@ -0,0 +1,470 @@
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_s3m.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
24
25 Screamtracker (S3M) 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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51/* header */
52typedef struct S3MHEADER {
53 CHAR songname[28];
54 UBYTE t1a;
55 UBYTE type;
56 UBYTE unused1[2];
57 UWORD ordnum;
58 UWORD insnum;
59 UWORD patnum;
60 UWORD flags;
61 UWORD tracker;
62 UWORD fileformat;
63 CHAR scrm[4];
64 UBYTE mastervol;
65 UBYTE initspeed;
66 UBYTE inittempo;
67 UBYTE mastermult;
68 UBYTE ultraclick;
69 UBYTE pantable;
70 UBYTE unused2[8];
71 UWORD special;
72 UBYTE channels[32];
73} S3MHEADER;
74
75/* sample information */
76typedef struct S3MSAMPLE {
77 UBYTE type;
78 CHAR filename[12];
79 UBYTE memsegh;
80 UWORD memsegl;
81 ULONG length;
82 ULONG loopbeg;
83 ULONG loopend;
84 UBYTE volume;
85 UBYTE dsk;
86 UBYTE pack;
87 UBYTE flags;
88 ULONG c2spd;
89 UBYTE unused[12];
90 CHAR sampname[28];
91 CHAR scrs[4];
92} S3MSAMPLE;
93
94typedef struct S3MNOTE {
95 UBYTE note,ins,vol,cmd,inf;
96} S3MNOTE;
97
98/*========== Loader variables */
99
100static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */
101static S3MHEADER *mh = NULL;
102static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */
103static unsigned int tracker; /* tracker id */
104
105/* tracker identifiers */
106#define NUMTRACKERS 4
107static CHAR* S3M_Version[] = {
108 "Screamtracker x.xx",
109 "Imago Orpheus x.xx (S3M format)",
110 "Impulse Tracker x.xx (S3M format)",
111 "Unknown tracker x.xx (S3M format)",
112 "Impulse Tracker 2.14p3 (S3M format)",
113 "Impulse Tracker 2.14p4 (S3M format)"
114};
115/* version number position in above array */
116static int numeric[NUMTRACKERS]={14,14,16,16};
117
118/*========== Loader code */
119
120int S3M_Test(void)
121{
122 UBYTE id[4];
123
124 _mm_fseek(modreader,0x2c,SEEK_SET);
125 if(!_mm_read_UBYTES(id,4,modreader)) return 0;
126 if(!memcmp(id,"SCRM",4)) return 1;
127 return 0;
128}
129
130int S3M_Init(void)
131{
132 if(!(s3mbuf=(S3MNOTE*)MikMod_malloc(32*64*sizeof(S3MNOTE)))) return 0;
133 if(!(mh=(S3MHEADER*)MikMod_malloc(sizeof(S3MHEADER)))) return 0;
134 if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0;
135 memset(poslookup,-1,256);
136
137 return 1;
138}
139
140void S3M_Cleanup(void)
141{
142 MikMod_free(s3mbuf);
143 MikMod_free(paraptr);
144 MikMod_free(poslookup);
145 MikMod_free(mh);
146 MikMod_free(origpositions);
147}
148
149/* Because so many s3m files have 16 channels as the set number used, but really
150 only use far less (usually 8 to 12 still), I had to make this function, which
151 determines the number of channels that are actually USED by a pattern.
152
153 For every channel that's used, it sets the appropriate array entry of the
154 global variable 'remap'
155
156 NOTE: You must first seek to the file location of the pattern before calling
157 this procedure.
158
159 Returns 1 on fail. */
160static int S3M_GetNumChannels(void)
161{
162 int row=0,flag,ch;
163
164 while(row<64) {
165 flag=_mm_read_UBYTE(modreader);
166
167 if(_mm_eof(modreader)) {
168 _mm_errno = MMERR_LOADING_PATTERN;
169 return 1;
170 }
171
172 if(flag) {
173 ch=flag&31;
174 if(mh->channels[ch]<32) remap[ch] = 0;
175 if(flag&32) {_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}
176 if(flag&64) _mm_read_UBYTE(modreader);
177 if(flag&128){_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}
178 } else row++;
179 }
180 return 0;
181}
182
183static int S3M_ReadPattern(void)
184{
185 int row=0,flag,ch;
186 S3MNOTE *n,dummy;
187
188 /* clear pattern data */
189 memset(s3mbuf,255,32*64*sizeof(S3MNOTE));
190
191 while(row<64) {
192 flag=_mm_read_UBYTE(modreader);
193
194 if(_mm_eof(modreader)) {
195 _mm_errno = MMERR_LOADING_PATTERN;
196 return 0;
197 }
198
199 if(flag) {
200 ch=remap[flag&31];
201
202 if(ch!=-1)
203 n=&s3mbuf[(64U*ch)+row];
204 else
205 n=&dummy;
206
207 if(flag&32) {
208 n->note=_mm_read_UBYTE(modreader);
209 n->ins=_mm_read_UBYTE(modreader);
210 }
211 if(flag&64) {
212 n->vol=_mm_read_UBYTE(modreader);
213 if (n->vol>64) n->vol=64;
214 }
215 if(flag&128) {
216 n->cmd=_mm_read_UBYTE(modreader);
217 n->inf=_mm_read_UBYTE(modreader);
218 }
219 } else row++;
220 }
221 return 1;
222}
223
224static UBYTE* S3M_ConvertTrack(S3MNOTE* tr)
225{
226 int t;
227
228 UniReset();
229 for(t=0;t<64;t++) {
230 UBYTE note,ins,vol;
231
232 note=tr[t].note;
233 ins=tr[t].ins;
234 vol=tr[t].vol;
235
236 if((ins)&&(ins!=255)) UniInstrument(ins-1);
237 if(note!=255) {
238 if(note==254) {
239 UniPTEffect(0xc,0); /* note cut command */
240 vol=255;
241 } else
242 UniNote(((note>>4)*OCTAVE)+(note&0xf)); /* normal note */
243 }
244 if(vol<255) UniPTEffect(0xc,vol);
245
246 S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,
247 tracker == 1 ? S3MIT_OLDSTYLE | S3MIT_SCREAM : S3MIT_OLDSTYLE);
248 UniNewline();
249 }
250 return UniDup();
251}
252
253int S3M_Load(int curious)
254{
255 int t,u,track = 0;
256 SAMPLE *q;
257 UBYTE pan[32];
258
259 /* try to read module header */
260 _mm_read_string(mh->songname,28,modreader);
261 mh->t1a =_mm_read_UBYTE(modreader);
262 mh->type =_mm_read_UBYTE(modreader);
263 _mm_read_UBYTES(mh->unused1,2,modreader);
264 mh->ordnum =_mm_read_I_UWORD(modreader);
265 mh->insnum =_mm_read_I_UWORD(modreader);
266 mh->patnum =_mm_read_I_UWORD(modreader);
267 mh->flags =_mm_read_I_UWORD(modreader);
268 mh->tracker =_mm_read_I_UWORD(modreader);
269 mh->fileformat =_mm_read_I_UWORD(modreader);
270 _mm_read_string(mh->scrm,4,modreader);
271 mh->mastervol =_mm_read_UBYTE(modreader);
272 mh->initspeed =_mm_read_UBYTE(modreader);
273 mh->inittempo =_mm_read_UBYTE(modreader);
274 mh->mastermult =_mm_read_UBYTE(modreader);
275 mh->ultraclick =_mm_read_UBYTE(modreader);
276 mh->pantable =_mm_read_UBYTE(modreader);
277 _mm_read_UBYTES(mh->unused2,8,modreader);
278 mh->special =_mm_read_I_UWORD(modreader);
279 _mm_read_UBYTES(mh->channels,32,modreader);
280
281 if(_mm_eof(modreader)) {
282 _mm_errno = MMERR_LOADING_HEADER;
283 return 0;
284 }
285
286 /* then we can decide the module type */
287 tracker=mh->tracker>>12;
288 if((!tracker)||(tracker>=NUMTRACKERS))
289 tracker=NUMTRACKERS-1; /* unknown tracker */
290 else {
291 if(mh->tracker>=0x3217)
292 tracker=NUMTRACKERS+1; /* IT 2.14p4 */
293 else if(mh->tracker>=0x3216)
294 tracker=NUMTRACKERS; /* IT 2.14p3 */
295 else tracker--;
296 }
297 of.modtype = StrDup(S3M_Version[tracker]);
298 if(tracker<NUMTRACKERS) {
299 of.modtype[numeric[tracker]] = ((mh->tracker>>8) &0xf)+'0';
300 of.modtype[numeric[tracker]+2] = ((mh->tracker>>4)&0xf)+'0';
301 of.modtype[numeric[tracker]+3] = ((mh->tracker)&0xf)+'0';
302 }
303 /* set module variables */
304 of.songname = DupStr(mh->songname,28,0);
305 of.numpat = mh->patnum;
306 of.reppos = 0;
307 of.numins = of.numsmp = mh->insnum;
308 of.initspeed = mh->initspeed;
309 of.inittempo = mh->inittempo;
310 of.initvolume = mh->mastervol<<1;
311 of.flags |= UF_ARPMEM | UF_PANNING;
312 if((mh->tracker==0x1300)||(mh->flags&64))
313 of.flags|=UF_S3MSLIDES;
314 of.bpmlimit = 32;
315
316 /* read the order data */
317 if(!AllocPositions(mh->ordnum)) return 0;
318 if(!(origpositions=MikMod_calloc(mh->ordnum,sizeof(UWORD)))) return 0;
319
320 for(t=0;t<mh->ordnum;t++) {
321 origpositions[t]=_mm_read_UBYTE(modreader);
322 if((origpositions[t]>=mh->patnum)&&(origpositions[t]<254))
323 origpositions[t]=255/*mh->patnum-1*/;
324 }
325
326 if(_mm_eof(modreader)) {
327 _mm_errno = MMERR_LOADING_HEADER;
328 return 0;
329 }
330
331 poslookupcnt=mh->ordnum;
332 S3MIT_CreateOrders(curious);
333
334 if(!(paraptr=(UWORD*)MikMod_malloc((of.numins+of.numpat)*sizeof(UWORD))))
335 return 0;
336
337 /* read the instrument+pattern parapointers */
338 _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modreader);
339
340 if(mh->pantable==252) {
341 /* read the panning table (ST 3.2 addition. See below for further
342 portions of channel panning [past reampper]). */
343 _mm_read_UBYTES(pan,32,modreader);
344 }
345
346 if(_mm_eof(modreader)) {
347 _mm_errno = MMERR_LOADING_HEADER;
348 return 0;
349 }
350
351 /* load samples */
352 if(!AllocSamples()) return 0;
353 q = of.samples;
354 for(t=0;t<of.numins;t++) {
355 S3MSAMPLE s;
356
357 /* seek to instrument position */
358 _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);
359 /* and load sample info */
360 s.type =_mm_read_UBYTE(modreader);
361 _mm_read_string(s.filename,12,modreader);
362 s.memsegh =_mm_read_UBYTE(modreader);
363 s.memsegl =_mm_read_I_UWORD(modreader);
364 s.length =_mm_read_I_ULONG(modreader);
365 s.loopbeg =_mm_read_I_ULONG(modreader);
366 s.loopend =_mm_read_I_ULONG(modreader);
367 s.volume =_mm_read_UBYTE(modreader);
368 s.dsk =_mm_read_UBYTE(modreader);
369 s.pack =_mm_read_UBYTE(modreader);
370 s.flags =_mm_read_UBYTE(modreader);
371 s.c2spd =_mm_read_I_ULONG(modreader);
372 _mm_read_UBYTES(s.unused,12,modreader);
373 _mm_read_string(s.sampname,28,modreader);
374 _mm_read_string(s.scrs,4,modreader);
375
376 /* ScreamTracker imposes a 64000 bytes (not 64k !) limit */
377 if (s.length > 64000)
378 s.length = 64000;
379
380 if(_mm_eof(modreader)) {
381 _mm_errno = MMERR_LOADING_SAMPLEINFO;
382 return 0;
383 }
384
385 q->samplename = DupStr(s.sampname,28,0);
386 q->speed = s.c2spd;
387 q->length = s.length;
388 q->loopstart = s.loopbeg;
389 q->loopend = s.loopend;
390 q->volume = s.volume;
391 q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4;
392
393 if(s.flags&1) q->flags |= SF_LOOP;
394 if(s.flags&4) q->flags |= SF_16BITS;
395 if(mh->fileformat==1) q->flags |= SF_SIGNED;
396
397 /* don't load sample if it doesn't have the SCRS tag */
398 if(memcmp(s.scrs,"SCRS",4)) q->length = 0;
399
400 q++;
401 }
402
403 /* determine the number of channels actually used. */
404 of.numchn = 0;
405 memset(remap,-1,32*sizeof(UBYTE));
406 for(t=0;t<of.numpat;t++) {
407 /* seek to pattern position (+2 skip pattern length) */
408 _mm_fseek(modreader,(long)((paraptr[of.numins+t])<<4)+2,SEEK_SET);
409 if(S3M_GetNumChannels()) return 0;
410 }
411
412 /* build the remap array */
413 for(t=0;t<32;t++)
414 if(!remap[t])
415 remap[t]=of.numchn++;
416
417 /* set panning positions after building remap chart! */
418 for(t=0;t<32;t++)
419 if((mh->channels[t]<32)&&(remap[t]!=-1)) {
420 if(mh->channels[t]<8)
421 of.panning[remap[t]]=0x30;
422 else
423 of.panning[remap[t]]=0xc0;
424 }
425 if(mh->pantable==252)
426 /* set panning positions according to panning table (new for st3.2) */
427 for(t=0;t<32;t++)
428 if((pan[t]&0x20)&&(mh->channels[t]<32)&&(remap[t]!=-1))
429 of.panning[remap[t]]=(pan[t]&0xf)<<4;
430
431 /* load pattern info */
432 of.numtrk=of.numpat*of.numchn;
433 if(!AllocTracks()) return 0;
434 if(!AllocPatterns()) return 0;
435
436 for(t=0;t<of.numpat;t++) {
437 /* seek to pattern position (+2 skip pattern length) */
438 _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);
439 if(!S3M_ReadPattern()) return 0;
440 for(u=0;u<of.numchn;u++)
441 if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;
442 }
443
444 return 1;
445}
446
447CHAR *S3M_LoadTitle(void)
448{
449 CHAR s[28];
450
451 _mm_fseek(modreader,0,SEEK_SET);
452 if(!_mm_read_UBYTES(s,28,modreader)) return NULL;
453
454 return(DupStr(s,28,0));
455}
456
457/*========== Loader information */
458
459MIKMODAPI MLOADER load_s3m={
460 NULL,
461 "S3M",
462 "S3M (Scream Tracker 3)",
463 S3M_Init,
464 S3M_Test,
465 S3M_Load,
466 S3M_Cleanup,
467 S3M_LoadTitle
468};
469
470/* ex:set ts=4: */