~ubuntu-branches/ubuntu/quantal/gst-plugins-bad-multiverse0.10/quantal

« back to all changes in this revision

Viewing changes to gst/modplug/libmodplug/load_dmf.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2009-03-12 22:01:41 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20090312220141-glnhvwf1g52g91xq
Tags: 0.10.10.2-1ubuntu1
New upstream release.

Show diffs side-by-side

added added

removed removed

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