home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Games Machine 25
/
GNOME_DEMO.iso
/
amiga
/
music
/
mikmod.lzx
/
mikmod
/
load_s3m.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-05
|
11KB
|
571 lines
/*
Name:
LOAD_S3M.C
Description:
Screamtracker (S3M) module loader
Portability:
All systems - all compilers (hopefully)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "mikmod.h"
/**************************************************************************
**************************************************************************/
typedef struct S3MNOTE{
UBYTE note,ins,vol,cmd,inf;
} S3MNOTE;
typedef S3MNOTE S3MTRACK[64];
/* Raw S3M header struct: */
typedef struct S3MHEADER{
char songname[28];
char t1a;
char type;
char unused1[2];
UWORD ordnum;
UWORD insnum;
UWORD patnum;
UWORD flags;
UWORD tracker;
UWORD fileformat;
char scrm[4];
UBYTE mastervol;
UBYTE initspeed;
UBYTE inittempo;
UBYTE mastermult;
UBYTE ultraclick;
UBYTE pantable;
char unused2[8];
UWORD special;
UBYTE channels[32];
} S3MHEADER;
/* Raw S3M sampleinfo struct: */
typedef struct S3MSAMPLE{
UBYTE type;
char filename[12];
UBYTE memsegh;
UWORD memsegl;
ULONG length;
ULONG loopbeg;
ULONG loopend;
UBYTE volume;
UBYTE dsk;
UBYTE pack;
UBYTE flags;
ULONG c2spd;
char unused[12];
char sampname[28];
char scrs[4];
} S3MSAMPLE;
/**************************************************************************
**************************************************************************/
S3MNOTE *s3mbuf; /* pointer to a complete S3M pattern */
UWORD *paraptr; /* parapointer array (see S3M docs) */
static S3MHEADER *mh;
UBYTE remap[32];
char S3M_Version[]="Screamtracker 3.xx";
BOOL S3M_Test(void)
{
char id[4];
_mm_fseek(modfp,0x2c,SEEK_SET);
if(!fread(id,4,1,modfp)) return 0;
if(!memcmp(id,"SCRM",4)) return 1;
return 0;
}
BOOL S3M_Init(void)
{
s3mbuf=NULL;
paraptr=NULL;
if(!(s3mbuf=MyMalloc(16*64*sizeof(S3MNOTE)))) return 0;
if(!(mh=MyCalloc(1,sizeof(S3MHEADER)))) return 0;
return 1;
}
void S3M_Cleanup(void)
{
if(s3mbuf!=NULL) free(s3mbuf);
if(paraptr!=NULL) free(paraptr);
if(mh!=NULL) free(mh);
}
BOOL S3M_ReadPattern(void)
{
int row=0,flag,ch;
S3MNOTE *n;
S3MNOTE dummy;
/* clear pattern data */
memset(s3mbuf,255,16*64*sizeof(S3MNOTE));
while(row<64){
flag=fgetc(modfp);
if(flag==EOF){
myerr="Error loading pattern";
return 0;
}
if(flag){
ch=flag&31;
if(mh->channels[ch]<16){
n=&s3mbuf[(64U*remap[ch])+row];
}
else{
n=&dummy;
}
if(flag&32){
n->note=fgetc(modfp);
n->ins=fgetc(modfp);
}
if(flag&64){
n->vol=fgetc(modfp);
}
if(flag&128){
n->cmd=fgetc(modfp);
n->inf=fgetc(modfp);
}
}
else row++;
}
return 1;
}
UBYTE *S3M_ConvertTrack(S3MNOTE *tr)
{
int t;
UBYTE note,ins,vol,cmd,inf,lo,hi;
UniReset();
for(t=0;t<64;t++){
note=tr[t].note;
ins=tr[t].ins;
vol=tr[t].vol;
cmd=tr[t].cmd;
inf=tr[t].inf;
lo=inf&0xf;
hi=inf>>4;
if(ins!=0 && ins!=255){
UniInstrument(ins-1);
}
if(note!=255){
if(note==254) UniPTEffect(0xc,0); /* <- note off command */
else UniNote(((note>>4)*12)+(note&0xf)); /* <- normal note */
}
if(vol<255){
UniPTEffect(0xc,vol);
/* UniWrite(UNI_S3MVOLUME); */
/* UniWrite(vol); */
}
if(cmd!=255){
switch(cmd){
case 1: /* Axx set speed to xx */
UniWrite(UNI_S3MEFFECTA);
UniWrite(inf);
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;
case 0xf: /* Oxx set sampleoffset xx00h */
UniPTEffect(0x9,inf);
break;
case 0x11: /* Qxy Retrig (+volumeslide) */
UniWrite(UNI_S3MEFFECTQ);
UniWrite(inf);
break;
case 0x12: /* Rxy tremolo speed x, depth y */
UniPTEffect(0x6,inf);
break;
case 0x13: /* Sxx special commands */
switch(hi){
case 0: /* S0x set filter */
UniPTEffect(0xe,0x00|lo);
break;
case 1: /* S1x set glissando control */
UniPTEffect(0xe,0x30|lo);
break;
case 2: /* S2x set finetune */
UniPTEffect(0xe,0x50|lo);
break;
case 3: /* S3x set vibrato waveform */
UniPTEffect(0xe,0x40|lo);
break;
case 4: /* S4x set tremolo waveform */
UniPTEffect(0xe,0x70|lo);
break;
case 8: /* S8x set panning position */
UniPTEffect(0xe,0x80|lo);
break;
case 0xb: /* SBx pattern loop */
UniPTEffect(0xe,0x60|lo);
break;
case 0xc: /* SCx notecut */
UniPTEffect(0xe,0xC0|lo);
break;
case 0xd: /* SDx notedelay */
UniPTEffect(0xe,0xD0|lo);
break;
case 0xe: /* SDx patterndelay */
UniPTEffect(0xe,0xE0|lo);
break;
}
break;
case 0x14: /* Txx tempo */
if(inf>0x20){
UniWrite(UNI_S3MEFFECTT);
UniWrite(inf);
}
break;
case 0x18: /* Xxx amiga command 8xx */
UniPTEffect(0x8,inf);
break;
}
}
UniNewline();
}
return UniDup();
}
BOOL S3M_Load(void)
{
int t,u,track=0;
INSTRUMENT *d;
SAMPLE *q;
UBYTE isused[16];
UBYTE pan[32];
/* try to read module header */
_mm_read_str(mh->songname,28,modfp);
mh->t1a =_mm_read_UBYTE(modfp);
mh->type =_mm_read_UBYTE(modfp);
_mm_read_UBYTES(mh->unused1,2,modfp);
mh->ordnum =_mm_read_I_UWORD(modfp);
mh->insnum =_mm_read_I_UWORD(modfp);
mh->patnum =_mm_read_I_UWORD(modfp);
mh->flags =_mm_read_I_UWORD(modfp);
mh->tracker =_mm_read_I_UWORD(modfp);
mh->fileformat =_mm_read_I_UWORD(modfp);
_mm_read_str(mh->scrm,4,modfp);
mh->mastervol =_mm_read_UBYTE(modfp);
mh->initspeed =_mm_read_UBYTE(modfp);
mh->inittempo =_mm_read_UBYTE(modfp);
mh->mastermult =_mm_read_UBYTE(modfp);
mh->ultraclick =_mm_read_UBYTE(modfp);
mh->pantable =_mm_read_UBYTE(modfp);
_mm_read_UBYTES(mh->unused2,8,modfp);
mh->special =_mm_read_I_UWORD(modfp);
_mm_read_UBYTES(mh->channels,32,modfp);
if(feof(modfp)){
myerr="Error loading header";
return 0;
}
/* set module variables */
of.modtype=strdup(S3M_Version);
of.songname=DupStr(mh->songname,28); /* make a cstr of songname */
of.numpat=mh->patnum;
of.numins=mh->insnum;
of.initspeed=mh->initspeed;
of.inittempo=mh->inittempo;
/* count the number of channels used */
of.numchn=0;
for(t=0;t<32;t++) printf("%2.2x ",mh->channels[t]);
for(t=0;t<32;t++) remap[t]=0;
for(t=0;t<16;t++) isused[t]=0;
/* set a flag for each channel (1 out of of 16) thats being used: */
for(t=0;t<32;t++){
if(mh->channels[t]<16){
isused[mh->channels[t]]=1;
}
}
/* give each of them a different number */
for(t=0;t<16;t++){
if(isused[t]){
isused[t]=of.numchn;
of.numchn++;
}
}
/* build the remap array */
for(t=0;t<32;t++){
if(mh->channels[t]<16){
remap[t]=isused[mh->channels[t]];
}
}
/* set panning positions */
for(t=0;t<32;t++){
if(mh->channels[t]<16){
if(mh->channels[t]<8){
of.panning[remap[t]]=0x30;
}
else{
of.panning[remap[t]]=0xc0;
}
}
}
of.numtrk=of.numpat*of.numchn;
printf("Uses %d channels\n",of.numchn);
/* read the order data */
_mm_read_UBYTES(of.positions,mh->ordnum,modfp);
of.numpos=0;
for(t=0;t<mh->ordnum;t++){
of.positions[of.numpos]=of.positions[t];
if(of.positions[t]<254) of.numpos++;
}
if((paraptr=MyMalloc((of.numins+of.numpat)*sizeof(UWORD)))==NULL) return 0;
/* read the instrument+pattern parapointers */
_mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modfp);
printf("pantab %d\n",mh->pantable);
if(mh->pantable==252){
/* read the panning table */
_mm_read_UBYTES(pan,32,modfp);
/* set panning positions according to panning table (new for st3.2) */
for(t=0;t<32;t++){
if((pan[t]&0x20) && mh->channels[t]<16){
of.panning[remap[t]]=(pan[t]&0xf)<<4;
}
}
}
/* now is a good time to check if the header was too short :) */
if(feof(modfp)){
myerr="Error loading header";
return 0;
}
if(!AllocInstruments()) return 0;
d=of.instruments;
for(t=0;t<of.numins;t++){
S3MSAMPLE s;
d->numsmp=1;
if(!AllocSamples(d)) return 0;
q=d->samples;
/* seek to instrument position */
_mm_fseek(modfp,((long)paraptr[t])<<4,SEEK_SET);
/* and load sample info */
s.type =_mm_read_UBYTE(modfp);
_mm_read_str(s.filename,12,modfp);
s.memsegh =_mm_read_UBYTE(modfp);
s.memsegl =_mm_read_I_UWORD(modfp);
s.length =_mm_read_I_ULONG(modfp);
s.loopbeg =_mm_read_I_ULONG(modfp);
s.loopend =_mm_read_I_ULONG(modfp);
s.volume =_mm_read_UBYTE(modfp);
s.dsk =_mm_read_UBYTE(modfp);
s.pack =_mm_read_UBYTE(modfp);
s.flags =_mm_read_UBYTE(modfp);
s.c2spd =_mm_read_I_ULONG(modfp);
_mm_read_UBYTES(s.unused,12,modfp);
_mm_read_str(s.sampname,28,modfp);
_mm_read_str(s.scrs,4,modfp);
if(feof(modfp)){
myerr=ERROR_LOADING_HEADER;
return 0;
}
d->insname=DupStr(s.sampname,28);
q->c2spd=s.c2spd;
q->length=s.length;
q->loopstart=s.loopbeg;
q->loopend=s.loopend;
q->volume=s.volume;
q->seekpos=(((long)s.memsegh)<<16|s.memsegl)<<4;
q->flags=0;
if(s.flags&1) q->flags|=SF_LOOP;
if(s.flags&4) q->flags|=SF_16BITS;
if(mh->fileformat==1) q->flags|=SF_SIGNED;
/* DON'T load sample if it doesn't have the SCRS tag */
if(memcmp(s.scrs,"SCRS",4)!=0) q->length=0;
printf("%s\n",d->insname);
d++;
}
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
for(t=0;t<of.numpat;t++){
/* seek to pattern position ( + 2 skip pattern length ) */
_mm_fseek(modfp,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);
if(!S3M_ReadPattern()) return 0;
for(u=0;u<of.numchn;u++){
if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;
}
}
return 1;
}
LOADER load_s3m={
NULL,
"S3M",
"Portable S3M loader v0.2",
S3M_Init,
S3M_Test,
S3M_Load,
S3M_Cleanup
};