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