initial import
[dosrtxon] / libs / mikmod / playercode / mloader.c
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$
24
25   These routines are used to access the available module loaders
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 #ifdef HAVE_MEMORY_H
38 #include <memory.h>
39 #endif
40 #include <string.h>
41
42 #include "mikmod_internals.h"
43
44 #ifdef SUNOS
45 extern int fprintf(FILE *, const char *, ...);
46 #endif
47
48 MREADER *modreader;
49 MODULE of;
50
51 static  MLOADER *firstloader=NULL;
52
53 static  MUNPACKER unpackers[] = {
54         PP20_Unpack,
55         MMCMP_Unpack,
56         XPK_Unpack,
57         S404_Unpack,
58         NULL
59 };
60
61 const UWORD finetune[16] = {
62         8363,8413,8463,8529,8581,8651,8723,8757,
63         7895,7941,7985,8046,8107,8169,8232,8280
64 };
65
66 MIKMODAPI CHAR* MikMod_InfoLoader(void)
67 {
68         int len=0;
69         MLOADER *l;
70         CHAR *list=NULL;
71
72         MUTEX_LOCK(lists);
73         /* compute size of buffer */
74         for(l = firstloader; l; l = l->next)
75                 len += 1 + (l->next ? 1 : 0) + strlen(l->version);
76
77         if(len)
78           if((list=(CHAR*)MikMod_malloc(len*sizeof(CHAR))) != NULL) {
79                 CHAR *list_end = list;
80                 list[0] = 0;
81                 /* list all registered module loders */
82                 for(l = firstloader; l; l = l->next) {
83                     list_end += sprintf(list_end, "%s%s", l->version, (l->next) ? "\n" : "");
84                 }
85         }
86         MUTEX_UNLOCK(lists);
87         return list;
88 }
89
90 void _mm_registerloader(MLOADER* ldr)
91 {
92         MLOADER *cruise=firstloader;
93
94         if(cruise) {
95                 while(cruise->next) cruise = cruise->next;
96                 cruise->next=ldr;
97         } else
98                 firstloader=ldr;
99 }
100
101 MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
102 {
103         /* if we try to register an invalid loader, or an already registered loader,
104            ignore this attempt */
105         if ((!ldr)||(ldr->next))
106                 return;
107
108         MUTEX_LOCK(lists);
109         _mm_registerloader(ldr);
110         MUTEX_UNLOCK(lists);
111 }
112
113 BOOL ReadComment(UWORD len)
114 {
115         if(len) {
116                 int i;
117
118                 if(!(of.comment=(CHAR*)MikMod_malloc(len+1))) return 0;
119                 _mm_read_UBYTES(of.comment,len,modreader);
120
121                 /* translate IT linefeeds */
122                 for(i=0;i<len;i++)
123                         if(of.comment[i]=='\r') of.comment[i]='\n';
124
125                 of.comment[len]=0;      /* just in case */
126         }
127         if(!of.comment[0]) {
128                 MikMod_free(of.comment);
129                 of.comment=NULL;
130         }
131         return 1;
132 }
133
134 BOOL ReadLinedComment(UWORD len,UWORD linelen)
135 {
136         CHAR *tempcomment,*line,*storage;
137         UWORD total=0,t,lines;
138         int i;
139
140         lines = (len + linelen - 1) / linelen;
141         if (len) {
142                 if(!(tempcomment=(CHAR*)MikMod_malloc(len+1))) return 0;
143                 if(!(storage=(CHAR*)MikMod_malloc(linelen+1))) {
144                         MikMod_free(tempcomment);
145                         return 0;
146                 }
147                 memset(tempcomment, ' ', len);
148                 _mm_read_UBYTES(tempcomment,len,modreader);
149
150                 /* compute message length */
151                 for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {
152                         for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0;
153                         for(i=0;i<linelen;i++) if (!line[i]) break;
154                         total+=1+i;
155                 }
156
157                 if(total>lines) {
158                         if(!(of.comment=(CHAR*)MikMod_malloc(total+1))) {
159                                 MikMod_free(storage);
160                                 MikMod_free(tempcomment);
161                                 return 0;
162                         }
163
164                         /* convert message */
165                         for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {
166                                 for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;
167                                 storage[i]=0; /* if (i==linelen) */
168                                 strcat(of.comment,storage);strcat(of.comment,"\r");
169                         }
170                         MikMod_free(storage);
171                         MikMod_free(tempcomment);
172                 }
173         }
174         return 1;
175 }
176
177 BOOL AllocPositions(int total)
178 {
179         if(!total) {
180                 _mm_errno=MMERR_NOT_A_MODULE;
181                 return 0;
182         }
183         if(!(of.positions=(UWORD*)MikMod_calloc(total,sizeof(UWORD)))) return 0;
184         return 1;
185 }
186
187 BOOL AllocPatterns(void)
188 {
189         int s,t,tracks = 0;
190
191         if((!of.numpat)||(!of.numchn)) {
192                 _mm_errno=MMERR_NOT_A_MODULE;
193                 return 0;
194         }
195         /* Allocate track sequencing array */
196         if(!(of.patterns=(UWORD*)MikMod_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
197         if(!(of.pattrows=(UWORD*)MikMod_calloc(of.numpat+1,sizeof(UWORD)))) return 0;
198
199         for(t=0;t<=of.numpat;t++) {
200                 of.pattrows[t]=64;
201                 for(s=0;s<of.numchn;s++)
202                 of.patterns[(t*of.numchn)+s]=tracks++;
203         }
204
205         return 1;
206 }
207
208 BOOL AllocTracks(void)
209 {
210         if(!of.numtrk) {
211                 _mm_errno=MMERR_NOT_A_MODULE;
212                 return 0;
213         }
214         if(!(of.tracks=(UBYTE **)MikMod_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
215         return 1;
216 }
217
218 BOOL AllocInstruments(void)
219 {
220         int t,n;
221
222         if(!of.numins) {
223                 _mm_errno=MMERR_NOT_A_MODULE;
224                 return 0;
225         }
226         if(!(of.instruments=(INSTRUMENT*)MikMod_calloc(of.numins,sizeof(INSTRUMENT))))
227                 return 0;
228
229         for(t=0;t<of.numins;t++) {
230                 for(n=0;n<INSTNOTES;n++) {
231                         /* Init note / sample lookup table */
232                         of.instruments[t].samplenote[n]   = n;
233                         of.instruments[t].samplenumber[n] = t;
234                 }
235                 of.instruments[t].globvol = 64;
236         }
237         return 1;
238 }
239
240 BOOL AllocSamples(void)
241 {
242         UWORD u;
243
244         if(!of.numsmp) {
245                 _mm_errno=MMERR_NOT_A_MODULE;
246                 return 0;
247         }
248         if(!(of.samples=(SAMPLE*)MikMod_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
249
250         for(u=0;u<of.numsmp;u++) {
251                 of.samples[u].panning = 128; /* center */
252                 of.samples[u].handle  = -1;
253                 of.samples[u].globvol = 64;
254                 of.samples[u].volume  = 64;
255         }
256         return 1;
257 }
258
259 static BOOL ML_LoadSamples(void)
260 {
261         SAMPLE *s;
262         int u;
263
264         for(u=of.numsmp,s=of.samples;u;u--,s++)
265                 if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);
266
267         return 1;
268 }
269
270 /* Creates a CSTR out of a character buffer of 'len' bytes, but strips any
271    terminating non-printing characters like 0, spaces etc. */
272 CHAR *DupStr(const CHAR* s, UWORD len, BOOL strict)
273 {
274         UWORD t;
275         CHAR *d=NULL;
276
277         /* Scan for last printing char in buffer [includes high ascii up to 254] */
278         while(len) {
279                 if(s[len-1]>0x20) break;
280                 len--;
281         }
282
283         /* Scan forward for possible NULL character */
284         if(strict) {
285                 for(t=0;t<len;t++) if (!s[t]) break;
286                 if (t<len) len=t;
287         }
288
289         /* When the buffer wasn't completely empty, allocate a cstring and copy the
290            buffer into that string, except for any control-chars */
291         if((d=(CHAR*)MikMod_malloc(sizeof(CHAR)*(len+1))) != NULL) {
292                 for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t];
293                 d[len]=0;
294         }
295         return d;
296 }
297
298 static void ML_XFreeSample(SAMPLE *s)
299 {
300         if(s->handle>=0)
301                 MD_SampleUnload(s->handle);
302
303 /* moved samplename freeing to our caller ML_FreeEx(),
304  * because we are called conditionally. */
305 }
306
307 static void ML_XFreeInstrument(INSTRUMENT *i)
308 {
309         MikMod_free(i->insname);
310 }
311
312 static void ML_FreeEx(MODULE *mf)
313 {
314         UWORD t;
315
316         MikMod_free(mf->songname);
317         MikMod_free(mf->comment);
318
319         MikMod_free(mf->modtype);
320         MikMod_free(mf->positions);
321         MikMod_free(mf->patterns);
322         MikMod_free(mf->pattrows);
323
324         if(mf->tracks) {
325                 for(t=0;t<mf->numtrk;t++)
326                         MikMod_free(mf->tracks[t]);
327                 MikMod_free(mf->tracks);
328         }
329         if(mf->instruments) {
330                 for(t=0;t<mf->numins;t++)
331                         ML_XFreeInstrument(&mf->instruments[t]);
332                 MikMod_free(mf->instruments);
333         }
334         if(mf->samples) {
335                 for(t=0;t<mf->numsmp;t++) {
336                         MikMod_free(mf->samples[t].samplename);
337                         if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
338                 }
339                 MikMod_free(mf->samples);
340         }
341         memset(mf,0,sizeof(MODULE));
342         if(mf!=&of) MikMod_free(mf);
343 }
344
345 static MODULE *ML_AllocUniMod(void)
346 {
347         return (MODULE *) MikMod_malloc(sizeof(MODULE));
348 }
349
350 static BOOL ML_TryUnpack(MREADER *reader,void **out,long *outlen)
351 {
352         int i;
353
354         *out = NULL;
355         *outlen = 0;
356
357         for(i=0;unpackers[i]!=NULL;++i) {
358                 _mm_rewind(reader);
359                 if(unpackers[i](reader,out,outlen)) return 1;
360         }
361         return 0;
362 }
363
364 static void Player_Free_internal(MODULE *mf)
365 {
366         if(mf) {
367                 Player_Exit_internal(mf);
368                 ML_FreeEx(mf);
369         }
370 }
371
372 MIKMODAPI void Player_Free(MODULE *mf)
373 {
374         MUTEX_LOCK(vars);
375         Player_Free_internal(mf);
376         MUTEX_UNLOCK(vars);
377 }
378
379 static CHAR* Player_LoadTitle_internal(MREADER *reader)
380 {
381         MLOADER *l;
382         CHAR *title;
383         void *unpk;
384         long newlen;
385
386         modreader=reader;
387         _mm_errno = 0;
388         _mm_critical = 0;
389         _mm_iobase_setcur(modreader);
390
391         if(ML_TryUnpack(modreader,&unpk,&newlen)) {
392                 if(!(modreader=_mm_new_mem_reader(unpk,newlen))) {
393                         modreader=reader;
394                         MikMod_free(unpk);
395                         return NULL;
396                 }
397         }
398
399         /* Try to find a loader that recognizes the module */
400         for(l=firstloader;l;l=l->next) {
401                 _mm_rewind(modreader);
402                 if(l->Test()) break;
403         }
404
405         if(l) {
406                 title = l->LoadTitle();
407         }
408         else {
409                 _mm_errno = MMERR_NOT_A_MODULE;
410                 if(_mm_errorhandler) _mm_errorhandler();
411                 title = NULL;
412         }
413
414         if (modreader!=reader) {
415                 _mm_delete_mem_reader(modreader);
416                 modreader=reader;
417                 MikMod_free(unpk);
418         }
419         return title;
420 }
421
422 MIKMODAPI CHAR* Player_LoadTitleFP(FILE *fp)
423 {
424         CHAR* result=NULL;
425         MREADER* reader;
426
427         if(fp && (reader=_mm_new_file_reader(fp)) != NULL) {
428                 MUTEX_LOCK(lists);
429                 result=Player_LoadTitle_internal(reader);
430                 MUTEX_UNLOCK(lists);
431                 _mm_delete_file_reader(reader);
432         }
433         return result;
434 }
435
436 MIKMODAPI CHAR* Player_LoadTitleMem(const char *buffer,int len)
437 {
438         CHAR *result=NULL;
439         MREADER* reader;
440
441         if (!buffer || len <= 0) return NULL;
442         if ((reader=_mm_new_mem_reader(buffer,len)) != NULL)
443         {
444                 MUTEX_LOCK(lists);
445                 result=Player_LoadTitle_internal(reader);
446                 MUTEX_UNLOCK(lists);
447                 _mm_delete_mem_reader(reader);
448         }
449
450         return result;
451 }
452
453 MIKMODAPI CHAR* Player_LoadTitleGeneric(MREADER *reader)
454 {
455         CHAR *result=NULL;
456
457         if (reader) {
458                 MUTEX_LOCK(lists);
459                 result=Player_LoadTitle_internal(reader);
460                 MUTEX_UNLOCK(lists);
461         }
462         return result;
463 }
464
465 MIKMODAPI CHAR* Player_LoadTitle(const CHAR* filename)
466 {
467         CHAR* result=NULL;
468         FILE* fp;
469         MREADER* reader;
470
471         if((fp=_mm_fopen(filename,"rb")) != NULL) {
472                 if((reader=_mm_new_file_reader(fp)) != NULL) {
473                         MUTEX_LOCK(lists);
474                         result=Player_LoadTitle_internal(reader);
475                         MUTEX_UNLOCK(lists);
476                         _mm_delete_file_reader(reader);
477                 }
478                 _mm_fclose(fp);
479         }
480         return result;
481 }
482
483 /* Loads a module given an reader */
484 static MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious)
485 {
486         int t;
487         MLOADER *l;
488         BOOL ok;
489         MODULE *mf;
490         void *unpk;
491         long newlen;
492
493         modreader = reader;
494         _mm_errno = 0;
495         _mm_critical = 0;
496         _mm_iobase_setcur(modreader);
497
498         if(ML_TryUnpack(modreader,&unpk,&newlen)) {
499                 if(!(modreader=_mm_new_mem_reader(unpk,newlen))) {
500                         modreader=reader;
501                         MikMod_free(unpk);
502                         return NULL;
503                 }
504         }
505
506         /* Try to find a loader that recognizes the module */
507         for(l=firstloader;l;l=l->next) {
508                 _mm_rewind(modreader);
509                 if(l->Test()) break;
510         }
511
512         if(!l) {
513                 _mm_errno = MMERR_NOT_A_MODULE;
514                 if(modreader!=reader) {
515                         _mm_delete_mem_reader(modreader);
516                         modreader=reader;
517                         MikMod_free(unpk);
518                 }
519                 if(_mm_errorhandler) _mm_errorhandler();
520                 _mm_rewind(modreader);
521                 _mm_iobase_revert(modreader);
522                 return NULL;
523         }
524
525         /* init unitrk routines */
526         if(!UniInit()) {
527                 if(modreader!=reader) {
528                         _mm_delete_mem_reader(modreader);
529                         modreader=reader;
530                         MikMod_free(unpk);
531                 }
532                 if(_mm_errorhandler) _mm_errorhandler();
533                 _mm_rewind(modreader);
534                 _mm_iobase_revert(modreader);
535                 return NULL;
536         }
537
538         /* init the module structure with vanilla settings */
539         memset(&of,0,sizeof(MODULE));
540         of.bpmlimit = 33;
541         of.initvolume = 128;
542         for (t = 0; t < UF_MAXCHAN; t++) of.chanvol[t] = 64;
543         for (t = 0; t < UF_MAXCHAN; t++)
544                 of.panning[t] = ((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT;
545
546         /* init module loader and load the header / patterns */
547         if (!l->Init || l->Init()) {
548                 _mm_rewind(modreader);
549                 ok = l->Load(curious);
550                 if (ok) {
551                         /* propagate inflags=flags for in-module samples */
552                         for (t = 0; t < of.numsmp; t++)
553                                 if (of.samples[t].inflags == 0)
554                                         of.samples[t].inflags = of.samples[t].flags;
555                 }
556         } else
557                 ok = 0;
558
559         /* free loader and unitrk allocations */
560         if (l->Cleanup) l->Cleanup();
561         UniCleanup();
562
563         if(ok) ok = ML_LoadSamples();
564         if(ok) ok = ((mf=ML_AllocUniMod()) != NULL);
565         if(!ok) {
566                 ML_FreeEx(&of);
567                 if(modreader!=reader) {
568                         _mm_delete_mem_reader(modreader);
569                         modreader=reader;
570                         MikMod_free(unpk);
571                 }
572                 if(_mm_errorhandler) _mm_errorhandler();
573                 _mm_rewind(modreader);
574                 _mm_iobase_revert(modreader);
575                 return NULL;
576         }
577
578         /* If the module doesn't have any specific panning, create a
579            MOD-like panning, with the channels half-separated. */
580         if (!(of.flags & UF_PANNING))
581                 for (t = 0; t < of.numchn; t++)
582                         of.panning[t] = ((t + 1) & 2) ? PAN_HALFRIGHT : PAN_HALFLEFT;
583
584         /* Copy the static MODULE contents into the dynamic MODULE struct. */
585         memcpy(mf,&of,sizeof(MODULE));
586
587         if(maxchan>0) {
588                 if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
589                         maxchan = mf->numchn;
590                 else
591                   if((mf->numvoices)&&(mf->numvoices<maxchan))
592                         maxchan = mf->numvoices;
593
594                 if(maxchan<mf->numchn) mf->flags |= UF_NNA;
595
596                 ok = !MikMod_SetNumVoices_internal(maxchan,-1);
597         }
598
599         if(ok) ok = !SL_LoadSamples();
600         if(ok) ok = !Player_Init(mf);
601
602         if(modreader!=reader) {
603                 _mm_delete_mem_reader(modreader);
604                 modreader=reader;
605                 MikMod_free(unpk);
606         }
607         _mm_iobase_revert(modreader);
608
609         if(!ok) {
610                 Player_Free_internal(mf);
611                 return NULL;
612         }
613         return mf;
614 }
615
616 MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)
617 {
618         MODULE* result;
619
620         MUTEX_LOCK(vars);
621         MUTEX_LOCK(lists);
622                 result=Player_LoadGeneric_internal(reader,maxchan,curious);
623         MUTEX_UNLOCK(lists);
624         MUTEX_UNLOCK(vars);
625
626         return result;
627 }
628
629 MIKMODAPI MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,BOOL curious)
630 {
631         MODULE* result=NULL;
632         MREADER* reader;
633
634         if (!buffer || len <= 0) return NULL;
635         if ((reader=_mm_new_mem_reader(buffer, len)) != NULL) {
636                 result=Player_LoadGeneric(reader,maxchan,curious);
637                 _mm_delete_mem_reader(reader);
638         }
639         return result;
640 }
641
642 /* Loads a module given a file pointer.
643    File is loaded from the current file seek position. */
644 MIKMODAPI MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious)
645 {
646         MODULE* result=NULL;
647         struct MREADER* reader;
648
649         if (fp && (reader=_mm_new_file_reader(fp)) != NULL) {
650                 result=Player_LoadGeneric(reader,maxchan,curious);
651                 _mm_delete_file_reader(reader);
652         }
653         return result;
654 }
655
656 /* Open a module via its filename.  The loader will initialize the specified
657    song-player 'player'. */
658 MIKMODAPI MODULE* Player_Load(const CHAR* filename,int maxchan,BOOL curious)
659 {
660         FILE *fp;
661         MODULE *mf=NULL;
662
663         if((fp=_mm_fopen(filename,"rb")) != NULL) {
664                 mf=Player_LoadFP(fp,maxchan,curious);
665                 _mm_fclose(fp);
666         }
667         return mf;
668 }
669
670 /* ex:set ts=4: */