2 Adplug - Replayer for many OPL2/OPL3 audio file formats.
3 Copyright (C) 1999 - 2004, 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 dmo.cpp - TwinTeam loader by Riven the Mage <riven@ok.ru>
25 A WORD ist 16 bits, a DWORD is 32 bits and a BYTE is 8 bits in this context.
34 #define LOWORD(l) ((l) & 0xffff)
35 #define HIWORD(l) ((l) >> 16)
36 #define LOBYTE(w) ((w) & 0xff)
37 #define HIBYTE(w) ((w) >> 8)
39 #define ARRAY_AS_DWORD(a, i) \
40 ((a[i + 3] << 24) + (a[i + 2] << 16) + (a[i + 1] << 8) + a[i])
41 #define ARRAY_AS_WORD(a, i) ((a[i + 1] << 8) + a[i])
43 #define CHARP_AS_WORD(p) (((*(p + 1)) << 8) + (*p))
45 /* -------- Public Methods -------------------------------- */
47 CPlayer *CdmoLoader::factory(Copl *newopl)
49 return new CdmoLoader(newopl);
52 bool CdmoLoader::load(const std::string &filename, const CFileProvider &fp)
58 dmo_unpacker *unpacker = new dmo_unpacker;
59 unsigned char chkhdr[16];
61 if(!fp.extension(filename, ".dmo")) return false;
62 f = fp.open(filename); if(!f) return false;
64 f->readString((char *)chkhdr, 16);
66 if (!unpacker->decrypt(chkhdr, 16))
74 long packed_length = fp.filesize(f);
77 unsigned char *packed_module = new unsigned char [packed_length];
80 f->readString((char *)packed_module, packed_length);
84 unpacker->decrypt(packed_module,packed_length);
86 long unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module, 12);
87 unsigned char *module = new unsigned char [unpacked_length];
90 if (!unpacker->unpack(packed_module+12,module,unpacked_length))
93 delete [] packed_module;
99 delete [] packed_module;
101 // "TwinTeam" - signed ?
102 if (memcmp(module,"TwinTeam Module File""\x0D\x0A",22))
109 binisstream uf(module, unpacked_length);
110 uf.setFlag(binio::BigEndian, false); uf.setFlag(binio::FloatIEEE);
112 memset(&header,0,sizeof(s3mheader));
114 uf.ignore(22); // ignore DMO header ID string
115 uf.readString(header.name, 28);
117 uf.ignore(2); // _unk_1
118 header.ordnum = uf.readInt(2);
119 header.insnum = uf.readInt(2);
120 header.patnum = uf.readInt(2);
121 uf.ignore(2); // _unk_2
122 header.is = uf.readInt(2);
123 header.it = uf.readInt(2);
125 memset(header.chanset,0xFF,32);
128 header.chanset[i] = 0x10 + i;
130 uf.ignore(32); // ignore panning settings for all 32 channels
133 for(i = 0; i < 256; i++) orders[i] = uf.readInt(1);
135 orders[header.ordnum] = 0xFF;
137 // load pattern lengths
138 unsigned short my_patlen[100];
139 for(i = 0; i < 100; i++) my_patlen[i] = uf.readInt(2);
142 for (i = 0; i < header.insnum; i++)
144 memset(&inst[i],0,sizeof(s3minst));
146 uf.readString(inst[i].name, 28);
148 inst[i].volume = uf.readInt(1);
149 inst[i].dsk = uf.readInt(1);
150 inst[i].c2spd = uf.readInt(4);
151 inst[i].type = uf.readInt(1);
152 inst[i].d00 = uf.readInt(1);
153 inst[i].d01 = uf.readInt(1);
154 inst[i].d02 = uf.readInt(1);
155 inst[i].d03 = uf.readInt(1);
156 inst[i].d04 = uf.readInt(1);
157 inst[i].d05 = uf.readInt(1);
158 inst[i].d06 = uf.readInt(1);
159 inst[i].d07 = uf.readInt(1);
160 inst[i].d08 = uf.readInt(1);
161 inst[i].d09 = uf.readInt(1);
162 inst[i].d0a = uf.readInt(1);
164 * Originally, riven sets d0b = d0a and ignores 1 byte in the
165 * stream, but i guess this was a typo, so i read it here.
167 inst[i].d0b = uf.readInt(1);
171 for (i = 0; i < header.patnum; i++) {
172 long cur_pos = uf.pos();
174 for (j = 0; j < 64; j++) {
176 unsigned char token = uf.readInt(1);
181 unsigned char chan = token & 31;
183 // note + instrument ?
185 unsigned char bufbyte = uf.readInt(1);
187 pattern[i][j][chan].note = bufbyte & 15;
188 pattern[i][j][chan].oct = bufbyte >> 4;
189 pattern[i][j][chan].instrument = uf.readInt(1);
194 pattern[i][j][chan].volume = uf.readInt(1);
198 pattern[i][j][chan].command = uf.readInt(1);
199 pattern[i][j][chan].info = uf.readInt(1);
204 uf.seek(cur_pos + my_patlen[i]);
212 std::string CdmoLoader::gettype()
214 return std::string("TwinTeam (packed S3M)");
217 std::string CdmoLoader::getauthor()
220 All available .DMO modules written by one composer. And because all .DMO
221 stuff was lost due to hd crash (TwinTeam guys said this), there are
224 return std::string("Benjamin GERARDIN");
227 /* -------- Private Methods ------------------------------- */
229 unsigned short CdmoLoader::dmo_unpacker::brand(unsigned short range)
231 unsigned short ax,bx,cx,dx;
236 ax = LOWORD(cx * 0x8405);
237 dx = HIWORD(cx * 0x8405);
239 cx = (((HIBYTE(cx) + LOBYTE(cx)) & 0xFF) << 8) + LOBYTE(cx);
244 dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx);
246 dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx);
250 // leave it that way or amd64 might get it wrong
255 return HIWORD(HIWORD(LOWORD(bseed) * range) + HIWORD(bseed) * range);
258 bool CdmoLoader::dmo_unpacker::decrypt(unsigned char *buf, long len)
260 unsigned long seed = 0;
263 bseed = ARRAY_AS_DWORD(buf, 0);
265 for (i=0; i < ARRAY_AS_WORD(buf, 4) + 1; i++)
266 seed += brand(0xffff);
268 bseed = seed ^ ARRAY_AS_DWORD(buf, 6);
270 if (ARRAY_AS_WORD(buf, 10) != brand(0xffff))
273 for (i=0;i<(len-12);i++)
274 buf[12+i] ^= brand(0x100);
276 buf[len - 2] = buf[len - 1] = 0;
281 short CdmoLoader::dmo_unpacker::unpack_block(unsigned char *ibuf, long ilen, unsigned char *obuf)
283 unsigned char code,par1,par2;
284 unsigned short ax,bx,cx;
286 unsigned char *ipos = ibuf;
287 unsigned char *opos = obuf;
290 while (ipos - ibuf < ilen)
294 // 00xxxxxx: copy (xxxxxx + 1) bytes
295 if ((code >> 6) == 0)
297 cx = (code & 0x3F) + 1;
299 if(opos + cx >= oend)
302 for (int i=0;i<cx;i++)
308 // 01xxxxxx xxxyyyyy: copy (Y + 3) bytes from (X + 1)
309 if ((code >> 6) == 1)
313 ax = ((code & 0x3F) << 3) + ((par1 & 0xE0) >> 5) + 1;
314 cx = (par1 & 0x1F) + 3;
316 if(opos + cx >= oend)
319 for(int i=0;i<cx;i++)
320 *opos++ = *(opos - ax);
325 // 10xxxxxx xyyyzzzz: copy (Y + 3) bytes from (X + 1); copy Z bytes
326 if ((code >> 6) == 2)
332 ax = ((code & 0x3F) << 1) + (par1 >> 7) + 1;
333 cx = ((par1 & 0x70) >> 4) + 3;
336 if(opos + bx + cx >= oend)
340 *opos++ = *(opos - ax);
348 // 11xxxxxx xxxxxxxy yyyyzzzz: copy (Y + 4) from X; copy Z bytes
349 if ((code >> 6) == 3)
356 bx = ((code & 0x3F) << 7) + (par1 >> 1);
357 cx = ((par1 & 0x01) << 4) + (par2 >> 4) + 4;
360 if(opos + ax + cx >= oend)
364 *opos++ = *(opos - bx);
376 long CdmoLoader::dmo_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf,
377 unsigned long outputsize)
380 unsigned short block_count = CHARP_AS_WORD(ibuf);
383 unsigned char *block_length = ibuf;
384 ibuf += 2 * block_count;
386 oend = obuf + outputsize;
388 for (int i=0;i<block_count;i++)
390 unsigned short bul = CHARP_AS_WORD(ibuf);
392 if(unpack_block(ibuf + 2,CHARP_AS_WORD(block_length) - 2,obuf) != bul)
398 ibuf += CHARP_AS_WORD(block_length);