4
|
1 /*
|
|
2
|
|
3 Name: LOAD_FAR.C
|
|
4
|
|
5 Description:
|
|
6 Farandole (FAR) 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 #include <string.h>
|
|
17 #include "mikmod.h"
|
|
18
|
|
19
|
|
20 typedef struct FARSAMPLE
|
|
21 { CHAR samplename[32];
|
|
22 ULONG length;
|
|
23 UBYTE finetune;
|
|
24 UBYTE volume;
|
|
25 ULONG reppos;
|
|
26 ULONG repend;
|
|
27 UBYTE type;
|
|
28 UBYTE loop;
|
|
29 } FARSAMPLE;
|
|
30
|
|
31
|
|
32
|
|
33 typedef struct FARHEADER1
|
|
34 { UBYTE id[4]; // file magic
|
|
35 CHAR songname[40]; // songname
|
|
36 CHAR blah[3]; // 13,10,26
|
|
37 UWORD headerlen; // remaining length of header in bytes
|
|
38 UBYTE version;
|
|
39 UBYTE onoff[16];
|
|
40 UBYTE edit1[9];
|
|
41 UBYTE speed;
|
|
42 UBYTE panning[16];
|
|
43 UBYTE edit2[4];
|
|
44 UWORD stlen;
|
|
45 } FARHEADER1;
|
|
46
|
|
47
|
|
48 typedef struct FARHEADER2
|
|
49 { UBYTE orders[256];
|
|
50 UBYTE numpat;
|
|
51 UBYTE snglen;
|
|
52 UBYTE loopto;
|
|
53 UWORD patsiz[256];
|
|
54 } FARHEADER2;
|
|
55
|
|
56
|
|
57 typedef struct FARNOTE
|
|
58 { UBYTE note,ins,vol,eff;
|
|
59 } FARNOTE;
|
|
60
|
|
61
|
|
62
|
|
63 static CHAR FAR_Version[] = "Farandole";
|
|
64 static FARHEADER1 *mh1 = NULL;
|
|
65 static FARHEADER2 *mh2 = NULL;
|
|
66 static FARNOTE *pat = NULL;
|
|
67
|
|
68
|
|
69 BOOL FAR_Test(void)
|
|
70 {
|
|
71 UBYTE id[4];
|
|
72
|
|
73 if(!_mm_read_UBYTES(id,4,modfp)) return 0;
|
|
74 return(!memcmp(id,"FAR=",4));
|
|
75 }
|
|
76
|
|
77
|
|
78 BOOL FAR_Init(void)
|
|
79 {
|
|
80 if(!(mh1 = (FARHEADER1 *)_mm_malloc(sizeof(FARHEADER1)))) return 0;
|
|
81 if(!(mh2 = (FARHEADER2 *)_mm_malloc(sizeof(FARHEADER2)))) return 0;
|
|
82 if(!(pat = (FARNOTE *)_mm_malloc(16*256*sizeof(FARNOTE)))) return 0;
|
|
83
|
|
84 return 1;
|
|
85 }
|
|
86
|
|
87
|
|
88 void FAR_Cleanup(void)
|
|
89 {
|
|
90 if(mh1!=NULL) free(mh1);
|
|
91 if(mh2!=NULL) free(mh2);
|
|
92 if(pat!=NULL) free(pat);
|
|
93
|
|
94 mh1 = NULL;
|
|
95 mh2 = NULL;
|
|
96 pat = NULL;
|
|
97 }
|
|
98
|
|
99
|
|
100 UBYTE *FAR_ConvertTrack(FARNOTE *n,int rows)
|
|
101 {
|
|
102 int t;
|
|
103
|
|
104 UniReset();
|
|
105
|
|
106 for(t=0; t<rows; t++)
|
|
107 { if(n->note)
|
|
108 { UniInstrument(n->ins);
|
|
109 UniNote(n->note+23+12);
|
|
110 }
|
|
111
|
|
112 if(n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2);
|
|
113 switch(n->eff>>4)
|
|
114 { case 0xf:
|
|
115 UniPTEffect(0xf,n->eff&0xf);
|
|
116 break;
|
|
117
|
|
118 // others not yet implemented
|
|
119 }
|
|
120
|
|
121 UniNewline();
|
|
122 n+=16;
|
|
123 }
|
|
124 return UniDup();
|
|
125 }
|
|
126
|
|
127
|
|
128 BOOL FAR_Load(void)
|
|
129 {
|
|
130 int t,u,tracks=0;
|
|
131 SAMPLE *q;
|
|
132 FARSAMPLE s;
|
|
133 FARNOTE *crow;
|
|
134 UBYTE smap[8];
|
|
135
|
|
136 // try to read module header (first part)
|
|
137 _mm_read_UBYTES(mh1->id,4,modfp);
|
|
138 _mm_read_SBYTES(mh1->songname,40,modfp);
|
|
139 _mm_read_SBYTES(mh1->blah,3,modfp);
|
|
140 mh1->headerlen = _mm_read_I_UWORD (modfp);
|
|
141 mh1->version = _mm_read_UBYTE (modfp);
|
|
142 _mm_read_UBYTES(mh1->onoff,16,modfp);
|
|
143 _mm_read_UBYTES(mh1->edit1,9,modfp);
|
|
144 mh1->speed = _mm_read_UBYTE(modfp);
|
|
145 _mm_read_UBYTES(mh1->panning,16,modfp);
|
|
146 _mm_read_UBYTES(mh1->edit2,4,modfp);
|
|
147 mh1->stlen = _mm_read_I_UWORD (modfp);
|
|
148
|
|
149
|
|
150 // init modfile data
|
|
151
|
|
152 of.modtype = strdup(FAR_Version);
|
|
153 of.songname = DupStr(mh1->songname,40);
|
|
154 of.numchn = 16;
|
|
155 of.initspeed = mh1->speed;
|
|
156 of.inittempo = 99;
|
|
157
|
|
158 for(t=0; t<16; t++) of.panning[t] = mh1->panning[t]<<4;
|
|
159
|
|
160 // read songtext into comment field
|
|
161 if(!ReadComment(mh1->stlen)) return 0;
|
|
162
|
|
163 // try to read module header (second part)
|
|
164 _mm_read_UBYTES(mh2->orders,256,modfp);
|
|
165 mh2->numpat = _mm_read_UBYTE(modfp);
|
|
166 mh2->snglen = _mm_read_UBYTE(modfp);
|
|
167 mh2->loopto = _mm_read_UBYTE(modfp);
|
|
168 _mm_read_I_UWORDS(mh2->patsiz,256,modfp);
|
|
169
|
|
170 // of.numpat=mh2->numpat;
|
|
171 of.numpos = mh2->snglen;
|
|
172 if(!AllocPositions(of.numpos)) return 0;
|
|
173 for(t=0; t<of.numpos; t++)
|
|
174 { if(mh2->orders[t]==0xff) break;
|
|
175 of.positions[t] = mh2->orders[t];
|
|
176 }
|
|
177
|
|
178 // count number of patterns stored in file
|
|
179 of.numpat = 0;
|
|
180 for(t=0; t<256; t++)
|
|
181 if(mh2->patsiz[t]) if((t+1)>of.numpat) of.numpat=t+1;
|
|
182
|
|
183 of.numtrk = of.numpat*of.numchn;
|
|
184
|
|
185 // seek across eventual new data
|
|
186 _mm_fseek(modfp,mh1->headerlen-(869+mh1->stlen),SEEK_CUR);
|
|
187
|
|
188 // alloc track and pattern structures
|
|
189 if(!AllocTracks()) return 0;
|
|
190 if(!AllocPatterns()) return 0;
|
|
191
|
|
192 for(t=0; t<of.numpat; t++)
|
|
193 { UBYTE rows=0,tempo;
|
|
194
|
|
195 memset(pat,0,16*256*sizeof(FARNOTE));
|
|
196 if(mh2->patsiz[t])
|
|
197 { rows = _mm_read_UBYTE(modfp);
|
|
198 tempo = _mm_read_UBYTE(modfp);
|
|
199
|
|
200 crow = pat;
|
|
201 for(u=mh2->patsiz[t]-2; u; u--, crow++)
|
|
202 { crow->note = _mm_read_UBYTE(modfp);
|
|
203 crow->ins = _mm_read_UBYTE(modfp);
|
|
204 crow->vol = _mm_read_UBYTE(modfp);
|
|
205 crow->eff = _mm_read_UBYTE(modfp);
|
|
206 }
|
|
207
|
|
208 if(feof(modfp))
|
|
209 { _mm_errno = MMERR_LOADING_PATTERN;
|
|
210 return 0;
|
|
211 }
|
|
212
|
|
213 of.pattrows[t] = rows+2;
|
|
214 crow = pat;
|
|
215 for(u=16; u; u--)
|
|
216 if(!(of.tracks[tracks++] = FAR_ConvertTrack(crow,rows+2))) return 0;
|
|
217 }
|
|
218 }
|
|
219
|
|
220 // read sample map
|
|
221 if(!_mm_read_UBYTES(smap,8,modfp))
|
|
222 { _mm_errno = MMERR_LOADING_HEADER;
|
|
223 return 0;
|
|
224 }
|
|
225
|
|
226 // count number of samples used
|
|
227 of.numins = 0;
|
|
228 for(t=0; t<64; t++)
|
|
229 if(smap[t>>3] & (1 << (t&7))) of.numins++;
|
|
230 of.numsmp = of.numins;
|
|
231
|
|
232 // alloc sample structs
|
|
233 if(!AllocSamples()) return 0;
|
|
234 q = of.samples;
|
|
235
|
|
236 for(t=0; t<64; t++)
|
|
237 { if(smap[t>>3] & (1 << (t&7)))
|
|
238 { _mm_read_SBYTES(s.samplename,32,modfp);
|
|
239 s.length = _mm_read_I_ULONG(modfp);
|
|
240 s.finetune = _mm_read_UBYTE(modfp);
|
|
241 s.volume = _mm_read_UBYTE(modfp);
|
|
242 s.reppos = _mm_read_I_ULONG(modfp);
|
|
243 s.repend = _mm_read_I_ULONG(modfp);
|
|
244 s.type = _mm_read_UBYTE(modfp);
|
|
245 s.loop = _mm_read_UBYTE(modfp);
|
|
246
|
|
247 q->samplename = DupStr(s.samplename,32);
|
|
248 q->length = s.length;
|
|
249 q->loopstart = s.reppos;
|
|
250 q->loopend = s.repend;
|
|
251 q->volume = 64;
|
|
252 q->speed = 8363;
|
|
253
|
|
254 q->flags=SF_SIGNED;
|
|
255 if(s.type&1) q->flags|=SF_16BITS;
|
|
256 if(s.loop) q->flags|=SF_LOOP;
|
|
257
|
|
258 q->seekpos = _mm_ftell(modfp);
|
|
259 _mm_fseek(modfp,q->length,SEEK_CUR);
|
|
260 }
|
|
261 q++;
|
|
262 }
|
|
263 return 1;
|
|
264 }
|
|
265
|
|
266
|
|
267 CHAR *FAR_LoadTitle(void)
|
|
268 {
|
|
269 CHAR s[40];
|
|
270
|
|
271 _mm_fseek(modfp,4,SEEK_SET);
|
|
272 if(!fread(s,40,1,modfp)) return NULL;
|
|
273
|
|
274 return(DupStr(s,40));
|
|
275 }
|
|
276
|
|
277
|
|
278 MLOADER load_far =
|
|
279 { NULL,
|
|
280 "FAR",
|
|
281 "Portable FAR loader v0.1",
|
|
282 FAR_Init,
|
|
283 FAR_Test,
|
|
284 FAR_Load,
|
|
285 FAR_Cleanup,
|
|
286 FAR_LoadTitle
|
|
287 };
|
|
288
|