home *** CD-ROM | disk | FTP | other *** search
/ PC Loisirs 18 / cd.iso / sharewar / mikm202 / source / loaders / medload.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-18  |  10.7 KB  |  553 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include "mloader.h"
  6. #include "munitrk.h"
  7.  
  8.  
  9. typedef struct MMD0 {
  10.     ULONG   id;
  11.     ULONG   modlen;
  12.     ULONG   MMD0songP;              // struct MMD0song *song;
  13.     UWORD   psecnum;        /* for the player routine, MMD2 only */
  14.     UWORD   pseq;           /*  "   "   "   "    */
  15.     ULONG   MMD0BlockPP;    // struct MMD0Block **blockarr;
  16.     ULONG   reserved1;
  17.     ULONG   InstrHdrPP;             // struct InstrHdr **smplarr;
  18.     ULONG   reserved2;
  19.     ULONG   MMD0expP;               // struct MMD0exp *expdata;
  20.     ULONG   reserved3;
  21.     UWORD   pstate;                 // some data for the player routine */
  22.     UWORD   pblock;
  23.     UWORD   pline;
  24.     UWORD   pseqnum;
  25.     WORD    actplayline;
  26.     UBYTE   counter;
  27.     UBYTE   extra_songs;    /* number of songs - 1 */
  28. } MMD0;                                         /* length = 52 bytes */
  29.  
  30.  
  31. typedef struct MMD0sample {
  32.     UWORD rep,replen;       /* offs: 0(s), 2(s) */
  33.     UBYTE midich;           /* offs: 4(s) */
  34.     UBYTE midipreset;       /* offs: 5(s) */
  35.     UBYTE svol;                     /* offs: 6(s) */
  36.     BYTE strans;            /* offs: 7(s) */
  37. } MMD0sample;
  38.  
  39.  
  40. typedef struct MMD0song {
  41.     MMD0sample sample[63];  /* 63 * 8 bytes = 504 bytes */
  42.     UWORD   numblocks;      /* offs: 504 */
  43.     UWORD   songlen;        /* offs: 506 */
  44.     UBYTE   playseq[256];   /* offs: 508 */
  45.     UWORD   deftempo;       /* offs: 764 */
  46.     BYTE    playtransp;     /* offs: 766 */
  47.     UBYTE   flags;          /* offs: 767 */
  48.     UBYTE   flags2;         /* offs: 768 */
  49.     UBYTE   tempo2;         /* offs: 769 */
  50.     UBYTE   trkvol[16];     /* offs: 770 */
  51.     UBYTE   mastervol;      /* offs: 786 */
  52.     UBYTE   numsamples;     /* offs: 787 */
  53. } MMD0song;                             /* length = 788 bytes */
  54.  
  55.  
  56. typedef struct MMD0NOTE{
  57.     UBYTE a,b,c;
  58. } MMD0NOTE;
  59.  
  60.  
  61. typedef struct MMD1NOTE{
  62.     UBYTE a,b,c,d;
  63. } MMD1NOTE;
  64.  
  65.  
  66. typedef struct InstrHdr {
  67.         ULONG   length;
  68.         WORD    type;
  69.         /* Followed by actual data */
  70. } InstrHdr;
  71.  
  72. static MMD0 *mh;
  73. static MMD0song *ms;
  74. static ULONG *ba;
  75.  
  76. static MMD0NOTE *mmd0pat;
  77. static MMD1NOTE *mmd1pat;
  78.  
  79. #define d0note(row,col) mmd0pat[(row*(UWORD)of.numchn)+col]
  80. #define d1note(row,col) mmd1pat[(row*(UWORD)of.numchn)+col]
  81.  
  82. char MED_Version[]="MED";
  83.  
  84.  
  85. ULONG mlong(ULONG p)
  86. {
  87.     return( ((p&0xff000000)>>24) |
  88.             ((p&0x00ff0000)>>8)  |
  89.             ((p&0x0000ff00)<<8)  |
  90.             ((p&0x000000ff)<<24) );
  91. }
  92.  
  93.  
  94. UWORD mword(UWORD p)
  95. {
  96. #ifdef __BORLANDC__
  97.     asm{
  98.         mov ax,p
  99.         xchg al,ah
  100.     }
  101.     return _AX;
  102. #else
  103.     return( ((p&0xff00)>>8) |
  104.             ((p&0x00ff)<<8) );
  105. #endif
  106. }
  107.  
  108.  
  109. #define clong(a) a=mlong(a)
  110. #define cword(a) a=mword(a)
  111.  
  112.  
  113.  
  114.  
  115. BOOL MED_Test(void)
  116. {
  117.     char id[4];
  118.     rewind(modfp);
  119.     if(!fread(id,4,1,modfp)) return 0;
  120.     if(!memcmp(id,"MMD0",4)) return 1;
  121.     if(!memcmp(id,"MMD1",4)) return 1;
  122.     return 0;
  123. }
  124.  
  125.  
  126. BOOL MED_Init(void)
  127. {
  128.     mh=NULL;
  129.     ms=NULL;
  130.     ba=NULL;        // blockarr
  131.     mmd0pat=NULL;
  132.     mmd1pat=NULL;
  133.  
  134.     if(!(mh=(MMD0 *)MyCalloc(1,sizeof(MMD0)))) return 0;
  135.     if(!(ms=(MMD0song *)MyCalloc(1,sizeof(MMD0song)))) return 0;
  136.     return 1;
  137. }
  138.  
  139.  
  140. void MED_Cleanup(void)
  141. {
  142.     if(mh!=NULL) free(mh);
  143.     if(ms!=NULL) free(ms);
  144.     if(ba!=NULL) free(ba);
  145.  
  146.     if(mmd0pat!=NULL) free(mmd0pat);
  147.     if(mmd1pat!=NULL) free(mmd1pat);
  148. }
  149.  
  150.  
  151.  
  152. void MMD02Intel(MMD0 *p)
  153. {
  154.     clong(p->id);
  155.     clong(p->modlen);
  156.     clong(p->MMD0songP);            // struct MMD0song *song;
  157.     cword(p->psecnum);              // for the player routine, MMD2 only
  158.     cword(p->pseq);                 //  "   "   "   "
  159.     clong(p->MMD0BlockPP);          // struct MMD0Block **blockarr;
  160.     clong(p->reserved1);
  161.     clong(p->InstrHdrPP);           // struct InstrHdr **smplarr;
  162.     clong(p->reserved2);
  163.     clong(p->MMD0expP);                     // struct MMD0exp *expdata;
  164.     clong(p->reserved3);
  165.     cword(p->pstate);                       // some data for the player routine
  166.     cword(p->pblock);
  167.     cword(p->pline);
  168.     cword(p->pseqnum);
  169.     cword(p->actplayline);
  170. }
  171.  
  172.  
  173.  
  174. void MMD0song2Intel(MMD0song *p)
  175. {
  176.     int t;
  177.     for(t=0;t<63;t++){
  178.         cword(p->sample[t].rep);
  179.         cword(p->sample[t].replen);
  180.     }
  181.     cword(p->numblocks);      /* offs: 504 */
  182.     cword(p->songlen);        /* offs: 506 */
  183.     cword(p->deftempo);       /* offs: 764 */
  184. }
  185.  
  186.  
  187.  
  188. void EffectCvt(UBYTE eff,UBYTE dat)
  189. {
  190.     switch(eff){
  191.  
  192.         // 0x0 0x1 0x2 0x3 0x4      // PT effects
  193.  
  194.         case 0x5:       // PT vibrato with speed/depth nibbles swapped
  195.             UniPTEffect(0x4,(dat>>4) | ((dat&0xf)<<4) );
  196.             break;
  197.  
  198.         case 0x6:       // not used
  199.         case 0x7:       // not used
  200.         case 0x8:       // midi hold/decay
  201.             break;
  202.  
  203.         case 0x9:
  204.             if(dat<=0x20) UniPTEffect(0xf,dat);
  205.             break;
  206.  
  207.         // 0xa 0xb 0xc all PT effects
  208.  
  209.         case 0xd:       // same as PT volslide
  210.             UniPTEffect(0xa,dat);
  211.             break;
  212.  
  213.         case 0xe:       // synth jmp - midi
  214.             break;
  215.  
  216.         case 0xf:
  217.  
  218.             // F00 does patternbreak with med
  219.  
  220.             if(dat==0) UniPTEffect(0xd,0);
  221.             else if(dat<=0xa) UniPTEffect(0xf,dat);
  222.             else if(dat<0xf1) UniPTEffect(0xf,((UWORD)dat*125)/33);
  223.             else if(dat==0xff) UniPTEffect(0xc,0);  // stop note
  224.             break;
  225.  
  226.         default:        // all normal PT effects are handled here :)
  227.             UniPTEffect(eff,dat);
  228.             break;
  229.     }
  230. }
  231.  
  232.  
  233.  
  234. UBYTE *MED_Convert1(int col)
  235. {
  236.     int t;
  237.     UBYTE a,b,c,d,inst,note,eff,dat;
  238.     MMD1NOTE *n;
  239.  
  240.     UniReset();
  241.     for(t=0;t<64;t++){
  242.  
  243.         n=&d1note(t,col);
  244.  
  245.         a=n->a;
  246.         b=n->b;
  247.         c=n->c;
  248.         d=n->d;
  249.  
  250.         note=a&0x7f;
  251.         inst=b&0x3f;
  252.         eff=c&0xf;
  253.         dat=d;
  254.  
  255.         if(inst!=0){
  256.             UniInstrument(inst-1);
  257.         }
  258.  
  259.         if(note!=0){
  260.             UniNote(note+23);
  261.         }
  262.  
  263.         EffectCvt(eff,dat);
  264.  
  265.         UniNewline();
  266.     }
  267.     return UniDup();
  268. }
  269.  
  270.  
  271.  
  272. UBYTE *MED_Convert0(int col)
  273. {
  274.     int t;
  275.     UBYTE a,b,c,inst,note,eff,dat;
  276.     MMD0NOTE *n;
  277.  
  278.     UniReset();
  279.     for(t=0;t<64;t++){
  280.  
  281.         n=&d0note(t,col);
  282.  
  283.         a=n->a;
  284.         b=n->b;
  285.         c=n->c;
  286.  
  287.         note=a&0x3f;
  288.         a>>=6;
  289.         a=((a&1)<<1)|(a>>1);
  290.         inst=(b>>4)|(a<<4);
  291.         eff=b&0xf;
  292.         dat=c;
  293.  
  294.         if(inst!=0){
  295.             UniInstrument(inst-1);
  296.         }
  297.  
  298.         if(note!=0){
  299.             UniNote(note+35);
  300.         }
  301.  
  302.         EffectCvt(eff,dat);
  303.         UniNewline();
  304.     }
  305.     return UniDup();
  306. }
  307.  
  308.  
  309.  
  310. BOOL LoadMMD0Patterns(void)
  311. {
  312.     int t,row,col;
  313.     UWORD numtracks,numlines,maxlines=0,track=0;
  314.  
  315.     // first, scan patterns to see how many channels are used
  316.  
  317.     for(t=0;t<of.numpat;t++){
  318.  
  319.         fseek(modfp,mlong(ba[t]),SEEK_SET);
  320.  
  321.         numtracks=fgetc(modfp);
  322.         numlines=fgetc(modfp);
  323.  
  324.         if(numtracks>of.numchn) of.numchn=numtracks;
  325.         if(numlines>maxlines) maxlines=numlines;
  326.     }
  327.  
  328.     of.numtrk=of.numpat*of.numchn;
  329.  
  330.     if(!AllocTracks()) return 0;
  331.     if(!AllocPatterns()) return 0;
  332.  
  333.     if(!(mmd0pat=(MMD0NOTE *)MyCalloc(of.numchn*(maxlines+1),sizeof(MMD0NOTE)))) return 0;
  334.  
  335.     /* second read: no more mr. nice guy,
  336.        really read and convert patterns */
  337.  
  338.     for(t=0;t<of.numpat;t++){
  339.  
  340.         fseek(modfp,mlong(ba[t]),SEEK_SET);
  341.  
  342.         numtracks=fgetc(modfp);
  343.         numlines=fgetc(modfp);
  344.  
  345.         of.pattrows[t]=numlines+1;
  346.  
  347.         memset(mmd0pat,0,of.numchn*maxlines*sizeof(MMD0NOTE));
  348.  
  349.         for(row=0;row<=numlines;row++){
  350.             fread(&d0note(row,0),sizeof(MMD0NOTE),numtracks,modfp);
  351.         }
  352.  
  353.         for(col=0;col<of.numchn;col++){
  354.             of.tracks[track]=MED_Convert0(col);
  355.             track++;
  356.         }
  357.     }
  358.  
  359.     return 1;
  360. }
  361.  
  362.  
  363.  
  364. BOOL LoadMMD1Patterns(void)
  365. {
  366.     int t,row,col;
  367.     UWORD numtracks,numlines,maxlines=0,track=0;
  368.  
  369.     // first, scan patterns to see how many channels are used
  370.  
  371.     for(t=0;t<of.numpat;t++){
  372.  
  373.         fseek(modfp,mlong(ba[t]),SEEK_SET);
  374.  
  375.         fread(&numtracks,sizeof(UWORD),1,modfp); cword(numtracks);
  376.         fread(&numlines,sizeof(UWORD),1,modfp); cword(numlines);
  377.         fseek(modfp,sizeof(ULONG),SEEK_CUR);
  378.  
  379.         if(numtracks>of.numchn) of.numchn=numtracks;
  380.         if(numlines>maxlines) maxlines=numlines;
  381.  
  382.         if(numlines>255){
  383.             puts("Can't load patterns > 256 rows");
  384.             return 0;
  385.         }
  386.     }
  387.  
  388.     of.numtrk=of.numpat*of.numchn;
  389.  
  390.     if(!AllocTracks()) return 0;
  391.     if(!AllocPatterns()) return 0;
  392.  
  393.     if(!(mmd1pat=MyCalloc(of.numchn*(maxlines+1),sizeof(MMD1NOTE)))) return 0;
  394.  
  395.     /* second read: no more mr. nice guy,
  396.        really read and convert patterns */
  397.  
  398.     for(t=0;t<of.numpat;t++){
  399.  
  400.         fseek(modfp,mlong(ba[t]),SEEK_SET);
  401.  
  402.         fread(&numtracks,sizeof(UWORD),1,modfp); cword(numtracks);
  403.         fread(&numlines,sizeof(UWORD),1,modfp); cword(numlines);
  404.         fseek(modfp,sizeof(ULONG),SEEK_CUR);
  405.  
  406.         of.pattrows[t]=numlines;
  407.  
  408.         memset(mmd1pat,0,of.numchn*maxlines*sizeof(MMD1NOTE));
  409.  
  410.         for(row=0;row<=numlines;row++){
  411.             fread(&d1note(row,0),sizeof(MMD1NOTE),numtracks,modfp);
  412.         }
  413.  
  414.         for(col=0;col<of.numchn;col++){
  415.             of.tracks[track]=MED_Convert1(col);
  416.             track++;
  417.         }
  418.     }
  419.  
  420.     return 1;
  421. }
  422.  
  423.  
  424.  
  425. BOOL MED_Load(void)
  426. {
  427.     int t;
  428.     ULONG sa[64];
  429.     InstrHdr s;
  430.     INSTRUMENT *d;
  431.     SAMPLE *q;
  432.  
  433.     rewind(modfp);
  434.  
  435.     // try to read module header
  436.  
  437.     if(!fread(mh,sizeof(MMD0),1,modfp)){
  438.         myerr=ERROR_LOADING_HEADER;
  439.         return 0;
  440.     }
  441.  
  442.     MMD02Intel(mh);
  443.  
  444.     // Seek to MMD0song struct
  445.  
  446.     fseek(modfp,mh->MMD0songP,SEEK_SET);
  447.  
  448.     if(!fread(ms,sizeof(MMD0song),1,modfp)){
  449.         myerr=ERROR_LOADING_HEADER;
  450.         return 0;
  451.     }
  452.  
  453.     MMD0song2Intel(ms);
  454.  
  455.     // seek to samplepointer array
  456.  
  457.     fseek(modfp,mh->InstrHdrPP,SEEK_SET);
  458.  
  459.     // read sample array
  460.  
  461.     if(fread(sa,sizeof(ULONG),ms->numsamples,modfp)<ms->numsamples){
  462.         myerr=ERROR_LOADING_HEADER;
  463.         return 0;
  464.     }
  465.  
  466.     // alloc blockpointer array
  467.  
  468.     if(!(ba=MyCalloc(ms->numblocks,sizeof(ULONG)))) return 0;
  469.  
  470.     // seek to blockpointer array
  471.  
  472.     fseek(modfp,mh->MMD0BlockPP,SEEK_SET);
  473.  
  474.     // read blockpointer array
  475.  
  476.     if(fread(ba,sizeof(ULONG),ms->numblocks,modfp)<ms->numblocks){
  477.         myerr=ERROR_LOADING_HEADER;
  478.         return 0;
  479.     }
  480.  
  481.     // copy song positions
  482.  
  483.     for(t=0;t<ms->songlen;t++){
  484.         of.positions[t]=ms->playseq[t];
  485.     }
  486.  
  487.     of.initspeed=6;
  488.     of.inittempo=((UWORD)ms->deftempo*125)/33;
  489.     of.modtype=strdup("MED");
  490.     of.numchn=0;                                    // will be counted later
  491.     of.numpat=ms->numblocks;
  492.     of.numpos=ms->songlen;
  493.     of.numins=ms->numsamples;
  494.  
  495.     if(!AllocInstruments()) return 0;
  496.  
  497.     d=of.instruments;
  498.  
  499.     for(t=0;t<of.numins;t++){
  500.  
  501.         d->numsmp=1;
  502.         if(!AllocSamples(d)) return 0;
  503.         q=d->samples;
  504.  
  505.         fseek(modfp,mlong(sa[t]),SEEK_SET);
  506.  
  507.         if(!fread(&s,sizeof(InstrHdr),1,modfp)){
  508.             myerr=ERROR_LOADING_SAMPLEINFO;
  509.             return 0;
  510.         }
  511.  
  512.         d->insname=NULL;
  513.         q->length=mlong(s.length);
  514.         q->seekpos=ftell(modfp);
  515.         q->loopstart=ms->sample[t].rep<<1;
  516.         q->loopend=q->loopstart+(ms->sample[t].replen<<1);
  517.         q->flags=SF_SIGNED;
  518.         q->c2spd=8363;
  519.         q->volume=64;
  520.         if(ms->sample[t].replen>1) q->flags|=SF_LOOP;
  521.  
  522.         // don't load sample if length>='MMD0' hah.. hah.. very funny.. NOT!
  523.  
  524.         if(q->length>=0x4d4d4430) q->length=0;
  525.  
  526.         d++;
  527.     }
  528.  
  529.     if(mh->id==0x4D4D4430){
  530.         if(!LoadMMD0Patterns()) return 0;
  531.     }
  532.     else if(mh->id==0x4D4D4431){
  533.         if(!LoadMMD1Patterns()) return 0;
  534.     }
  535.     else{
  536.         puts("Can't load MMD2 yet");
  537.         return 0;
  538.     }
  539.  
  540.     return 1;
  541. }
  542.  
  543.  
  544. LOADER medload={
  545.     NULL,
  546.     "MED",
  547.     "MED loader v0.1",
  548.     MED_Init,
  549.     MED_Test,
  550.     MED_Load,
  551.     MED_Cleanup
  552. };
  553.