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

load_dbm.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  *          Adam Goode       <adam@evdebs.org> (endian and char fixes for PPC)
00009 */
00010 
00012 //
00013 // DigiBooster Pro Module Loader (*.dbm)
00014 //
00015 // Note: this loader doesn't handle multiple songs
00016 //
00018 
00019 #include "stdafx.h"
00020 #include "sndfile.h"
00021 
00022 //#pragma warning(disable:4244)
00023 
00024 #define DBM_FILE_MAGIC  0x304d4244
00025 #define DBM_ID_NAME             0x454d414e
00026 #define DBM_NAMELEN             0x2c000000
00027 #define DBM_ID_INFO             0x4f464e49
00028 #define DBM_INFOLEN             0x0a000000
00029 #define DBM_ID_SONG             0x474e4f53
00030 #define DBM_ID_INST             0x54534e49
00031 #define DBM_ID_VENV             0x564e4556
00032 #define DBM_ID_PATT             0x54544150
00033 #define DBM_ID_SMPL             0x4c504d53
00034 
00035 #pragma pack(1)
00036 
00037 typedef struct DBMFILEHEADER
00038 {
00039         DWORD dbm_id;           // "DBM0" = 0x304d4244
00040         WORD trkver;            // Tracker version: 02.15
00041         WORD reserved;
00042         DWORD name_id;          // "NAME" = 0x454d414e
00043         DWORD name_len;         // name length: always 44
00044         CHAR songname[44];
00045         DWORD info_id;          // "INFO" = 0x4f464e49
00046         DWORD info_len;         // 0x0a000000
00047         WORD instruments;
00048         WORD samples;
00049         WORD songs;
00050         WORD patterns;
00051         WORD channels;
00052         DWORD song_id;          // "SONG" = 0x474e4f53
00053         DWORD song_len;
00054         CHAR songname2[44];
00055         WORD orders;
00056 //      WORD orderlist[0];      // orderlist[orders] in words
00057 } Q_PACKED DBMFILEHEADER;
00058 
00059 typedef struct DBMINSTRUMENT
00060 {
00061         CHAR name[30];
00062         WORD sampleno;
00063         WORD volume;
00064         DWORD finetune;
00065         DWORD loopstart;
00066         DWORD looplen;
00067         WORD panning;
00068         WORD flags;
00069 } Q_PACKED DBMINSTRUMENT;
00070 
00071 typedef struct DBMENVELOPE
00072 {
00073         WORD instrument;
00074         BYTE flags;
00075         BYTE numpoints;
00076         BYTE sustain1;
00077         BYTE loopbegin;
00078         BYTE loopend;
00079         BYTE sustain2;
00080         WORD volenv[2*32];
00081 } Q_PACKED DBMENVELOPE;
00082 
00083 typedef struct DBMPATTERN
00084 {
00085         WORD rows;
00086         DWORD packedsize;
00087         BYTE patterndata[2];    // [packedsize]
00088 } Q_PACKED DBMPATTERN;
00089 
00090 typedef struct DBMSAMPLE
00091 {
00092         DWORD flags;
00093         DWORD samplesize;
00094         BYTE sampledata[2];             // [samplesize]
00095 } Q_PACKED DBMSAMPLE;
00096 
00097 #pragma pack()
00098 
00099 
00100 BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
00101 //---------------------------------------------------------------
00102 {
00103         DBMFILEHEADER *pfh = (DBMFILEHEADER *)lpStream;
00104         DWORD dwMemPos;
00105         UINT nOrders, nSamples, nInstruments, nPatterns;
00106         
00107         if ((!lpStream) || (dwMemLength <= sizeof(DBMFILEHEADER)) || (!pfh->channels)
00108          || (pfh->dbm_id != DBM_FILE_MAGIC) || (!pfh->songs) || (pfh->song_id != DBM_ID_SONG)
00109          || (pfh->name_id != DBM_ID_NAME) || (pfh->name_len != DBM_NAMELEN)
00110          || (pfh->info_id != DBM_ID_INFO) || (pfh->info_len != DBM_INFOLEN)) return FALSE;
00111         dwMemPos = sizeof(DBMFILEHEADER);
00112         nOrders = bswapBE16(pfh->orders);
00113         if (dwMemPos + 2 * nOrders + 8*3 >= dwMemLength) return FALSE;
00114         nInstruments = bswapBE16(pfh->instruments);
00115         nSamples = bswapBE16(pfh->samples);
00116         nPatterns = bswapBE16(pfh->patterns);
00117         m_nType = MOD_TYPE_DBM;
00118         m_nChannels = bswapBE16(pfh->channels);
00119         if (m_nChannels < 4) m_nChannels = 4;
00120         if (m_nChannels > 64) m_nChannels = 64;
00121         memcpy(m_szNames[0], (pfh->songname[0]) ? pfh->songname : pfh->songname2, 32);
00122         m_szNames[0][31] = 0;
00123         for (UINT iOrd=0; iOrd < nOrders; iOrd++)
00124         {
00125                 Order[iOrd] = lpStream[dwMemPos+iOrd*2+1];
00126                 if (iOrd >= MAX_ORDERS-2) break;
00127         }
00128         dwMemPos += 2*nOrders;
00129         while (dwMemPos + 10 < dwMemLength)
00130         {
00131                 DWORD chunk_id = ((LPDWORD)(lpStream+dwMemPos))[0];
00132                 DWORD chunk_size = bswapBE32(((LPDWORD)(lpStream+dwMemPos))[1]);
00133                 DWORD chunk_pos;
00134                 
00135                 dwMemPos += 8;
00136                 chunk_pos = dwMemPos;
00137                 if ((dwMemPos + chunk_size > dwMemLength) || (chunk_size > dwMemLength)) break;
00138                 dwMemPos += chunk_size;
00139                 // Instruments
00140                 if (chunk_id == DBM_ID_INST)
00141                 {
00142                         if (nInstruments >= MAX_INSTRUMENTS) nInstruments = MAX_INSTRUMENTS-1;
00143                         for (UINT iIns=0; iIns<nInstruments; iIns++)
00144                         {
00145                                 MODINSTRUMENT *psmp;
00146                                 INSTRUMENTHEADER *penv;
00147                                 DBMINSTRUMENT *pih;
00148                                 UINT nsmp;
00149 
00150                                 if (chunk_pos + sizeof(DBMINSTRUMENT) > dwMemPos) break;
00151                                 if ((penv = new INSTRUMENTHEADER) == NULL) break;
00152                                 pih = (DBMINSTRUMENT *)(lpStream+chunk_pos);
00153                                 nsmp = bswapBE16(pih->sampleno);
00154                                 psmp = ((nsmp) && (nsmp < MAX_SAMPLES)) ? &Ins[nsmp] : NULL;
00155                                 memset(penv, 0, sizeof(INSTRUMENTHEADER));
00156                                 memcpy(penv->name, pih->name, 30);
00157                                 if (psmp)
00158                                 {
00159                                         memcpy(m_szNames[nsmp], pih->name, 30);
00160                                         m_szNames[nsmp][30] = 0;
00161                                 }
00162                                 Headers[iIns+1] = penv;
00163                                 penv->nFadeOut = 1024;  // ???
00164                                 penv->nGlobalVol = 64;
00165                                 penv->nPan = bswapBE16(pih->panning);
00166                                 if ((penv->nPan) && (penv->nPan < 256))
00167                                         penv->dwFlags = ENV_SETPANNING;
00168                                 else
00169                                         penv->nPan = 128;
00170                                 penv->nPPC = 5*12;
00171                                 for (UINT i=0; i<120; i++)
00172                                 {
00173                                         penv->Keyboard[i] = nsmp;
00174                                         penv->NoteMap[i] = i+1;
00175                                 }
00176                                 // Sample Info
00177                                 if (psmp)
00178                                 {
00179                                         DWORD sflags = bswapBE16(pih->flags);
00180                                         psmp->nVolume = bswapBE16(pih->volume) * 4;
00181                                         if ((!psmp->nVolume) || (psmp->nVolume > 256)) psmp->nVolume = 256;
00182                                         psmp->nGlobalVol = 64;
00183                                         psmp->nC4Speed = bswapBE32(pih->finetune);
00184                                         int f2t = FrequencyToTranspose(psmp->nC4Speed);
00185                                         psmp->RelativeTone = f2t >> 7;
00186                                         psmp->nFineTune = f2t & 0x7F;
00187                                         if ((pih->looplen) && (sflags & 3))
00188                                         {
00189                                                 psmp->nLoopStart = bswapBE32(pih->loopstart);
00190                                                 psmp->nLoopEnd = psmp->nLoopStart + bswapBE32(pih->looplen);
00191                                                 psmp->uFlags |= CHN_LOOP;
00192                                                 psmp->uFlags &= ~CHN_PINGPONGLOOP;
00193                                                 if (sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP;
00194                                         }
00195                                 }
00196                                 chunk_pos += sizeof(DBMINSTRUMENT);
00197                                 m_nInstruments = iIns+1;
00198                         }
00199                 } else
00200                 // Volume Envelopes
00201                 if (chunk_id == DBM_ID_VENV)
00202                 {
00203                         UINT nEnvelopes = lpStream[chunk_pos+1];
00204                         
00205                         chunk_pos += 2;
00206                         for (UINT iEnv=0; iEnv<nEnvelopes; iEnv++)
00207                         {
00208                                 DBMENVELOPE *peh;
00209                                 UINT nins;
00210                                 
00211                                 if (chunk_pos + sizeof(DBMENVELOPE) > dwMemPos) break;
00212                                 peh = (DBMENVELOPE *)(lpStream+chunk_pos);
00213                                 nins = bswapBE16(peh->instrument);
00214                                 if ((nins) && (nins < MAX_INSTRUMENTS) && (Headers[nins]) && (peh->numpoints))
00215                                 {
00216                                         INSTRUMENTHEADER *penv = Headers[nins];
00217 
00218                                         if (peh->flags & 1) penv->dwFlags |= ENV_VOLUME;
00219                                         if (peh->flags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
00220                                         if (peh->flags & 4) penv->dwFlags |= ENV_VOLLOOP;
00221                                         penv->nVolEnv = peh->numpoints + 1;
00222                                         if (penv->nVolEnv > MAX_ENVPOINTS) penv->nVolEnv = MAX_ENVPOINTS;
00223                                         penv->nVolLoopStart = peh->loopbegin;
00224                                         penv->nVolLoopEnd = peh->loopend;
00225                                         penv->nVolSustainBegin = penv->nVolSustainEnd = peh->sustain1;
00226                                         for (UINT i=0; i<penv->nVolEnv; i++)
00227                                         {
00228                                                 penv->VolPoints[i] = bswapBE16(peh->volenv[i*2]);
00229                                                 penv->VolEnv[i] = (BYTE)bswapBE16(peh->volenv[i*2+1]);
00230                                         }
00231                                 }
00232                                 chunk_pos += sizeof(DBMENVELOPE);
00233                         }
00234                 } else
00235                 // Packed Pattern Data
00236                 if (chunk_id == DBM_ID_PATT)
00237                 {
00238                         if (nPatterns > MAX_PATTERNS) nPatterns = MAX_PATTERNS;
00239                         for (UINT iPat=0; iPat<nPatterns; iPat++)
00240                         {
00241                                 DBMPATTERN *pph;
00242                                 DWORD pksize;
00243                                 UINT nRows;
00244 
00245                                 if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break;
00246                                 pph = (DBMPATTERN *)(lpStream+chunk_pos);
00247                                 pksize = bswapBE32(pph->packedsize);
00248                                 if ((chunk_pos + pksize + 6 > dwMemPos) || (pksize > dwMemPos)) break;
00249                                 nRows = bswapBE16(pph->rows);
00250                                 if ((nRows >= 4) && (nRows <= 256))
00251                                 {
00252                                         MODCOMMAND *m = AllocatePattern(nRows, m_nChannels);
00253                                         if (m)
00254                                         {
00255                                                 LPBYTE pkdata = (LPBYTE)&pph->patterndata;
00256                                                 UINT row = 0;
00257                                                 UINT i = 0;
00258 
00259                                                 PatternSize[iPat] = nRows;
00260                                                 Patterns[iPat] = m;
00261                                                 while ((i+3<pksize) && (row < nRows))
00262                                                 {
00263                                                         UINT ch = pkdata[i++];
00264 
00265                                                         if (ch)
00266                                                         {
00267                                                                 BYTE b = pkdata[i++];
00268                                                                 ch--;
00269                                                                 if (ch < m_nChannels)
00270                                                                 {
00271                                                                         if (b & 0x01)
00272                                                                         {
00273                                                                                 UINT note = pkdata[i++];
00274 
00275                                                                                 if (note == 0x1F) note = 0xFF; else
00276                                                                                 if ((note) && (note < 0xFE))
00277                                                                                 {
00278                                                                                         note = ((note >> 4)*12) + (note & 0x0F) + 13;
00279                                                                                 }
00280                                                                                 m[ch].note = note;
00281                                                                         }
00282                                                                         if (b & 0x02) m[ch].instr = pkdata[i++];
00283                                                                         if (b & 0x3C)
00284                                                                         {
00285                                                                                 UINT cmd1 = 0xFF, param1 = 0, cmd2 = 0xFF, param2 = 0;
00286                                                                                 if (b & 0x04) cmd1 = (UINT)pkdata[i++];
00287                                                                                 if (b & 0x08) param1 = pkdata[i++];
00288                                                                                 if (b & 0x10) cmd2 = (UINT)pkdata[i++];
00289                                                                                 if (b & 0x20) param2 = pkdata[i++];
00290                                                                                 if (cmd1 == 0x0C)
00291                                                                                 {
00292                                                                                         m[ch].volcmd = VOLCMD_VOLUME;
00293                                                                                         m[ch].vol = param1;
00294                                                                                         cmd1 = 0xFF;
00295                                                                                 } else
00296                                                                                 if (cmd2 == 0x0C)
00297                                                                                 {
00298                                                                                         m[ch].volcmd = VOLCMD_VOLUME;
00299                                                                                         m[ch].vol = param2;
00300                                                                                         cmd2 = 0xFF;
00301                                                                                 }
00302                                                                                 if ((cmd1 > 0x13) || ((cmd1 >= 0x10) && (cmd2 < 0x10)))
00303                                                                                 {
00304                                                                                         cmd1 = cmd2;
00305                                                                                         param1 = param2;
00306                                                                                         cmd2 = 0xFF;
00307                                                                                 }
00308                                                                                 if (cmd1 <= 0x13)
00309                                                                                 {
00310                                                                                         m[ch].command = cmd1;
00311                                                                                         m[ch].param = param1;
00312                                                                                         ConvertModCommand(&m[ch]);
00313                                                                                 }
00314                                                                         }
00315                                                                 } else
00316                                                                 {
00317                                                                         if (b & 0x01) i++;
00318                                                                         if (b & 0x02) i++;
00319                                                                         if (b & 0x04) i++;
00320                                                                         if (b & 0x08) i++;
00321                                                                         if (b & 0x10) i++;
00322                                                                         if (b & 0x20) i++;
00323                                                                 }
00324                                                         } else
00325                                                         {
00326                                                                 row++;
00327                                                                 m += m_nChannels;
00328                                                         }
00329                                                 }
00330                                         }
00331                                 }
00332                                 chunk_pos += 6 + pksize;
00333                         }
00334                 } else
00335                 // Reading Sample Data
00336                 if (chunk_id == DBM_ID_SMPL)
00337                 {
00338                         if (nSamples >= MAX_SAMPLES) nSamples = MAX_SAMPLES-1;
00339                         m_nSamples = nSamples;
00340                         for (UINT iSmp=1; iSmp<=nSamples; iSmp++)
00341                         {
00342                                 MODINSTRUMENT *pins;
00343                                 DBMSAMPLE *psh;
00344                                 DWORD samplesize;
00345                                 DWORD sampleflags;
00346 
00347                                 if (chunk_pos + sizeof(DBMSAMPLE) >= dwMemPos) break;
00348                                 psh = (DBMSAMPLE *)(lpStream+chunk_pos);
00349                                 chunk_pos += 8;
00350                                 samplesize = bswapBE32(psh->samplesize);
00351                                 sampleflags = bswapBE32(psh->flags);
00352                                 pins = &Ins[iSmp];
00353                                 pins->nLength = samplesize;
00354                                 if (sampleflags & 2)
00355                                 {
00356                                         pins->uFlags |= CHN_16BIT;
00357                                         samplesize <<= 1;
00358                                 }
00359                                 if ((chunk_pos+samplesize > dwMemPos) || (samplesize > dwMemLength)) break;
00360                                 if (sampleflags & 3)
00361                                 {
00362                                         ReadSample(pins, (pins->uFlags & CHN_16BIT) ? RS_PCM16M : RS_PCM8S,
00363                                                                 (LPSTR)(psh->sampledata), samplesize);
00364                                 }
00365                                 chunk_pos += samplesize;
00366                         }
00367                 }
00368         }
00369         return TRUE;
00370 }
00371 

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