Mercurial > ~darius > hgwebdir.cgi > mikmod
comparison playercode/mloader.c @ 4:5d614bcc4287
Initial entry of mikmod into the CVS tree.
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:08 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:71e20a32bd84 | 4:5d614bcc4287 |
---|---|
1 /* | |
2 | |
3 Name: MLOADER.C | |
4 | |
5 Description: | |
6 These routines are used to access the available module loaders | |
7 | |
8 Portability: | |
9 All systems - all compilers | |
10 | |
11 */ | |
12 | |
13 #include <string.h> | |
14 #include "mikmod.h" | |
15 | |
16 | |
17 FILE *modfp; | |
18 UNIMOD of; | |
19 | |
20 static MLOADER *firstloader = NULL; | |
21 | |
22 UWORD finetune[16] = | |
23 { 8363, 8413, 8463, 8529, 8581, 8651, 8723, 8757, | |
24 7895, 7941, 7985, 8046, 8107, 8169, 8232, 8280 | |
25 }; | |
26 | |
27 | |
28 void ML_InfoLoader(void) | |
29 { | |
30 int t; | |
31 MLOADER *l; | |
32 | |
33 // list all registered devicedrivers: | |
34 | |
35 for(t=1,l=firstloader; l!=NULL; l=l->next, t++) | |
36 printf("%d. %s\n",t,l->version); | |
37 } | |
38 | |
39 | |
40 void ML_RegisterLoader(MLOADER *ldr) | |
41 { | |
42 MLOADER *cruise = firstloader; | |
43 | |
44 if(cruise!=NULL) | |
45 { while(cruise->next!=NULL) cruise = cruise->next; | |
46 cruise->next = ldr; | |
47 } else | |
48 firstloader = ldr; | |
49 } | |
50 | |
51 | |
52 BOOL ReadComment(UWORD len) | |
53 { | |
54 //int t; | |
55 | |
56 if(len) | |
57 { if(!(of.comment=(CHAR *)_mm_malloc(len+1))) return 0; | |
58 fread(of.comment,len,1,modfp); | |
59 of.comment[len] = 0; | |
60 } | |
61 return 1; | |
62 } | |
63 | |
64 | |
65 BOOL AllocPositions(int total) | |
66 { | |
67 if((of.positions = _mm_calloc(total,sizeof(UWORD))) == NULL) return 0; | |
68 return 1; | |
69 } | |
70 | |
71 | |
72 BOOL AllocPatterns(void) | |
73 { | |
74 int s,t,tracks = 0; | |
75 | |
76 // Allocate track sequencing array | |
77 | |
78 if(!(of.patterns = (UWORD *)_mm_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0; | |
79 if(!(of.pattrows = (UWORD *)_mm_calloc(of.numpat+1,sizeof(UWORD)))) return 0; | |
80 | |
81 for(t=0; t<of.numpat+1; t++) | |
82 { of.pattrows[t] = 64; | |
83 for(s=0; s<of.numchn; s++) | |
84 of.patterns[(t*of.numchn)+s] = tracks++; | |
85 } | |
86 | |
87 return 1; | |
88 } | |
89 | |
90 | |
91 BOOL AllocTracks(void) | |
92 { | |
93 if(!(of.tracks=(UBYTE **)_mm_calloc(of.numtrk,sizeof(UBYTE *)))) return 0; | |
94 return 1; | |
95 } | |
96 | |
97 | |
98 BOOL AllocInstruments(void) | |
99 { | |
100 int t,n; | |
101 | |
102 if((of.instruments=(INSTRUMENT *)_mm_calloc(of.numins,sizeof(INSTRUMENT)))==NULL) return 0; | |
103 | |
104 for(t=0; t<of.numins; t++) | |
105 { for(n=0; n<120; n++) // Init note / sample lookup table | |
106 { of.instruments[t].samplenote[n] = n; | |
107 of.instruments[t].samplenumber[n] = t; | |
108 } | |
109 of.instruments[t].globvol = 64; | |
110 } | |
111 return 1; | |
112 } | |
113 | |
114 | |
115 BOOL AllocSamples(void) | |
116 { | |
117 UWORD u; | |
118 | |
119 if((of.samples = (SAMPLE *)_mm_calloc(of.numsmp,sizeof(SAMPLE)))==NULL) return 0; | |
120 | |
121 for(u=0; u<of.numsmp; u++) | |
122 { of.samples[u].panning = 128; | |
123 of.samples[u].handle = -1; | |
124 of.samples[u].globvol = 64; | |
125 of.samples[u].volume = 64; | |
126 } | |
127 return 1; | |
128 } | |
129 | |
130 | |
131 BOOL ML_LoadSamples(void) | |
132 { | |
133 SAMPLE *s; | |
134 int u; | |
135 | |
136 for(u=of.numsmp, s=of.samples; u; u--, s++) | |
137 if(s->length) SL_RegisterSample(s,MD_MUSIC,modfp); | |
138 | |
139 return 1; | |
140 } | |
141 | |
142 | |
143 CHAR *DupStr(CHAR *s, UWORD len) | |
144 // Creates a CSTR out of a character buffer of 'len' bytes, but strips | |
145 // any terminating non-printing characters like 0, spaces etc. | |
146 { | |
147 UWORD t; | |
148 CHAR *d = NULL; | |
149 | |
150 // Scan for first printing char in buffer [includes high ascii up to 254] | |
151 while(len) | |
152 { if(s[len-1] > 0x20) break; | |
153 len--; | |
154 } | |
155 | |
156 // When the buffer wasn't completely empty, allocate | |
157 // a cstring and copy the buffer into that string, except | |
158 // for any control-chars | |
159 | |
160 #ifdef __GNUC__ | |
161 if(len<16) len = 16; | |
162 #endif | |
163 | |
164 if((d=(CHAR *)_mm_malloc(len+1)) != NULL) | |
165 { for(t=0; t<len; t++) d[t] = (s[t]<32) ? ' ' : s[t]; | |
166 d[t] = 0; | |
167 } | |
168 | |
169 return d; | |
170 } | |
171 | |
172 | |
173 static void ML_XFreeSample(SAMPLE *s) | |
174 { | |
175 if(s->handle>=0) | |
176 MD_SampleUnLoad(s->handle); | |
177 if(s->samplename!=NULL) free(s->samplename); | |
178 } | |
179 | |
180 | |
181 static void ML_XFreeInstrument(INSTRUMENT *i) | |
182 { | |
183 if(i->insname!=NULL) free(i->insname); | |
184 } | |
185 | |
186 | |
187 static void ML_FreeEx(UNIMOD *mf) | |
188 { | |
189 UWORD t; | |
190 | |
191 if(mf->songname!=NULL) free(mf->songname); | |
192 if(mf->composer!=NULL) free(mf->composer); | |
193 if(mf->comment!=NULL) free(mf->comment); | |
194 | |
195 if(mf->modtype!=NULL) free(mf->modtype); | |
196 if(mf->positions!=NULL) free(mf->positions); | |
197 if(mf->patterns!=NULL) free(mf->patterns); | |
198 if(mf->pattrows!=NULL) free(mf->pattrows); | |
199 | |
200 if(mf->tracks!=NULL) | |
201 { for(t=0; t<mf->numtrk; t++) | |
202 if(mf->tracks[t]!=NULL) free(mf->tracks[t]); | |
203 free(mf->tracks); | |
204 } | |
205 | |
206 if(mf->instruments != NULL) | |
207 { for(t=0; t<mf->numins; t++) | |
208 ML_XFreeInstrument(&mf->instruments[t]); | |
209 free(mf->instruments); | |
210 } | |
211 | |
212 if(mf->samples != NULL) | |
213 { for(t=0; t<mf->numsmp; t++) | |
214 if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]); | |
215 free(mf->samples); | |
216 } | |
217 | |
218 memset(mf,0,sizeof(UNIMOD)); | |
219 } | |
220 | |
221 | |
222 static UNIMOD *ML_AllocUniMod(void) | |
223 { | |
224 UNIMOD *mf; | |
225 | |
226 if((mf=_mm_calloc(1,sizeof(UNIMOD))) == NULL) return NULL; | |
227 return mf; | |
228 } | |
229 | |
230 | |
231 /****************************************** | |
232 | |
233 Next are the user-callable functions | |
234 | |
235 ******************************************/ | |
236 | |
237 | |
238 void MikMod_FreeSong(UNIMOD *mf) | |
239 { | |
240 if(mf!=NULL) | |
241 { Player_Exit(mf); | |
242 ML_FreeEx(mf); | |
243 } | |
244 } | |
245 | |
246 | |
247 CHAR *MikMod_LoadSongTitle(CHAR *filename) | |
248 { | |
249 MLOADER *l; | |
250 CHAR *retval; | |
251 FILE *fp; | |
252 | |
253 if((fp = _mm_fopen(filename,"rb"))==NULL) return NULL; | |
254 | |
255 _mm_errno = 0; | |
256 _mm_critical = 0; | |
257 _mm_iobase_setcur(modfp); | |
258 | |
259 // Try to find a loader that recognizes the module | |
260 | |
261 for(l=firstloader; l!=NULL; l=l->next) | |
262 { _mm_rewind(modfp); | |
263 if(l->Test()) break; | |
264 } | |
265 | |
266 if(l==NULL) | |
267 { _mm_errno = MMERR_NOT_A_MODULE; | |
268 _mm_iobase_revert(); | |
269 if(_mm_errorhandler!=NULL) _mm_errorhandler(); | |
270 return NULL; | |
271 } | |
272 | |
273 retval = l->LoadTitle(); | |
274 | |
275 fclose(fp); | |
276 return(retval); | |
277 } | |
278 | |
279 | |
280 UNIMOD *MikMod_LoadSongFP(FILE *fp, int maxchan) | |
281 | |
282 // Loads a module given a file pointer. | |
283 // File is loaded from the current file seek position. | |
284 | |
285 { | |
286 int t; | |
287 MLOADER *l; | |
288 BOOL ok; | |
289 UNIMOD *mf; | |
290 | |
291 modfp = fp; | |
292 _mm_errno = 0; | |
293 _mm_critical = 0; | |
294 | |
295 _mm_iobase_setcur(modfp); | |
296 | |
297 // Try to find a loader that recognizes the module | |
298 | |
299 for(l=firstloader; l!=NULL; l=l->next) | |
300 { _mm_rewind(modfp); | |
301 if(l->Test()) break; | |
302 } | |
303 | |
304 if(l==NULL) | |
305 { _mm_errno = MMERR_NOT_A_MODULE; | |
306 _mm_iobase_revert(); | |
307 if(_mm_errorhandler!=NULL) _mm_errorhandler(); | |
308 return NULL; | |
309 } | |
310 | |
311 // init unitrk routines | |
312 if(!UniInit()) | |
313 { if(_mm_errorhandler!=NULL) _mm_errorhandler(); | |
314 return NULL; | |
315 } | |
316 | |
317 // load the song using the song's loader variable | |
318 memset(&of,0,sizeof(UNIMOD)); | |
319 of.initvolume = 128; | |
320 | |
321 // init panning array | |
322 for(t=0; t<64; t++) of.panning[t] = ((t+1)&2) ? 255 : 0; | |
323 for(t=0; t<64; t++) of.chanvol[t] = 64; | |
324 | |
325 // init module loader and load the header / patterns | |
326 if(l->Init()) | |
327 { _mm_rewind(modfp); | |
328 ok = l->Load(); | |
329 } else ok = 0; | |
330 | |
331 // free loader and unitrk allocations | |
332 l->Cleanup(); | |
333 UniCleanup(); | |
334 | |
335 if(!ok) | |
336 { ML_FreeEx(&of); | |
337 _mm_iobase_revert(); | |
338 if(_mm_errorhandler!=NULL) _mm_errorhandler(); | |
339 return NULL; | |
340 } | |
341 | |
342 if(!ML_LoadSamples()) | |
343 { ML_FreeEx(&of); | |
344 _mm_iobase_revert(); | |
345 if(_mm_errorhandler!=NULL) _mm_errorhandler(); | |
346 return NULL; | |
347 } | |
348 | |
349 if((mf=ML_AllocUniMod()) == NULL) | |
350 { ML_FreeEx(&of); | |
351 _mm_iobase_revert(); | |
352 if(_mm_errorhandler!=NULL) _mm_errorhandler(); | |
353 return NULL; | |
354 } | |
355 | |
356 // Copy the static UNIMOD contents into the dynamic UNIMOD struct. | |
357 memcpy(mf,&of,sizeof(UNIMOD)); | |
358 | |
359 _mm_iobase_revert(); | |
360 | |
361 if(maxchan > 0) | |
362 { if(!(mf->flags & UF_NNA) && (mf->numchn < maxchan)) | |
363 maxchan = mf->numchn; | |
364 else if((mf->numvoices!=0) && mf->numvoices < maxchan) | |
365 maxchan = mf->numvoices; | |
366 | |
367 if(maxchan < mf->numchn) mf->flags |= UF_NNA; | |
368 | |
369 if(MikMod_SetNumVoices(maxchan,-1)) | |
370 { MikMod_FreeSong(mf); | |
371 return NULL; | |
372 } | |
373 } | |
374 | |
375 return mf; | |
376 } | |
377 | |
378 | |
379 UNIMOD *MikMod_LoadSong(CHAR *filename, int maxchan) | |
380 | |
381 // Open a module via it's filename. The loader will initialize the specified | |
382 // song-player 'player'. | |
383 | |
384 { | |
385 FILE *fp; | |
386 UNIMOD *mf; | |
387 | |
388 if((fp = _mm_fopen(filename,"rb"))==NULL) return NULL; | |
389 if((mf = MikMod_LoadSongFP(fp, maxchan)) != NULL) | |
390 { if(SL_LoadSamples() || Player_Init(mf)) | |
391 { MikMod_FreeSong(mf); | |
392 mf = NULL; | |
393 } | |
394 } | |
395 | |
396 fclose(fp); | |
397 return mf; | |
398 } | |
399 |