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