////////////////////////////////////////////////////// // Load DisorderTracker II module ////////////////////////////////////////////////////// mp_sint32 LoaderPLM::load(XMFileBase& f, XModule* module) { mp_sint32 i,j; module->cleanUp(); // this will make code much easier to read TXMHeader* header = &module->header; TXMInstrument* instr = module->instr; TXMSample* smp = module->smp; TXMPattern* phead = module->phead; // we're already out of memory here if (!phead || !instr || !smp) return MP_OUT_OF_MEMORY; /////////////////////////////////////////////////// // read header /////////////////////////////////////////////////// f.read(header->sig,1,3); f.readByte(); mp_uint32 hdrSize = f.readByte(); mp_ubyte ver = f.readByte(); if (ver != 0x10) return MP_LOADER_FAILED; f.read(header->name, 1, 32); // skip remaining bytes from the song name f.readDword(); // 36 f.readDword(); // 40 f.readDword(); // 44 f.readDword(); // 48 => skipped rest of song name :) header->channum = f.readByte(); f.readByte(); // doc says ignore flags byte mp_ubyte maxVol = f.readByte(); f.readByte(); // skip soundblaster amplify header->speed = f.readByte(); header->tempo = f.readByte(); // panning positions for (i = 0; i < 32; i++) header->pan[i] = (mp_ubyte)XModule::pan15to255(f.readByte()); header->smpnum = header->insnum = f.readByte(); mp_sint32 numPatterns = f.readByte(); mp_sint32 numOrders = f.readWord(); header->mainvol = 255; /////////////////////////////////////////////////// // read orderlist, special with PLM /////////////////////////////////////////////////// f.seekWithBaseOffset(hdrSize); TOrdHdr* ordHeaders = new TOrdHdr[numOrders]; for (i = 0; i < numOrders; i++) { ordHeaders[i].startPos = f.readWord(); ordHeaders[i].startChannel = f.readByte(); ordHeaders[i].patternIndex = f.readByte(); /*printf("%x, %i, %i, %i\n",f.posWithBaseOffset(), ordHeaders[i].startPos, ordHeaders[i].startChannel, ordHeaders[i].patternIndex); getch();*/ } mp_uint32* patOffsets = new mp_uint32[numPatterns]; mp_uint32* smpOffsets = new mp_uint32[header->insnum]; f.readDwords(patOffsets, numPatterns); f.readDwords(smpOffsets, header->insnum); /////////////////////////////////////////////////// // read patterns /////////////////////////////////////////////////// mp_ubyte* patterns[256]; for (i = 0; i < numPatterns; i++) { if (patOffsets[i] != 0) { f.seekWithBaseOffset(patOffsets[i]); mp_uint32 size = f.readDword(); patterns[i] = new mp_ubyte[size]; if (patterns[i] == NULL) { for (j = 0; j < i; j++) delete[] patterns[j]; delete[] smpOffsets; delete[] patOffsets; return MP_OUT_OF_MEMORY; } f.read(patterns[i], 1, size); } else { patterns[i] = NULL; } } /////////////////////////////////////////////////// // read instruments (+samples) /////////////////////////////////////////////////// /* Sample layout: id 4 bytes 0 ; ID (PLS+28) headersize 1 byte 4 ; size of header in bytes, including ID etc version 1 byte 5 fullname 32 byte 6 ; NOT asciiz filename 12 byte 38 ; ditto pan byte 50 ; default pan, 0..f, >f=none vol byte 51 ; default vol 0..40h flags byte 52 ; 1 = 16 bit , 0=8 bit c4spd word 53 ; c4spd (as for S3M) gusloc dword 55 ; posn in gusram (not used in file) loopst dword 59 ; loopstart loopen dword 63 ; loopend len dword 67 ; data size IN BYTES data lots of bytes ; unsigned data*/ for (i = 0; i < header->insnum; i++) { if (!smpOffsets[i]) continue; f.seekWithBaseOffset(smpOffsets[i]); mp_uint32 id = f.readDword(); if (id != 0x1a534c50) { for (j = 0; j < numPatterns; j++) delete[] patterns[j]; delete[] smpOffsets; delete[] patOffsets; return MP_LOADER_FAILED; } mp_uint32 sHdrSize = f.readByte(); mp_ubyte ver = f.readByte(); f.read(instr[i].name, 1, 32); f.read(smp[i].name, 1, 12); mp_ubyte pan = f.readByte(); smp[i].flags = 4; if (pan <= 0xf) { smp[i].pan = (mp_ubyte)XModule::pan15to255(pan); smp[i].flags|=2; } mp_ubyte vol = f.readByte(); smp[i].vol = vol <= 64 ? XModule::vol64to255(vol) : 255/*0xff*/; mp_ubyte flags = f.readByte(); smp[i].type = (flags&1)?16:0; XModule::convertc4spd(f.readWord(), &smp[i].finetune, &smp[i].relnote); f.readDword(); // skip guspos smp[i].loopstart = f.readDword(); //smp[i].looplen = f.readDword(); mp_sint32 looplen = ((mp_sint32)f.readDword() - (mp_sint32)smp[i].loopstart) - ((flags&1)?2:1); if (looplen < 0) looplen = 0; smp[i].looplen = looplen; if (smp[i].looplen) { smp[i].type = (flags & 2) ? 2 : 1; } smp[i].samplen = f.readDword(); #ifdef VERBOSE printf("%i: %i, %i, %x\n",i+1,vol,flags,smp[i].samplen); #endif if (smp[i].samplen) { instr[i].samp = 1; for (j = 0; j < 120; j++) { instr[i].snum[j] = i; } smp[i].sample = (mp_sbyte*)module->allocSampleMem(smp[i].samplen); if (smp[i].sample == NULL) { for (j = 0; j < numPatterns; j++) delete[] patterns[j]; delete[] smpOffsets; delete[] patOffsets; return MP_OUT_OF_MEMORY; } if (flags&1) { module->loadSample(f, smp[i].sample, smp[i].samplen, smp[i].samplen>>1, XModule::ST_UNSIGNED); smp[i].samplen>>=1; } else {
mp_sint32 LoaderCBA::load(XMFileBase& f, XModule* module) { module->cleanUp(); // this will make code much easier to read TXMHeader* header = &module->header; TXMInstrument* instr = module->instr; TXMSample* smp = module->smp; TXMPattern* phead = module->phead; // we're already out of memory here if (!phead || !instr || !smp) return MP_OUT_OF_MEMORY; f.read(header->sig, 1, 3); f.readByte(); // skip 0xF9 f.read(header->name, 1, 32); f.readByte(); // skip 0x1A mp_sint32 songMsgLen = f.readWord(); header->channum = f.readByte(); header->patnum = f.readByte()+1; // number of patterns header->ordnum = f.readByte(); // song length header->insnum = f.readByte(); // number of instruments header->tempo = f.readByte(); // default tickspeed header->speed = f.readByte(); // default tempo header->flags = XModule::MODULE_ST3NEWINSTRUMENT; header->mainvol = 255; f.read(header->pan, 1, 32); f.read(header->ord, 1, 255); mp_sint32 i, s = 0; for (i = 0; i < header->insnum; i++) { mp_ubyte name[32]; mp_ubyte flags; mp_ubyte vol; mp_uword c4spd; mp_sint32 len; mp_sint32 loopstart; mp_sint32 loopend; f.read(name, 1, 32); flags = f.readByte(); vol = f.readByte(); c4spd = f.readWord(); len = f.readDword(); loopstart = f.readDword(); loopend = f.readDword(); memcpy(instr[i].name, name, 32); if ((flags & 0x02) && len) { instr[i].samp = 1; memcpy(smp[s].name, name, 32); for (mp_sint32 j = 0; j < 120; j++) instr[i].snum[j] = s; smp[s].flags = 1; smp[s].samplen = len; mp_sint32 looplen = (loopend - loopstart); if (looplen < 0) looplen = 0; smp[s].looplen = looplen; smp[s].loopstart = loopstart; smp[s].vol = XModule::vol64to255(vol); if (flags & 0x08) smp[s].type = 1; XModule::convertc4spd(c4spd, &smp[s].finetune, &smp[s].relnote); s++; } } header->smpnum = s; mp_ubyte* pattern = new mp_ubyte[header->channum*64*5]; if (pattern == NULL) return MP_OUT_OF_MEMORY; for (i = 0; i < header->patnum;i++) { f.read(pattern, 1, header->channum*64*5); phead[i].rows = 64; phead[i].effnum = 2; phead[i].channum = (mp_ubyte)header->channum; phead[i].patternData = new mp_ubyte[phead[i].rows*header->channum * (phead[i].effnum * 2 + 2)]; // out of memory? if (phead[i].patternData == NULL) { delete[] pattern; return MP_OUT_OF_MEMORY; } memset(phead[i].patternData,0,phead[i].rows*header->channum * (phead[i].effnum * 2 + 2)); mp_sint32 r,c,cnt = 0; mp_sint32 offs = 0; for (r=0; r < 64; r++) { for (c = 0; c < header->channum; c++) { mp_ubyte ins = pattern[cnt]; mp_ubyte note = pattern[cnt+1]; mp_ubyte vol = pattern[cnt+2]; mp_ubyte eff = pattern[cnt+3]; mp_ubyte op = pattern[cnt+4]; if (note == 255) note = 122; phead[i].patternData[offs] = note; phead[i].patternData[offs+1] = ins; if (vol) { phead[i].patternData[offs+2] = 0x0C; phead[i].patternData[offs+3] = XModule::vol64to255(vol-1); } convertEffect(eff, op); #ifdef VERBOSE if (eff == 0 && pattern[cnt+3]) { printf("pattern: %i, row: %i, channel %i: %x, %x\n", i, r, c, pattern[cnt+3], pattern[cnt+4]); } #endif phead[i].patternData[offs+4] = eff; phead[i].patternData[offs+5] = op; cnt+=5; offs+=(phead[i].effnum * 2 + 2); } } } delete[] pattern; mp_sint32 result = module->loadModuleSamples(f, XModule::ST_DELTA); if (result != MP_OK) return result; module->allocateSongMessage(songMsgLen+1); if (module->message) { memset(module->message, 0, songMsgLen+1); f.read(module->message, 1, songMsgLen); } strcpy(header->tracker,"..converted.."); //module->setDefaultPanning(); module->postProcessSamples(); return MP_OK; }