00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00014 #include "stdafx.h"
00015 #include "sndfile.h"
00016
00017
00018
00019 #pragma pack(1)
00020
00021 typedef struct PTMFILEHEADER
00022 {
00023 CHAR songname[28];
00024 CHAR eof;
00025 BYTE version_lo;
00026 BYTE version_hi;
00027 BYTE reserved1;
00028 WORD norders;
00029 WORD nsamples;
00030 WORD npatterns;
00031 WORD nchannels;
00032 WORD fileflags;
00033 WORD reserved2;
00034 DWORD ptmf_id;
00035 BYTE reserved3[16];
00036 BYTE chnpan[32];
00037 BYTE orders[256];
00038 WORD patseg[128];
00039 } Q_PACKED PTMFILEHEADER, *LPPTMFILEHEADER;
00040
00041 #define SIZEOF_PTMFILEHEADER 608
00042
00043
00044 typedef struct PTMSAMPLE
00045 {
00046 BYTE sampletype;
00047 CHAR filename[12];
00048 BYTE volume;
00049 WORD nC4Spd;
00050 WORD sampleseg;
00051 WORD fileofs[2];
00052 WORD length[2];
00053 WORD loopbeg[2];
00054 WORD loopend[2];
00055 WORD gusdata[8];
00056 char samplename[28];
00057 DWORD ptms_id;
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
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