Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

load_dmf.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is  free software; you can redistribute it  and modify it
00003  * under the terms of the GNU  General Public License as published by the
00004  * Free Software Foundation; either version 2  of the license or (at your
00005  * option) any later version.
00006  *
00007  * Authors: Olivier Lapicque <olivierl@jps.net>
00008 */
00009 
00011 // DMF DELUSION DIGITAL MUSIC FILEFORMAT (X-Tracker) //
00013 #include "stdafx.h"
00014 #include "sndfile.h"
00015 
00016 //#define DMFLOG
00017 
00018 //#pragma warning(disable:4244)
00019 
00020 #pragma pack(1)
00021 
00022 typedef struct DMFHEADER
00023 {
00024         DWORD id;                               // "DDMF" = 0x464d4444
00025         BYTE version;                   // 4
00026         CHAR trackername[8];    // "XTRACKER"
00027         CHAR songname[30];
00028         CHAR composer[20];
00029         BYTE date[3];
00030 } Q_PACKED DMFHEADER;
00031 
00032 typedef struct DMFINFO
00033 {
00034         DWORD id;                       // "INFO"
00035         DWORD infosize;
00036 } Q_PACKED DMFINFO;
00037 
00038 typedef struct DMFSEQU
00039 {
00040         DWORD id;                       // "SEQU"
00041         DWORD seqsize;
00042         WORD loopstart;
00043         WORD loopend;
00044         WORD sequ[2];
00045 } Q_PACKED DMFSEQU;
00046 
00047 typedef struct DMFPATT
00048 {
00049         DWORD id;                       // "PATT"
00050         DWORD patsize;
00051         WORD numpat;            // 1-1024
00052         BYTE tracks;
00053         BYTE firstpatinfo;
00054 } Q_PACKED DMFPATT;
00055 
00056 typedef struct DMFTRACK
00057 {
00058         BYTE tracks;
00059         BYTE beat;              // [hi|lo] -> hi=ticks per beat, lo=beats per measure
00060         WORD ticks;             // max 512
00061         DWORD jmpsize;
00062 } Q_PACKED DMFTRACK;
00063 
00064 typedef struct DMFSMPI
00065 {
00066         DWORD id;
00067         DWORD size;
00068         BYTE samples;
00069 } Q_PACKED DMFSMPI;
00070 
00071 typedef struct DMFSAMPLE
00072 {
00073         DWORD len;
00074         DWORD loopstart;
00075         DWORD loopend;
00076         WORD c3speed;
00077         BYTE volume;
00078         BYTE flags;
00079 } Q_PACKED DMFSAMPLE;
00080 
00081 #pragma pack()
00082 
00083 
00084 #ifdef DMFLOG
00085 extern void Log(LPCSTR s, ...);
00086 #endif
00087 
00088 
00089 BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
00090 //---------------------------------------------------------------
00091 {
00092         DMFHEADER *pfh = (DMFHEADER *)lpStream;
00093         DMFINFO *psi;
00094         DMFSEQU *sequ;
00095         DWORD dwMemPos;
00096         BYTE infobyte[32];
00097         BYTE smplflags[MAX_SAMPLES];
00098 
00099         if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
00100         if ((pfh->id != 0x464d4444) || (!pfh->version) || (pfh->version & 0xF0)) return FALSE;
00101         dwMemPos = 66;
00102         memcpy(m_szNames[0], pfh->songname, 30);
00103         m_szNames[0][30] = 0;
00104         m_nType = MOD_TYPE_DMF;
00105         m_nChannels = 0;
00106 #ifdef DMFLOG
00107         Log("DMF version %d: \"%s\": %d bytes (0x%04X)\n", pfh->version, m_szNames[0], dwMemLength, dwMemLength);
00108 #endif
00109         while (dwMemPos + 7 < dwMemLength)
00110         {
00111                 DWORD id = *((LPDWORD)(lpStream+dwMemPos));
00112 
00113                 switch(id)
00114                 {
00115                 // "INFO"
00116                 case 0x4f464e49:
00117                 // "CMSG"
00118                 case 0x47534d43:
00119                         psi = (DMFINFO *)(lpStream+dwMemPos);
00120                         if (id == 0x47534d43) dwMemPos++;
00121                         if ((psi->infosize > dwMemLength) || (psi->infosize + dwMemPos + 8 > dwMemLength)) goto dmfexit;
00122                         if ((psi->infosize >= 8) && (!m_lpszSongComments))
00123                         {
00124                             m_lpszSongComments = new char[psi->infosize]; // changed from CHAR
00125                                 if (m_lpszSongComments)
00126                                 {
00127                                         for (UINT i=0; i<psi->infosize-1; i++)
00128                                         {
00129                                                 CHAR c = lpStream[dwMemPos+8+i];
00130                                                 if ((i % 40) == 39)
00131                                                         m_lpszSongComments[i] = 0x0d;
00132                                                 else
00133                                                         m_lpszSongComments[i] = (c < ' ') ? ' ' : c;
00134                                         }
00135                                         m_lpszSongComments[psi->infosize-1] = 0;
00136                                 }
00137                         }
00138                         dwMemPos += psi->infosize + 8 - 1;
00139                         break;
00140 
00141                 // "SEQU"
00142                 case 0x55514553:
00143                         sequ = (DMFSEQU *)(lpStream+dwMemPos);
00144                         if ((sequ->seqsize >= dwMemLength) || (dwMemPos + sequ->seqsize + 12 > dwMemLength)) goto dmfexit;
00145                         {
00146                                 UINT nseq = sequ->seqsize >> 1;
00147                                 if (nseq >= MAX_ORDERS-1) nseq = MAX_ORDERS-1;
00148                                 if (sequ->loopstart < nseq) m_nRestartPos = sequ->loopstart;
00149                                 for (UINT i=0; i<nseq; i++) Order[i] = (BYTE)sequ->sequ[i];
00150                         }
00151                         dwMemPos += sequ->seqsize + 8;
00152                         break;
00153 
00154                 // "PATT"
00155                 case 0x54544150:
00156                         if (!m_nChannels)
00157                         {
00158                                 DMFPATT *patt = (DMFPATT *)(lpStream+dwMemPos);
00159                                 UINT numpat;
00160                                 DWORD dwPos = dwMemPos + 11;
00161                                 if ((patt->patsize >= dwMemLength) || (dwMemPos + patt->patsize + 8 > dwMemLength)) goto dmfexit;
00162                                 numpat = patt->numpat;
00163                                 if (numpat > MAX_PATTERNS) numpat = MAX_PATTERNS;
00164                                 m_nChannels = patt->tracks;
00165                                 if (m_nChannels < patt->firstpatinfo) m_nChannels = patt->firstpatinfo;
00166                                 if (m_nChannels > 32) m_nChannels = 32;
00167                                 if (m_nChannels < 4) m_nChannels = 4;
00168                                 for (UINT npat=0; npat<numpat; npat++)
00169                                 {
00170                                         DMFTRACK *pt = (DMFTRACK *)(lpStream+dwPos);
00171                                 #ifdef DMFLOG
00172                                         Log("Pattern #%d: %d tracks, %d rows\n", npat, pt->tracks, pt->ticks);
00173                                 #endif
00174                                         UINT tracks = pt->tracks;
00175                                         if (tracks > 32) tracks = 32;
00176                                         UINT ticks = pt->ticks;
00177                                         if (ticks > 256) ticks = 256;
00178                                         if (ticks < 16) ticks = 16;
00179                                         dwPos += 8;
00180                                         if ((pt->jmpsize >= dwMemLength) || (dwPos + pt->jmpsize + 4 >= dwMemLength)) break;
00181                                         PatternSize[npat] = (WORD)ticks;
00182                                         MODCOMMAND *m = AllocatePattern(PatternSize[npat], m_nChannels);
00183                                         if (!m) goto dmfexit;
00184                                         Patterns[npat] = m;
00185                                         DWORD d = dwPos;
00186                                         dwPos += pt->jmpsize;
00187                                         UINT ttype = 1;
00188                                         UINT tempo = 125;
00189                                         UINT glbinfobyte = 0;
00190                                         UINT pbeat = (pt->beat & 0xf0) ? pt->beat>>4 : 8;
00191                                         BOOL tempochange = (pt->beat & 0xf0) ? TRUE : FALSE;
00192                                         memset(infobyte, 0, sizeof(infobyte));
00193                                         for (UINT row=0; row<ticks; row++)
00194                                         {
00195                                                 MODCOMMAND *p = &m[row*m_nChannels];
00196                                                 // Parse track global effects
00197                                                 if (!glbinfobyte)
00198                                                 {
00199                                                         BYTE info = lpStream[d++];
00200                                                         BYTE infoval = 0;
00201                                                         if ((info & 0x80) && (d < dwPos)) glbinfobyte = lpStream[d++];
00202                                                         info &= 0x7f;
00203                                                         if ((info) && (d < dwPos)) infoval = lpStream[d++];
00204                                                         switch(info)
00205                                                         {
00206                                                         case 1: ttype = 0; tempo = infoval; tempochange = TRUE; break;
00207                                                         case 2: ttype = 1; tempo = infoval; tempochange = TRUE; break;
00208                                                         case 3: pbeat = infoval>>4; tempochange = ttype; break;
00209                                                         #ifdef DMFLOG
00210                                                         default: if (info) Log("GLB: %02X.%02X\n", info, infoval);
00211                                                         #endif
00212                                                         }
00213                                                 } else
00214                                                 {
00215                                                         glbinfobyte--;
00216                                                 }
00217                                                 // Parse channels
00218                                                 for (UINT i=0; i<tracks; i++) if (!infobyte[i])
00219                                                 {
00220                                                         MODCOMMAND cmd = {0,0,0,0,0,0};
00221                                                         BYTE info = lpStream[d++];
00222                                                         if (info & 0x80) infobyte[i] = lpStream[d++];
00223                                                         // Instrument
00224                                                         if (info & 0x40)
00225                                                         {
00226                                                                 cmd.instr = lpStream[d++];
00227                                                         }
00228                                                         // Note
00229                                                         if (info & 0x20)
00230                                                         {
00231                                                                 cmd.note = lpStream[d++];
00232                                                                 if ((cmd.note) && (cmd.note < 0xfe)) cmd.note &= 0x7f;
00233                                                                 if ((cmd.note) && (cmd.note < 128)) cmd.note += 24;
00234                                                         }
00235                                                         // Volume
00236                                                         if (info & 0x10)
00237                                                         {
00238                                                                 cmd.volcmd = VOLCMD_VOLUME;
00239                                                                 cmd.vol = (lpStream[d++]+3)>>2;
00240                                                         }
00241                                                         // Effect 1
00242                                                         if (info & 0x08)
00243                                                         {
00244                                                                 BYTE efx = lpStream[d++];
00245                                                                 BYTE eval = lpStream[d++];
00246                                                                 switch(efx)
00247                                                                 {
00248                                                                 // 1: Key Off
00249                                                                 case 1: if (!cmd.note) cmd.note = 0xFE; break;
00250                                                                 // 2: Set Loop
00251                                                                 // 4: Sample Delay
00252                                                                 case 4: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break;
00253                                                                 // 5: Retrig
00254                                                                 case 5: if (eval&0xe0) { cmd.command = CMD_RETRIG; cmd.param = (eval>>5); } break;
00255                                                                 // 6: Offset
00256                                                                 case 6: cmd.command = CMD_OFFSET; cmd.param = eval; break;
00257                                                                 #ifdef DMFLOG
00258                                                                 default: Log("FX1: %02X.%02X\n", efx, eval);
00259                                                                 #endif
00260                                                                 }
00261                                                         }
00262                                                         // Effect 2
00263                                                         if (info & 0x04)
00264                                                         {
00265                                                                 BYTE efx = lpStream[d++];
00266                                                                 BYTE eval = lpStream[d++];
00267                                                                 switch(efx)
00268                                                                 {
00269                                                                 // 1: Finetune
00270                                                                 case 1: if (eval&0xf0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>4)|0x20; } break;
00271                                                                 // 2: Note Delay
00272                                                                 case 2: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break;
00273                                                                 // 3: Arpeggio
00274                                                                 case 3: if (eval) { cmd.command = CMD_ARPEGGIO; cmd.param = eval; } break;
00275                                                                 // 4: Portamento Up
00276                                                                 case 4: cmd.command = CMD_PORTAMENTOUP; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break;
00277                                                                 // 5: Portamento Down
00278                                                                 case 5: cmd.command = CMD_PORTAMENTODOWN; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break;
00279                                                                 // 6: Tone Portamento
00280                                                                 case 6: cmd.command = CMD_TONEPORTAMENTO; cmd.param = eval; break;
00281                                                                 // 8: Vibrato
00282                                                                 case 8: cmd.command = CMD_VIBRATO; cmd.param = eval; break;
00283                                                                 // 12: Note cut
00284                                                                 case 12: if (eval & 0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xc0; }
00285                                                                                 else if (!cmd.note) { cmd.note = 0xfe; } break;
00286                                                                 #ifdef DMFLOG
00287                                                                 default: Log("FX2: %02X.%02X\n", efx, eval);
00288                                                                 #endif
00289                                                                 }
00290                                                         }
00291                                                         // Effect 3
00292                                                         if (info & 0x02)
00293                                                         {
00294                                                                 BYTE efx = lpStream[d++];
00295                                                                 BYTE eval = lpStream[d++];
00296                                                                 switch(efx)
00297                                                                 {
00298                                                                 // 1: Vol Slide Up
00299                                                                 case 1: if (eval == 0xff) break;
00300                                                                                 eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
00301                                                                                 cmd.command = CMD_VOLUMESLIDE; cmd.param = eval<<4; break;
00302                                                                 // 2: Vol Slide Down
00303                                                                 case 2: if (eval == 0xff) break;
00304                                                                                 eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
00305                                                                                 cmd.command = CMD_VOLUMESLIDE; cmd.param = eval; break;
00306                                                                 // 7: Set Pan
00307                                                                 case 7: if (!cmd.volcmd) { cmd.volcmd = VOLCMD_PANNING; cmd.vol = (eval+3)>>2; }
00308                                                                                 else { cmd.command = CMD_PANNING8; cmd.param = eval; } break;
00309                                                                 // 8: Pan Slide Left
00310                                                                 case 8: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
00311                                                                                 cmd.command = CMD_PANNINGSLIDE; cmd.param = eval<<4; break;
00312                                                                 // 9: Pan Slide Right
00313                                                                 case 9: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
00314                                                                                 cmd.command = CMD_PANNINGSLIDE; cmd.param = eval; break;
00315                                                                 #ifdef DMFLOG
00316                                                                 default: Log("FX3: %02X.%02X\n", efx, eval);
00317                                                                 #endif
00318 
00319                                                                 }
00320                                                         }
00321                                                         // Store effect
00322                                                         if (i < m_nChannels) p[i] = cmd;
00323                                                         if (d > dwPos)
00324                                                         {
00325                                                         #ifdef DMFLOG
00326                                                                 Log("Unexpected EOP: row=%d\n", row);
00327                                                         #endif
00328                                                                 break;
00329                                                         }
00330                                                 } else
00331                                                 {
00332                                                         infobyte[i]--;
00333                                                 }
00334 
00335                                                 // Find free channel for tempo change
00336                                                 if (tempochange)
00337                                                 {
00338                                                         tempochange = FALSE;
00339                                                         UINT speed=6, modtempo=tempo;
00340                                                         UINT rpm = ((ttype) && (pbeat)) ? tempo*pbeat : (tempo+1)*15;
00341                                                         for (speed=30; speed>1; speed--)
00342                                                         {
00343                                                                 modtempo = rpm*speed/24;
00344                                                                 if (modtempo <= 200) break;
00345                                                                 if ((speed < 6) && (modtempo < 256)) break;
00346                                                         }
00347                                                 #ifdef DMFLOG
00348                                                         Log("Tempo change: ttype=%d pbeat=%d tempo=%3d -> speed=%d tempo=%d\n",
00349                                                                 ttype, pbeat, tempo, speed, modtempo);
00350                                                 #endif
00351                                                         for (UINT ich=0; ich<m_nChannels; ich++) if (!p[ich].command)
00352                                                         {
00353                                                                 if (speed)
00354                                                                 {
00355                                                                         p[ich].command = CMD_SPEED;
00356                                                                         p[ich].param = (BYTE)speed;
00357                                                                         speed = 0;
00358                                                                 } else
00359                                                                 if ((modtempo >= 32) && (modtempo < 256))
00360                                                                 {
00361                                                                         p[ich].command = CMD_TEMPO;
00362                                                                         p[ich].param = (BYTE)modtempo;
00363                                                                         modtempo = 0;
00364                                                                 } else
00365                                                                 {
00366                                                                         break;
00367                                                                 }
00368                                                         }
00369                                                 }
00370                                                 if (d >= dwPos) break;
00371                                         }
00372                                 #ifdef DMFLOG
00373                                         Log(" %d/%d bytes remaining\n", dwPos-d, pt->jmpsize);
00374                                 #endif
00375                                         if (dwPos + 8 >= dwMemLength) break;
00376                                 }
00377                                 dwMemPos += patt->patsize + 8;
00378                         }
00379                         break;
00380 
00381                 // "SMPI": Sample Info
00382                 case 0x49504d53:
00383                         {
00384                                 DMFSMPI *pds = (DMFSMPI *)(lpStream+dwMemPos);
00385                                 if (pds->size <= dwMemLength - dwMemPos)
00386                                 {
00387                                         DWORD dwPos = dwMemPos + 9;
00388                                         m_nSamples = pds->samples;
00389                                         if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
00390                                         for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
00391                                         {
00392                                                 UINT namelen = lpStream[dwPos];
00393                                                 smplflags[iSmp] = 0;
00394                                                 if (dwPos+namelen+1+sizeof(DMFSAMPLE) > dwMemPos+pds->size+8) break;
00395                                                 if (namelen)
00396                                                 {
00397                                                         UINT rlen = (namelen < 32) ? namelen : 31;
00398                                                         memcpy(m_szNames[iSmp], lpStream+dwPos+1, rlen);
00399                                                         m_szNames[iSmp][rlen] = 0;
00400                                                 }
00401                                                 dwPos += namelen + 1;
00402                                                 DMFSAMPLE *psh = (DMFSAMPLE *)(lpStream+dwPos);
00403                                                 MODINSTRUMENT *psmp = &Ins[iSmp];
00404                                                 psmp->nLength = psh->len;
00405                                                 psmp->nLoopStart = psh->loopstart;
00406                                                 psmp->nLoopEnd = psh->loopend;
00407                                                 psmp->nC4Speed = psh->c3speed;
00408                                                 psmp->nGlobalVol = 64;
00409                                                 psmp->nVolume = (psh->volume) ? ((WORD)psh->volume)+1 : (WORD)256;
00410                                                 psmp->uFlags = (psh->flags & 2) ? CHN_16BIT : 0;
00411                                                 if (psmp->uFlags & CHN_16BIT) psmp->nLength >>= 1;
00412                                                 if (psh->flags & 1) psmp->uFlags |= CHN_LOOP;
00413                                                 smplflags[iSmp] = psh->flags;
00414                                                 dwPos += (pfh->version < 8) ? 22 : 30;
00415                                         #ifdef DMFLOG
00416                                                 Log("SMPI %d/%d: len=%d flags=0x%02X\n", iSmp, m_nSamples, psmp->nLength, psh->flags);
00417                                         #endif
00418                                         }
00419                                 }
00420                                 dwMemPos += pds->size + 8;
00421                         }
00422                         break;
00423 
00424                 // "SMPD": Sample Data
00425                 case 0x44504d53:
00426                         {
00427                                 DWORD dwPos = dwMemPos + 8;
00428                                 UINT ismpd = 0;
00429                                 for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
00430                                 {
00431                                         ismpd++;
00432                                         DWORD pksize;
00433                                         if (dwPos + 4 >= dwMemLength)
00434                                         {
00435                                         #ifdef DMFLOG
00436                                                 Log("Unexpected EOF at sample %d/%d! (pos=%d)\n", iSmp, m_nSamples, dwPos);
00437                                         #endif
00438                                                 break;
00439                                         }
00440                                         pksize = *((LPDWORD)(lpStream+dwPos));
00441                                 #ifdef DMFLOG
00442                                         Log("sample %d: pos=0x%X pksize=%d ", iSmp, dwPos, pksize);
00443                                         Log("len=%d flags=0x%X [%08X]\n", Ins[iSmp].nLength, smplflags[ismpd], *((LPDWORD)(lpStream+dwPos+4)));
00444                                 #endif
00445                                         dwPos += 4;
00446                                         if (pksize > dwMemLength - dwPos)
00447                                         {
00448                                         #ifdef DMFLOG
00449                                                 Log("WARNING: pksize=%d, but only %d bytes left\n", pksize, dwMemLength-dwPos);
00450                                         #endif
00451                                                 pksize = dwMemLength - dwPos;
00452                                         }
00453                                         if ((pksize) && (iSmp <= m_nSamples))
00454                                         {
00455                                                 UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
00456                                                 if (smplflags[ismpd] & 4) flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_DMF16 : RS_DMF8;
00457                                                 ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwPos), pksize);
00458                                         }
00459                                         dwPos += pksize;
00460                                 }
00461                                 dwMemPos = dwPos;
00462                         }
00463                         break;
00464 
00465                 // "ENDE": end of file
00466                 case 0x45444e45:
00467                         goto dmfexit;
00468                 
00469                 // Unrecognized id, or "ENDE" field
00470                 default:
00471                         dwMemPos += 4;
00472                         break;
00473                 }
00474         }
00475 dmfexit:
00476         if (!m_nChannels)
00477         {
00478                 if (!m_nSamples)
00479                 {
00480                         m_nType = MOD_TYPE_NONE;
00481                         return FALSE;
00482                 }
00483                 m_nChannels = 4;
00484         }
00485         return TRUE;
00486 }
00487 
00488 
00490 // DMF Compression
00491 
00492 #pragma pack(1)
00493 
00494 typedef struct DMF_HNODE
00495 {
00496         short int left, right;
00497         BYTE value;
00498 } Q_PACKED DMF_HNODE;
00499 
00500 typedef struct DMF_HTREE
00501 {
00502         LPBYTE ibuf, ibufmax;
00503         DWORD bitbuf;
00504         UINT bitnum;
00505         UINT lastnode, nodecount;
00506         DMF_HNODE nodes[256];
00507 } Q_PACKED DMF_HTREE;
00508 
00509 #pragma pack()
00510 
00511 
00512 // DMF Huffman ReadBits
00513 BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits)
00514 //-------------------------------------------
00515 {
00516         BYTE x = 0, bitv = 1;
00517         while (nbits--)
00518         {
00519                 if (tree->bitnum)
00520                 {
00521                         tree->bitnum--;
00522                 } else
00523                 {
00524                         tree->bitbuf = (tree->ibuf < tree->ibufmax) ? *(tree->ibuf++) : 0;
00525                         tree->bitnum = 7;
00526                 }
00527                 if (tree->bitbuf & 1) x |= bitv;
00528                 bitv <<= 1;
00529                 tree->bitbuf >>= 1;
00530         }
00531         return x;
00532 }
00533 
00534 //
00535 // tree: [8-bit value][12-bit index][12-bit index] = 32-bit
00536 //
00537 
00538 void DMFNewNode(DMF_HTREE *tree)
00539 //------------------------------
00540 {
00541         BYTE isleft, isright;
00542         UINT actnode;
00543 
00544         actnode = tree->nodecount;
00545         if (actnode > 255) return;
00546         tree->nodes[actnode].value = DMFReadBits(tree, 7);
00547         isleft = DMFReadBits(tree, 1);
00548         isright = DMFReadBits(tree, 1);
00549         actnode = tree->lastnode;
00550         if (actnode > 255) return;
00551         tree->nodecount++;
00552         tree->lastnode = tree->nodecount;
00553         if (isleft)
00554         {
00555                 tree->nodes[actnode].left = tree->lastnode;
00556                 DMFNewNode(tree);
00557         } else
00558         {
00559                 tree->nodes[actnode].left = -1;
00560         }
00561         tree->lastnode = tree->nodecount;
00562         if (isright)
00563         {
00564                 tree->nodes[actnode].right = tree->lastnode;
00565                 DMFNewNode(tree);
00566         } else
00567         {
00568                 tree->nodes[actnode].right = -1;
00569         }
00570 }
00571 
00572 
00573 int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen)
00574 //----------------------------------------------------------------------
00575 {
00576         DMF_HTREE tree;
00577         UINT actnode;
00578         BYTE value, sign, delta = 0;
00579         
00580         memset(&tree, 0, sizeof(tree));
00581         tree.ibuf = ibuf;
00582         tree.ibufmax = ibufmax;
00583         DMFNewNode(&tree);
00584         value = 0;
00585         for (UINT i=0; i<maxlen; i++)
00586         {
00587                 actnode = 0;
00588                 sign = DMFReadBits(&tree, 1);
00589                 do
00590                 {
00591                         if (DMFReadBits(&tree, 1))
00592                                 actnode = tree.nodes[actnode].right;
00593                         else
00594                                 actnode = tree.nodes[actnode].left;
00595                         if (actnode > 255) break;
00596                         delta = tree.nodes[actnode].value;
00597                         if ((tree.ibuf >= tree.ibufmax) && (!tree.bitnum)) break;
00598                 } while ((tree.nodes[actnode].left >= 0) && (tree.nodes[actnode].right >= 0));
00599                 if (sign) delta ^= 0xFF;
00600                 value += delta;
00601                 psample[i] = (i) ? value : 0;
00602         }
00603 #ifdef DMFLOG
00604 //      Log("DMFUnpack: %d remaining bytes\n", tree.ibufmax-tree.ibuf);
00605 #endif
00606         return tree.ibuf - ibuf;
00607 }
00608 
00609 

Generated on Sat Nov 5 16:15:38 2005 for OPIE by  doxygen 1.4.2