home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / linux / mikmod-3.000 / mikmod-3 / mikmod-3.1.2 / playercode / mloader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  9.4 KB  |  447 lines

  1. /*    MikMod sound library
  2.     (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
  3.  
  4.     This library is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU Library General Public License as
  6.     published by the Free Software Foundation; either version 2 of
  7.     the License, or (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU Library General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU Library General Public
  15.     License along with this library; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*==============================================================================
  20.  
  21.   $Id: mloader.c,v 1.20 1998/12/07 06:00:44 miod Exp $
  22.  
  23.   These routines are used to access the available module loaders
  24.  
  25. ==============================================================================*/
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30.  
  31. #include <mikmod_internals.h>
  32.  
  33. #include <string.h>
  34.  
  35.         FILE *modfp;
  36.         MODULE of;
  37.  
  38. static    MLOADER *firstloader=NULL;
  39.  
  40. UWORD finetune[16]={
  41.     8363,8413,8463,8529,8581,8651,8723,8757,
  42.     7895,7941,7985,8046,8107,8169,8232,8280
  43. };
  44.  
  45. CHAR* MikMod_InfoLoader(void)
  46. {
  47.     int t,len=0;
  48.     MLOADER *l;
  49.     CHAR *list=NULL;
  50.  
  51.     /* compute size of buffer */
  52.     for(l=firstloader;l;l=l->next) len+=4+(l->next?1:0)+strlen(l->version);
  53.  
  54.     if(len)
  55.         if((list=_mm_malloc(len*sizeof(CHAR)))) {
  56.             list[0]=0;
  57.             /* list all registered module loders */
  58.             for(t=1,l=firstloader;l;l=l->next,t++)
  59.                 sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",list,t,l->version);
  60.         }
  61.     return list;
  62. }
  63.  
  64. void MikMod_RegisterLoader(MLOADER* ldr)
  65. {
  66.     MLOADER *cruise=firstloader;
  67.  
  68.     /* if we try to register an invalid loader, or an already registered loader,
  69.        ignore this attempt */
  70.     if ((!ldr)||(ldr->next))
  71.         return;
  72.  
  73.     if(cruise) {
  74.         while(cruise->next) cruise = cruise->next;
  75.         cruise->next=ldr;
  76.     } else
  77.         firstloader=ldr; 
  78. }
  79.  
  80. BOOL ReadComment(UWORD len)
  81. {
  82.     if(len) {
  83.         if(!(of.comment=(CHAR*)_mm_malloc(len+1))) return 0;
  84.         fread(of.comment,len,1,modfp);
  85.         of.comment[len]=0;    /* just in case */
  86.     }
  87.     return 1;
  88. }
  89.  
  90. BOOL ReadLinedComment(UWORD lines,UWORD linelen)
  91. {
  92.     CHAR *tempcomment,*line,*storage;
  93.     UWORD total,t,i,len=lines*linelen;
  94.  
  95.     if (lines) {
  96.         if(!(tempcomment=(CHAR*)_mm_malloc(len))) return 0;
  97.         if(!(storage=(CHAR*)_mm_malloc(linelen+1))) {
  98.             free(tempcomment);
  99.             return 0;
  100.         }
  101.         fread(tempcomment,len,1,modfp);
  102.  
  103.         /* compute message length */
  104.         for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {
  105.             for(i=0;i<linelen;i++) if (!line[i]) break;
  106.             total+=1+i;
  107.         }
  108.  
  109.         if(!(of.comment=(CHAR*)_mm_malloc(total+1))) {
  110.             free(tempcomment);
  111.             return 0;
  112.         }
  113.  
  114.         /* convert message */
  115.         for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {
  116.             for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;
  117.             storage[i]=0; /* if (i==linelen) */
  118.             strcat(of.comment,storage);strcat(of.comment,"\r");
  119.         }
  120.         free(storage);
  121.     }
  122.     return 1;
  123. }
  124.  
  125. BOOL AllocPositions(int total)
  126. {
  127.     if(!total) {
  128.         _mm_errno=MMERR_NOT_A_MODULE;
  129.         return 0;
  130.     }
  131.     if(!(of.positions=_mm_calloc(total,sizeof(UWORD)))) return 0;
  132.     return 1;
  133. }
  134.  
  135. BOOL AllocPatterns(void)
  136. {
  137.     int s,t,tracks = 0;
  138.  
  139.     if((!of.numpat)||(!of.numchn)) {
  140.         _mm_errno=MMERR_NOT_A_MODULE;
  141.         return 0;
  142.     }
  143.     /* Allocate track sequencing array */
  144.     if(!(of.patterns=(UWORD*)_mm_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
  145.     if(!(of.pattrows=(UWORD*)_mm_calloc(of.numpat+1,sizeof(UWORD)))) return 0;
  146.  
  147.     for(t=0;t<=of.numpat;t++) {
  148.         of.pattrows[t]=64;
  149.         for(s=0;s<of.numchn;s++)
  150.         of.patterns[(t*of.numchn)+s]=tracks++;
  151.     }
  152.  
  153.     return 1;
  154. }
  155.  
  156. BOOL AllocTracks(void)
  157. {
  158.     if(!of.numtrk) {
  159.         _mm_errno=MMERR_NOT_A_MODULE;
  160.         return 0;
  161.     }
  162.     if(!(of.tracks=(UBYTE **)_mm_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
  163.     return 1;
  164. }
  165.  
  166. BOOL AllocInstruments(void)
  167. {
  168.     int t,n;
  169.     
  170.     if(!of.numins) {
  171.         _mm_errno=MMERR_NOT_A_MODULE;
  172.         return 0;
  173.     }
  174.     if(!(of.instruments=(INSTRUMENT*)_mm_calloc(of.numins,sizeof(INSTRUMENT))))
  175.         return 0;
  176.  
  177.     for(t=0;t<of.numins;t++) {
  178.         for(n=0;n<INSTNOTES;n++) { 
  179.             /* Init note / sample lookup table */
  180.             of.instruments[t].samplenote[n]   = n;
  181.             of.instruments[t].samplenumber[n] = t;
  182.         }   
  183.         of.instruments[t].globvol = 64;
  184.     }
  185.     return 1;
  186. }
  187.  
  188. BOOL AllocSamples(void)
  189. {
  190.     UWORD u;
  191.  
  192.     if(!of.numsmp) {
  193.         _mm_errno=MMERR_NOT_A_MODULE;
  194.         return 0;
  195.     }
  196.     if(!(of.samples=(SAMPLE*)_mm_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
  197.  
  198.     for(u=0;u<of.numsmp;u++) {
  199.         of.samples[u].panning = 128; /* center */
  200.         of.samples[u].handle  = -1;
  201.         of.samples[u].globvol = 64;
  202.         of.samples[u].volume  = 64;
  203.     }
  204.     return 1;
  205. }
  206.  
  207. static BOOL ML_LoadSamples(void)
  208. {
  209.     SAMPLE *s;
  210.     int u;
  211.  
  212.     for(u=of.numsmp,s=of.samples;u;u--,s++)
  213.     if(s->length) SL_RegisterSample(s,MD_MUSIC,modfp);
  214.  
  215.     return 1;
  216. }
  217.  
  218. /* Creates a CSTR out of a character buffer of 'len' bytes, but strips any
  219.    terminating non-printing characters like 0, spaces etc.                    */
  220. CHAR *DupStr(CHAR* s,UWORD len)
  221. {
  222.     UWORD t;
  223.     CHAR *d=NULL;
  224.  
  225.     /* Scan for last printing char in buffer [includes high ascii up to 254] */
  226.     while(len) {
  227.         if(s[len-1]>0x20) break;
  228.         len--;
  229.     }
  230.     /* Scan forward for possible NULL character */
  231. /*    for(t=0;t<len;t++) if (!s[t]) break;
  232.     if (t<len) len=t;
  233. */
  234.     /* When the buffer wasn't completely empty, allocate a cstring and copy the
  235.        buffer into that string, except for any control-chars */
  236.     if((d=(CHAR*)_mm_malloc(len+1))) {
  237.         for(t=0;t<len;t++) d[t]=(s[t]<32)?' ':s[t];
  238.         d[len]=0;
  239.     }
  240.     return d;
  241. }
  242.  
  243. static void ML_XFreeSample(SAMPLE *s)
  244. {
  245.     if(s->handle>=0)
  246.         MD_SampleUnload(s->handle);
  247.     if(s->samplename) free(s->samplename);
  248. }
  249.  
  250. static void ML_XFreeInstrument(INSTRUMENT *i)
  251. {
  252.     if(i->insname) free(i->insname);
  253. }
  254.  
  255. static void ML_FreeEx(MODULE *mf)
  256. {
  257.     UWORD t;
  258.  
  259.     if(mf->songname) free(mf->songname);
  260.     if(mf->comment)  free(mf->comment);
  261.  
  262.     if(mf->modtype)   free(mf->modtype);
  263.     if(mf->positions) free(mf->positions);
  264.     if(mf->patterns)  free(mf->patterns);
  265.     if(mf->pattrows)  free(mf->pattrows);
  266.  
  267.     if(mf->tracks) {
  268.         for(t=0;t<mf->numtrk;t++)
  269.             if(mf->tracks[t]) free(mf->tracks[t]);
  270.         free(mf->tracks);
  271.     }
  272.     if(mf->instruments) {
  273.         for(t=0;t<mf->numins;t++)
  274.             ML_XFreeInstrument(&mf->instruments[t]);
  275.         free(mf->instruments);
  276.     }
  277.     if(mf->samples) {
  278.         for(t=0;t<mf->numsmp;t++)
  279.             if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
  280.         free(mf->samples);
  281.     }
  282.     memset(mf,0,sizeof(MODULE));
  283.     if(mf!=&of) free(mf);
  284. }
  285.  
  286. static MODULE *ML_AllocUniMod(void)
  287. {
  288.     MODULE *mf;
  289.  
  290.     return (mf=_mm_malloc(sizeof(MODULE)));
  291. }
  292.  
  293. void Player_Free(MODULE *mf)
  294. {
  295.     if(mf) {
  296.         Player_Exit(mf);
  297.         ML_FreeEx(mf);
  298.     }
  299. }
  300.  
  301. CHAR* Player_LoadTitle(CHAR* filename)
  302. {
  303.     MLOADER *l;
  304.     CHAR *retval;
  305.     FILE *fp;
  306.  
  307.     if(!(fp=_mm_fopen(filename,"rb"))) return NULL;
  308.  
  309.     _mm_errno = 0;
  310.     _mm_critical = 0;
  311.     _mm_iobase_setcur(modfp);
  312.  
  313.     /* Try to find a loader that recognizes the module */
  314.     for(l=firstloader;l;l=l->next) {
  315.         _mm_rewind(modfp);
  316.         if(l->Test()) break;
  317.     }
  318.  
  319.     if(!l) {
  320.         _mm_errno = MMERR_NOT_A_MODULE;
  321.         if(_mm_errorhandler) _mm_errorhandler();
  322.         _mm_iobase_revert();
  323.         return NULL;
  324.     }
  325.  
  326.     retval=l->LoadTitle();
  327.     fclose(fp);
  328.     return(retval);
  329. }
  330.  
  331. /* Loads a module given a file pointer.
  332.    File is loaded from the current file seek position. */
  333. MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious)
  334. {
  335.     int t;
  336.     MLOADER *l;
  337.     BOOL ok;
  338.     MODULE *mf;
  339.  
  340.     modfp = fp;
  341.     _mm_errno = 0;
  342.     _mm_critical = 0;
  343.     _mm_iobase_setcur(modfp);
  344.  
  345.     /* Try to find a loader that recognizes the module */
  346.     for(l=firstloader;l;l=l->next) {
  347.         _mm_rewind(modfp);
  348.         if(l->Test()) break;
  349.     }
  350.  
  351.     if(!l) {
  352.         _mm_errno = MMERR_NOT_A_MODULE;
  353.         if(_mm_errorhandler) _mm_errorhandler();
  354.         _mm_iobase_revert();
  355.         return NULL;
  356.     }
  357.  
  358.     /* init unitrk routines */
  359.     if(!UniInit()) {
  360.         if(_mm_errorhandler) _mm_errorhandler();
  361.         return NULL;
  362.     }
  363.  
  364.     /* load the song using the song's loader variable */
  365.     memset(&of,0,sizeof(MODULE));
  366.     of.initvolume = 128;
  367.  
  368.     /* init panning array */
  369.     for(t=0; t<64; t++) of.panning[t] = ((t+1)&2) ? 255 : 0;
  370.     for(t=0; t<64; t++) of.chanvol[t] = 64;
  371.  
  372.     /* init module loader and load the header / patterns */
  373.     if(l->Init()) {
  374.         _mm_rewind(modfp);
  375.         ok = l->Load(curious);
  376.     } else
  377.         ok = 0;
  378.  
  379.     /* free loader and unitrk allocations */
  380.     l->Cleanup();
  381.     UniCleanup();
  382.  
  383.     if(!ok) {
  384.         ML_FreeEx(&of);
  385.         if(_mm_errorhandler) _mm_errorhandler();
  386.         _mm_iobase_revert();
  387.         return NULL;
  388.     }
  389.  
  390.     if(!ML_LoadSamples()) {
  391.         ML_FreeEx(&of);
  392.         if(_mm_errorhandler) _mm_errorhandler();
  393.         _mm_iobase_revert();
  394.         return NULL;
  395.     }
  396.  
  397.     if(!(mf=ML_AllocUniMod())) {
  398.         ML_FreeEx(&of);
  399.         _mm_iobase_revert();
  400.         if(_mm_errorhandler) _mm_errorhandler();
  401.         return NULL;
  402.     }
  403.  
  404.     /* Copy the static MODULE contents into the dynamic MODULE struct. */
  405.     memcpy(mf,&of,sizeof(MODULE));
  406.     _mm_iobase_revert();
  407.  
  408.     if(maxchan>0) {
  409.         if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
  410.             maxchan = mf->numchn;
  411.         else
  412.           if((mf->numvoices)&&(mf->numvoices<maxchan))
  413.             maxchan = mf->numvoices;
  414.  
  415.         if(maxchan<mf->numchn) mf->flags |= UF_NNA;
  416.  
  417.         if(MikMod_SetNumVoices(maxchan,-1)) {
  418.             Player_Free(mf);
  419.             return NULL;
  420.         }
  421.     }
  422.     if(SL_LoadSamples()) {
  423.         Player_Free(mf);
  424.         return NULL;
  425.     }
  426.     return mf;
  427. }
  428.  
  429. /* Open a module via it's filename.  The loader will initialize the specified
  430.    song-player 'player'. */
  431. MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious)
  432. {
  433.     FILE *fp;
  434.     MODULE *mf;
  435.  
  436.     if(!(fp=_mm_fopen(filename,"rb"))) return NULL;
  437.  
  438.     if((mf=Player_LoadFP(fp, maxchan,curious))) 
  439.         if(Player_Init(mf)) {
  440.             Player_Free(mf);
  441.             mf=NULL;
  442.         }
  443.  
  444.     fclose(fp);
  445.     return mf;
  446. }
  447.