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 / loaders / load_m15.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  9.7 KB  |  430 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: load_m15.c,v 1.15 1998/12/07 06:00:15 miod Exp $
  22.  
  23.   15 instrument MOD loader
  24.   Also supports Ultimate Sound Tracker (old M15 format)
  25.  
  26. ==============================================================================*/
  27.  
  28. #ifdef HAVE_CONFIG_H
  29. #include "config.h"
  30. #endif
  31.  
  32. #include <string.h>
  33.  
  34. #include <mikmod_internals.h>
  35.  
  36. /*========== Module Structure */
  37.  
  38. typedef struct MSAMPINFO {
  39.     CHAR  samplename[23];    /* 22 in module, 23 in memory */
  40.     UWORD length;
  41.     UBYTE finetune;
  42.     UBYTE volume;
  43.     UWORD reppos;
  44.     UWORD replen;
  45. } MSAMPINFO;
  46.  
  47. typedef struct MODULEHEADER {
  48.     CHAR      songname[21];        /* the songname.., 20 in module, 21 in memory */
  49.     MSAMPINFO samples[15];        /* all sampleinfo */
  50.     UBYTE     songlength;        /* number of patterns used */
  51.     UBYTE     magic1;           /* should be 127 */
  52.     UBYTE     positions[128];    /* which pattern to play at pos */
  53. } MODULEHEADER;
  54.  
  55. typedef struct MODNOTE {
  56.     UBYTE a,b,c,d;
  57. } MODNOTE;
  58.  
  59. /*========== Loader variables */
  60.  
  61. static MODULEHEADER *mh = NULL;
  62. static MODNOTE *patbuf = NULL;
  63. static BOOL ust_loader = 0;        /* if TRUE, load as an ust module. */
  64.  
  65. /* known file formats which can confuse the loader */
  66. #define REJECT 2
  67. static char *signatures[REJECT]={
  68.     "CAKEWALK",    /* cakewalk midi files */
  69.     "SZDD"        /* Microsoft compressed files */
  70. };
  71.  
  72. /*========== Loader code */
  73.  
  74. BOOL LoadModuleHeader(MODULEHEADER *mh)
  75. {
  76.     int t;
  77.  
  78.     _mm_read_string(mh->songname,20,modfp);
  79.     mh->songname[20]=0;    /* just in case */
  80.  
  81.     for(t=0;t<15;t++) {
  82.         MSAMPINFO *s=&mh->samples[t];
  83.  
  84.         _mm_read_string(s->samplename,22,modfp);
  85.         s->samplename[22]=0;    /* just in case */
  86.         s->length   =_mm_read_M_UWORD(modfp);
  87.         s->finetune =_mm_read_UBYTE(modfp);
  88.         s->volume   =_mm_read_UBYTE(modfp);
  89.         s->reppos   =_mm_read_M_UWORD(modfp);
  90.         s->replen   =_mm_read_M_UWORD(modfp);
  91.     }
  92.  
  93.     mh->songlength  =_mm_read_UBYTE(modfp);
  94.     mh->magic1      =_mm_read_UBYTE(modfp);    /* should be 127 */
  95.     _mm_read_UBYTES(mh->positions,128,modfp);
  96.  
  97.     return(!feof(modfp));
  98. }
  99.  
  100. /* Checks the patterns in the modfile for UST / 15-inst indications.
  101.    For example, if an effect 3xx is found, it is assumed that the song 
  102.    is 15-inst.  If a 1xx effect has dat greater than 0x20, it is UST.   
  103.  
  104.    Returns:  0 indecisive; 1 = UST; 2 = 15-inst                               */
  105. int CheckPatternType(int numpat)
  106. {
  107.     int t;
  108.     UBYTE eff, dat;
  109.  
  110.     for(t=0;t<numpat*(64U*4);t++) {
  111.         /* Load the pattern into the temp buffer and convert it */
  112.         _mm_read_UBYTE(modfp);_mm_read_UBYTE(modfp);
  113.         eff = _mm_read_UBYTE(modfp);
  114.         dat = _mm_read_UBYTE(modfp);
  115.  
  116.         switch(eff) {
  117.             case 1:
  118.                 if(dat>0x1f) return 1;
  119.                 if(dat<0x3)  return 2;
  120.                 break;
  121.             case 2:
  122.                 if(dat>0x1f) return 1;
  123.                 return 2;
  124.             case 3:
  125.                 if (dat) return 2;
  126.                 break;
  127.             default:
  128.                 return 2;
  129.         }
  130.     }
  131.     return 0;
  132. }
  133.  
  134. BOOL M15_Test(void)
  135. {
  136.     int t, numpat;
  137.     MODULEHEADER mh;
  138.  
  139.     ust_loader = 0;
  140.     if(!LoadModuleHeader(&mh)) return 0;
  141.  
  142.     /* reject other file types */
  143.     for(t=0;t<REJECT;t++)
  144.         if(!memcmp(mh.songname,signatures[t],strlen(signatures[t]))) return 0;
  145.  
  146.     if(mh.magic1>127) return 0;
  147.     if((!mh.songlength)||(mh.songlength>mh.magic1)) return 0;
  148.  
  149.     for(t=0;t<15;t++) {
  150.         /* all finetunes should be zero */
  151.         if(mh.samples[t].finetune) return 0;
  152.  
  153.         /* all volumes should be <= 64 */
  154.         if(mh.samples[t].volume>64) return 0;
  155.  
  156.         /* all instrument names should begin with s, st-, or a number */
  157.         if(mh.samples[t].samplename[0]=='s') {
  158.             if((memcmp(mh.samples[t].samplename,"st-",3)) &&
  159.                (memcmp(mh.samples[t].samplename,"ST-",3)) &&
  160.                (*mh.samples[t].samplename))
  161.                 ust_loader = 1;
  162.         } else
  163.           if((mh.samples[t].samplename[0]<'0')||
  164.              (mh.samples[t].samplename[0]>'9'))
  165.                 ust_loader = 1;
  166.  
  167.         if(mh.samples[t].length>4999) {
  168.             ust_loader = 0;
  169.             if(mh.samples[t].length>32768) return 0;
  170.         }
  171.  
  172.         if(!ust_loader) return 1; 
  173.  
  174.         if((mh.samples[t].reppos+mh.samples[t].replen)>(mh.samples[t].length+10)) {
  175.             ust_loader = 1;
  176.             return 1;
  177.         }
  178.     }
  179.  
  180.     for(numpat=0,t=0;t<mh.songlength;t++) 
  181.         if(mh.positions[t]>numpat)
  182.             numpat = mh.positions[t];
  183.     numpat++;
  184.     switch(CheckPatternType(numpat)) {
  185.         case 0:   /* indecisive, so check more clues... */
  186.             break;
  187.         case 1:
  188.             ust_loader = 1;
  189.             break;
  190.         case 2:
  191.             ust_loader = 0;
  192.             break;
  193.     }
  194.     return 1;
  195. }
  196.  
  197. BOOL M15_Init(void)
  198. {
  199.     if(!(mh=(MODULEHEADER*)_mm_malloc(sizeof(MODULEHEADER)))) return 0;
  200.     return 1;
  201. }
  202.  
  203. void M15_Cleanup(void)
  204. {
  205.     if(mh) free(mh);
  206.     if(patbuf) free(patbuf);
  207.  
  208.     mh = NULL;
  209.     patbuf = NULL;
  210. }
  211.  
  212. /*
  213. Old (amiga) noteinfo:
  214.  
  215.  _____byte 1_____   byte2_    _____byte 3_____   byte4_
  216. /                \ /      \  /                \ /      \
  217. 0000          0000-00000000  0000          0000-00000000
  218.  
  219. Upper four    12 bits for    Lower four    Effect command.
  220. bits of sam-  note period.   bits of sam-
  221. ple number.                  ple number.
  222. */
  223.  
  224. void M15_ConvertNote(MODNOTE* n)
  225. {
  226.     UBYTE instrument,effect,effdat,note;
  227.     UWORD period;
  228.     UBYTE lastnote=0;
  229.  
  230.     /* decode the 4 bytes that make up a single note */
  231.     instrument = n->c>>4;
  232.     period     = (((UWORD)n->a&0xf)<<8)+n->b;
  233.     effect     = n->c&0xf;
  234.     effdat     = n->d;
  235.  
  236.     /* Convert the period to a note number */
  237.     note=0;
  238.     if(period) {
  239.         for(note=0;note<7*OCTAVE;note++)
  240.             if(period>=npertab[note]) break;
  241.         if(note==7*OCTAVE) note=0;
  242.         else note++;
  243.     }
  244.  
  245.     if(instrument) {
  246.         UniInstrument(instrument-1);
  247.         if(!note) note=lastnote;
  248.     }
  249.     if(note) {
  250.         UniNote(note+2*OCTAVE-1);
  251.         lastnote=note;
  252.     }
  253.  
  254.     /* Convert pattern jump from Dec to Hex */
  255.     if(effect == 0xd)
  256.         effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf);
  257.  
  258.     if(ust_loader) {
  259.         switch(effect) {
  260.             case 0:
  261.             case 3:
  262.                 break;
  263.             case 1:
  264.                 UniPTEffect(0,effdat);
  265.                 break;
  266.             case 2:  
  267.                 if(effdat&0xf) UniPTEffect(1,effdat&0xf);
  268.                 if(effdat>>2)  UniPTEffect(2,effdat>>2);
  269.                 break;
  270.             default:
  271.                 UniPTEffect(effect,effdat);
  272.                 break;
  273.         }
  274.     } else {
  275.         /* finetune conversion to Lxx */
  276.         if(effect==5)
  277.             S3MIT_ProcessCmd(0xc,effdat,1);
  278.         else
  279.             UniPTEffect(effect,effdat);
  280.     }
  281. }
  282.  
  283. UBYTE *M15_ConvertTrack(MODNOTE* n)
  284. {
  285.     int t;
  286.  
  287.     UniReset();
  288.     for(t=0;t<64;t++) {
  289.         M15_ConvertNote(n);
  290.         UniNewline();
  291.         n+=4;
  292.     }
  293.     return UniDup();
  294. }
  295.  
  296. /* Loads all patterns of a modfile and converts them into the 3 byte format. */
  297. BOOL M15_LoadPatterns(void)
  298. {
  299.     int t,s,tracks=0;
  300.  
  301.     if(!AllocPatterns()) return 0;
  302.     if(!AllocTracks()) return 0;
  303.  
  304.     /* Allocate temporary buffer for loading and converting the patterns */
  305.     if(!(patbuf=(MODNOTE*)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0;
  306.  
  307.     for(t=0;t<of.numpat;t++) {
  308.         /* Load the pattern into the temp buffer and convert it */
  309.         for(s=0;s<(64U*4);s++) {
  310.             patbuf[s].a=_mm_read_UBYTE(modfp);
  311.             patbuf[s].b=_mm_read_UBYTE(modfp);
  312.             patbuf[s].c=_mm_read_UBYTE(modfp);
  313.             patbuf[s].d=_mm_read_UBYTE(modfp);
  314.         }
  315.  
  316.         for(s=0;s<4;s++)
  317.             if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
  318.     }
  319.     return 1;
  320. }
  321.  
  322. BOOL M15_Load(BOOL curious)
  323. {
  324.     int t,scan;
  325.     SAMPLE *q;
  326.     MSAMPINFO *s;
  327.  
  328.     /* try to read module header */
  329.     if(!LoadModuleHeader(mh)) {
  330.         _mm_errno = MMERR_LOADING_HEADER;
  331.         return 0;
  332.     }
  333.  
  334.     if(ust_loader)
  335.         of.modtype = strdup("Ultimate Soundtracker");
  336.     else
  337.         of.modtype = strdup("Soundtracker");
  338.  
  339.     /* set module variables */
  340.     of.initspeed = 6;
  341.     of.inittempo = 125;
  342.     of.numchn    = 4;                
  343.     of.songname  = DupStr(mh->songname,21);
  344.     of.numpos    = mh->songlength;
  345.     of.reppos    = 0;
  346.  
  347.     /* Count the number of patterns */
  348.     of.numpat = 0;
  349.     for(t=0;t<of.numpos;t++)
  350.         if(mh->positions[t]>of.numpat)
  351.             of.numpat=mh->positions[t];
  352.     /* since some old modules embed extra patterns, we have to check the
  353.        whole list to get the samples' file offsets right - however we can find
  354.        garbage here, so check carefully */
  355.     scan=1;
  356.     for(t=of.numpos;t<128;t++)
  357.         if(mh->positions[t]>=0x80) scan=0;
  358.     if (scan)
  359.         for(t=of.numpos;t<128;t++) {
  360.             if(mh->positions[t]>of.numpat)
  361.                 of.numpat=mh->positions[t];
  362.             if((curious)&&(mh->positions[t])) of.numpos=t+1;
  363.         }
  364.     of.numpat++;
  365.     of.numtrk = of.numpat*of.numchn;
  366.  
  367.     if(!AllocPositions(of.numpos)) return 0;
  368.     for(t=0;t<of.numpos;t++)
  369.         of.positions[t]=mh->positions[t];
  370.  
  371.     /* Finally, init the sampleinfo structures */
  372.     of.numins=of.numsmp=15;
  373.     if(!AllocSamples()) return 0;
  374.  
  375.     s = mh->samples;
  376.     q = of.samples;
  377.  
  378.     for(t=0;t<of.numins;t++) {
  379.         /* convert the samplename */
  380.         q->samplename = DupStr(s->samplename,23);
  381.  
  382.         /* init the sampleinfo variables and convert the size pointers */
  383.         q->speed     = finetune[s->finetune&0xf];
  384.         q->volume    = s->volume;
  385.         if(ust_loader)
  386.             q->loopstart = s->reppos;
  387.         else
  388.             q->loopstart = s->reppos<<1;
  389.         q->loopend   = q->loopstart+(s->replen<<1);
  390.         q->length    = s->length<<1;
  391.  
  392.         q->flags = SF_SIGNED | SF_UST_LOOP;
  393.         if(s->replen>1) q->flags |= SF_LOOP;
  394.  
  395.         /* fix replen if repend>length */
  396.         if(q->loopend>q->length) q->loopend = q->length;
  397.  
  398.         s++;
  399.         q++;
  400.     }
  401.  
  402.     if(!M15_LoadPatterns()) return 0;
  403.     ust_loader = 0;
  404.  
  405.     return 1;
  406. }
  407.  
  408. CHAR *M15_LoadTitle(void)
  409. {
  410.     CHAR s[21];
  411.  
  412.     fseek(modfp,0,SEEK_SET);
  413.     if(!fread(s,20,1,modfp)) return NULL;
  414.     s[20]=0;    /* just in case */
  415.     return(DupStr(s,21));
  416. }
  417.  
  418. /*========== Loader information */
  419.  
  420. MLOADER load_m15={
  421.     NULL,
  422.     "15-instrument module",
  423.     "MOD-15 loader v1.0",
  424.     M15_Init,
  425.     M15_Test,
  426.     M15_Load,
  427.     M15_Cleanup,
  428.     M15_LoadTitle
  429. };
  430.