/*
Name:
LOAD_MOD.C
Description:
Generic MOD loader
Portability:
All systems - all compilers (hopefully)
*/
/*************************************************************************
*************************************************************************/
package audio.jmikmod.MikMod.Loaders;
import java.io.IOException;
import audio.jmikmod.MikMod.clLOADER;
import audio.jmikmod.MikMod.clMainBase;
class MSAMPINFO
{ /* sample header as it appears in a module */
public byte samplename[];
public int length;
public short finetune;
public short volume;
public int reppos;
public int replen;
public MSAMPINFO()
{
samplename = new byte[22];
}
};
class MODNOTE{
public short a,b,c,d;
};
class MODULEHEADER{ /* verbatim module header */
public byte songname[]; /* the songname.. */
public MSAMPINFO samples[]; /* all sampleinfo */
public short songlength; /* number of patterns used */
public short magic1; /* should be 127 */
public byte positions[]; /* which pattern to play at pos */
public byte magic2[]; /* string "M.K." or "FLT4" or "FLT8" */
public MODULEHEADER()
{
songname = new byte [20];
samples = new MSAMPINFO[31];
int i;
for(i=0;i<31;i++)
samples[i] = new MSAMPINFO();
positions = new byte[128];
magic2 = new byte[4];
}
};
class MODTYPE
{ /* struct to identify type of module */
public byte id[];
public short channels;
public String name; //char * name;
public MODTYPE()
{
id = new byte[5];
}
public MODTYPE(String init_id, int init_chn, String init_name)
{
id = new byte[5];
init_id.getBytes(0,4,id,0);
id[4] = '\0';
channels = (short)init_chn;
name = new String(init_name);
}
}
public class MOD_Loader extends clLOADER
{
protected MODULEHEADER mh; /* raw as-is module header */
protected MODNOTE patbuf[];
final int MODULEHEADERSIZE = 1084;
/*************************************************************************
*************************************************************************/
final String protracker="Protracker";
final String startracker="Startracker";
final String fasttracker="Fasttracker";
final String ins15tracker="15-instrument";
final String oktalyzer="Oktalyzer";
final String taketracker="TakeTracker";
final MODTYPE modtypes[]= {
new MODTYPE ("M.K.",4,protracker), /* protracker 4 channel */
new MODTYPE ("M!K!",4,protracker), /* protracker 4 channel */
new MODTYPE ("FLT4",4,startracker), /* startracker 4 channel */
new MODTYPE ("4CHN",4,fasttracker), /* fasttracker 4 channel */
new MODTYPE ("6CHN",6,fasttracker), /* fasttracker 6 channel */
new MODTYPE ("8CHN",8,fasttracker), /* fasttracker 8 channel */
new MODTYPE ("CD81",8,oktalyzer), /* atari oktalyzer 8 channel */
new MODTYPE ("OKTA",8,oktalyzer), /* atari oktalyzer 8 channel */
new MODTYPE ("16CN",16,taketracker), /* taketracker 16 channel */
new MODTYPE ("32CN",32,taketracker), /* taketracker 32 channel */
new MODTYPE (" ",4,ins15tracker) /* 15-instrument 4 channel */
};
/*
Old (amiga) noteinfo:
_____byte 1_____ byte2_ _____byte 3_____ byte4_
/ \ / \ / \ / \
0000 0000-00000000 0000 0000-00000000
Upper four 12 bits for Lower four Effect command.
bits of sam- note period. bits of sam-
ple number. ple number.
*/
final short npertab[]={
/* . Tuning 0 */
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
856,808,762,720,678,640,604,570,538,508,480,453,
428,404,381,360,339,320,302,285,269,254,240,226,
214,202,190,180,170,160,151,143,135,127,120,113,
107,101,95,90,85,80,75,71,67,63,60,56
};
public MOD_Loader(clMainBase theMain)
{
super(theMain);
mh = null;
patbuf = null;
type = new String("Standard module");
version = new String("Portable MOD loader v0.11");
}
public boolean Test()
{
int t, i;
byte id[] = new byte[4];
m_.mmIO._mm_fseek(m_.MLoader.modfp,MODULEHEADERSIZE-4,m_.mmIO.SEEK_SET);
//if(!fread(id,4,1,m_.MLoader.modfp)) return 0;
if (m_.MLoader.modfp.read(id,0,4) != 4) return false;
/* find out which ID string */
for(t=0;t<10;t++){
for(i=0;i<4;i++)
if (id[i] != modtypes[t].id[i])
break;
if (i == 4)
return true;
//if(!memcmp(id,modtypes[t].id,4)) return 1;
}
return false;
}
public boolean Init()
{
int i, j;
patbuf=null;
//if(!(mh=(MODULEHEADER *)m_.MLoader.MyCalloc(1,sizeof(MODULEHEADER)))) return 0;
mh = new MODULEHEADER();
mh.songlength = mh.magic1 = 0;
for(i=0;i<20;i++)
mh.songname[i] = 0;
for(i=0;i<128;i++)
mh.positions[i] = 0;
for(i=0;i<4;i++)
mh.magic2[i] = 0;
for(i=0;i<31;i++)
{
mh.samples[i].length = mh.samples[i].reppos =
mh.samples[i].replen = 0;
mh.samples[i].finetune = mh.samples[i].volume = 0;
for(j=0;j<22;j++)
mh.samples[i].samplename[j] = 0;
}
return true;
}
public void Cleanup()
{
if (mh != null) mh = null;
if(patbuf!=null) patbuf = null;
}
public void ConvertNote(MODNOTE n)
{
short instrument,effect,effdat,note;
int period;
/* extract the various information from the 4 bytes that
make up a single note */
instrument=(short)((n.a&0x10)|(n.c>>4));
period=(((int)n.a&0xf)<<8)+n.b;
effect=(short)(n.c&0xf);
effdat=n.d;
/* Convert the period to a note number */
note=0;
if(period!=0){
for(note=0;note<60;note++){
if(period>=npertab[note]) break;
}
note++;
if(note==61) note=0;
}
if(instrument!=0){
m_.MUniTrk.UniInstrument((short)(instrument-1));
}
if(note!=0){
m_.MUniTrk.UniNote((short)(note+23));
}
m_.MUniTrk.UniPTEffect(effect,effdat);
}
public short [] ConvertTrack(MODNOTE [] n, int which_track)
{
int t;
int idx_n=0;
m_.MUniTrk.UniReset();
for(t=0;t<64;t++){
ConvertNote(n[idx_n+which_track]);
m_.MUniTrk.UniNewline();
idx_n+=m_.MLoader.of.numchn;
}
return m_.MUniTrk.UniDup();
}
public boolean ML_LoadPatterns()
/*
Loads all patterns of a modfile and converts them into the
3 byte format.
*/
{
int t,s,tracks=0;
if(!m_.MLoader.AllocPatterns()) return false;
if(!m_.MLoader.AllocTracks()) return false;
/* Allocate temporary buffer for loading
and converting the patterns */
//if(!(patbuf=(MODNOTE *)m_.MLoader.MyCalloc(64U*m_.MLoader.of.numchn,sizeof(MODNOTE)))) return 0;
patbuf = new MODNOTE[64*m_.MLoader.of.numchn];
for(t=0;t<64*m_.MLoader.of.numchn;t++)
{
patbuf[t] = new MODNOTE();
patbuf[t].a = patbuf[t].b = patbuf[t].c = patbuf[t].d = 0;
}
for(t=0;t<m_.MLoader.of.numpat;t++){
/* Load the pattern into the temp buffer
and convert it */
for(s=0;s<(int)(64*m_.MLoader.of.numchn);s++){
patbuf[s].a=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
patbuf[s].b=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
patbuf[s].c=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
patbuf[s].d=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
}
for(s=0;s<m_.MLoader.of.numchn;s++){
if((m_.MLoader.of.tracks[tracks++]=ConvertTrack(patbuf,s)) == null) return false;
}
}
return true;
}
public boolean Load()
{
try
{
int t,modtype;
//INSTRUMENT *d; /* new sampleinfo structure */
//SAMPLE *q;
//MSAMPINFO *s; /* old module sampleinfo */
int inst_num, smpinfo_num;
/* try to read module header */
m_.mmIO._mm_read_str(mh.songname,20,m_.MLoader.modfp);
for(t=0;t<31;t++){
//s=&mh.samples[t];
m_.mmIO._mm_read_str(mh.samples[t].samplename,22,m_.MLoader.modfp);
mh.samples[t].length =m_.mmIO._mm_read_M_UWORD(m_.MLoader.modfp);
mh.samples[t].finetune =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
mh.samples[t].volume =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
mh.samples[t].reppos =m_.mmIO._mm_read_M_UWORD(m_.MLoader.modfp);
mh.samples[t].replen =m_.mmIO._mm_read_M_UWORD(m_.MLoader.modfp);
}
mh.songlength =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
mh.magic1 =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp);
m_.mmIO._mm_read_SBYTES(mh.positions,128,m_.MLoader.modfp);
m_.mmIO._mm_read_SBYTES(mh.magic2,4,m_.MLoader.modfp);
//if(feof(m_.MLoader.modfp)){
if (m_.MLoader.modfp.getFilePointer() >= m_.MLoader.modfp.length()) {
m_.mmIO.myerr=m_.ERROR_LOADING_HEADER;
return false;
}
/* find out which ID string */
for(modtype=0;modtype<10;modtype++){
int pos;
for(pos=0;pos<4;pos++)
if (mh.magic2[pos] != modtypes[modtype].id[pos])
break;
if (pos==4)
break;
//if(!memcmp(mh.magic2,modtypes[modtype].id,4)) break;
}
if(modtype==10){
/* unknown modtype */
m_.mmIO.myerr=m_.ERROR_NOT_A_MODULE;
return false;
}
/* set module variables */
m_.MLoader.of.initspeed=6;
m_.MLoader.of.inittempo=125;
m_.MLoader.of.numchn=modtypes[modtype].channels; /* get number of channels */
m_.MLoader.of.modtype=new String(modtypes[modtype].name); /* get ascii type of mod */
m_.MLoader.of.songname=m_.MLoader.DupStr(mh.songname,20); /* make a cstr m_.MLoader.of songname */
m_.MLoader.of.numpos=mh.songlength; /* copy the songlength */
/* copy the position array */
for(t=0;t<128;t++)
{
m_.MLoader.of.positions[t] = mh.positions[t];
}
/* Count the number of patterns */
m_.MLoader.of.numpat=0;
for(t=0;t<128;t++){ /* <-- BUGFIX... have to check ALL positions */
if(m_.MLoader.of.positions[t] > m_.MLoader.of.numpat){
m_.MLoader.of.numpat=m_.MLoader.of.positions[t];
}
}
m_.MLoader.of.numpat++;
m_.MLoader.of.numtrk=(short)(m_.MLoader.of.numpat*m_.MLoader.of.numchn);
/* Finally, init the sampleinfo structures */
m_.MLoader.of.numins=31;
if(!m_.MLoader.AllocInstruments()) return false;
//s=mh.samples; /* init source pointer */
//d=m_.MLoader.of.instruments; /* init dest pointer */
smpinfo_num = 0; /* init source pointer */
inst_num = 0; /* init dest pointer */
for(t=0;t<m_.MLoader.of.numins;t++){
m_.MLoader.of.instruments[inst_num].numsmp=1;
if(!m_.MLoader.AllocSamples((m_.MLoader.of.instruments[inst_num])))
return false;
//q=m_.MLoader.of.instruments[inst_num].samples;
/* convert the samplename */
m_.MLoader.of.instruments[inst_num].insname=m_.MLoader.DupStr(mh.samples[smpinfo_num].samplename,22);
/* init the sampleinfo variables and
convert the size pointers to longword format */
m_.MLoader.of.instruments[inst_num].samples[0].c2spd = m_.MLoader.finetune[mh.samples[smpinfo_num].finetune&0xf];
m_.MLoader.of.instruments[inst_num].samples[0].volume = mh.samples[smpinfo_num].volume;
m_.MLoader.of.instruments[inst_num].samples[0].loopstart = (int)mh.samples[smpinfo_num].reppos << 1;
m_.MLoader.of.instruments[inst_num].samples[0].loopend = m_.MLoader.of.instruments[inst_num].samples[0].loopstart + ((int)mh.samples[smpinfo_num].replen << 1);
m_.MLoader.of.instruments[inst_num].samples[0].length = (int)mh.samples[smpinfo_num].length << 1;
m_.MLoader.of.instruments[inst_num].samples[0].seekpos = 0;
m_.MLoader.of.instruments[inst_num].samples[0].flags = (m_.MDriver.SF_SIGNED);
if(mh.samples[smpinfo_num].replen>1)
m_.MLoader.of.instruments[inst_num].samples[0].flags |= (m_.MDriver.SF_LOOP);
/* fix replen if repend>length */
if(m_.MLoader.of.instruments[inst_num].samples[0].loopend > m_.MLoader.of.instruments[inst_num].samples[0].length)
m_.MLoader.of.instruments[inst_num].samples[0].loopend=m_.MLoader.of.instruments[inst_num].samples[0].length;
smpinfo_num++; /* point to next source sampleinfo */
inst_num++; /* point to next destiny sampleinfo */
}
if(!ML_LoadPatterns()) return false;
return true;
}
catch (IOException ioe1)
{
return false;
}
}
}