bool CdmoLoader::load(const std::string &filename, const CFileProvider &fp) { int i,j; binistream *f; // check header dmo_unpacker *unpacker = new dmo_unpacker; unsigned char chkhdr[16]; if(!fp.extension(filename, ".dmo")) return false; f = fp.open(filename); if(!f) return false; f->readString((char *)chkhdr, 16); if (!unpacker->decrypt(chkhdr, 16)) { delete unpacker; fp.close(f); return false; } // get file size long packed_length = fp.filesize(f); f->seek(0); unsigned char *packed_module = new unsigned char [packed_length]; // load file f->readString((char *)packed_module, packed_length); fp.close(f); // decrypt unpacker->decrypt(packed_module,packed_length); long unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module, 12); unsigned char *module = new unsigned char [unpacked_length]; // unpack if (!unpacker->unpack(packed_module+12,module,unpacked_length)) { delete unpacker; delete [] packed_module; delete [] module; return false; } delete unpacker; delete [] packed_module; // "TwinTeam" - signed ? if (memcmp(module,"TwinTeam Module File""\x0D\x0A",22)) { delete module; return false; } // load header binisstream uf(module, unpacked_length); uf.setFlag(binio::BigEndian, false); uf.setFlag(binio::FloatIEEE); memset(&header,0,sizeof(s3mheader)); uf.ignore(22); // ignore DMO header ID string uf.readString(header.name, 28); uf.ignore(2); // _unk_1 header.ordnum = uf.readInt(2); header.insnum = uf.readInt(2); header.patnum = uf.readInt(2); uf.ignore(2); // _unk_2 header.is = uf.readInt(2); header.it = uf.readInt(2); memset(header.chanset,0xFF,32); for (i=0;i<9;i++) header.chanset[i] = 0x10 + i; uf.ignore(32); // ignore panning settings for all 32 channels // load orders for(i = 0; i < 256; i++) orders[i] = uf.readInt(1); orders[header.ordnum] = 0xFF; // load pattern lengths unsigned short my_patlen[100]; for(i = 0; i < 100; i++) my_patlen[i] = uf.readInt(2); // load instruments for (i = 0; i < header.insnum; i++) { memset(&inst[i],0,sizeof(s3minst)); uf.readString(inst[i].name, 28); inst[i].volume = uf.readInt(1); inst[i].dsk = uf.readInt(1); inst[i].c2spd = uf.readInt(4); inst[i].type = uf.readInt(1); inst[i].d00 = uf.readInt(1); inst[i].d01 = uf.readInt(1); inst[i].d02 = uf.readInt(1); inst[i].d03 = uf.readInt(1); inst[i].d04 = uf.readInt(1); inst[i].d05 = uf.readInt(1); inst[i].d06 = uf.readInt(1); inst[i].d07 = uf.readInt(1); inst[i].d08 = uf.readInt(1); inst[i].d09 = uf.readInt(1); inst[i].d0a = uf.readInt(1); /* * Originally, riven sets d0b = d0a and ignores 1 byte in the * stream, but i guess this was a typo, so i read it here. */ inst[i].d0b = uf.readInt(1); } // load patterns for (i = 0; i < header.patnum; i++) { long cur_pos = uf.pos(); for (j = 0; j < 64; j++) { while (1) { unsigned char token = uf.readInt(1); if (!token) break; unsigned char chan = token & 31; // note + instrument ? if (token & 32) { unsigned char bufbyte = uf.readInt(1); pattern[i][j][chan].note = bufbyte & 15; pattern[i][j][chan].oct = bufbyte >> 4; pattern[i][j][chan].instrument = uf.readInt(1); } // volume ? if (token & 64) pattern[i][j][chan].volume = uf.readInt(1); // command ? if (token & 128) { pattern[i][j][chan].command = uf.readInt(1); pattern[i][j][chan].info = uf.readInt(1); } } } uf.seek(cur_pos + my_patlen[i]); }
bool DmoPlayer::load(const std::string& filename) { FileStream f(filename); if(!f || f.extension() != ".dmo") return false; unsigned char chkhdr[16]; f.read(chkhdr, 16); DMOUnpacker unpacker; if(!unpacker.decrypt(chkhdr, 16)) { return false; } f.seek(0); std::vector<uint8_t> packed_module(f.size()); // load file f.read(packed_module.data(), f.size()); // decrypt unpacker.decrypt(packed_module.data(), packed_module.size()); const auto unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module.data(), 12); std::vector<uint8_t> module(unpacked_length); // unpack if(!unpacker.unpack(packed_module.data() + 12, module.data(), unpacked_length)) { return false; } // "TwinTeam" - signed ? if(memcmp(module.data(), "TwinTeam Module File" "\x0D\x0A", 22)) { return false; } // load header MemoryStream uf; uf.write(module.data(), module.size()); uf.seek(0); S3mHeader header; uf.seekrel(22); // ignore DMO header ID string uf.read(header.name, 28); uf.seekrel(2); // _unk_1 uf >> header.orderCount >> header.instrumentCount >> header.patternCount; uf.seekrel(2); // _unk_2 uf >> header.initialSpeed >> header.initialTempo; header.chanset.fill(0xff); for(int i = 0; i < 9; i++) header.chanset[i] = 0x10 + i; uf.seekrel(32); // ignore panning settings for all 32 channels // load orders for(int i = 0; i < header.orderCount; ++i) { uint8_t tmp; uf >> tmp; addOrder(tmp); std::cerr << "ORD=" << int(tmp) << "\n"; } addOrder(0xff); uf.seekrel(256 - header.orderCount); // load pattern lengths uint16_t my_patlen[100]; uf.read(my_patlen, 100); // load instruments for(int i = 0; i < header.instrumentCount; i++) { S3mInstrument instrument; uf.read(instrument.name, 28); uf >> instrument.volume; uf >> instrument.dsk; uf >> instrument.c2spd; uf >> instrument.type; uf >> instrument.d00; uf >> instrument.d01; uf >> instrument.d02; uf >> instrument.d03; uf >> instrument.d04; uf >> instrument.d05; uf >> instrument.d06; uf >> instrument.d07; uf >> instrument.d08; uf >> instrument.d09; uf >> instrument.d0a; /* * Originally, riven sets d0b = d0a and ignores 1 byte in the * stream, but i guess this was a typo, so i read it here. */ uf >> instrument.d0b; setInstrument(i, instrument); } // load patterns for(int pattern = 0; pattern < header.patternCount; pattern++) { const auto cur_pos = uf.pos(); for(int row = 0; row < 64; row++) { S3mCell* currentChannel = patternChannel(pattern, row); while(true) { uint8_t token; uf >> token; if(!token) break; const auto chan = token & 31; // note + instrument ? if(token & 32) { uint8_t bufbyte; uf >> bufbyte; currentChannel[chan].note = bufbyte & 15; currentChannel[chan].octave = bufbyte >> 4; uf >> currentChannel[chan].instrument; } // volume ? if(token & 64) uf >> currentChannel[chan].volume; // command ? if(token & 128) { uf >> currentChannel[chan].effect; uf >> currentChannel[chan].effectValue; } } }