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

load_ptm.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 // PTM PolyTracker module loader            //
00014 #include "stdafx.h"
00015 #include "sndfile.h"
00016 
00017 //#pragma warning(disable:4244)
00018 
00019 #pragma pack(1)
00020 
00021 typedef struct PTMFILEHEADER
00022 {
00023         CHAR songname[28];              // name of song, asciiz string
00024         CHAR eof;                               // 26
00025         BYTE version_lo;                // 03 version of file, currently 0203h
00026         BYTE version_hi;                // 02
00027         BYTE reserved1;                 // reserved, set to 0
00028         WORD norders;                   // number of orders (0..256)
00029         WORD nsamples;                  // number of instruments (1..255)
00030         WORD npatterns;                 // number of patterns (1..128)
00031         WORD nchannels;                 // number of channels (voices) used (1..32)
00032         WORD fileflags;                 // set to 0
00033         WORD reserved2;                 // reserved, set to 0
00034         DWORD ptmf_id;                  // song identification, 'PTMF' or 0x464d5450
00035         BYTE reserved3[16];             // reserved, set to 0
00036         BYTE chnpan[32];                // channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
00037         BYTE orders[256];               // order list, valid entries 0..nOrders-1
00038         WORD patseg[128];               // pattern offsets (*16)
00039 } Q_PACKED PTMFILEHEADER, *LPPTMFILEHEADER;
00040 
00041 #define SIZEOF_PTMFILEHEADER    608
00042 
00043 
00044 typedef struct PTMSAMPLE
00045 {
00046         BYTE sampletype;                // sample type (bit array)
00047         CHAR filename[12];              // name of external sample file
00048         BYTE volume;                    // default volume
00049         WORD nC4Spd;                    // C4 speed
00050         WORD sampleseg;                 // sample segment (used internally)
00051         WORD fileofs[2];                // offset of sample data
00052         WORD length[2];                 // sample size (in bytes)
00053         WORD loopbeg[2];                // start of loop
00054         WORD loopend[2];                // end of loop
00055         WORD gusdata[8];
00056         char  samplename[28];   // name of sample, asciiz  // changed from CHAR
00057         DWORD ptms_id;                  // sample identification, 'PTMS' or 0x534d5450
00058 } Q_PACKED PTMSAMPLE;
00059 
00060 #define SIZEOF_PTMSAMPLE        80
00061 
00062 #pragma pack()
00063 
00064 
00065 BOOL CSoundFile::ReadPTM(const BYTE *lpStream, DWORD dwMemLength)
00066 //---------------------------------------------------------------
00067 {
00068         PTMFILEHEADER pfh = *(LPPTMFILEHEADER)lpStream;
00069         DWORD dwMemPos;
00070         UINT nOrders;
00071 
00072         pfh.norders = bswapLE16(pfh.norders);
00073         pfh.nsamples = bswapLE16(pfh.nsamples);
00074         pfh.npatterns = bswapLE16(pfh.npatterns);
00075         pfh.nchannels = bswapLE16(pfh.nchannels);
00076         pfh.fileflags = bswapLE16(pfh.fileflags);
00077         pfh.reserved2 = bswapLE16(pfh.reserved2);
00078         pfh.ptmf_id = bswapLE32(pfh.ptmf_id);
00079         for (UINT j=0; j<128; j++)
00080         {
00081                 pfh.patseg[j] = bswapLE16(pfh.patseg[j]);
00082         }
00083 
00084         if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
00085         if ((pfh.ptmf_id != 0x464d5450) || (!pfh.nchannels)
00086          || (pfh.nchannels > 32)
00087          || (pfh.norders > 256) || (!pfh.norders)
00088          || (!pfh.nsamples) || (pfh.nsamples > 255)
00089          || (!pfh.npatterns) || (pfh.npatterns > 128)
00090          || (SIZEOF_PTMFILEHEADER+pfh.nsamples*SIZEOF_PTMSAMPLE >= (int)dwMemLength)) return FALSE;
00091         memcpy(m_szNames[0], pfh.songname, 28);
00092         m_szNames[0][28] = 0;
00093         m_nType = MOD_TYPE_PTM;
00094         m_nChannels = pfh.nchannels;
00095         m_nSamples = (pfh.nsamples < MAX_SAMPLES) ? pfh.nsamples : MAX_SAMPLES-1;
00096         dwMemPos = SIZEOF_PTMFILEHEADER;
00097         nOrders = (pfh.norders < MAX_ORDERS) ? pfh.norders : MAX_ORDERS-1;
00098         memcpy(Order, pfh.orders, nOrders);
00099         for (UINT ipan=0; ipan<m_nChannels; ipan++)
00100         {
00101                 ChnSettings[ipan].nVolume = 64;
00102                 ChnSettings[ipan].nPan = ((pfh.chnpan[ipan] & 0x0F) << 4) + 4;
00103         }
00104         for (UINT ismp=0; ismp<m_nSamples; ismp++, dwMemPos += SIZEOF_PTMSAMPLE)
00105         {
00106                 MODINSTRUMENT *pins = &Ins[ismp+1];
00107                 PTMSAMPLE *psmp = (PTMSAMPLE *)(lpStream+dwMemPos);
00108 
00109                 lstrcpyn(m_szNames[ismp+1], psmp->samplename, 28);
00110                 memcpy(pins->name, psmp->filename, 12);
00111                 pins->name[12] = 0;
00112                 pins->nGlobalVol = 64;
00113                 pins->nPan = 128;
00114                 pins->nVolume = psmp->volume << 2;
00115                 pins->nC4Speed = bswapLE16(psmp->nC4Spd) << 1;
00116                 pins->uFlags = 0;
00117                 if ((psmp->sampletype & 3) == 1)
00118                 {
00119                         UINT smpflg = RS_PCM8D;
00120                         DWORD samplepos;
00121                         pins->nLength = bswapLE32(*(LPDWORD)(psmp->length));
00122                         pins->nLoopStart = bswapLE32(*(LPDWORD)(psmp->loopbeg));
00123                         pins->nLoopEnd = bswapLE32(*(LPDWORD)(psmp->loopend));
00124                         samplepos = bswapLE32(*(LPDWORD)(&psmp->fileofs));
00125                         if (psmp->sampletype & 4) pins->uFlags |= CHN_LOOP;
00126                         if (psmp->sampletype & 8) pins->uFlags |= CHN_PINGPONGLOOP;
00127                         if (psmp->sampletype & 16)
00128                         {
00129                                 pins->uFlags |= CHN_16BIT;
00130                                 pins->nLength >>= 1;
00131                                 pins->nLoopStart >>= 1;
00132                                 pins->nLoopEnd >>= 1;
00133                                 smpflg = RS_PTM8DTO16;
00134                         }
00135                         if ((pins->nLength) && (samplepos) && (samplepos < dwMemLength))
00136                         {
00137                                 ReadSample(pins, smpflg, (LPSTR)(lpStream+samplepos), dwMemLength-samplepos);
00138                         }
00139                 }
00140         }
00141         // Reading Patterns
00142         for (UINT ipat=0; ipat<pfh.npatterns; ipat++)
00143         {
00144                 dwMemPos = ((UINT)pfh.patseg[ipat]) << 4;
00145                 if ((!dwMemPos) || (dwMemPos >= dwMemLength)) continue;
00146                 PatternSize[ipat] = 64;
00147                 if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
00148                 //
00149                 MODCOMMAND *m = Patterns[ipat];
00150                 for (UINT row=0; ((row < 64) && (dwMemPos < dwMemLength)); )
00151                 {
00152                         UINT b = lpStream[dwMemPos++];
00153 
00154                         if (dwMemPos >= dwMemLength) break;
00155                         if (b)
00156                         {
00157                                 UINT nChn = b & 0x1F;
00158 
00159                                 if (b & 0x20)
00160                                 {
00161                                         if (dwMemPos + 2 > dwMemLength) break;
00162                                         m[nChn].note = lpStream[dwMemPos++];
00163                                         m[nChn].instr = lpStream[dwMemPos++];
00164                                 }
00165                                 if (b & 0x40)
00166                                 {
00167                                         if (dwMemPos + 2 > dwMemLength) break;
00168                                         m[nChn].command = lpStream[dwMemPos++];
00169                                         m[nChn].param = lpStream[dwMemPos++];
00170                                         if ((m[nChn].command == 0x0E) && ((m[nChn].param & 0xF0) == 0x80))
00171                                         {
00172                                                 m[nChn].command = CMD_S3MCMDEX;
00173                                         } else
00174                                         if (m[nChn].command < 0x10)
00175                                         {
00176                                                 ConvertModCommand(&m[nChn]);
00177                                         } else
00178                                         {
00179                                                 switch(m[nChn].command)
00180                                                 {
00181                                                 case 16:
00182                                                         m[nChn].command = CMD_GLOBALVOLUME;
00183                                                         break;
00184                                                 case 17:
00185                                                         m[nChn].command = CMD_RETRIG;
00186                                                         break;
00187                                                 case 18:
00188                                                         m[nChn].command = CMD_FINEVIBRATO;
00189                                                         break;
00190                                                 default:
00191                                                         m[nChn].command = 0;
00192                                                 }
00193                                         }
00194                                 }
00195                                 if (b & 0x80)
00196                                 {
00197                                         if (dwMemPos >= dwMemLength) break;
00198                                         m[nChn].volcmd = VOLCMD_VOLUME;
00199                                         m[nChn].vol = lpStream[dwMemPos++];
00200                                 }
00201                         } else
00202                         {
00203                                 row++;
00204                                 m += m_nChannels;
00205                         }
00206                 }
00207         }
00208         return TRUE;
00209 }
00210 

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