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

  1. // ScreamTracker 2 Loader - Version 1.oOo Release 2
  2. // A Coding Nightmare by Rao and Air Richter of HaRDCoDE
  3. // You can now play all of those wonderful old C.C. Catch STM's!
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <ctype.h>
  8. #include "mloader.h"
  9. #include "munitrk.h"
  10.  
  11.  
  12. typedef struct STMNOTE{
  13.    UBYTE note,insvol,volcmd,cmdinf;
  14. } STMNOTE;
  15.  
  16.  
  17. // Raw STM sampleinfo struct:
  18.  
  19. typedef struct STMSAMPLE{
  20.    char  filename[12]; // Can't have long comments - just filename comments :)
  21.    char  unused;       // 0x00
  22.    UBYTE instdisk;     // Instrument disk
  23.    UWORD reserved;     // ISA in memory when in ST 2
  24.    UWORD length;       // Sample length
  25.    UWORD loopbeg;      // Loop start point
  26.    UWORD loopend;      // Loop end point
  27.    UBYTE volume;       // Volume
  28.    UBYTE reserved2;    // More reserved crap
  29.    UWORD c2spd;        // Good old c2spd
  30.    UBYTE reserved3[4]; // Yet more of PSi's reserved crap
  31.    UWORD isa;          // Internal Segment Address ->
  32.                        //    contrary to the tech specs, this is NOT actually
  33.                        //    written to the stm file.
  34. } STMSAMPLE;
  35.  
  36. // Raw STM header struct:
  37.  
  38. typedef struct STMHEADER{
  39.    char songname[20];
  40.    char trackername[8];   // !SCREAM! for ST 2.xx
  41.    char unused;           // 0x1A
  42.    char filetype;         // 1=song, 2=module (only 2 is supported, of course) :)
  43.    char ver_major;        // Like 2
  44.    char ver_minor;        // "ditto"
  45.    UBYTE inittempo;       // initspeed= stm inittempo>>4
  46.    UBYTE  numpat;         // number of patterns
  47.    UBYTE   globalvol;     // <- WoW! a RiGHT TRiANGLE =8*)
  48.    UBYTE    reserved[13]; // More of PSi's internal crap
  49.    STMSAMPLE sample[31];  // STM sample data
  50.    UBYTE patorder[128];   // Docs say 64 - actually 128
  51. } STMHEADER;
  52.  
  53.  
  54. static STMNOTE *stmbuf;
  55. static STMHEADER *mh;
  56.  
  57. char STM_Version[]="Screamtracker 2";
  58.  
  59.  
  60.  
  61. BOOL STM_Test(void)
  62. {
  63.    char str[9],filetype;
  64.  
  65.    fseek(modfp,21,SEEK_SET);
  66.    fread(str,1,9,modfp);
  67.    fread(&filetype,1,1,modfp);
  68.    if(!memcmp(str,"!SCREAM!",8) || (filetype!=2)) // STM Module = filetype 2
  69.       return 0;
  70.    return 1;
  71. }
  72.  
  73.  
  74.  
  75. BOOL STM_Init(void)
  76. {
  77.     stmbuf=NULL;
  78.     if(!(mh=MyCalloc(1,sizeof(STMHEADER)))) return 0;
  79.     return 1;
  80. }
  81.  
  82. void STM_Cleanup(void)
  83. {
  84.     if(mh!=NULL) free(mh);
  85.     if(stmbuf!=NULL) free(stmbuf);
  86. }
  87.  
  88.  
  89.  
  90. void STM_ConvertNote(STMNOTE *n)
  91. {
  92.     UBYTE note,ins,vol,cmd,inf;
  93.  
  94.     /* extract the various information from the 4 bytes that
  95.        make up a single note */
  96.  
  97.         note=n->note;
  98.         ins=n->insvol>>3;
  99.         vol=(n->insvol&7)+(n->volcmd>>1);
  100.         cmd=n->volcmd&15;
  101.         inf=n->cmdinf;
  102.  
  103.         if(ins!=0 && ins<32){
  104.             UniInstrument(ins-1);
  105.         }
  106.  
  107.       // special values of [BYTE0] are handled here ->
  108.       // we have no idea if these strange values will ever be encountered
  109.       // but it appears as though stms sound correct.
  110.       if(note==254 || note==252) UniPTEffect(0xc,0); // <- note off command (???)
  111.          else
  112.       // if note < 251, then all three bytes are stored in the file
  113.       if(note<251) UniNote((((note>>4)+2)*12)+(note&0xf));      // <- normal note and up the octave by two
  114.  
  115.         if(vol<65){
  116.             UniPTEffect(0xc,vol);
  117.         }
  118.  
  119.         if(cmd!=255){
  120.             switch(cmd){
  121.  
  122.                 case 1:                 // Axx set speed to xx and add 0x1c to fix StoOoPiD STM 2.x
  123.                     UniPTEffect(0xf,inf>>4);
  124.                     break;
  125.  
  126.                 case 2:                 // Bxx position jump
  127.                     UniPTEffect(0xb,inf);
  128.                     break;
  129.  
  130.                 case 3:                 // Cxx patternbreak to row xx
  131.                     UniPTEffect(0xd,inf);
  132.                     break;
  133.  
  134.                 case 4:                 // Dxy volumeslide
  135.                     UniWrite(UNI_S3MEFFECTD);
  136.                     UniWrite(inf);
  137.                     break;
  138.  
  139.                 case 5:                 // Exy toneslide down
  140.                     UniWrite(UNI_S3MEFFECTE);
  141.                     UniWrite(inf);
  142.                     break;
  143.  
  144.                 case 6:                 // Fxy toneslide up
  145.                     UniWrite(UNI_S3MEFFECTF);
  146.                     UniWrite(inf);
  147.                     break;
  148.  
  149.                 case 7:                 // Gxx Tone portamento,speed xx
  150.                     UniPTEffect(0x3,inf);
  151.                     break;
  152.  
  153.                 case 8:                 // Hxy vibrato
  154.                     UniPTEffect(0x4,inf);
  155.                     break;
  156.  
  157.                 case 9:                 // Ixy tremor, ontime x, offtime y
  158.                     UniWrite(UNI_S3MEFFECTI);
  159.                     UniWrite(inf);
  160.                     break;
  161.  
  162.                 case 0xa:               // Jxy arpeggio
  163.                     UniPTEffect(0x0,inf);
  164.                     break;
  165.  
  166.                 case 0xb:               // Kxy Dual command H00 & Dxy
  167.                     UniPTEffect(0x4,0);
  168.                     UniWrite(UNI_S3MEFFECTD);
  169.                     UniWrite(inf);
  170.                     break;
  171.  
  172.                 case 0xc:               // Lxy Dual command G00 & Dxy
  173.                     UniPTEffect(0x3,0);
  174.                     UniWrite(UNI_S3MEFFECTD);
  175.                     UniWrite(inf);
  176.                     break;
  177.  
  178.         // Support all these above, since ST2 can LOAD these values
  179.         // but can actually only play up to J - and J is only
  180.         // half-way implemented in ST2
  181.  
  182.                 case 0x18:      // Xxx amiga command 8xx - What the hell, support panning. :)
  183.                     UniPTEffect(0x8,inf);
  184.                     break;
  185.             }
  186.         }
  187.  
  188. }
  189.  
  190.  
  191. UBYTE *STM_ConvertTrack(STMNOTE *n)
  192. {
  193.     int t;
  194.  
  195.     UniReset();
  196.     for(t=0;t<64;t++)
  197.     {       STM_ConvertNote(n);
  198.         UniNewline();
  199.         n+=of.numchn;
  200.     }
  201.     return UniDup();
  202. }
  203.  
  204.  
  205.  
  206.  
  207. BOOL STM_LoadPatterns(void)
  208. {
  209.     int t,s,tracks=0;
  210.  
  211.     if(!AllocPatterns()) return 0;
  212.     if(!AllocTracks()) return 0;
  213.  
  214.     /* Allocate temporary buffer for loading
  215.        and converting the patterns */
  216.  
  217.     if(!(stmbuf=MyCalloc(64U*of.numchn,sizeof(STMNOTE)))) return 0;
  218.  
  219.     for(t=0;t<of.numpat;t++){
  220.  
  221.         if(fread(stmbuf,64U*of.numchn*sizeof(STMNOTE),1,modfp)!=1){
  222.             myerr=ERROR_LOADING_PATTERN;
  223.             return 0;
  224.         }
  225.  
  226.  
  227.         for(s=0;s<of.numchn;s++){
  228.             if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
  229.         }
  230.     }
  231.  
  232.     return 1;
  233. }
  234.  
  235.  
  236.  
  237. BOOL STM_Load(void)
  238. {
  239.     int t;
  240.     ULONG MikMod_ISA; // We MUST generate our own ISA - NOT stored in the stm
  241.     INSTRUMENT *d;
  242.     SAMPLE *q;
  243.  
  244.     rewind(modfp);
  245.  
  246.     // try to read stm header
  247.  
  248.     if(!fread(mh,sizeof(STMHEADER),1,modfp)){
  249.         myerr=ERROR_LOADING_HEADER;
  250.         return 0;
  251.     }
  252.     /* set module variables */
  253.  
  254.     of.modtype=strdup(STM_Version);
  255.     of.songname=DupStr(mh->songname,20); // make a cstr of songname
  256.  
  257. //      MikMak: This line is not neccesary, DupStr handles that:
  258. //  of.songname[20]=NULL; // Make sure 20 is a NULL - Could have a songname of 20 chars
  259.  
  260.     of.numpat=mh->numpat;
  261.  
  262.     of.initspeed=6; // Always this
  263.  
  264.     // STM 2.x tempo has always been fucked... The default of 96
  265.     // is actually 124, so we add 1ch to the initial value of 60h
  266.  
  267.     // MikMak: No it's not.. STM tempo is UNI speed << 4
  268.  
  269.     of.inittempo=125;               // mh->inittempo+0x1c;
  270.     of.initspeed=mh->inittempo>>4;
  271.     of.numchn=4; // get number of channels
  272.  
  273.     t=0;
  274.     while(mh->patorder[t]!=99){ // 99 terminates the patorder list
  275.         of.positions[t]=mh->patorder[t];
  276.         t++;
  277.     }
  278.     of.numpos=--t;
  279.     of.numtrk=of.numpat*of.numchn;
  280.  
  281.     // Finally, init the sampleinfo structures
  282.  
  283.     of.numins=31; // always this
  284.  
  285.     if(!AllocInstruments()) return 0;
  286.     if(!STM_LoadPatterns()) return 0;
  287.  
  288.     d=of.instruments;
  289.  
  290.     MikMod_ISA=ftell(modfp);
  291.     MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;
  292.  
  293.  
  294.     for(t=0;t<of.numins;t++){
  295.  
  296.         d->numsmp=1;
  297.         if(!AllocSamples(d)) return 0;
  298.         q=d->samples;
  299.  
  300.         // load sample info
  301.  
  302.         d->insname=DupStr(mh->sample[t].filename,12);
  303.         q->c2spd=mh->sample[t].c2spd;
  304.         q->volume=mh->sample[t].volume;
  305.         q->length=mh->sample[t].length;
  306.         if (!mh->sample[t].volume || q->length==1 ) q->length = 0; // if vol = 0 or length = 1, then no sample
  307.         q->loopstart=mh->sample[t].loopbeg;
  308.         q->loopend=mh->sample[t].loopend;
  309.         q->seekpos=MikMod_ISA;
  310.  
  311.         MikMod_ISA+=q->length;
  312.  
  313.         MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;
  314.  
  315.       // Once again, contrary to the STM specs, all the sample data is
  316.       // actually SIGNED! Sheesh
  317.  
  318.         q->flags=SF_SIGNED;
  319.  
  320.         if(mh->sample[t].loopend>0 && mh->sample[t].loopend!=0xffff) q->flags|=SF_LOOP;
  321.  
  322.         /* fix replen if repend>length */
  323.  
  324.         if(q->loopend>q->length) q->loopend=q->length;
  325.  
  326.         d++;
  327.     }
  328.  
  329.     return 1;
  330. }
  331.  
  332.  
  333. LOADER stmload={
  334.     NULL,
  335.     "STM",
  336.     "STM Loader - V 1.1 - A Coding Nightmare by Rao and Air Richter of HaRDCoDE",
  337.     STM_Init,
  338.     STM_Test,
  339.     STM_Load,
  340.     STM_Cleanup
  341. };
  342.