]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/adplug/src/dmo.cpp
wwww~
[16.git] / 16 / adplug / adplug / src / dmo.cpp
1 /*
2   Adplug - Replayer for many OPL2/OPL3 audio file formats.
3   Copyright (C) 1999 - 2004, 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
4
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.
9
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.
14
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
18
19   dmo.cpp - TwinTeam loader by Riven the Mage <riven@ok.ru>
20 */
21 /*
22   NOTES:
23   Panning is ignored.
24
25   A WORD ist 16 bits, a DWORD is 32 bits and a BYTE is 8 bits in this context.
26 */
27
28 #include <string.h>
29 #include <binstr.h>
30
31 #include "dmo.h"
32 #include "debug.h"
33
34 #define LOWORD(l) ((l) & 0xffff)
35 #define HIWORD(l) ((l) >> 16)
36 #define LOBYTE(w) ((w) & 0xff)
37 #define HIBYTE(w) ((w) >> 8)
38
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])
42
43 #define CHARP_AS_WORD(p)        (((*(p + 1)) << 8) + (*p))
44
45 /* -------- Public Methods -------------------------------- */
46
47 CPlayer *CdmoLoader::factory(Copl *newopl)
48 {
49   return new CdmoLoader(newopl);
50 }
51
52 bool CdmoLoader::load(const std::string &filename, const CFileProvider &fp)
53 {
54   int i,j;
55   binistream *f;
56
57   // check header
58   dmo_unpacker *unpacker = new dmo_unpacker;
59   unsigned char chkhdr[16];
60
61   if(!fp.extension(filename, ".dmo")) return false;
62   f = fp.open(filename); if(!f) return false;
63
64   f->readString((char *)chkhdr, 16);
65
66   if (!unpacker->decrypt(chkhdr, 16))
67     {
68       delete unpacker;
69       fp.close(f);
70       return false;
71     }
72
73   // get file size
74   long packed_length = fp.filesize(f);
75   f->seek(0);
76
77   unsigned char *packed_module = new unsigned char [packed_length];
78
79   // load file
80   f->readString((char *)packed_module, packed_length);
81   fp.close(f);
82
83   // decrypt
84   unpacker->decrypt(packed_module,packed_length);
85
86   long unpacked_length = 0x2000 * ARRAY_AS_WORD(packed_module, 12);
87   unsigned char *module = new unsigned char [unpacked_length];
88
89   // unpack
90   if (!unpacker->unpack(packed_module+12,module,unpacked_length))
91     {
92       delete unpacker;
93       delete [] packed_module;
94       delete [] module;
95       return false;
96     }
97
98   delete unpacker;
99   delete [] packed_module;
100
101   // "TwinTeam" - signed ?
102   if (memcmp(module,"TwinTeam Module File""\x0D\x0A",22))
103     {
104       delete module;
105       return false;
106     }
107
108   // load header
109   binisstream   uf(module, unpacked_length);
110   uf.setFlag(binio::BigEndian, false); uf.setFlag(binio::FloatIEEE);
111
112   memset(&header,0,sizeof(s3mheader));
113
114   uf.ignore(22);                                // ignore DMO header ID string
115   uf.readString(header.name, 28);
116
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);
124
125   memset(header.chanset,0xFF,32);
126
127   for (i=0;i<9;i++)
128     header.chanset[i] = 0x10 + i;
129
130   uf.ignore(32);                                // ignore panning settings for all 32 channels
131
132   // load orders
133   for(i = 0; i < 256; i++) orders[i] = uf.readInt(1);
134
135   orders[header.ordnum] = 0xFF;
136
137   // load pattern lengths
138   unsigned short my_patlen[100];
139   for(i = 0; i < 100; i++) my_patlen[i] = uf.readInt(2);
140
141   // load instruments
142   for (i = 0; i < header.insnum; i++)
143     {
144       memset(&inst[i],0,sizeof(s3minst));
145
146       uf.readString(inst[i].name, 28);
147
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);
163       /*
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.
166        */
167       inst[i].d0b    = uf.readInt(1);
168     }
169
170   // load patterns
171   for (i = 0; i < header.patnum; i++) {
172     long cur_pos = uf.pos();
173
174     for (j = 0; j < 64; j++) {
175       while (1) {
176         unsigned char token = uf.readInt(1);
177
178         if (!token)
179           break;
180
181         unsigned char chan = token & 31;
182
183         // note + instrument ?
184         if (token & 32) {
185           unsigned char bufbyte = uf.readInt(1);
186
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);
190         }
191
192         // volume ?
193         if (token & 64)
194           pattern[i][j][chan].volume = uf.readInt(1);
195
196         // command ?
197         if (token & 128) {
198           pattern[i][j][chan].command = uf.readInt(1);
199           pattern[i][j][chan].info = uf.readInt(1);
200         }
201       }
202     }
203
204     uf.seek(cur_pos + my_patlen[i]);
205   }
206
207   delete [] module;
208   rewind(0);
209   return true;
210 }
211
212 std::string CdmoLoader::gettype()
213 {
214   return std::string("TwinTeam (packed S3M)");
215 }
216
217 std::string CdmoLoader::getauthor()
218 {
219   /*
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
222     never(?) be another.
223   */
224   return std::string("Benjamin GERARDIN");
225 }
226
227 /* -------- Private Methods ------------------------------- */
228
229 unsigned short CdmoLoader::dmo_unpacker::brand(unsigned short range)
230 {
231   unsigned short ax,bx,cx,dx;
232
233   ax = LOWORD(bseed);
234   bx = HIWORD(bseed);
235   cx = ax;
236   ax = LOWORD(cx * 0x8405);
237   dx = HIWORD(cx * 0x8405);
238   cx <<= 3;
239   cx = (((HIBYTE(cx) + LOBYTE(cx)) & 0xFF) << 8) + LOBYTE(cx);
240   dx += cx;
241   dx += bx;
242   bx <<= 2;
243   dx += bx;
244   dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx);
245   bx <<= 5;
246   dx = (((HIBYTE(dx) + LOBYTE(bx)) & 0xFF) << 8) + LOBYTE(dx);
247   ax += 1;
248   if (!ax) dx += 1;
249
250   // leave it that way or amd64 might get it wrong
251   bseed = dx;
252   bseed <<= 16;
253   bseed += ax;
254
255   return HIWORD(HIWORD(LOWORD(bseed) * range) + HIWORD(bseed) * range);
256 }
257
258 bool CdmoLoader::dmo_unpacker::decrypt(unsigned char *buf, long len)
259 {
260   unsigned long seed = 0;
261   int i;
262
263   bseed = ARRAY_AS_DWORD(buf, 0);
264
265   for (i=0; i < ARRAY_AS_WORD(buf, 4) + 1; i++)
266     seed += brand(0xffff);
267
268   bseed = seed ^ ARRAY_AS_DWORD(buf, 6);
269
270   if (ARRAY_AS_WORD(buf, 10) != brand(0xffff))
271     return false;
272
273   for (i=0;i<(len-12);i++)
274     buf[12+i] ^= brand(0x100);
275
276   buf[len - 2] = buf[len - 1] = 0;
277
278   return true;
279 }
280
281 short CdmoLoader::dmo_unpacker::unpack_block(unsigned char *ibuf, long ilen, unsigned char *obuf)
282 {
283   unsigned char code,par1,par2;
284   unsigned short ax,bx,cx;
285
286   unsigned char *ipos = ibuf;
287   unsigned char *opos = obuf;
288
289   // LZ77 child
290   while (ipos - ibuf < ilen)
291     {
292       code = *ipos++;
293
294       // 00xxxxxx: copy (xxxxxx + 1) bytes
295       if ((code >> 6) == 0)
296         {
297           cx = (code & 0x3F) + 1;
298
299           if(opos + cx >= oend)
300             return -1;
301
302           for (int i=0;i<cx;i++)
303             *opos++ = *ipos++;
304
305           continue;
306         }
307
308       // 01xxxxxx xxxyyyyy: copy (Y + 3) bytes from (X + 1)
309       if ((code >> 6) == 1)
310         {
311           par1 = *ipos++;
312
313           ax = ((code & 0x3F) << 3) + ((par1 & 0xE0) >> 5) + 1;
314           cx = (par1 & 0x1F) + 3;
315
316           if(opos + cx >= oend)
317             return -1;
318
319           for(int i=0;i<cx;i++)
320             *opos++ = *(opos - ax);
321
322           continue;
323         }
324
325       // 10xxxxxx xyyyzzzz: copy (Y + 3) bytes from (X + 1); copy Z bytes
326       if ((code >> 6) == 2)
327         {
328           int i;
329
330           par1 = *ipos++;
331
332           ax = ((code & 0x3F) << 1) + (par1 >> 7) + 1;
333           cx = ((par1 & 0x70) >> 4) + 3;
334           bx = par1 & 0x0F;
335
336           if(opos + bx + cx >= oend)
337             return -1;
338
339           for(i=0;i<cx;i++)
340             *opos++ = *(opos - ax);
341
342           for (i=0;i<bx;i++)
343             *opos++ = *ipos++;
344
345           continue;
346         }
347
348       // 11xxxxxx xxxxxxxy yyyyzzzz: copy (Y + 4) from X; copy Z bytes
349       if ((code >> 6) == 3)
350         {
351           int i;
352
353           par1 = *ipos++;
354           par2 = *ipos++;
355
356           bx = ((code & 0x3F) << 7) + (par1 >> 1);
357           cx = ((par1 & 0x01) << 4) + (par2 >> 4) + 4;
358           ax = par2 & 0x0F;
359
360           if(opos + ax + cx >= oend)
361             return -1;
362
363           for(i=0;i<cx;i++)
364             *opos++ = *(opos - bx);
365
366           for (i=0;i<ax;i++)
367             *opos++ = *ipos++;
368
369           continue;
370         }
371     }
372
373   return opos - obuf;
374 }
375
376 long CdmoLoader::dmo_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf,
377                                       unsigned long outputsize)
378 {
379   long                  olen = 0;
380   unsigned short        block_count = CHARP_AS_WORD(ibuf);
381
382   ibuf += 2;
383   unsigned char *block_length = ibuf;
384   ibuf += 2 * block_count;
385
386   oend = obuf + outputsize;
387
388   for (int i=0;i<block_count;i++)
389     {
390       unsigned short bul = CHARP_AS_WORD(ibuf);
391
392       if(unpack_block(ibuf + 2,CHARP_AS_WORD(block_length) - 2,obuf) != bul)
393         return 0;
394
395       obuf += bul;
396       olen += bul;
397
398       ibuf += CHARP_AS_WORD(block_length);
399       block_length += 2;
400     }
401
402   return olen;
403 }