4
|
1 /*
|
|
2
|
|
3 Name: LOAD_MOD.C
|
|
4
|
|
5 Description:
|
|
6 Generic MOD loader (Protracker, StarTracker, FastTracker, etc)
|
|
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 /*************************************************************************
|
|
21 *************************************************************************/
|
|
22
|
|
23
|
|
24 typedef struct MSAMPINFO // sample header as it appears in a module
|
|
25 { CHAR samplename[22];
|
|
26 UWORD length;
|
|
27 UBYTE finetune;
|
|
28 UBYTE volume;
|
|
29 UWORD reppos;
|
|
30 UWORD replen;
|
|
31 } MSAMPINFO;
|
|
32
|
|
33
|
|
34 typedef struct MODULEHEADER // verbatim module header
|
|
35 { CHAR songname[20]; // the songname..
|
|
36 MSAMPINFO samples[31]; // all sampleinfo
|
|
37 UBYTE songlength; // number of patterns used
|
|
38 UBYTE magic1; // should be 127
|
|
39 UBYTE positions[128]; // which pattern to play at pos
|
|
40 UBYTE magic2[4]; // string "M.K." or "FLT4" or "FLT8"
|
|
41 } MODULEHEADER;
|
|
42
|
|
43 #define MODULEHEADERSIZE 1084
|
|
44
|
|
45
|
|
46 typedef struct MODTYPE // struct to identify type of module
|
|
47 { CHAR id[5];
|
|
48 UBYTE channels;
|
|
49 CHAR *name;
|
|
50 } MODTYPE;
|
|
51
|
|
52
|
|
53 typedef struct MODNOTE
|
|
54 { UBYTE a,b,c,d;
|
|
55 } MODNOTE;
|
|
56
|
|
57
|
|
58 /*************************************************************************
|
|
59 *************************************************************************/
|
|
60
|
|
61
|
|
62 CHAR protracker[] = "Protracker";
|
|
63 CHAR startracker[] = "Startracker";
|
|
64 CHAR fasttracker[] = "Fasttracker";
|
|
65 CHAR ins15tracker[] = "15-instrument";
|
|
66 CHAR oktalyzer[] = "Oktalyzer";
|
|
67 CHAR taketracker[] = "TakeTracker";
|
|
68
|
|
69
|
|
70 MODTYPE modtypes[] =
|
|
71 { "M.K.",4,protracker, // protracker 4 channel
|
|
72 "M!K!",4,protracker, // protracker 4 channel
|
|
73 "FLT4",4,startracker, // startracker 4 channel
|
|
74 "2CHN",2,fasttracker, // fasttracker 2 channel
|
|
75 "4CHN",4,fasttracker, // fasttracker 4 channel
|
|
76 "6CHN",6,fasttracker, // fasttracker 6 channel
|
|
77 "8CHN",8,fasttracker, // fasttracker 8 channel
|
|
78 "10CH",10,fasttracker, // fasttracker 10 channel
|
|
79 "12CH",12,fasttracker, // fasttracker 12 channel
|
|
80 "14CH",14,fasttracker, // fasttracker 14 channel
|
|
81 "16CH",16,fasttracker, // fasttracker 16 channel
|
|
82 "18CH",18,fasttracker, // fasttracker 18 channel
|
|
83 "20CH",20,fasttracker, // fasttracker 20 channel
|
|
84 "22CH",22,fasttracker, // fasttracker 22 channel
|
|
85 "24CH",24,fasttracker, // fasttracker 24 channel
|
|
86 "26CH",26,fasttracker, // fasttracker 26 channel
|
|
87 "28CH",28,fasttracker, // fasttracker 28 channel
|
|
88 "30CH",30,fasttracker, // fasttracker 30 channel
|
|
89 "32CH",32,fasttracker, // fasttracker 32 channel
|
|
90 "CD81",8,oktalyzer, // atari oktalyzer 8 channel
|
|
91 "OKTA",8,oktalyzer, // atari oktalyzer 8 channel
|
|
92 "16CN",16,taketracker, // taketracker 16 channel
|
|
93 "32CN",32,taketracker, // taketracker 32 channel
|
|
94 " ",4,ins15tracker // 15-instrument 4 channel
|
|
95 };
|
|
96
|
|
97 static MODULEHEADER *mh = NULL; // raw as-is module header
|
|
98 static MODNOTE *patbuf = NULL;
|
|
99 static int modtype = 0;
|
|
100
|
|
101 BOOL MOD_Test(void)
|
|
102 {
|
|
103 UBYTE id[4];
|
|
104
|
|
105 _mm_fseek(modfp,MODULEHEADERSIZE-4,SEEK_SET);
|
|
106 if(!fread(id,4,1,modfp)) return 0;
|
|
107
|
|
108 // find out which ID string
|
|
109
|
|
110 for(modtype=0; modtype<23; modtype++)
|
|
111 if(!memcmp(id,modtypes[modtype].id,4)) return 1;
|
|
112
|
|
113 return 0;
|
|
114 }
|
|
115
|
|
116
|
|
117 BOOL MOD_Init(void)
|
|
118 {
|
|
119 if(!(mh=(MODULEHEADER *)_mm_calloc(1,sizeof(MODULEHEADER)))) return 0;
|
|
120 return 1;
|
|
121 }
|
|
122
|
|
123
|
|
124 void MOD_Cleanup(void)
|
|
125 {
|
|
126 if(mh!=NULL) free(mh);
|
|
127 if(patbuf!=NULL) free(patbuf);
|
|
128
|
|
129 mh = NULL;
|
|
130 patbuf = NULL;
|
|
131 }
|
|
132
|
|
133
|
|
134 /*
|
|
135 Old (amiga) noteinfo:
|
|
136
|
|
137 _____byte 1_____ byte2_ _____byte 3_____ byte4_
|
|
138 / \ / \ / \ / \
|
|
139 0000 0000-00000000 0000 0000-00000000
|
|
140
|
|
141 Upper four 12 bits for Lower four Effect command.
|
|
142 bits of sam- note period. bits of sam-
|
|
143 ple number. ple number.
|
|
144
|
|
145 */
|
|
146
|
|
147
|
|
148 void ConvertNote(MODNOTE *n)
|
|
149 {
|
|
150 UBYTE instrument,effect,effdat,note;
|
|
151 UWORD period;
|
|
152
|
|
153 // extract the various information from the 4 bytes that
|
|
154 // make up a single note
|
|
155
|
|
156 instrument = (n->a&0x10)|(n->c>>4);
|
|
157 period = (((UWORD)n->a&0xf)<<8)+n->b;
|
|
158 effect = n->c&0xf;
|
|
159 effdat = n->d;
|
|
160
|
|
161 // Convert the period to a note number
|
|
162
|
|
163 note=0;
|
|
164 if(period!=0)
|
|
165 { for(note=0; note<60; note++)
|
|
166 if(period >= npertab[note]) break;
|
|
167 note++;
|
|
168 if(note==61) note = 0;
|
|
169 }
|
|
170
|
|
171 if(instrument!=0) UniInstrument(instrument-1);
|
|
172 if(note!=0) UniNote(note+23);
|
|
173
|
|
174 // Convert pattern jump from Dec to Hex
|
|
175 if(effect == 0xd)
|
|
176 effdat = (((effdat&0xf0)>>4)*10)+(effdat&0xf);
|
|
177
|
|
178 UniPTEffect(effect,effdat);
|
|
179 }
|
|
180
|
|
181
|
|
182 UBYTE *ConvertTrack(MODNOTE *n)
|
|
183 {
|
|
184 int t;
|
|
185
|
|
186 UniReset();
|
|
187 for(t=0;t<64;t++)
|
|
188 { ConvertNote(n);
|
|
189 UniNewline();
|
|
190 n+=of.numchn;
|
|
191 }
|
|
192 return UniDup();
|
|
193 }
|
|
194
|
|
195
|
|
196 BOOL ML_LoadPatterns(void)
|
|
197 // Loads all patterns of a modfile and converts them into the
|
|
198 // 3 byte format.
|
|
199 {
|
|
200 int t,s,tracks = 0;
|
|
201
|
|
202 if(!AllocPatterns()) return 0;
|
|
203 if(!AllocTracks()) return 0;
|
|
204
|
|
205 // Allocate temporary buffer for loading
|
|
206 // and converting the patterns
|
|
207
|
|
208 if(!(patbuf=(MODNOTE *)_mm_calloc(64U*of.numchn,sizeof(MODNOTE)))) return 0;
|
|
209
|
|
210 for(t=0; t<of.numpat; t++)
|
|
211 { // Load the pattern into the temp buffer
|
|
212 // and convert it
|
|
213
|
|
214 for(s=0; s<(64U*of.numchn); s++)
|
|
215 { patbuf[s].a = _mm_read_UBYTE(modfp);
|
|
216 patbuf[s].b = _mm_read_UBYTE(modfp);
|
|
217 patbuf[s].c = _mm_read_UBYTE(modfp);
|
|
218 patbuf[s].d = _mm_read_UBYTE(modfp);
|
|
219 }
|
|
220
|
|
221 for(s=0; s<of.numchn; s++)
|
|
222 if(!(of.tracks[tracks++]=ConvertTrack(patbuf+s))) return 0;
|
|
223 }
|
|
224
|
|
225 return 1;
|
|
226 }
|
|
227
|
|
228
|
|
229 BOOL MOD_Load(void)
|
|
230 {
|
|
231 int t;
|
|
232 SAMPLE *q;
|
|
233 MSAMPINFO *s; // old module sampleinfo
|
|
234
|
|
235 // try to read module header
|
|
236
|
|
237 _mm_read_string((CHAR *)mh->songname,20,modfp);
|
|
238
|
|
239 for(t=0; t<31; t++)
|
|
240 { s = &mh->samples[t];
|
|
241 _mm_read_string(s->samplename,22,modfp);
|
|
242 s->length =_mm_read_M_UWORD(modfp);
|
|
243 s->finetune =_mm_read_UBYTE(modfp);
|
|
244 s->volume =_mm_read_UBYTE(modfp);
|
|
245 s->reppos =_mm_read_M_UWORD(modfp);
|
|
246 s->replen =_mm_read_M_UWORD(modfp);
|
|
247 }
|
|
248
|
|
249 mh->songlength =_mm_read_UBYTE(modfp);
|
|
250 mh->magic1 =_mm_read_UBYTE(modfp);
|
|
251
|
|
252 _mm_read_UBYTES(mh->positions,128,modfp);
|
|
253 _mm_read_UBYTES(mh->magic2,4,modfp);
|
|
254
|
|
255 if(feof(modfp))
|
|
256 { _mm_errno = MMERR_LOADING_HEADER;
|
|
257 return 0;
|
|
258 }
|
|
259
|
|
260 // set module variables
|
|
261
|
|
262 of.initspeed = 6;
|
|
263 of.inittempo = 125;
|
|
264 of.numchn = modtypes[modtype].channels; // get number of channels
|
|
265 of.modtype = strdup(modtypes[modtype].name); // get ascii type of mod
|
|
266 of.songname = DupStr(mh->songname,20); // make a cstr of songname
|
|
267 of.numpos = mh->songlength; // copy the songlength
|
|
268
|
|
269 if(!AllocPositions(of.numpos)) return 0;
|
|
270 for(t=0; t<of.numpos; t++)
|
|
271 of.positions[t] = mh->positions[t];
|
|
272
|
|
273 // Count the number of patterns
|
|
274
|
|
275 of.numpat = 0;
|
|
276
|
|
277 for(t=0; t<of.numpos; t++)
|
|
278 { if(of.positions[t] > of.numpat)
|
|
279 of.numpat = of.positions[t];
|
|
280 }
|
|
281 of.numpat++;
|
|
282 of.numtrk = of.numpat*of.numchn;
|
|
283
|
|
284 // Finally, init the sampleinfo structures
|
|
285 of.numins = of.numsmp = 31;
|
|
286
|
|
287 if(!AllocSamples()) return 0;
|
|
288
|
|
289 s = mh->samples; // init source pointer
|
|
290 q = of.samples;
|
|
291
|
|
292 for(t=0; t<of.numins; t++)
|
|
293 { // convert the samplename
|
|
294 q->samplename = DupStr(s->samplename, 22);
|
|
295
|
|
296 // init the sampleinfo variables and
|
|
297 // convert the size pointers to longword format
|
|
298
|
|
299 q->speed = finetune[s->finetune & 0xf];
|
|
300 q->volume = s->volume;
|
|
301 q->loopstart = (ULONG)s->reppos << 1;
|
|
302 q->loopend = q->loopstart + ((ULONG)s->replen << 1);
|
|
303 q->length = (ULONG)s->length << 1;
|
|
304
|
|
305 q->flags = SF_SIGNED;
|
|
306 if(s->replen > 1) q->flags |= SF_LOOP;
|
|
307
|
|
308 // fix replen if repend > length
|
|
309 if(q->loopend > q->length) q->loopend = q->length;
|
|
310
|
|
311 s++; // point to next source sampleinfo
|
|
312 q++;
|
|
313 }
|
|
314
|
|
315 if(!ML_LoadPatterns()) return 0;
|
|
316 return 1;
|
|
317 }
|
|
318
|
|
319
|
|
320 CHAR *MOD_LoadTitle(void)
|
|
321 {
|
|
322 CHAR s[20];
|
|
323
|
|
324 _mm_fseek(modfp,0,SEEK_SET);
|
|
325 if(!fread(s,20,1,modfp)) return NULL;
|
|
326
|
|
327 return(DupStr(s,20));
|
|
328 }
|
|
329
|
|
330
|
|
331 MLOADER load_mod =
|
|
332 { NULL,
|
|
333 "Standard module",
|
|
334 "Portable MOD loader v0.11",
|
|
335 MOD_Init,
|
|
336 MOD_Test,
|
|
337 MOD_Load,
|
|
338 MOD_Cleanup,
|
|
339 MOD_LoadTitle
|
|
340 };
|
|
341
|