/* Name: LOAD_ULT.C Description: Ultratracker (ULT) module 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 ULTEVENT{ short note,sample,eff,dat1,dat2; } /* Raw ULT header struct: */ class ULTHEADER{ byte id[]; byte songtitle[]; byte reserved; public ULTHEADER() { id = new byte[15]; songtitle = new byte[32]; } } /* Raw ULT sampleinfo struct: */ class ULTSAMPLE{ byte samplename[]; byte dosname[]; int loopstart; int loopend; int sizestart; int sizeend; short volume; short flags; short finetune; public ULTSAMPLE() { samplename = new byte[32]; dosname = new byte[12]; } } public class ULT_Loader extends clLOADER { public final int ULTS_16BITS = 4; public final int ULTS_LOOP = 8; public final int ULTS_REVERSE = 16; public final String ULT_Version[]={ "Ultra Tracker V1.3", "Ultra Tracker V1.4", "Ultra Tracker V1.5", "Ultra Tracker V1.6" }; public ULTEVENT ev; public ULT_Loader(clMainBase theMain) { super(theMain); type = new String("ULT"); version = new String("Portable ULT loader v0.1"); ev = new ULTEVENT(); } public boolean Test() { byte id[] = new byte[15]; byte should_be[] = new byte[20]; //"MAS_UTrack_V00"; String szShould_be = "MAS_UTrack_V00"; int a; szShould_be.getBytes(0, 14, should_be, 0); //if(!fread(id,15,1,m_.MLoader.modfp)) return 0; if (m_.MLoader.modfp.read(id,0,15) != 15) return false; for(a=0;a<14;a++) if (id[a] != should_be[a]) return false; return true; //return(!strncmp(id,"MAS_UTrack_V00",14)); } public boolean Init() { return true; } public void Cleanup() { } public int ReadUltEvent(ULTEVENT event) { short flag; byte rep [] = new byte[2]; rep[0] = 1; flag=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); if(flag==0xfc){ //fread(&rep,1,1,m_.MLoader.modfp); m_.MLoader.modfp.read(rep,0,1); event.note =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); } else{ event.note=flag; } event.sample =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); event.eff =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); event.dat1 =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); event.dat2 =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); //return rep[0]; return (rep[0]<0) ? ((int)rep[0]+256) : rep[0]; } public boolean Load() { try { int t,u,tracks=0; //INSTRUMENT *d; int inst_num; //SAMPLE *q; ULTSAMPLE s = new ULTSAMPLE(); ULTHEADER mh = new ULTHEADER(); short nos,noc,nop; /* try to read module header */ m_.mmIO._mm_read_str(mh.id,15,m_.MLoader.modfp); m_.mmIO._mm_read_str(mh.songtitle,32,m_.MLoader.modfp); mh.reserved=(byte)m_.mmIO._mm_read_UBYTE(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; } if(mh.id[14]<'1' || mh.id[14]>'4') { System.out.print("This version is not yet supported\n"); return false; } m_.MLoader.of.modtype=new String(ULT_Version[mh.id[14]-'1']); m_.MLoader.of.initspeed=6; m_.MLoader.of.inittempo=125; /* read songtext */ if(!m_.MLoader.ReadComment((short)(mh.reserved*32))) return false; nos=m_.mmIO._mm_read_UBYTE(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; } m_.MLoader.of.songname=m_.MLoader.DupStr(mh.songtitle,32); m_.MLoader.of.numins=nos; if(!m_.MLoader.AllocInstruments()) return false; //d=m_.MLoader.of.instruments; inst_num=0; for(t=0;t<nos;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; /* try to read sample info */ m_.mmIO._mm_read_str(s.samplename,32,m_.MLoader.modfp); m_.mmIO._mm_read_str(s.dosname,12,m_.MLoader.modfp); s.loopstart =m_.mmIO._mm_read_I_ULONG(m_.MLoader.modfp); s.loopend =m_.mmIO._mm_read_I_ULONG(m_.MLoader.modfp); s.sizestart =m_.mmIO._mm_read_I_ULONG(m_.MLoader.modfp); s.sizeend =m_.mmIO._mm_read_I_ULONG(m_.MLoader.modfp); s.volume =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); s.flags =m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); s.finetune =m_.mmIO._mm_read_I_SWORD(m_.MLoader.modfp); //if(feof(m_.MLoader.modfp)){ if (m_.MLoader.modfp.getFilePointer() >= m_.MLoader.modfp.length()) { m_.mmIO.myerr=m_.ERROR_LOADING_SAMPLEINFO; return false; } m_.MLoader.of.instruments[inst_num].insname=m_.MLoader.DupStr(s.samplename,32); m_.MLoader.of.instruments[inst_num].samples[0].seekpos=0; m_.MLoader.of.instruments[inst_num].samples[0].c2spd=8363; if(mh.id[14]>='4'){ m_.mmIO._mm_read_I_UWORD(m_.MLoader.modfp); /* read 1.6 extra info(??) word */ m_.MLoader.of.instruments[inst_num].samples[0].c2spd=s.finetune; } m_.MLoader.of.instruments[inst_num].samples[0].length = s.sizeend-s.sizestart; m_.MLoader.of.instruments[inst_num].samples[0].volume = (short)(s.volume>>2); m_.MLoader.of.instruments[inst_num].samples[0].loopstart = s.loopstart; m_.MLoader.of.instruments[inst_num].samples[0].loopend = s.loopend; m_.MLoader.of.instruments[inst_num].samples[0].flags = (m_.MDriver.SF_SIGNED); if((s.flags&ULTS_LOOP) != 0) { m_.MLoader.of.instruments[inst_num].samples[0].flags |= (m_.MDriver.SF_LOOP); } if((s.flags&ULTS_16BITS) != 0) { m_.MLoader.of.instruments[inst_num].samples[0].flags |= (m_.MDriver.SF_16BITS); m_.MLoader.of.instruments[inst_num].samples[0].loopstart >>= 1; m_.MLoader.of.instruments[inst_num].samples[0].loopend >>= 1; } /* printf("Sample %d %s length %ld\n",t,m_.MLoader.of.instruments[inst_num].samplename,m_.MLoader.of.instruments[inst_num].length); */ //d++; inst_num++; } m_.mmIO._mm_read_UBYTES2(m_.MLoader.of.positions,256,m_.MLoader.modfp); for(t=0;t<256;t++){ if(m_.MLoader.of.positions[t]==255) break; } m_.MLoader.of.numpos=(short)t; noc=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); nop=m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp); m_.MLoader.of.numchn=(short)(noc+1); m_.MLoader.of.numpat=(short)(nop+1); m_.MLoader.of.numtrk=(short)(m_.MLoader.of.numchn*m_.MLoader.of.numpat); if(!m_.MLoader.AllocTracks()) return false; if(!m_.MLoader.AllocPatterns()) return false; for(u=0;u<m_.MLoader.of.numchn;u++){ for(t=0;t<m_.MLoader.of.numpat;t++){ m_.MLoader.of.patterns[(t*m_.MLoader.of.numchn)+u]=(short)(tracks++); } } /* read pan position table for v1.5 and higher */ if(mh.id[14]>='3'){ for(t=0;t<m_.MLoader.of.numchn;t++) m_.MLoader.of.panning[t]=(short)(m_.mmIO._mm_read_UBYTE(m_.MLoader.modfp)<<4); } for(t=0;t<m_.MLoader.of.numtrk;t++){ int rep,s_,done; m_.MUniTrk.UniReset(); done=0; while(done<64){ rep=ReadUltEvent(ev); //if(feof(m_.MLoader.modfp)){ if (m_.MLoader.modfp.getFilePointer() >= m_.MLoader.modfp.length()) { m_.mmIO.myerr=m_.ERROR_LOADING_TRACK; return false; } /* printf("rep %d: n %d i %d e %x d1 %d d2 %d \n",rep,ev.note,ev.sample,ev.eff,ev.dat1,ev.dat2); */ for(s_=0;s_<rep;s_++){ short eff; if(ev.sample != 0){ m_.MUniTrk.UniInstrument((short)(ev.sample-1)); } if(ev.note != 0){ m_.MUniTrk.UniNote((short)(ev.note+23)); } eff=(short)(ev.eff>>4); /* ULT panning effect fixed by Alexander Kerkhove : */ if (eff==0xc) m_.MUniTrk.UniPTEffect(eff,(short)(ev.dat2>>2)); else if (eff==0xb) m_.MUniTrk.UniPTEffect((short)8,(short)(ev.dat2*0xf)); else m_.MUniTrk.UniPTEffect(eff,ev.dat2); eff=(short)(ev.eff&0xf); if (eff==0xc) m_.MUniTrk.UniPTEffect(eff,(short)(ev.dat1>>2)); else if (eff==0xb) m_.MUniTrk.UniPTEffect((short)8,(short)(ev.dat1*0xf)); else m_.MUniTrk.UniPTEffect(eff,ev.dat1); m_.MUniTrk.UniNewline(); done++; } } /* printf("----------------"); */ if((m_.MLoader.of.tracks[t]=m_.MUniTrk.UniDup()) == null) return false; } /* printf("%d channels %d patterns\n",m_.MLoader.of.numchn,m_.MLoader.of.numpat); */ /* printf("Song %32.32s: There's %d samples\n",mh.songtitle,nos); */ return true; } catch (IOException ioe1) { return false; } } }