comparison Plugins/Input/adplug/core/dmo.cpp @ 359:8df427a314a8 trunk

[svn] Adlib synthesizer (AdPlug) support.
author chainsaw
date Fri, 30 Dec 2005 16:31:39 -0800
parents
children eb41901d38f5 0a73d1faeb4e
comparison
equal deleted inserted replaced
358:70075730e187 359:8df427a314a8
1 /*
2 Adplug - Replayer for many OPL2/OPL3 audio file formats.
3 Copyright (C) 1999 - 2004 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))
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 for (int i=0;i<cx;i++)
300 *opos++ = *ipos++;
301
302 continue;
303 }
304
305 // 01xxxxxx xxxyyyyy: copy (Y + 3) bytes from (X + 1)
306 if ((code >> 6) == 1)
307 {
308 par1 = *ipos++;
309
310 ax = ((code & 0x3F) << 3) + ((par1 & 0xE0) >> 5) + 1;
311 cx = (par1 & 0x1F) + 3;
312
313 for(int i=0;i<cx;i++)
314 *opos++ = *(opos - ax);
315
316 continue;
317 }
318
319 // 10xxxxxx xyyyzzzz: copy (Y + 3) bytes from (X + 1); copy Z bytes
320 if ((code >> 6) == 2)
321 {
322 int i;
323
324 par1 = *ipos++;
325
326 ax = ((code & 0x3F) << 1) + (par1 >> 7) + 1;
327 cx = ((par1 & 0x70) >> 4) + 3;
328 bx = par1 & 0x0F;
329
330 for(i=0;i<cx;i++)
331 *opos++ = *(opos - ax);
332
333 for (i=0;i<bx;i++)
334 *opos++ = *ipos++;
335
336 continue;
337 }
338
339 // 11xxxxxx xxxxxxxy yyyyzzzz: copy (Y + 4) from X; copy Z bytes
340 if ((code >> 6) == 3)
341 {
342 int i;
343
344 par1 = *ipos++;
345 par2 = *ipos++;
346
347 bx = ((code & 0x3F) << 7) + (par1 >> 1);
348 cx = ((par1 & 0x01) << 4) + (par2 >> 4) + 4;
349 ax = par2 & 0x0F;
350
351 for(i=0;i<cx;i++)
352 *opos++ = *(opos - bx);
353
354 for (i=0;i<ax;i++)
355 *opos++ = *ipos++;
356
357 continue;
358 }
359 }
360
361 return opos - obuf;
362 }
363
364 long CdmoLoader::dmo_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf)
365 {
366 long olen = 0;
367
368 unsigned short block_count = CHARP_AS_WORD(ibuf);
369
370 ibuf += 2;
371
372 unsigned char *block_length = ibuf;
373
374 ibuf += 2 * block_count;
375
376 for (int i=0;i<block_count;i++)
377 {
378 unsigned short bul = CHARP_AS_WORD(ibuf);
379
380 if (unpack_block(ibuf + 2,CHARP_AS_WORD(block_length) - 2,obuf) != bul)
381 return 0;
382
383 obuf += bul;
384 olen += bul;
385
386 ibuf += CHARP_AS_WORD(block_length);
387 block_length += 2;
388 }
389
390 return olen;
391 }