All kernel objects in code shared amongs targets (core, plugins, codecs) should be...
[kugel-rb.git] / apps / plugins / mikmod / mloader.c
blob7bce40578e0c5f5cd4cfce5b3009dadaacbea954
1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for complete list.
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.
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.
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.
21 /*==============================================================================
23 $Id: mloader.c,v 1.3 2005/04/07 19:57:39 realtech Exp $
25 These routines are used to access the available module loaders
27 ==============================================================================*/
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
37 #ifdef HAVE_MEMORY_H
38 #include <memory.h>
39 #endif
40 #include <string.h>
42 #include "mikmod_internals.h"
44 #ifdef SUNOS
45 extern int fprintf(FILE *, const char *, ...);
46 #endif
48 MREADER *modreader;
49 MODULE of;
51 static MLOADER *firstloader=NULL;
53 UWORD finetune[16]={
54 8363,8413,8463,8529,8581,8651,8723,8757,
55 7895,7941,7985,8046,8107,8169,8232,8280
58 MIKMODAPI CHAR* MikMod_InfoLoader(void)
60 int len=0;
61 MLOADER *l;
62 CHAR *list=NULL;
64 MUTEX_LOCK(lists);
65 /* compute size of buffer */
66 for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version);
68 if(len)
69 if((list=MikMod_malloc(len*sizeof(CHAR)))) {
70 list[0]=0;
71 /* list all registered module loders */
72 for(l=firstloader;l;l=l->next)
73 sprintf(list,(l->next)?"%s%s\n":"%s%s",list,l->version);
75 MUTEX_UNLOCK(lists);
76 return list;
79 void _mm_registerloader(MLOADER* ldr)
81 MLOADER *cruise=firstloader;
83 if(cruise) {
84 while(cruise->next) cruise = cruise->next;
85 cruise->next=ldr;
86 } else
87 firstloader=ldr;
90 MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
92 /* if we try to register an invalid loader, or an already registered loader,
93 ignore this attempt */
94 if ((!ldr)||(ldr->next))
95 return;
97 MUTEX_LOCK(lists);
98 _mm_registerloader(ldr);
99 MUTEX_UNLOCK(lists);
102 int ReadComment(UWORD len)
104 if(len) {
105 int i;
107 if(!(of.comment=(CHAR*)MikMod_malloc(len+1))) return 0;
108 _mm_read_UBYTES(of.comment,len,modreader);
110 /* translate IT linefeeds */
111 for(i=0;i<len;i++)
112 if(of.comment[i]=='\r') of.comment[i]='\n';
114 of.comment[len]=0; /* just in case */
116 if(!of.comment[0]) {
117 MikMod_free(of.comment);
118 of.comment=NULL;
120 return 1;
123 int ReadLinedComment(UWORD len,UWORD linelen)
125 CHAR *tempcomment,*line,*storage;
126 UWORD total=0,t,lines;
127 int i;
129 lines = (len + linelen - 1) / linelen;
130 if (len) {
131 if(!(tempcomment=(CHAR*)MikMod_malloc(len+1))) return 0;
132 if(!(storage=(CHAR*)MikMod_malloc(linelen+1))) {
133 MikMod_free(tempcomment);
134 return 0;
136 memset(tempcomment, ' ', len);
137 _mm_read_UBYTES(tempcomment,len,modreader);
139 /* compute message length */
140 for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {
141 for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0;
142 for(i=0;i<linelen;i++) if (!line[i]) break;
143 total+=1+i;
146 if(total>lines) {
147 if(!(of.comment=(CHAR*)MikMod_malloc(total+1))) {
148 MikMod_free(storage);
149 MikMod_free(tempcomment);
150 return 0;
153 /* convert message */
154 for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {
155 for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;
156 storage[i]=0; /* if (i==linelen) */
157 strcat(of.comment,storage);strcat(of.comment,"\r");
159 MikMod_free(storage);
160 MikMod_free(tempcomment);
163 return 1;
166 int AllocPositions(int total)
168 if(!total) {
169 _mm_errno=MMERR_NOT_A_MODULE;
170 return 0;
172 if(!(of.positions=MikMod_calloc(total,sizeof(UWORD)))) return 0;
173 return 1;
176 int AllocPatterns(void)
178 int s,t,tracks = 0;
180 if((!of.numpat)||(!of.numchn)) {
181 _mm_errno=MMERR_NOT_A_MODULE;
182 return 0;
184 /* Allocate track sequencing array */
185 if(!(of.patterns=(UWORD*)MikMod_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
186 if(!(of.pattrows=(UWORD*)MikMod_calloc(of.numpat+1,sizeof(UWORD)))) return 0;
188 for(t=0;t<=of.numpat;t++) {
189 of.pattrows[t]=64;
190 for(s=0;s<of.numchn;s++)
191 of.patterns[(t*of.numchn)+s]=tracks++;
194 return 1;
197 int AllocTracks(void)
199 if(!of.numtrk) {
200 _mm_errno=MMERR_NOT_A_MODULE;
201 return 0;
203 if(!(of.tracks=(UBYTE **)MikMod_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
204 return 1;
207 int AllocInstruments(void)
209 int t,n;
211 if(!of.numins) {
212 _mm_errno=MMERR_NOT_A_MODULE;
213 return 0;
215 if(!(of.instruments=(INSTRUMENT*)MikMod_calloc(of.numins,sizeof(INSTRUMENT))))
216 return 0;
218 for(t=0;t<of.numins;t++) {
219 for(n=0;n<INSTNOTES;n++) {
220 /* Init note / sample lookup table */
221 of.instruments[t].samplenote[n] = n;
222 of.instruments[t].samplenumber[n] = t;
224 of.instruments[t].globvol = 64;
226 return 1;
229 int AllocSamples(void)
231 UWORD u;
233 if(!of.numsmp) {
234 _mm_errno=MMERR_NOT_A_MODULE;
235 return 0;
237 if(!(of.samples=(SAMPLE*)MikMod_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
239 for(u=0;u<of.numsmp;u++) {
240 of.samples[u].panning = 128; /* center */
241 of.samples[u].handle = -1;
242 of.samples[u].globvol = 64;
243 of.samples[u].volume = 64;
245 return 1;
248 static int ML_LoadSamples(void)
250 SAMPLE *s;
251 int u;
253 for(u=of.numsmp,s=of.samples;u;u--,s++)
254 if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);
256 return 1;
259 /* Creates a CSTR out of a character buffer of 'len' bytes, but strips any
260 terminating non-printing characters like 0, spaces etc. */
261 CHAR *DupStr(CHAR* s,UWORD len,int strict)
263 UWORD t;
264 CHAR *d=NULL;
266 /* Scan for last printing char in buffer [includes high ascii up to 254] */
267 while(len) {
268 if(s[len-1]>0x20) break;
269 len--;
272 /* Scan forward for possible NULL character */
273 if(strict) {
274 for(t=0;t<len;t++) if (!s[t]) break;
275 if (t<len) len=t;
278 /* When the buffer wasn't completely empty, allocate a cstring and copy the
279 buffer into that string, except for any control-chars */
280 if((d=(CHAR*)MikMod_malloc(sizeof(CHAR)*(len+1)))) {
281 for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t];
282 d[len]=0;
284 return d;
287 CHAR *StrDup(CHAR *s)
289 size_t l = strlen(s) + 1;
290 CHAR *d = MikMod_malloc(l);
291 strcpy(d, s);
292 return d;
295 static void ML_XFreeSample(SAMPLE *s)
297 if(s->handle>=0)
298 MD_SampleUnload(s->handle);
299 if(s->samplename) MikMod_free(s->samplename);
302 static void ML_XFreeInstrument(INSTRUMENT *i)
304 if(i->insname) MikMod_free(i->insname);
307 static void ML_FreeEx(MODULE *mf)
309 UWORD t;
311 if(mf->songname) MikMod_free(mf->songname);
312 if(mf->comment) MikMod_free(mf->comment);
314 if(mf->modtype) MikMod_free(mf->modtype);
315 if(mf->positions) MikMod_free(mf->positions);
316 if(mf->patterns) MikMod_free(mf->patterns);
317 if(mf->pattrows) MikMod_free(mf->pattrows);
319 if(mf->tracks) {
320 for(t=0;t<mf->numtrk;t++)
321 if(mf->tracks[t]) MikMod_free(mf->tracks[t]);
322 MikMod_free(mf->tracks);
324 if(mf->instruments) {
325 for(t=0;t<mf->numins;t++)
326 ML_XFreeInstrument(&mf->instruments[t]);
327 MikMod_free(mf->instruments);
329 if(mf->samples) {
330 for(t=0;t<mf->numsmp;t++)
331 if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
332 MikMod_free(mf->samples);
334 memset(mf,0,sizeof(MODULE));
335 if(mf!=&of) MikMod_free(mf);
338 static MODULE *ML_AllocUniMod(void)
340 MODULE *mf;
342 return (mf=MikMod_malloc(sizeof(MODULE)));
345 void Player_Free_internal(MODULE *mf)
347 if(mf) {
348 Player_Exit_internal(mf);
349 ML_FreeEx(mf);
353 MIKMODAPI void Player_Free(MODULE *mf)
355 MUTEX_LOCK(vars);
356 Player_Free_internal(mf);
357 MUTEX_UNLOCK(vars);
360 static CHAR* Player_LoadTitle_internal(MREADER *reader)
362 MLOADER *l;
364 modreader=reader;
365 _mm_errno = 0;
366 _mm_critical = 0;
367 _mm_iobase_setcur(modreader);
369 /* Try to find a loader that recognizes the module */
370 for(l=firstloader;l;l=l->next) {
371 _mm_rewind(modreader);
372 if(l->Test()) break;
375 if(!l) {
376 _mm_errno = MMERR_NOT_A_MODULE;
377 if(_mm_errorhandler) _mm_errorhandler();
378 return NULL;
381 return l->LoadTitle();
384 MIKMODAPI CHAR* Player_LoadTitleFP(int fp)
386 CHAR* result=NULL;
387 MREADER* reader;
389 if(fp && (reader=_mm_new_file_reader(fp))) {
390 MUTEX_LOCK(lists);
391 result=Player_LoadTitle_internal(reader);
392 MUTEX_UNLOCK(lists);
393 _mm_delete_file_reader(reader);
395 return result;
398 MIKMODAPI CHAR* Player_LoadTitleMem(const char *buffer,int len)
400 CHAR *result=NULL;
401 MREADER* reader;
403 if ((reader=_mm_new_mem_reader(buffer,len)))
405 MUTEX_LOCK(lists);
406 result=Player_LoadTitle_internal(reader);
407 MUTEX_UNLOCK(lists);
408 _mm_delete_mem_reader(reader);
412 return result;
415 MIKMODAPI CHAR* Player_LoadTitleGeneric(MREADER *reader)
417 CHAR *result=NULL;
419 if (reader) {
420 MUTEX_LOCK(lists);
421 result=Player_LoadTitle_internal(reader);
422 MUTEX_UNLOCK(lists);
424 return result;
427 MIKMODAPI CHAR* Player_LoadTitle(CHAR* filename)
429 CHAR* result=NULL;
430 int fp;
431 MREADER* reader;
433 if((fp=_mm_fopen(filename,"rb"))) {
434 if((reader=_mm_new_file_reader(fp))) {
435 MUTEX_LOCK(lists);
436 result=Player_LoadTitle_internal(reader);
437 MUTEX_UNLOCK(lists);
438 _mm_delete_file_reader(reader);
440 _mm_fclose(fp);
442 return result;
445 /* Loads a module given an reader */
446 MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,int curious)
448 int t;
449 MLOADER *l;
450 int ok;
451 MODULE *mf;
453 modreader = reader;
454 _mm_errno = 0;
455 _mm_critical = 0;
456 _mm_iobase_setcur(modreader);
458 /* Try to find a loader that recognizes the module */
459 for(l=firstloader;l;l=l->next) {
460 _mm_rewind(modreader);
461 if(l->Test()) break;
464 if(!l) {
465 _mm_errno = MMERR_NOT_A_MODULE;
466 if(_mm_errorhandler) _mm_errorhandler();
467 _mm_rewind(modreader);_mm_iobase_revert(modreader);
468 return NULL;
471 /* init unitrk routines */
472 if(!UniInit()) {
473 if(_mm_errorhandler) _mm_errorhandler();
474 _mm_rewind(modreader);_mm_iobase_revert(modreader);
475 return NULL;
478 /* init the module structure with vanilla settings */
479 memset(&of,0,sizeof(MODULE));
480 of.bpmlimit = 33;
481 of.initvolume = 128;
482 for (t = 0; t < UF_MAXCHAN; t++) of.chanvol[t] = 64;
483 for (t = 0; t < UF_MAXCHAN; t++)
484 of.panning[t] = ((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT;
486 /* init module loader and load the header / patterns */
487 if (!l->Init || l->Init()) {
488 _mm_rewind(modreader);
489 ok = l->Load(curious);
490 if (ok) {
491 /* propagate inflags=flags for in-module samples */
492 for (t = 0; t < of.numsmp; t++)
493 if (of.samples[t].inflags == 0)
494 of.samples[t].inflags = of.samples[t].flags;
496 } else
497 ok = 0;
499 /* free loader and unitrk allocations */
500 if (l->Cleanup) l->Cleanup();
501 UniCleanup();
503 if(!ok) {
504 ML_FreeEx(&of);
505 if(_mm_errorhandler) _mm_errorhandler();
506 _mm_rewind(modreader);_mm_iobase_revert(modreader);
507 return NULL;
510 if(!ML_LoadSamples()) {
511 ML_FreeEx(&of);
512 if(_mm_errorhandler) _mm_errorhandler();
513 _mm_rewind(modreader);_mm_iobase_revert(modreader);
514 return NULL;
517 if(!(mf=ML_AllocUniMod())) {
518 ML_FreeEx(&of);
519 _mm_rewind(modreader);_mm_iobase_revert(modreader);
520 if(_mm_errorhandler) _mm_errorhandler();
521 return NULL;
524 /* If the module doesn't have any specific panning, create a
525 MOD-like panning, with the channels half-separated. */
526 if (!(of.flags & UF_PANNING))
527 for (t = 0; t < of.numchn; t++)
528 of.panning[t] = ((t + 1) & 2) ? PAN_HALFRIGHT : PAN_HALFLEFT;
530 /* Copy the static MODULE contents into the dynamic MODULE struct. */
531 memcpy(mf,&of,sizeof(MODULE));
533 if(maxchan>0) {
534 if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
535 maxchan = mf->numchn;
536 else
537 if((mf->numvoices)&&(mf->numvoices<maxchan))
538 maxchan = mf->numvoices;
540 if(maxchan<mf->numchn) mf->flags |= UF_NNA;
542 if(MikMod_SetNumVoices_internal(maxchan,-1)) {
543 _mm_iobase_revert(modreader);
544 Player_Free(mf);
545 return NULL;
548 if(SL_LoadSamples()) {
549 _mm_iobase_revert(modreader);
550 Player_Free_internal(mf);
551 return NULL;
553 if(Player_Init(mf)) {
554 _mm_iobase_revert(modreader);
555 Player_Free_internal(mf);
556 mf=NULL;
558 _mm_iobase_revert(modreader);
559 return mf;
562 MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,int curious)
564 MODULE* result;
566 MUTEX_LOCK(vars);
567 MUTEX_LOCK(lists);
568 result=Player_LoadGeneric_internal(reader,maxchan,curious);
569 MUTEX_UNLOCK(lists);
570 MUTEX_UNLOCK(vars);
572 return result;
575 MIKMODAPI MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,int curious)
577 MODULE* result=NULL;
578 MREADER* reader;
580 if ((reader=_mm_new_mem_reader(buffer, len))) {
581 result=Player_LoadGeneric(reader,maxchan,curious);
582 _mm_delete_mem_reader(reader);
584 return result;
587 /* Loads a module given a file pointer.
588 File is loaded from the current file seek position. */
589 MIKMODAPI MODULE* Player_LoadFP(int fp,int maxchan,int curious)
591 MODULE* result=NULL;
592 struct MREADER* reader=_mm_new_file_reader (fp);
594 if (reader) {
595 result=Player_LoadGeneric(reader,maxchan,curious);
596 _mm_delete_file_reader(reader);
598 return result;
601 /* Open a module via its filename. The loader will initialize the specified
602 song-player 'player'. */
603 MIKMODAPI MODULE* Player_Load(CHAR* filename,int maxchan,int curious)
605 int fp;
606 MODULE *mf=NULL;
608 if((fp=_mm_fopen(filename,"rb"))) {
609 mf=Player_LoadFP(fp,maxchan,curious);
610 _mm_fclose(fp);
612 return mf;
615 /* ex:set ts=4: */