Mercurial > audlegacy-plugins
diff src/modplug/load_ptm.cxx @ 136:6b5a52635b3b trunk
[svn] - like with so many other things, modplug is now maintained by us.
author | nenolod |
---|---|
date | Sun, 29 Oct 2006 01:04:52 -0700 |
parents | |
children | 032053ca08ab 3673c7ec4ea2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/modplug/load_ptm.cxx Sun Oct 29 01:04:52 2006 -0700 @@ -0,0 +1,207 @@ +/* + * This source code is public domain. + * + * Authors: Olivier Lapicque <olivierl@jps.net>, + * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC) +*/ + +////////////////////////////////////////////// +// PTM PolyTracker module loader // +////////////////////////////////////////////// +#include "stdafx.h" +#include "sndfile.h" + +//#pragma warning(disable:4244) + +#pragma pack(1) + +typedef struct PTMFILEHEADER +{ + CHAR songname[28]; // name of song, asciiz string + CHAR eof; // 26 + BYTE version_lo; // 03 version of file, currently 0203h + BYTE version_hi; // 02 + BYTE reserved1; // reserved, set to 0 + WORD norders; // number of orders (0..256) + WORD nsamples; // number of instruments (1..255) + WORD npatterns; // number of patterns (1..128) + WORD nchannels; // number of channels (voices) used (1..32) + WORD fileflags; // set to 0 + WORD reserved2; // reserved, set to 0 + DWORD ptmf_id; // song identification, 'PTMF' or 0x464d5450 + BYTE reserved3[16]; // reserved, set to 0 + BYTE chnpan[32]; // channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right + BYTE orders[256]; // order list, valid entries 0..nOrders-1 + WORD patseg[128]; // pattern offsets (*16) +} PTMFILEHEADER, *LPPTMFILEHEADER; + +#define SIZEOF_PTMFILEHEADER 608 + + +typedef struct PTMSAMPLE +{ + BYTE sampletype; // sample type (bit array) + CHAR filename[12]; // name of external sample file + BYTE volume; // default volume + WORD nC4Spd; // C4 speed + WORD sampleseg; // sample segment (used internally) + WORD fileofs[2]; // offset of sample data + WORD length[2]; // sample size (in bytes) + WORD loopbeg[2]; // start of loop + WORD loopend[2]; // end of loop + WORD gusdata[8]; + char samplename[28]; // name of sample, asciiz // changed from CHAR + DWORD ptms_id; // sample identification, 'PTMS' or 0x534d5450 +} PTMSAMPLE; + +#define SIZEOF_PTMSAMPLE 80 + +#pragma pack() + + +BOOL CSoundFile::ReadPTM(const BYTE *lpStream, DWORD dwMemLength) +//--------------------------------------------------------------- +{ + PTMFILEHEADER pfh = *(LPPTMFILEHEADER)lpStream; + DWORD dwMemPos; + UINT nOrders; + + pfh.norders = bswapLE16(pfh.norders); + pfh.nsamples = bswapLE16(pfh.nsamples); + pfh.npatterns = bswapLE16(pfh.npatterns); + pfh.nchannels = bswapLE16(pfh.nchannels); + pfh.fileflags = bswapLE16(pfh.fileflags); + pfh.reserved2 = bswapLE16(pfh.reserved2); + pfh.ptmf_id = bswapLE32(pfh.ptmf_id); + for (UINT j=0; j<128; j++) + { + pfh.patseg[j] = bswapLE16(pfh.patseg[j]); + } + + if ((!lpStream) || (dwMemLength < 1024)) return FALSE; + if ((pfh.ptmf_id != 0x464d5450) || (!pfh.nchannels) + || (pfh.nchannels > 32) + || (pfh.norders > 256) || (!pfh.norders) + || (!pfh.nsamples) || (pfh.nsamples > 255) + || (!pfh.npatterns) || (pfh.npatterns > 128) + || (SIZEOF_PTMFILEHEADER+pfh.nsamples*SIZEOF_PTMSAMPLE >= (int)dwMemLength)) return FALSE; + memcpy(m_szNames[0], pfh.songname, 28); + m_szNames[0][28] = 0; + m_nType = MOD_TYPE_PTM; + m_nChannels = pfh.nchannels; + m_nSamples = (pfh.nsamples < MAX_SAMPLES) ? pfh.nsamples : MAX_SAMPLES-1; + dwMemPos = SIZEOF_PTMFILEHEADER; + nOrders = (pfh.norders < MAX_ORDERS) ? pfh.norders : MAX_ORDERS-1; + memcpy(Order, pfh.orders, nOrders); + for (UINT ipan=0; ipan<m_nChannels; ipan++) + { + ChnSettings[ipan].nVolume = 64; + ChnSettings[ipan].nPan = ((pfh.chnpan[ipan] & 0x0F) << 4) + 4; + } + for (UINT ismp=0; ismp<m_nSamples; ismp++, dwMemPos += SIZEOF_PTMSAMPLE) + { + MODINSTRUMENT *pins = &Ins[ismp+1]; + PTMSAMPLE *psmp = (PTMSAMPLE *)(lpStream+dwMemPos); + + lstrcpyn(m_szNames[ismp+1], psmp->samplename, 28); + memcpy(pins->name, psmp->filename, 12); + pins->name[12] = 0; + pins->nGlobalVol = 64; + pins->nPan = 128; + pins->nVolume = psmp->volume << 2; + pins->nC4Speed = bswapLE16(psmp->nC4Spd) << 1; + pins->uFlags = 0; + if ((psmp->sampletype & 3) == 1) + { + UINT smpflg = RS_PCM8D; + DWORD samplepos; + pins->nLength = bswapLE32(*(LPDWORD)(psmp->length)); + pins->nLoopStart = bswapLE32(*(LPDWORD)(psmp->loopbeg)); + pins->nLoopEnd = bswapLE32(*(LPDWORD)(psmp->loopend)); + samplepos = bswapLE32(*(LPDWORD)(&psmp->fileofs)); + if (psmp->sampletype & 4) pins->uFlags |= CHN_LOOP; + if (psmp->sampletype & 8) pins->uFlags |= CHN_PINGPONGLOOP; + if (psmp->sampletype & 16) + { + pins->uFlags |= CHN_16BIT; + pins->nLength >>= 1; + pins->nLoopStart >>= 1; + pins->nLoopEnd >>= 1; + smpflg = RS_PTM8DTO16; + } + if ((pins->nLength) && (samplepos) && (samplepos < dwMemLength)) + { + ReadSample(pins, smpflg, (LPSTR)(lpStream+samplepos), dwMemLength-samplepos); + } + } + } + // Reading Patterns + for (UINT ipat=0; ipat<pfh.npatterns; ipat++) + { + dwMemPos = ((UINT)pfh.patseg[ipat]) << 4; + if ((!dwMemPos) || (dwMemPos >= dwMemLength)) continue; + PatternSize[ipat] = 64; + if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break; + // + MODCOMMAND *m = Patterns[ipat]; + for (UINT row=0; ((row < 64) && (dwMemPos < dwMemLength)); ) + { + UINT b = lpStream[dwMemPos++]; + + if (dwMemPos >= dwMemLength) break; + if (b) + { + UINT nChn = b & 0x1F; + + if (b & 0x20) + { + if (dwMemPos + 2 > dwMemLength) break; + m[nChn].note = lpStream[dwMemPos++]; + m[nChn].instr = lpStream[dwMemPos++]; + } + if (b & 0x40) + { + if (dwMemPos + 2 > dwMemLength) break; + m[nChn].command = lpStream[dwMemPos++]; + m[nChn].param = lpStream[dwMemPos++]; + if ((m[nChn].command == 0x0E) && ((m[nChn].param & 0xF0) == 0x80)) + { + m[nChn].command = CMD_S3MCMDEX; + } else + if (m[nChn].command < 0x10) + { + ConvertModCommand(&m[nChn]); + } else + { + switch(m[nChn].command) + { + case 16: + m[nChn].command = CMD_GLOBALVOLUME; + break; + case 17: + m[nChn].command = CMD_RETRIG; + break; + case 18: + m[nChn].command = CMD_FINEVIBRATO; + break; + default: + m[nChn].command = 0; + } + } + } + if (b & 0x80) + { + if (dwMemPos >= dwMemLength) break; + m[nChn].volcmd = VOLCMD_VOLUME; + m[nChn].vol = lpStream[dwMemPos++]; + } + } else + { + row++; + m += m_nChannels; + } + } + } + return TRUE; +} +