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 /*==============================================================================
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;
53 static MUNPACKER unpackers[] = {
61 const UWORD finetune[16] = {
62 8363,8413,8463,8529,8581,8651,8723,8757,
63 7895,7941,7985,8046,8107,8169,8232,8280
66 MIKMODAPI CHAR* MikMod_InfoLoader(void)
73 /* compute size of buffer */
74 for(l = firstloader; l; l = l->next)
75 len += 1 + (l->next ? 1 : 0) + strlen(l->version);
78 if((list=(CHAR*)MikMod_malloc(len*sizeof(CHAR))) != NULL) {
79 CHAR *list_end = list;
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" : "");
90 void _mm_registerloader(MLOADER* ldr)
92 MLOADER *cruise=firstloader;
95 while(cruise->next) cruise = cruise->next;
101 MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
103 /* if we try to register an invalid loader, or an already registered loader,
104 ignore this attempt */
105 if ((!ldr)||(ldr->next))
109 _mm_registerloader(ldr);
113 BOOL ReadComment(UWORD len)
118 if(!(of.comment=(CHAR*)MikMod_malloc(len+1))) return 0;
119 _mm_read_UBYTES(of.comment,len,modreader);
121 /* translate IT linefeeds */
123 if(of.comment[i]=='\r') of.comment[i]='\n';
125 of.comment[len]=0; /* just in case */
128 MikMod_free(of.comment);
134 BOOL ReadLinedComment(UWORD len,UWORD linelen)
136 CHAR *tempcomment,*line,*storage;
137 UWORD total=0,t,lines;
140 lines = (len + linelen - 1) / linelen;
142 if(!(tempcomment=(CHAR*)MikMod_malloc(len+1))) return 0;
143 if(!(storage=(CHAR*)MikMod_malloc(linelen+1))) {
144 MikMod_free(tempcomment);
147 memset(tempcomment, ' ', len);
148 _mm_read_UBYTES(tempcomment,len,modreader);
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;
158 if(!(of.comment=(CHAR*)MikMod_malloc(total+1))) {
159 MikMod_free(storage);
160 MikMod_free(tempcomment);
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");
170 MikMod_free(storage);
171 MikMod_free(tempcomment);
177 BOOL AllocPositions(int total)
180 _mm_errno=MMERR_NOT_A_MODULE;
183 if(!(of.positions=(UWORD*)MikMod_calloc(total,sizeof(UWORD)))) return 0;
187 BOOL AllocPatterns(void)
191 if((!of.numpat)||(!of.numchn)) {
192 _mm_errno=MMERR_NOT_A_MODULE;
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;
199 for(t=0;t<=of.numpat;t++) {
201 for(s=0;s<of.numchn;s++)
202 of.patterns[(t*of.numchn)+s]=tracks++;
208 BOOL AllocTracks(void)
211 _mm_errno=MMERR_NOT_A_MODULE;
214 if(!(of.tracks=(UBYTE **)MikMod_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
218 BOOL AllocInstruments(void)
223 _mm_errno=MMERR_NOT_A_MODULE;
226 if(!(of.instruments=(INSTRUMENT*)MikMod_calloc(of.numins,sizeof(INSTRUMENT))))
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;
235 of.instruments[t].globvol = 64;
240 BOOL AllocSamples(void)
245 _mm_errno=MMERR_NOT_A_MODULE;
248 if(!(of.samples=(SAMPLE*)MikMod_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
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;
259 static BOOL ML_LoadSamples(void)
264 for(u=of.numsmp,s=of.samples;u;u--,s++)
265 if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);
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)
277 /* Scan for last printing char in buffer [includes high ascii up to 254] */
279 if(s[len-1]>0x20) break;
283 /* Scan forward for possible NULL character */
285 for(t=0;t<len;t++) if (!s[t]) break;
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];
298 static void ML_XFreeSample(SAMPLE *s)
301 MD_SampleUnload(s->handle);
303 /* moved samplename freeing to our caller ML_FreeEx(),
304 * because we are called conditionally. */
307 static void ML_XFreeInstrument(INSTRUMENT *i)
309 MikMod_free(i->insname);
312 static void ML_FreeEx(MODULE *mf)
316 MikMod_free(mf->songname);
317 MikMod_free(mf->comment);
319 MikMod_free(mf->modtype);
320 MikMod_free(mf->positions);
321 MikMod_free(mf->patterns);
322 MikMod_free(mf->pattrows);
325 for(t=0;t<mf->numtrk;t++)
326 MikMod_free(mf->tracks[t]);
327 MikMod_free(mf->tracks);
329 if(mf->instruments) {
330 for(t=0;t<mf->numins;t++)
331 ML_XFreeInstrument(&mf->instruments[t]);
332 MikMod_free(mf->instruments);
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]);
339 MikMod_free(mf->samples);
341 memset(mf,0,sizeof(MODULE));
342 if(mf!=&of) MikMod_free(mf);
345 static MODULE *ML_AllocUniMod(void)
347 return (MODULE *) MikMod_malloc(sizeof(MODULE));
350 static BOOL ML_TryUnpack(MREADER *reader,void **out,long *outlen)
357 for(i=0;unpackers[i]!=NULL;++i) {
359 if(unpackers[i](reader,out,outlen)) return 1;
364 static void Player_Free_internal(MODULE *mf)
367 Player_Exit_internal(mf);
372 MIKMODAPI void Player_Free(MODULE *mf)
375 Player_Free_internal(mf);
379 static CHAR* Player_LoadTitle_internal(MREADER *reader)
389 _mm_iobase_setcur(modreader);
391 if(ML_TryUnpack(modreader,&unpk,&newlen)) {
392 if(!(modreader=_mm_new_mem_reader(unpk,newlen))) {
399 /* Try to find a loader that recognizes the module */
400 for(l=firstloader;l;l=l->next) {
401 _mm_rewind(modreader);
406 title = l->LoadTitle();
409 _mm_errno = MMERR_NOT_A_MODULE;
410 if(_mm_errorhandler) _mm_errorhandler();
414 if (modreader!=reader) {
415 _mm_delete_mem_reader(modreader);
422 MIKMODAPI CHAR* Player_LoadTitleFP(FILE *fp)
427 if(fp && (reader=_mm_new_file_reader(fp)) != NULL) {
429 result=Player_LoadTitle_internal(reader);
431 _mm_delete_file_reader(reader);
436 MIKMODAPI CHAR* Player_LoadTitleMem(const char *buffer,int len)
441 if (!buffer || len <= 0) return NULL;
442 if ((reader=_mm_new_mem_reader(buffer,len)) != NULL)
445 result=Player_LoadTitle_internal(reader);
447 _mm_delete_mem_reader(reader);
453 MIKMODAPI CHAR* Player_LoadTitleGeneric(MREADER *reader)
459 result=Player_LoadTitle_internal(reader);
465 MIKMODAPI CHAR* Player_LoadTitle(const CHAR* filename)
471 if((fp=_mm_fopen(filename,"rb")) != NULL) {
472 if((reader=_mm_new_file_reader(fp)) != NULL) {
474 result=Player_LoadTitle_internal(reader);
476 _mm_delete_file_reader(reader);
483 /* Loads a module given an reader */
484 static MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious)
496 _mm_iobase_setcur(modreader);
498 if(ML_TryUnpack(modreader,&unpk,&newlen)) {
499 if(!(modreader=_mm_new_mem_reader(unpk,newlen))) {
506 /* Try to find a loader that recognizes the module */
507 for(l=firstloader;l;l=l->next) {
508 _mm_rewind(modreader);
513 _mm_errno = MMERR_NOT_A_MODULE;
514 if(modreader!=reader) {
515 _mm_delete_mem_reader(modreader);
519 if(_mm_errorhandler) _mm_errorhandler();
520 _mm_rewind(modreader);
521 _mm_iobase_revert(modreader);
525 /* init unitrk routines */
527 if(modreader!=reader) {
528 _mm_delete_mem_reader(modreader);
532 if(_mm_errorhandler) _mm_errorhandler();
533 _mm_rewind(modreader);
534 _mm_iobase_revert(modreader);
538 /* init the module structure with vanilla settings */
539 memset(&of,0,sizeof(MODULE));
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;
546 /* init module loader and load the header / patterns */
547 if (!l->Init || l->Init()) {
548 _mm_rewind(modreader);
549 ok = l->Load(curious);
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;
559 /* free loader and unitrk allocations */
560 if (l->Cleanup) l->Cleanup();
563 if(ok) ok = ML_LoadSamples();
564 if(ok) ok = ((mf=ML_AllocUniMod()) != NULL);
567 if(modreader!=reader) {
568 _mm_delete_mem_reader(modreader);
572 if(_mm_errorhandler) _mm_errorhandler();
573 _mm_rewind(modreader);
574 _mm_iobase_revert(modreader);
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;
584 /* Copy the static MODULE contents into the dynamic MODULE struct. */
585 memcpy(mf,&of,sizeof(MODULE));
588 if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
589 maxchan = mf->numchn;
591 if((mf->numvoices)&&(mf->numvoices<maxchan))
592 maxchan = mf->numvoices;
594 if(maxchan<mf->numchn) mf->flags |= UF_NNA;
596 ok = !MikMod_SetNumVoices_internal(maxchan,-1);
599 if(ok) ok = !SL_LoadSamples();
600 if(ok) ok = !Player_Init(mf);
602 if(modreader!=reader) {
603 _mm_delete_mem_reader(modreader);
607 _mm_iobase_revert(modreader);
610 Player_Free_internal(mf);
616 MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)
622 result=Player_LoadGeneric_internal(reader,maxchan,curious);
629 MIKMODAPI MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,BOOL curious)
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);
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)
647 struct MREADER* reader;
649 if (fp && (reader=_mm_new_file_reader(fp)) != NULL) {
650 result=Player_LoadGeneric(reader,maxchan,curious);
651 _mm_delete_file_reader(reader);
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)
663 if((fp=_mm_fopen(filename,"rb")) != NULL) {
664 mf=Player_LoadFP(fp,maxchan,curious);