home *** CD-ROM | disk | FTP | other *** search
- // ScreamTracker 2 Loader - Version 1.oOo Release 2
- // A Coding Nightmare by Rao and Air Richter of HaRDCoDE
- // You can now play all of those wonderful old C.C. Catch STM's!
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include "mloader.h"
- #include "munitrk.h"
-
-
- typedef struct STMNOTE{
- UBYTE note,insvol,volcmd,cmdinf;
- } STMNOTE;
-
-
- // Raw STM sampleinfo struct:
-
- typedef struct STMSAMPLE{
- char filename[12]; // Can't have long comments - just filename comments :)
- char unused; // 0x00
- UBYTE instdisk; // Instrument disk
- UWORD reserved; // ISA in memory when in ST 2
- UWORD length; // Sample length
- UWORD loopbeg; // Loop start point
- UWORD loopend; // Loop end point
- UBYTE volume; // Volume
- UBYTE reserved2; // More reserved crap
- UWORD c2spd; // Good old c2spd
- UBYTE reserved3[4]; // Yet more of PSi's reserved crap
- UWORD isa; // Internal Segment Address ->
- // contrary to the tech specs, this is NOT actually
- // written to the stm file.
- } STMSAMPLE;
-
- // Raw STM header struct:
-
- typedef struct STMHEADER{
- char songname[20];
- char trackername[8]; // !SCREAM! for ST 2.xx
- char unused; // 0x1A
- char filetype; // 1=song, 2=module (only 2 is supported, of course) :)
- char ver_major; // Like 2
- char ver_minor; // "ditto"
- UBYTE inittempo; // initspeed= stm inittempo>>4
- UBYTE numpat; // number of patterns
- UBYTE globalvol; // <- WoW! a RiGHT TRiANGLE =8*)
- UBYTE reserved[13]; // More of PSi's internal crap
- STMSAMPLE sample[31]; // STM sample data
- UBYTE patorder[128]; // Docs say 64 - actually 128
- } STMHEADER;
-
-
- static STMNOTE *stmbuf;
- static STMHEADER *mh;
-
- char STM_Version[]="Screamtracker 2";
-
-
-
- BOOL STM_Test(void)
- {
- char str[9],filetype;
-
- fseek(modfp,21,SEEK_SET);
- fread(str,1,9,modfp);
- fread(&filetype,1,1,modfp);
- if(!memcmp(str,"!SCREAM!",8) || (filetype!=2)) // STM Module = filetype 2
- return 0;
- return 1;
- }
-
-
-
- BOOL STM_Init(void)
- {
- stmbuf=NULL;
- if(!(mh=MyCalloc(1,sizeof(STMHEADER)))) return 0;
- return 1;
- }
-
- void STM_Cleanup(void)
- {
- if(mh!=NULL) free(mh);
- if(stmbuf!=NULL) free(stmbuf);
- }
-
-
-
- void STM_ConvertNote(STMNOTE *n)
- {
- UBYTE note,ins,vol,cmd,inf;
-
- /* extract the various information from the 4 bytes that
- make up a single note */
-
- note=n->note;
- ins=n->insvol>>3;
- vol=(n->insvol&7)+(n->volcmd>>1);
- cmd=n->volcmd&15;
- inf=n->cmdinf;
-
- if(ins!=0 && ins<32){
- UniInstrument(ins-1);
- }
-
- // special values of [BYTE0] are handled here ->
- // we have no idea if these strange values will ever be encountered
- // but it appears as though stms sound correct.
- if(note==254 || note==252) UniPTEffect(0xc,0); // <- note off command (???)
- else
- // if note < 251, then all three bytes are stored in the file
- if(note<251) UniNote((((note>>4)+2)*12)+(note&0xf)); // <- normal note and up the octave by two
-
- if(vol<65){
- UniPTEffect(0xc,vol);
- }
-
- if(cmd!=255){
- switch(cmd){
-
- case 1: // Axx set speed to xx and add 0x1c to fix StoOoPiD STM 2.x
- UniPTEffect(0xf,inf>>4);
- break;
-
- case 2: // Bxx position jump
- UniPTEffect(0xb,inf);
- break;
-
- case 3: // Cxx patternbreak to row xx
- UniPTEffect(0xd,inf);
- break;
-
- case 4: // Dxy volumeslide
- UniWrite(UNI_S3MEFFECTD);
- UniWrite(inf);
- break;
-
- case 5: // Exy toneslide down
- UniWrite(UNI_S3MEFFECTE);
- UniWrite(inf);
- break;
-
- case 6: // Fxy toneslide up
- UniWrite(UNI_S3MEFFECTF);
- UniWrite(inf);
- break;
-
- case 7: // Gxx Tone portamento,speed xx
- UniPTEffect(0x3,inf);
- break;
-
- case 8: // Hxy vibrato
- UniPTEffect(0x4,inf);
- break;
-
- case 9: // Ixy tremor, ontime x, offtime y
- UniWrite(UNI_S3MEFFECTI);
- UniWrite(inf);
- break;
-
- case 0xa: // Jxy arpeggio
- UniPTEffect(0x0,inf);
- break;
-
- case 0xb: // Kxy Dual command H00 & Dxy
- UniPTEffect(0x4,0);
- UniWrite(UNI_S3MEFFECTD);
- UniWrite(inf);
- break;
-
- case 0xc: // Lxy Dual command G00 & Dxy
- UniPTEffect(0x3,0);
- UniWrite(UNI_S3MEFFECTD);
- UniWrite(inf);
- break;
-
- // Support all these above, since ST2 can LOAD these values
- // but can actually only play up to J - and J is only
- // half-way implemented in ST2
-
- case 0x18: // Xxx amiga command 8xx - What the hell, support panning. :)
- UniPTEffect(0x8,inf);
- break;
- }
- }
-
- }
-
-
- UBYTE *STM_ConvertTrack(STMNOTE *n)
- {
- int t;
-
- UniReset();
- for(t=0;t<64;t++)
- { STM_ConvertNote(n);
- UniNewline();
- n+=of.numchn;
- }
- return UniDup();
- }
-
-
-
-
- BOOL STM_LoadPatterns(void)
- {
- int t,s,tracks=0;
-
- if(!AllocPatterns()) return 0;
- if(!AllocTracks()) return 0;
-
- /* Allocate temporary buffer for loading
- and converting the patterns */
-
- if(!(stmbuf=MyCalloc(64U*of.numchn,sizeof(STMNOTE)))) return 0;
-
- for(t=0;t<of.numpat;t++){
-
- if(fread(stmbuf,64U*of.numchn*sizeof(STMNOTE),1,modfp)!=1){
- myerr=ERROR_LOADING_PATTERN;
- return 0;
- }
-
-
- for(s=0;s<of.numchn;s++){
- if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
- }
- }
-
- return 1;
- }
-
-
-
- BOOL STM_Load(void)
- {
- int t;
- ULONG MikMod_ISA; // We MUST generate our own ISA - NOT stored in the stm
- INSTRUMENT *d;
- SAMPLE *q;
-
- rewind(modfp);
-
- // try to read stm header
-
- if(!fread(mh,sizeof(STMHEADER),1,modfp)){
- myerr=ERROR_LOADING_HEADER;
- return 0;
- }
- /* set module variables */
-
- of.modtype=strdup(STM_Version);
- of.songname=DupStr(mh->songname,20); // make a cstr of songname
-
- // MikMak: This line is not neccesary, DupStr handles that:
- // of.songname[20]=NULL; // Make sure 20 is a NULL - Could have a songname of 20 chars
-
- of.numpat=mh->numpat;
-
- of.initspeed=6; // Always this
-
- // STM 2.x tempo has always been fucked... The default of 96
- // is actually 124, so we add 1ch to the initial value of 60h
-
- // MikMak: No it's not.. STM tempo is UNI speed << 4
-
- of.inittempo=125; // mh->inittempo+0x1c;
- of.initspeed=mh->inittempo>>4;
- of.numchn=4; // get number of channels
-
- t=0;
- while(mh->patorder[t]!=99){ // 99 terminates the patorder list
- of.positions[t]=mh->patorder[t];
- t++;
- }
- of.numpos=--t;
- of.numtrk=of.numpat*of.numchn;
-
- // Finally, init the sampleinfo structures
-
- of.numins=31; // always this
-
- if(!AllocInstruments()) return 0;
- if(!STM_LoadPatterns()) return 0;
-
- d=of.instruments;
-
- MikMod_ISA=ftell(modfp);
- MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;
-
-
- for(t=0;t<of.numins;t++){
-
- d->numsmp=1;
- if(!AllocSamples(d)) return 0;
- q=d->samples;
-
- // load sample info
-
- d->insname=DupStr(mh->sample[t].filename,12);
- q->c2spd=mh->sample[t].c2spd;
- q->volume=mh->sample[t].volume;
- q->length=mh->sample[t].length;
- if (!mh->sample[t].volume || q->length==1 ) q->length = 0; // if vol = 0 or length = 1, then no sample
- q->loopstart=mh->sample[t].loopbeg;
- q->loopend=mh->sample[t].loopend;
- q->seekpos=MikMod_ISA;
-
- MikMod_ISA+=q->length;
-
- MikMod_ISA=(MikMod_ISA+15)&0xfffffff0;
-
- // Once again, contrary to the STM specs, all the sample data is
- // actually SIGNED! Sheesh
-
- q->flags=SF_SIGNED;
-
- if(mh->sample[t].loopend>0 && mh->sample[t].loopend!=0xffff) q->flags|=SF_LOOP;
-
- /* fix replen if repend>length */
-
- if(q->loopend>q->length) q->loopend=q->length;
-
- d++;
- }
-
- return 1;
- }
-
-
- LOADER stmload={
- NULL,
- "STM",
- "STM Loader - V 1.1 - A Coding Nightmare by Rao and Air Richter of HaRDCoDE",
- STM_Init,
- STM_Test,
- STM_Load,
- STM_Cleanup
- };
-