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
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 ==============================================================================*/
42 #include "mikmod_internals.h"
45 extern int fprintf(FILE *, const char *, ...);
51 static MLOADER
*firstloader
=NULL
;
54 8363,8413,8463,8529,8581,8651,8723,8757,
55 7895,7941,7985,8046,8107,8169,8232,8280
58 MIKMODAPI CHAR
* MikMod_InfoLoader(void)
65 /* compute size of buffer */
66 for(l
=firstloader
;l
;l
=l
->next
) len
+=1+(l
->next
?1:0)+strlen(l
->version
);
69 if((list
=MikMod_malloc(len
*sizeof(CHAR
)))) {
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
);
79 void _mm_registerloader(MLOADER
* ldr
)
81 MLOADER
*cruise
=firstloader
;
84 while(cruise
->next
) cruise
= cruise
->next
;
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
))
98 _mm_registerloader(ldr
);
102 int ReadComment(UWORD len
)
107 if(!(of
.comment
=(CHAR
*)MikMod_malloc(len
+1))) return 0;
108 _mm_read_UBYTES(of
.comment
,len
,modreader
);
110 /* translate IT linefeeds */
112 if(of
.comment
[i
]=='\r') of
.comment
[i
]='\n';
114 of
.comment
[len
]=0; /* just in case */
117 MikMod_free(of
.comment
);
123 int ReadLinedComment(UWORD len
,UWORD linelen
)
125 CHAR
*tempcomment
,*line
,*storage
;
126 UWORD total
=0,t
,lines
;
129 lines
= (len
+ linelen
- 1) / linelen
;
131 if(!(tempcomment
=(CHAR
*)MikMod_malloc(len
+1))) return 0;
132 if(!(storage
=(CHAR
*)MikMod_malloc(linelen
+1))) {
133 MikMod_free(tempcomment
);
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;
147 if(!(of
.comment
=(CHAR
*)MikMod_malloc(total
+1))) {
148 MikMod_free(storage
);
149 MikMod_free(tempcomment
);
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
);
166 int AllocPositions(int total
)
169 _mm_errno
=MMERR_NOT_A_MODULE
;
172 if(!(of
.positions
=MikMod_calloc(total
,sizeof(UWORD
)))) return 0;
176 int AllocPatterns(void)
180 if((!of
.numpat
)||(!of
.numchn
)) {
181 _mm_errno
=MMERR_NOT_A_MODULE
;
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
++) {
190 for(s
=0;s
<of
.numchn
;s
++)
191 of
.patterns
[(t
*of
.numchn
)+s
]=tracks
++;
197 int AllocTracks(void)
200 _mm_errno
=MMERR_NOT_A_MODULE
;
203 if(!(of
.tracks
=(UBYTE
**)MikMod_calloc(of
.numtrk
,sizeof(UBYTE
*)))) return 0;
207 int AllocInstruments(void)
212 _mm_errno
=MMERR_NOT_A_MODULE
;
215 if(!(of
.instruments
=(INSTRUMENT
*)MikMod_calloc(of
.numins
,sizeof(INSTRUMENT
))))
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;
229 int AllocSamples(void)
234 _mm_errno
=MMERR_NOT_A_MODULE
;
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;
248 static int ML_LoadSamples(void)
253 for(u
=of
.numsmp
,s
=of
.samples
;u
;u
--,s
++)
254 if(s
->length
) SL_RegisterSample(s
,MD_MUSIC
,modreader
);
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
)
266 /* Scan for last printing char in buffer [includes high ascii up to 254] */
268 if(s
[len
-1]>0x20) break;
272 /* Scan forward for possible NULL character */
274 for(t
=0;t
<len
;t
++) if (!s
[t
]) break;
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
];
287 CHAR
*StrDup(CHAR
*s
)
289 size_t l
= strlen(s
) + 1;
290 CHAR
*d
= MikMod_malloc(l
);
295 static void ML_XFreeSample(SAMPLE
*s
)
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
)
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
);
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
);
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)
342 return (mf
=MikMod_malloc(sizeof(MODULE
)));
345 void Player_Free_internal(MODULE
*mf
)
348 Player_Exit_internal(mf
);
353 MIKMODAPI
void Player_Free(MODULE
*mf
)
356 Player_Free_internal(mf
);
360 static CHAR
* Player_LoadTitle_internal(MREADER
*reader
)
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
);
376 _mm_errno
= MMERR_NOT_A_MODULE
;
377 if(_mm_errorhandler
) _mm_errorhandler();
381 return l
->LoadTitle();
384 MIKMODAPI CHAR
* Player_LoadTitleFP(int fp
)
389 if(fp
&& (reader
=_mm_new_file_reader(fp
))) {
391 result
=Player_LoadTitle_internal(reader
);
393 _mm_delete_file_reader(reader
);
398 MIKMODAPI CHAR
* Player_LoadTitleMem(const char *buffer
,int len
)
403 if ((reader
=_mm_new_mem_reader(buffer
,len
)))
406 result
=Player_LoadTitle_internal(reader
);
408 _mm_delete_mem_reader(reader
);
415 MIKMODAPI CHAR
* Player_LoadTitleGeneric(MREADER
*reader
)
421 result
=Player_LoadTitle_internal(reader
);
427 MIKMODAPI CHAR
* Player_LoadTitle(CHAR
* filename
)
433 if((fp
=_mm_fopen(filename
,"rb"))) {
434 if((reader
=_mm_new_file_reader(fp
))) {
436 result
=Player_LoadTitle_internal(reader
);
438 _mm_delete_file_reader(reader
);
445 /* Loads a module given an reader */
446 MODULE
* Player_LoadGeneric_internal(MREADER
*reader
,int maxchan
,int curious
)
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
);
465 _mm_errno
= MMERR_NOT_A_MODULE
;
466 if(_mm_errorhandler
) _mm_errorhandler();
467 _mm_rewind(modreader
);_mm_iobase_revert(modreader
);
471 /* init unitrk routines */
473 if(_mm_errorhandler
) _mm_errorhandler();
474 _mm_rewind(modreader
);_mm_iobase_revert(modreader
);
478 /* init the module structure with vanilla settings */
479 memset(&of
,0,sizeof(MODULE
));
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
);
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
;
499 /* free loader and unitrk allocations */
500 if (l
->Cleanup
) l
->Cleanup();
505 if(_mm_errorhandler
) _mm_errorhandler();
506 _mm_rewind(modreader
);_mm_iobase_revert(modreader
);
510 if(!ML_LoadSamples()) {
512 if(_mm_errorhandler
) _mm_errorhandler();
513 _mm_rewind(modreader
);_mm_iobase_revert(modreader
);
517 if(!(mf
=ML_AllocUniMod())) {
519 _mm_rewind(modreader
);_mm_iobase_revert(modreader
);
520 if(_mm_errorhandler
) _mm_errorhandler();
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
));
534 if(!(mf
->flags
&UF_NNA
)&&(mf
->numchn
<maxchan
))
535 maxchan
= mf
->numchn
;
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
);
548 if(SL_LoadSamples()) {
549 _mm_iobase_revert(modreader
);
550 Player_Free_internal(mf
);
553 if(Player_Init(mf
)) {
554 _mm_iobase_revert(modreader
);
555 Player_Free_internal(mf
);
558 _mm_iobase_revert(modreader
);
562 MIKMODAPI MODULE
* Player_LoadGeneric(MREADER
*reader
,int maxchan
,int curious
)
568 result
=Player_LoadGeneric_internal(reader
,maxchan
,curious
);
575 MIKMODAPI MODULE
* Player_LoadMem(const char *buffer
,int len
,int maxchan
,int curious
)
580 if ((reader
=_mm_new_mem_reader(buffer
, len
))) {
581 result
=Player_LoadGeneric(reader
,maxchan
,curious
);
582 _mm_delete_mem_reader(reader
);
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
)
592 struct MREADER
* reader
=_mm_new_file_reader (fp
);
595 result
=Player_LoadGeneric(reader
,maxchan
,curious
);
596 _mm_delete_file_reader(reader
);
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
)
608 if((fp
=_mm_fopen(filename
,"rb"))) {
609 mf
=Player_LoadFP(fp
,maxchan
,curious
);