Mercurial > audlegacy-plugins
comparison src/modplug/load_dmf.cxx @ 136:6b5a52635b3b trunk
[svn] - like with so many other things, modplug is now maintained by us.
author | nenolod |
---|---|
date | Sun, 29 Oct 2006 01:04:52 -0700 |
parents | |
children | 032053ca08ab 3673c7ec4ea2 |
comparison
equal
deleted
inserted
replaced
135:33d24bd94ccc | 136:6b5a52635b3b |
---|---|
1 /* | |
2 * This source code is public domain. | |
3 * | |
4 * Authors: Olivier Lapicque <olivierl@jps.net> | |
5 */ | |
6 | |
7 /////////////////////////////////////////////////////// | |
8 // DMF DELUSION DIGITAL MUSIC FILEFORMAT (X-Tracker) // | |
9 /////////////////////////////////////////////////////// | |
10 #include "stdafx.h" | |
11 #include "sndfile.h" | |
12 | |
13 //#define DMFLOG | |
14 | |
15 //#pragma warning(disable:4244) | |
16 | |
17 #pragma pack(1) | |
18 | |
19 typedef struct DMFHEADER | |
20 { | |
21 DWORD id; // "DDMF" = 0x464d4444 | |
22 BYTE version; // 4 | |
23 CHAR trackername[8]; // "XTRACKER" | |
24 CHAR songname[30]; | |
25 CHAR composer[20]; | |
26 BYTE date[3]; | |
27 } DMFHEADER; | |
28 | |
29 typedef struct DMFINFO | |
30 { | |
31 DWORD id; // "INFO" | |
32 DWORD infosize; | |
33 } DMFINFO; | |
34 | |
35 typedef struct DMFSEQU | |
36 { | |
37 DWORD id; // "SEQU" | |
38 DWORD seqsize; | |
39 WORD loopstart; | |
40 WORD loopend; | |
41 WORD sequ[2]; | |
42 } DMFSEQU; | |
43 | |
44 typedef struct DMFPATT | |
45 { | |
46 DWORD id; // "PATT" | |
47 DWORD patsize; | |
48 WORD numpat; // 1-1024 | |
49 BYTE tracks; | |
50 BYTE firstpatinfo; | |
51 } DMFPATT; | |
52 | |
53 typedef struct DMFTRACK | |
54 { | |
55 BYTE tracks; | |
56 BYTE beat; // [hi|lo] -> hi=ticks per beat, lo=beats per measure | |
57 WORD ticks; // max 512 | |
58 DWORD jmpsize; | |
59 } DMFTRACK; | |
60 | |
61 typedef struct DMFSMPI | |
62 { | |
63 DWORD id; | |
64 DWORD size; | |
65 BYTE samples; | |
66 } DMFSMPI; | |
67 | |
68 typedef struct DMFSAMPLE | |
69 { | |
70 DWORD len; | |
71 DWORD loopstart; | |
72 DWORD loopend; | |
73 WORD c3speed; | |
74 BYTE volume; | |
75 BYTE flags; | |
76 } DMFSAMPLE; | |
77 | |
78 #pragma pack() | |
79 | |
80 | |
81 #ifdef DMFLOG | |
82 extern void Log(LPCSTR s, ...); | |
83 #endif | |
84 | |
85 | |
86 BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength) | |
87 //--------------------------------------------------------------- | |
88 { | |
89 DMFHEADER *pfh = (DMFHEADER *)lpStream; | |
90 DMFINFO *psi; | |
91 DMFSEQU *sequ; | |
92 DWORD dwMemPos; | |
93 BYTE infobyte[32]; | |
94 BYTE smplflags[MAX_SAMPLES]; | |
95 | |
96 if ((!lpStream) || (dwMemLength < 1024)) return FALSE; | |
97 if ((pfh->id != 0x464d4444) || (!pfh->version) || (pfh->version & 0xF0)) return FALSE; | |
98 dwMemPos = 66; | |
99 memcpy(m_szNames[0], pfh->songname, 30); | |
100 m_szNames[0][30] = 0; | |
101 m_nType = MOD_TYPE_DMF; | |
102 m_nChannels = 0; | |
103 #ifdef DMFLOG | |
104 Log("DMF version %d: \"%s\": %d bytes (0x%04X)\n", pfh->version, m_szNames[0], dwMemLength, dwMemLength); | |
105 #endif | |
106 while (dwMemPos + 7 < dwMemLength) | |
107 { | |
108 DWORD id = *((LPDWORD)(lpStream+dwMemPos)); | |
109 | |
110 switch(id) | |
111 { | |
112 // "INFO" | |
113 case 0x4f464e49: | |
114 // "CMSG" | |
115 case 0x47534d43: | |
116 psi = (DMFINFO *)(lpStream+dwMemPos); | |
117 if (id == 0x47534d43) dwMemPos++; | |
118 if ((psi->infosize > dwMemLength) || (psi->infosize + dwMemPos + 8 > dwMemLength)) goto dmfexit; | |
119 if ((psi->infosize >= 8) && (!m_lpszSongComments)) | |
120 { | |
121 m_lpszSongComments = new char[psi->infosize]; // changed from CHAR | |
122 if (m_lpszSongComments) | |
123 { | |
124 for (UINT i=0; i<psi->infosize-1; i++) | |
125 { | |
126 CHAR c = lpStream[dwMemPos+8+i]; | |
127 if ((i % 40) == 39) | |
128 m_lpszSongComments[i] = 0x0d; | |
129 else | |
130 m_lpszSongComments[i] = (c < ' ') ? ' ' : c; | |
131 } | |
132 m_lpszSongComments[psi->infosize-1] = 0; | |
133 } | |
134 } | |
135 dwMemPos += psi->infosize + 8 - 1; | |
136 break; | |
137 | |
138 // "SEQU" | |
139 case 0x55514553: | |
140 sequ = (DMFSEQU *)(lpStream+dwMemPos); | |
141 if ((sequ->seqsize >= dwMemLength) || (dwMemPos + sequ->seqsize + 12 > dwMemLength)) goto dmfexit; | |
142 { | |
143 UINT nseq = sequ->seqsize >> 1; | |
144 if (nseq >= MAX_ORDERS-1) nseq = MAX_ORDERS-1; | |
145 if (sequ->loopstart < nseq) m_nRestartPos = sequ->loopstart; | |
146 for (UINT i=0; i<nseq; i++) Order[i] = (BYTE)sequ->sequ[i]; | |
147 } | |
148 dwMemPos += sequ->seqsize + 8; | |
149 break; | |
150 | |
151 // "PATT" | |
152 case 0x54544150: | |
153 if (!m_nChannels) | |
154 { | |
155 DMFPATT *patt = (DMFPATT *)(lpStream+dwMemPos); | |
156 UINT numpat; | |
157 DWORD dwPos = dwMemPos + 11; | |
158 if ((patt->patsize >= dwMemLength) || (dwMemPos + patt->patsize + 8 > dwMemLength)) goto dmfexit; | |
159 numpat = patt->numpat; | |
160 if (numpat > MAX_PATTERNS) numpat = MAX_PATTERNS; | |
161 m_nChannels = patt->tracks; | |
162 if (m_nChannels < patt->firstpatinfo) m_nChannels = patt->firstpatinfo; | |
163 if (m_nChannels > 32) m_nChannels = 32; | |
164 if (m_nChannels < 4) m_nChannels = 4; | |
165 for (UINT npat=0; npat<numpat; npat++) | |
166 { | |
167 DMFTRACK *pt = (DMFTRACK *)(lpStream+dwPos); | |
168 #ifdef DMFLOG | |
169 Log("Pattern #%d: %d tracks, %d rows\n", npat, pt->tracks, pt->ticks); | |
170 #endif | |
171 UINT tracks = pt->tracks; | |
172 if (tracks > 32) tracks = 32; | |
173 UINT ticks = pt->ticks; | |
174 if (ticks > 256) ticks = 256; | |
175 if (ticks < 16) ticks = 16; | |
176 dwPos += 8; | |
177 if ((pt->jmpsize >= dwMemLength) || (dwPos + pt->jmpsize + 4 >= dwMemLength)) break; | |
178 PatternSize[npat] = (WORD)ticks; | |
179 MODCOMMAND *m = AllocatePattern(PatternSize[npat], m_nChannels); | |
180 if (!m) goto dmfexit; | |
181 Patterns[npat] = m; | |
182 DWORD d = dwPos; | |
183 dwPos += pt->jmpsize; | |
184 UINT ttype = 1; | |
185 UINT tempo = 125; | |
186 UINT glbinfobyte = 0; | |
187 UINT pbeat = (pt->beat & 0xf0) ? pt->beat>>4 : 8; | |
188 BOOL tempochange = (pt->beat & 0xf0) ? TRUE : FALSE; | |
189 memset(infobyte, 0, sizeof(infobyte)); | |
190 for (UINT row=0; row<ticks; row++) | |
191 { | |
192 MODCOMMAND *p = &m[row*m_nChannels]; | |
193 // Parse track global effects | |
194 if (!glbinfobyte) | |
195 { | |
196 BYTE info = lpStream[d++]; | |
197 BYTE infoval = 0; | |
198 if ((info & 0x80) && (d < dwPos)) glbinfobyte = lpStream[d++]; | |
199 info &= 0x7f; | |
200 if ((info) && (d < dwPos)) infoval = lpStream[d++]; | |
201 switch(info) | |
202 { | |
203 case 1: ttype = 0; tempo = infoval; tempochange = TRUE; break; | |
204 case 2: ttype = 1; tempo = infoval; tempochange = TRUE; break; | |
205 case 3: pbeat = infoval>>4; tempochange = ttype; break; | |
206 #ifdef DMFLOG | |
207 default: if (info) Log("GLB: %02X.%02X\n", info, infoval); | |
208 #endif | |
209 } | |
210 } else | |
211 { | |
212 glbinfobyte--; | |
213 } | |
214 // Parse channels | |
215 for (UINT i=0; i<tracks; i++) if (!infobyte[i]) | |
216 { | |
217 MODCOMMAND cmd = {0,0,0,0,0,0}; | |
218 BYTE info = lpStream[d++]; | |
219 if (info & 0x80) infobyte[i] = lpStream[d++]; | |
220 // Instrument | |
221 if (info & 0x40) | |
222 { | |
223 cmd.instr = lpStream[d++]; | |
224 } | |
225 // Note | |
226 if (info & 0x20) | |
227 { | |
228 cmd.note = lpStream[d++]; | |
229 if ((cmd.note) && (cmd.note < 0xfe)) cmd.note &= 0x7f; | |
230 if ((cmd.note) && (cmd.note < 128)) cmd.note += 24; | |
231 } | |
232 // Volume | |
233 if (info & 0x10) | |
234 { | |
235 cmd.volcmd = VOLCMD_VOLUME; | |
236 cmd.vol = (lpStream[d++]+3)>>2; | |
237 } | |
238 // Effect 1 | |
239 if (info & 0x08) | |
240 { | |
241 BYTE efx = lpStream[d++]; | |
242 BYTE eval = lpStream[d++]; | |
243 switch(efx) | |
244 { | |
245 // 1: Key Off | |
246 case 1: if (!cmd.note) cmd.note = 0xFE; break; | |
247 // 2: Set Loop | |
248 // 4: Sample Delay | |
249 case 4: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break; | |
250 // 5: Retrig | |
251 case 5: if (eval&0xe0) { cmd.command = CMD_RETRIG; cmd.param = (eval>>5); } break; | |
252 // 6: Offset | |
253 case 6: cmd.command = CMD_OFFSET; cmd.param = eval; break; | |
254 #ifdef DMFLOG | |
255 default: Log("FX1: %02X.%02X\n", efx, eval); | |
256 #endif | |
257 } | |
258 } | |
259 // Effect 2 | |
260 if (info & 0x04) | |
261 { | |
262 BYTE efx = lpStream[d++]; | |
263 BYTE eval = lpStream[d++]; | |
264 switch(efx) | |
265 { | |
266 // 1: Finetune | |
267 case 1: if (eval&0xf0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>4)|0x20; } break; | |
268 // 2: Note Delay | |
269 case 2: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break; | |
270 // 3: Arpeggio | |
271 case 3: if (eval) { cmd.command = CMD_ARPEGGIO; cmd.param = eval; } break; | |
272 // 4: Portamento Up | |
273 case 4: cmd.command = CMD_PORTAMENTOUP; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break; | |
274 // 5: Portamento Down | |
275 case 5: cmd.command = CMD_PORTAMENTODOWN; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break; | |
276 // 6: Tone Portamento | |
277 case 6: cmd.command = CMD_TONEPORTAMENTO; cmd.param = eval; break; | |
278 // 8: Vibrato | |
279 case 8: cmd.command = CMD_VIBRATO; cmd.param = eval; break; | |
280 // 12: Note cut | |
281 case 12: if (eval & 0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xc0; } | |
282 else if (!cmd.note) { cmd.note = 0xfe; } break; | |
283 #ifdef DMFLOG | |
284 default: Log("FX2: %02X.%02X\n", efx, eval); | |
285 #endif | |
286 } | |
287 } | |
288 // Effect 3 | |
289 if (info & 0x02) | |
290 { | |
291 BYTE efx = lpStream[d++]; | |
292 BYTE eval = lpStream[d++]; | |
293 switch(efx) | |
294 { | |
295 // 1: Vol Slide Up | |
296 case 1: if (eval == 0xff) break; | |
297 eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f; | |
298 cmd.command = CMD_VOLUMESLIDE; cmd.param = eval<<4; break; | |
299 // 2: Vol Slide Down | |
300 case 2: if (eval == 0xff) break; | |
301 eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f; | |
302 cmd.command = CMD_VOLUMESLIDE; cmd.param = eval; break; | |
303 // 7: Set Pan | |
304 case 7: if (!cmd.volcmd) { cmd.volcmd = VOLCMD_PANNING; cmd.vol = (eval+3)>>2; } | |
305 else { cmd.command = CMD_PANNING8; cmd.param = eval; } break; | |
306 // 8: Pan Slide Left | |
307 case 8: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f; | |
308 cmd.command = CMD_PANNINGSLIDE; cmd.param = eval<<4; break; | |
309 // 9: Pan Slide Right | |
310 case 9: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f; | |
311 cmd.command = CMD_PANNINGSLIDE; cmd.param = eval; break; | |
312 #ifdef DMFLOG | |
313 default: Log("FX3: %02X.%02X\n", efx, eval); | |
314 #endif | |
315 | |
316 } | |
317 } | |
318 // Store effect | |
319 if (i < m_nChannels) p[i] = cmd; | |
320 if (d > dwPos) | |
321 { | |
322 #ifdef DMFLOG | |
323 Log("Unexpected EOP: row=%d\n", row); | |
324 #endif | |
325 break; | |
326 } | |
327 } else | |
328 { | |
329 infobyte[i]--; | |
330 } | |
331 | |
332 // Find free channel for tempo change | |
333 if (tempochange) | |
334 { | |
335 tempochange = FALSE; | |
336 UINT speed=6, modtempo=tempo; | |
337 UINT rpm = ((ttype) && (pbeat)) ? tempo*pbeat : (tempo+1)*15; | |
338 for (speed=30; speed>1; speed--) | |
339 { | |
340 modtempo = rpm*speed/24; | |
341 if (modtempo <= 200) break; | |
342 if ((speed < 6) && (modtempo < 256)) break; | |
343 } | |
344 #ifdef DMFLOG | |
345 Log("Tempo change: ttype=%d pbeat=%d tempo=%3d -> speed=%d tempo=%d\n", | |
346 ttype, pbeat, tempo, speed, modtempo); | |
347 #endif | |
348 for (UINT ich=0; ich<m_nChannels; ich++) if (!p[ich].command) | |
349 { | |
350 if (speed) | |
351 { | |
352 p[ich].command = CMD_SPEED; | |
353 p[ich].param = (BYTE)speed; | |
354 speed = 0; | |
355 } else | |
356 if ((modtempo >= 32) && (modtempo < 256)) | |
357 { | |
358 p[ich].command = CMD_TEMPO; | |
359 p[ich].param = (BYTE)modtempo; | |
360 modtempo = 0; | |
361 } else | |
362 { | |
363 break; | |
364 } | |
365 } | |
366 } | |
367 if (d >= dwPos) break; | |
368 } | |
369 #ifdef DMFLOG | |
370 Log(" %d/%d bytes remaining\n", dwPos-d, pt->jmpsize); | |
371 #endif | |
372 if (dwPos + 8 >= dwMemLength) break; | |
373 } | |
374 dwMemPos += patt->patsize + 8; | |
375 } | |
376 break; | |
377 | |
378 // "SMPI": Sample Info | |
379 case 0x49504d53: | |
380 { | |
381 DMFSMPI *pds = (DMFSMPI *)(lpStream+dwMemPos); | |
382 if (pds->size <= dwMemLength - dwMemPos) | |
383 { | |
384 DWORD dwPos = dwMemPos + 9; | |
385 m_nSamples = pds->samples; | |
386 if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1; | |
387 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) | |
388 { | |
389 UINT namelen = lpStream[dwPos]; | |
390 smplflags[iSmp] = 0; | |
391 if (dwPos+namelen+1+sizeof(DMFSAMPLE) > dwMemPos+pds->size+8) break; | |
392 if (namelen) | |
393 { | |
394 UINT rlen = (namelen < 32) ? namelen : 31; | |
395 memcpy(m_szNames[iSmp], lpStream+dwPos+1, rlen); | |
396 m_szNames[iSmp][rlen] = 0; | |
397 } | |
398 dwPos += namelen + 1; | |
399 DMFSAMPLE *psh = (DMFSAMPLE *)(lpStream+dwPos); | |
400 MODINSTRUMENT *psmp = &Ins[iSmp]; | |
401 psmp->nLength = psh->len; | |
402 psmp->nLoopStart = psh->loopstart; | |
403 psmp->nLoopEnd = psh->loopend; | |
404 psmp->nC4Speed = psh->c3speed; | |
405 psmp->nGlobalVol = 64; | |
406 psmp->nVolume = (psh->volume) ? ((WORD)psh->volume)+1 : (WORD)256; | |
407 psmp->uFlags = (psh->flags & 2) ? CHN_16BIT : 0; | |
408 if (psmp->uFlags & CHN_16BIT) psmp->nLength >>= 1; | |
409 if (psh->flags & 1) psmp->uFlags |= CHN_LOOP; | |
410 smplflags[iSmp] = psh->flags; | |
411 dwPos += (pfh->version < 8) ? 22 : 30; | |
412 #ifdef DMFLOG | |
413 Log("SMPI %d/%d: len=%d flags=0x%02X\n", iSmp, m_nSamples, psmp->nLength, psh->flags); | |
414 #endif | |
415 } | |
416 } | |
417 dwMemPos += pds->size + 8; | |
418 } | |
419 break; | |
420 | |
421 // "SMPD": Sample Data | |
422 case 0x44504d53: | |
423 { | |
424 DWORD dwPos = dwMemPos + 8; | |
425 UINT ismpd = 0; | |
426 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) | |
427 { | |
428 ismpd++; | |
429 DWORD pksize; | |
430 if (dwPos + 4 >= dwMemLength) | |
431 { | |
432 #ifdef DMFLOG | |
433 Log("Unexpected EOF at sample %d/%d! (pos=%d)\n", iSmp, m_nSamples, dwPos); | |
434 #endif | |
435 break; | |
436 } | |
437 pksize = *((LPDWORD)(lpStream+dwPos)); | |
438 #ifdef DMFLOG | |
439 Log("sample %d: pos=0x%X pksize=%d ", iSmp, dwPos, pksize); | |
440 Log("len=%d flags=0x%X [%08X]\n", Ins[iSmp].nLength, smplflags[ismpd], *((LPDWORD)(lpStream+dwPos+4))); | |
441 #endif | |
442 dwPos += 4; | |
443 if (pksize > dwMemLength - dwPos) | |
444 { | |
445 #ifdef DMFLOG | |
446 Log("WARNING: pksize=%d, but only %d bytes left\n", pksize, dwMemLength-dwPos); | |
447 #endif | |
448 pksize = dwMemLength - dwPos; | |
449 } | |
450 if ((pksize) && (iSmp <= m_nSamples)) | |
451 { | |
452 UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; | |
453 if (smplflags[ismpd] & 4) flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_DMF16 : RS_DMF8; | |
454 ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwPos), pksize); | |
455 } | |
456 dwPos += pksize; | |
457 } | |
458 dwMemPos = dwPos; | |
459 } | |
460 break; | |
461 | |
462 // "ENDE": end of file | |
463 case 0x45444e45: | |
464 goto dmfexit; | |
465 | |
466 // Unrecognized id, or "ENDE" field | |
467 default: | |
468 dwMemPos += 4; | |
469 break; | |
470 } | |
471 } | |
472 dmfexit: | |
473 if (!m_nChannels) | |
474 { | |
475 if (!m_nSamples) | |
476 { | |
477 m_nType = MOD_TYPE_NONE; | |
478 return FALSE; | |
479 } | |
480 m_nChannels = 4; | |
481 } | |
482 return TRUE; | |
483 } | |
484 | |
485 | |
486 /////////////////////////////////////////////////////////////////////// | |
487 // DMF Compression | |
488 | |
489 #pragma pack(1) | |
490 | |
491 typedef struct DMF_HNODE | |
492 { | |
493 short int left, right; | |
494 BYTE value; | |
495 } DMF_HNODE; | |
496 | |
497 typedef struct DMF_HTREE | |
498 { | |
499 LPBYTE ibuf, ibufmax; | |
500 DWORD bitbuf; | |
501 UINT bitnum; | |
502 UINT lastnode, nodecount; | |
503 DMF_HNODE nodes[256]; | |
504 } DMF_HTREE; | |
505 | |
506 #pragma pack() | |
507 | |
508 | |
509 // DMF Huffman ReadBits | |
510 BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits) | |
511 //------------------------------------------- | |
512 { | |
513 BYTE x = 0, bitv = 1; | |
514 while (nbits--) | |
515 { | |
516 if (tree->bitnum) | |
517 { | |
518 tree->bitnum--; | |
519 } else | |
520 { | |
521 tree->bitbuf = (tree->ibuf < tree->ibufmax) ? *(tree->ibuf++) : 0; | |
522 tree->bitnum = 7; | |
523 } | |
524 if (tree->bitbuf & 1) x |= bitv; | |
525 bitv <<= 1; | |
526 tree->bitbuf >>= 1; | |
527 } | |
528 return x; | |
529 } | |
530 | |
531 // | |
532 // tree: [8-bit value][12-bit index][12-bit index] = 32-bit | |
533 // | |
534 | |
535 void DMFNewNode(DMF_HTREE *tree) | |
536 //------------------------------ | |
537 { | |
538 BYTE isleft, isright; | |
539 UINT actnode; | |
540 | |
541 actnode = tree->nodecount; | |
542 if (actnode > 255) return; | |
543 tree->nodes[actnode].value = DMFReadBits(tree, 7); | |
544 isleft = DMFReadBits(tree, 1); | |
545 isright = DMFReadBits(tree, 1); | |
546 actnode = tree->lastnode; | |
547 if (actnode > 255) return; | |
548 tree->nodecount++; | |
549 tree->lastnode = tree->nodecount; | |
550 if (isleft) | |
551 { | |
552 tree->nodes[actnode].left = tree->lastnode; | |
553 DMFNewNode(tree); | |
554 } else | |
555 { | |
556 tree->nodes[actnode].left = -1; | |
557 } | |
558 tree->lastnode = tree->nodecount; | |
559 if (isright) | |
560 { | |
561 tree->nodes[actnode].right = tree->lastnode; | |
562 DMFNewNode(tree); | |
563 } else | |
564 { | |
565 tree->nodes[actnode].right = -1; | |
566 } | |
567 } | |
568 | |
569 | |
570 int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen) | |
571 //---------------------------------------------------------------------- | |
572 { | |
573 DMF_HTREE tree; | |
574 UINT actnode; | |
575 BYTE value, sign, delta = 0; | |
576 | |
577 memset(&tree, 0, sizeof(tree)); | |
578 tree.ibuf = ibuf; | |
579 tree.ibufmax = ibufmax; | |
580 DMFNewNode(&tree); | |
581 value = 0; | |
582 for (UINT i=0; i<maxlen; i++) | |
583 { | |
584 actnode = 0; | |
585 sign = DMFReadBits(&tree, 1); | |
586 do | |
587 { | |
588 if (DMFReadBits(&tree, 1)) | |
589 actnode = tree.nodes[actnode].right; | |
590 else | |
591 actnode = tree.nodes[actnode].left; | |
592 if (actnode > 255) break; | |
593 delta = tree.nodes[actnode].value; | |
594 if ((tree.ibuf >= tree.ibufmax) && (!tree.bitnum)) break; | |
595 } while ((tree.nodes[actnode].left >= 0) && (tree.nodes[actnode].right >= 0)); | |
596 if (sign) delta ^= 0xFF; | |
597 value += delta; | |
598 psample[i] = (i) ? value : 0; | |
599 } | |
600 #ifdef DMFLOG | |
601 // Log("DMFUnpack: %d remaining bytes\n", tree.ibufmax-tree.ibuf); | |
602 #endif | |
603 return tree.ibuf - ibuf; | |
604 } | |
605 | |
606 |