mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 16:26:39 +00:00
ac87bfc370
Original commit message from CVS: adding modplug
635 lines
17 KiB
C++
635 lines
17 KiB
C++
#include "stdafx.h"
|
|
#include "sndfile.h"
|
|
|
|
//#define MT2DEBUG
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef struct _MT2FILEHEADER
|
|
{
|
|
DWORD dwMT20; // 0x3032544D "MT20"
|
|
DWORD dwSpecial;
|
|
WORD wVersion;
|
|
CHAR szTrackerName[32]; // "MadTracker 2.0"
|
|
CHAR szSongName[64];
|
|
WORD nOrders;
|
|
WORD wRestart;
|
|
WORD wPatterns;
|
|
WORD wChannels;
|
|
WORD wSamplesPerTick;
|
|
BYTE bTicksPerLine;
|
|
BYTE bLinesPerBeat;
|
|
DWORD fulFlags; // b0=packed patterns
|
|
WORD wInstruments;
|
|
WORD wSamples;
|
|
BYTE Orders[256];
|
|
} MT2FILEHEADER;
|
|
|
|
typedef struct _MT2PATTERN
|
|
{
|
|
WORD wLines;
|
|
DWORD wDataLen;
|
|
} MT2PATTERN;
|
|
|
|
typedef struct _MT2COMMAND
|
|
{
|
|
BYTE note; // 0=nothing, 97=note off
|
|
BYTE instr;
|
|
BYTE vol;
|
|
BYTE pan;
|
|
BYTE fxcmd;
|
|
BYTE fxparam1;
|
|
BYTE fxparam2;
|
|
} MT2COMMAND;
|
|
|
|
typedef struct _MT2DRUMSDATA
|
|
{
|
|
WORD wDrumPatterns;
|
|
WORD wDrumSamples[8];
|
|
BYTE DrumPatternOrder[256];
|
|
} MT2DRUMSDATA;
|
|
|
|
typedef struct _MT2AUTOMATION
|
|
{
|
|
DWORD dwFlags;
|
|
DWORD dwEffectId;
|
|
DWORD nEnvPoints;
|
|
} MT2AUTOMATION;
|
|
|
|
typedef struct _MT2INSTRUMENT
|
|
{
|
|
CHAR szName[32];
|
|
DWORD dwDataLen;
|
|
WORD wSamples;
|
|
BYTE GroupsMapping[96];
|
|
BYTE bVibType;
|
|
BYTE bVibSweep;
|
|
BYTE bVibDepth;
|
|
BYTE bVibRate;
|
|
WORD wFadeOut;
|
|
WORD wNNA;
|
|
WORD wInstrFlags;
|
|
WORD wEnvFlags1;
|
|
WORD wEnvFlags2;
|
|
} MT2INSTRUMENT;
|
|
|
|
typedef struct _MT2ENVELOPE
|
|
{
|
|
BYTE nFlags;
|
|
BYTE nPoints;
|
|
BYTE nSustainPos;
|
|
BYTE nLoopStart;
|
|
BYTE nLoopEnd;
|
|
BYTE bReserved[3];
|
|
BYTE EnvData[64];
|
|
} MT2ENVELOPE;
|
|
|
|
typedef struct _MT2SYNTH
|
|
{
|
|
BYTE nSynthId;
|
|
BYTE nFxId;
|
|
WORD wCutOff;
|
|
BYTE nResonance;
|
|
BYTE nAttack;
|
|
BYTE nDecay;
|
|
BYTE bReserved[25];
|
|
} MT2SYNTH;
|
|
|
|
typedef struct _MT2SAMPLE
|
|
{
|
|
CHAR szName[32];
|
|
DWORD dwDataLen;
|
|
DWORD dwLength;
|
|
DWORD dwFrequency;
|
|
BYTE nQuality;
|
|
BYTE nChannels;
|
|
BYTE nFlags;
|
|
BYTE nLoop;
|
|
DWORD dwLoopStart;
|
|
DWORD dwLoopEnd;
|
|
WORD wVolume;
|
|
BYTE nPan;
|
|
BYTE nBaseNote;
|
|
WORD wSamplesPerBeat;
|
|
} MT2SAMPLE;
|
|
|
|
typedef struct _MT2GROUP
|
|
{
|
|
BYTE nSmpNo;
|
|
BYTE nVolume; // 0-128
|
|
BYTE nFinePitch;
|
|
BYTE Reserved[5];
|
|
} MT2GROUP;
|
|
|
|
#pragma pack()
|
|
|
|
|
|
static VOID ConvertMT2Command(CSoundFile *that, MODCOMMAND *m, MT2COMMAND *p)
|
|
//---------------------------------------------------------------------------
|
|
{
|
|
// Note
|
|
m->note = 0;
|
|
if (p->note) m->note = (p->note > 96) ? 0xFF : p->note+12;
|
|
// Instrument
|
|
m->instr = p->instr;
|
|
// Volume Column
|
|
if ((p->vol >= 0x10) && (p->vol <= 0x90))
|
|
{
|
|
m->volcmd = VOLCMD_VOLUME;
|
|
m->vol = (p->vol - 0x10) >> 1;
|
|
} else
|
|
if ((p->vol >= 0xA0) && (p->vol <= 0xAF))
|
|
{
|
|
m->volcmd = VOLCMD_VOLSLIDEDOWN;
|
|
m->vol = (p->vol & 0x0f);
|
|
} else
|
|
if ((p->vol >= 0xB0) && (p->vol <= 0xBF))
|
|
{
|
|
m->volcmd = VOLCMD_VOLSLIDEUP;
|
|
m->vol = (p->vol & 0x0f);
|
|
} else
|
|
if ((p->vol >= 0xC0) && (p->vol <= 0xCF))
|
|
{
|
|
m->volcmd = VOLCMD_FINEVOLDOWN;
|
|
m->vol = (p->vol & 0x0f);
|
|
} else
|
|
if ((p->vol >= 0xD0) && (p->vol <= 0xDF))
|
|
{
|
|
m->volcmd = VOLCMD_FINEVOLUP;
|
|
m->vol = (p->vol & 0x0f);
|
|
} else
|
|
{
|
|
m->volcmd = 0;
|
|
m->vol = 0;
|
|
}
|
|
// Effects
|
|
m->command = 0;
|
|
m->param = 0;
|
|
if ((p->fxcmd) || (p->fxparam1) || (p->fxparam2))
|
|
{
|
|
if (!p->fxcmd)
|
|
{
|
|
m->command = p->fxparam2;
|
|
m->param = p->fxparam1;
|
|
that->ConvertModCommand(m);
|
|
} else
|
|
{
|
|
// TODO: MT2 Effects
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CSoundFile::ReadMT2(LPCBYTE lpStream, DWORD dwMemLength)
|
|
//-----------------------------------------------------------
|
|
{
|
|
MT2FILEHEADER *pfh = (MT2FILEHEADER *)lpStream;
|
|
DWORD dwMemPos, dwDrumDataPos, dwExtraDataPos;
|
|
UINT nDrumDataLen, nExtraDataLen;
|
|
MT2DRUMSDATA *pdd;
|
|
MT2INSTRUMENT *InstrMap[255];
|
|
MT2SAMPLE *SampleMap[256];
|
|
|
|
if ((!lpStream) || (dwMemLength < sizeof(MT2FILEHEADER))
|
|
|| (pfh->dwMT20 != 0x3032544D)
|
|
|| (pfh->wVersion < 0x0200) || (pfh->wVersion >= 0x0300)
|
|
|| (pfh->wChannels < 4) || (pfh->wChannels > 64)) return FALSE;
|
|
pdd = NULL;
|
|
m_nType = MOD_TYPE_MT2;
|
|
m_nChannels = pfh->wChannels;
|
|
m_nRestartPos = pfh->wRestart;
|
|
m_nDefaultSpeed = pfh->bTicksPerLine;
|
|
m_nDefaultTempo = 125;
|
|
if ((pfh->wSamplesPerTick > 100) && (pfh->wSamplesPerTick < 5000))
|
|
{
|
|
m_nDefaultTempo = 110250 / pfh->wSamplesPerTick;
|
|
}
|
|
for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
|
|
{
|
|
Order[iOrd] = (BYTE)((iOrd < pfh->nOrders) ? pfh->Orders[iOrd] : 0xFF);
|
|
}
|
|
memcpy(m_szNames[0], pfh->szSongName, 32);
|
|
m_szNames[0][31] = 0;
|
|
dwMemPos = sizeof(MT2FILEHEADER);
|
|
nDrumDataLen = *(WORD *)(lpStream + dwMemPos);
|
|
dwDrumDataPos = dwMemPos + 2;
|
|
if (nDrumDataLen >= 2) pdd = (MT2DRUMSDATA *)(lpStream+dwDrumDataPos);
|
|
dwMemPos += 2 + nDrumDataLen;
|
|
#ifdef MT2DEBUG
|
|
|
|
Log("MT2 v%03X: \"%s\" (flags=%04X)\n", pfh->wVersion, m_szNames[0], pfh->fulFlags);
|
|
Log("%d Channels, %d Patterns, %d Instruments, %d Samples\n", pfh->wChannels, pfh->wPatterns, pfh->wInstruments, pfh->wSamples);
|
|
Log("Drum Data: %d bytes @%04X\n", nDrumDataLen, dwDrumDataPos);
|
|
#endif
|
|
if (dwMemPos >= dwMemLength-12) return TRUE;
|
|
if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
|
|
if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
|
|
nExtraDataLen = *(DWORD *)(lpStream+dwMemPos);
|
|
dwExtraDataPos = dwMemPos + 4;
|
|
dwMemPos += 4;
|
|
#ifdef MT2DEBUG
|
|
Log("Extra Data: %d bytes @%04X\n", nExtraDataLen, dwExtraDataPos);
|
|
#endif
|
|
if (dwMemPos + nExtraDataLen >= dwMemLength) return TRUE;
|
|
while (dwMemPos+8 < dwExtraDataPos + nExtraDataLen)
|
|
{
|
|
DWORD dwId = *(DWORD *)(lpStream+dwMemPos);
|
|
DWORD dwLen = *(DWORD *)(lpStream+dwMemPos+4);
|
|
dwMemPos += 8;
|
|
if (dwMemPos + dwLen > dwMemLength) return TRUE;
|
|
#ifdef MT2DEBUG
|
|
CHAR s[5];
|
|
memcpy(s, &dwId, 4);
|
|
s[4] = 0;
|
|
Log("pos=0x%04X: %s: %d bytes\n", dwMemPos-8, s, dwLen);
|
|
#endif
|
|
switch(dwId)
|
|
{
|
|
// MSG
|
|
case 0x0047534D:
|
|
if ((dwLen > 3) && (!m_lpszSongComments))
|
|
{
|
|
DWORD nTxtLen = dwLen;
|
|
if (nTxtLen > 32000) nTxtLen = 32000;
|
|
m_lpszSongComments = new char[nTxtLen]; // changed from CHAR
|
|
if (m_lpszSongComments)
|
|
{
|
|
memcpy(m_lpszSongComments, lpStream+dwMemPos+1, nTxtLen-1);
|
|
m_lpszSongComments[nTxtLen-1] = 0;
|
|
}
|
|
}
|
|
break;
|
|
// SUM -> author name (or "Unregistered")
|
|
// TMAP
|
|
// TRKS
|
|
case 0x534b5254:
|
|
break;
|
|
}
|
|
dwMemPos += dwLen;
|
|
}
|
|
// Load Patterns
|
|
dwMemPos = dwExtraDataPos + nExtraDataLen;
|
|
for (UINT iPat=0; iPat<pfh->wPatterns; iPat++) if (dwMemPos < dwMemLength-6)
|
|
{
|
|
MT2PATTERN *pmp = (MT2PATTERN *)(lpStream+dwMemPos);
|
|
UINT wDataLen = (pmp->wDataLen + 1) & ~1;
|
|
dwMemPos += 6;
|
|
if (dwMemPos + wDataLen > dwMemLength) break;
|
|
UINT nLines = pmp->wLines;
|
|
if ((iPat < MAX_PATTERNS) && (nLines > 0) && (nLines <= 256))
|
|
{
|
|
#ifdef MT2DEBUG
|
|
Log("Pattern #%d @%04X: %d lines, %d bytes\n", iPat, dwMemPos-6, nLines, pmp->wDataLen);
|
|
#endif
|
|
PatternSize[iPat] = nLines;
|
|
Patterns[iPat] = AllocatePattern(nLines, m_nChannels);
|
|
if (!Patterns[iPat]) return TRUE;
|
|
MODCOMMAND *m = Patterns[iPat];
|
|
UINT len = wDataLen;
|
|
if (pfh->fulFlags & 1) // Packed Patterns
|
|
{
|
|
BYTE *p = (BYTE *)(lpStream+dwMemPos);
|
|
UINT pos = 0, row=0, ch=0;
|
|
while (pos < len)
|
|
{
|
|
MT2COMMAND cmd;
|
|
UINT infobyte = p[pos++];
|
|
UINT rptcount = 0;
|
|
if (infobyte == 0xff)
|
|
{
|
|
rptcount = p[pos++];
|
|
infobyte = p[pos++];
|
|
#if 0
|
|
Log("(%d.%d) FF(%02X).%02X\n", row, ch, rptcount, infobyte);
|
|
} else
|
|
{
|
|
Log("(%d.%d) %02X\n", row, ch, infobyte);
|
|
#endif
|
|
}
|
|
if (infobyte & 0x7f)
|
|
{
|
|
UINT patpos = row*m_nChannels+ch;
|
|
cmd.note = cmd.instr = cmd.vol = cmd.pan = cmd.fxcmd = cmd.fxparam1 = cmd.fxparam2 = 0;
|
|
if (infobyte & 1) cmd.note = p[pos++];
|
|
if (infobyte & 2) cmd.instr = p[pos++];
|
|
if (infobyte & 4) cmd.vol = p[pos++];
|
|
if (infobyte & 8) cmd.pan = p[pos++];
|
|
if (infobyte & 16) cmd.fxcmd = p[pos++];
|
|
if (infobyte & 32) cmd.fxparam1 = p[pos++];
|
|
if (infobyte & 64) cmd.fxparam2 = p[pos++];
|
|
#ifdef MT2DEBUG
|
|
if (cmd.fxcmd)
|
|
{
|
|
Log("(%d.%d) MT2 FX=%02X.%02X.%02X\n", row, ch, cmd.fxcmd, cmd.fxparam1, cmd.fxparam2);
|
|
}
|
|
#endif
|
|
ConvertMT2Command(this, &m[patpos], &cmd);
|
|
}
|
|
row += rptcount+1;
|
|
while (row >= nLines) { row-=nLines; ch++; }
|
|
if (ch >= m_nChannels) break;
|
|
}
|
|
} else
|
|
{
|
|
MT2COMMAND *p = (MT2COMMAND *)(lpStream+dwMemPos);
|
|
UINT n = 0;
|
|
while ((len > sizeof(MT2COMMAND)) && (n < m_nChannels*nLines))
|
|
{
|
|
ConvertMT2Command(this, m, p);
|
|
len -= sizeof(MT2COMMAND);
|
|
n++;
|
|
p++;
|
|
m++;
|
|
}
|
|
}
|
|
}
|
|
dwMemPos += wDataLen;
|
|
}
|
|
// Skip Drum Patterns
|
|
if (pdd)
|
|
{
|
|
#ifdef MT2DEBUG
|
|
Log("%d Drum Patterns at offset 0x%08X\n", pdd->wDrumPatterns, dwMemPos);
|
|
#endif
|
|
for (UINT iDrm=0; iDrm<pdd->wDrumPatterns; iDrm++)
|
|
{
|
|
if (dwMemPos > dwMemLength-2) return TRUE;
|
|
UINT nLines = *(WORD *)(lpStream+dwMemPos);
|
|
#ifdef MT2DEBUG
|
|
if (nLines != 64) Log("Drum Pattern %d: %d Lines @%04X\n", iDrm, nLines, dwMemPos);
|
|
#endif
|
|
dwMemPos += 2 + nLines * 32;
|
|
}
|
|
}
|
|
// Automation
|
|
if (pfh->fulFlags & 2)
|
|
{
|
|
#ifdef MT2DEBUG
|
|
Log("Automation at offset 0x%08X\n", dwMemPos);
|
|
#endif
|
|
UINT nAutoCount = m_nChannels;
|
|
if (pfh->fulFlags & 0x10) nAutoCount++; // Master Automation
|
|
if ((pfh->fulFlags & 0x08) && (pdd)) nAutoCount += 8; // Drums Automation
|
|
nAutoCount *= pfh->wPatterns;
|
|
for (UINT iAuto=0; iAuto<nAutoCount; iAuto++)
|
|
{
|
|
if (dwMemPos+12 >= dwMemLength) return TRUE;
|
|
MT2AUTOMATION *pma = (MT2AUTOMATION *)(lpStream+dwMemPos);
|
|
dwMemPos += (pfh->wVersion <= 0x201) ? 4 : 8;
|
|
for (UINT iEnv=0; iEnv<14; iEnv++)
|
|
{
|
|
if (pma->dwFlags & (1 << iEnv))
|
|
{
|
|
#ifdef MT2DEBUG
|
|
UINT nPoints = *(DWORD *)(lpStream+dwMemPos);
|
|
Log(" Env[%d/%d] %04X @%04X: %d points\n", iAuto, nAutoCount, 1 << iEnv, dwMemPos-8, nPoints);
|
|
#endif
|
|
dwMemPos += 260;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Load Instruments
|
|
#ifdef MT2DEBUG
|
|
Log("Loading instruments at offset 0x%08X\n", dwMemPos);
|
|
#endif
|
|
memset(InstrMap, 0, sizeof(InstrMap));
|
|
m_nInstruments = (pfh->wInstruments < MAX_INSTRUMENTS) ? pfh->wInstruments : MAX_INSTRUMENTS-1;
|
|
for (UINT iIns=1; iIns<=255; iIns++)
|
|
{
|
|
if (dwMemPos+36 > dwMemLength) return TRUE;
|
|
MT2INSTRUMENT *pmi = (MT2INSTRUMENT *)(lpStream+dwMemPos);
|
|
INSTRUMENTHEADER *penv = NULL;
|
|
if (iIns <= m_nInstruments)
|
|
{
|
|
penv = new INSTRUMENTHEADER;
|
|
Headers[iIns] = penv;
|
|
if (penv)
|
|
{
|
|
memset(penv, 0, sizeof(INSTRUMENTHEADER));
|
|
memcpy(penv->name, pmi->szName, 32);
|
|
penv->nGlobalVol = 64;
|
|
penv->nPan = 128;
|
|
for (UINT i=0; i<120; i++)
|
|
{
|
|
penv->NoteMap[i] = i+1;
|
|
}
|
|
}
|
|
}
|
|
#ifdef MT2DEBUG
|
|
if (iIns <= pfh->wInstruments) Log(" Instrument #%d at offset %04X: %d bytes\n", iIns, dwMemPos, pmi->dwDataLen);
|
|
#endif
|
|
if (((LONG)pmi->dwDataLen > 0) && (dwMemPos + pmi->dwDataLen + 40 <= dwMemLength))
|
|
{
|
|
InstrMap[iIns-1] = pmi;
|
|
if (penv)
|
|
{
|
|
penv->nFadeOut = pmi->wFadeOut;
|
|
penv->nNNA = pmi->wNNA & 3;
|
|
penv->nDCT = (pmi->wNNA>>8) & 3;
|
|
penv->nDNA = (pmi->wNNA>>12) & 3;
|
|
MT2ENVELOPE *pehdr[4];
|
|
WORD *pedata[4];
|
|
if (pfh->wVersion <= 0x201)
|
|
{
|
|
DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT) - 4;
|
|
pehdr[0] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
|
|
pehdr[1] = (MT2ENVELOPE *)(lpStream+dwEnvPos+8);
|
|
pehdr[2] = pehdr[3] = NULL;
|
|
pedata[0] = (WORD *)(lpStream+dwEnvPos+16);
|
|
pedata[1] = (WORD *)(lpStream+dwEnvPos+16+64);
|
|
pedata[2] = pedata[3] = NULL;
|
|
} else
|
|
{
|
|
DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT);
|
|
for (UINT i=0; i<4; i++)
|
|
{
|
|
if (pmi->wEnvFlags1 & (1<<i))
|
|
{
|
|
pehdr[i] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
|
|
pedata[i] = (WORD *)pehdr[i]->EnvData;
|
|
dwEnvPos += sizeof(MT2ENVELOPE);
|
|
} else
|
|
{
|
|
pehdr[i] = NULL;
|
|
pedata[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
// Load envelopes
|
|
for (UINT iEnv=0; iEnv<4; iEnv++) if (pehdr[iEnv])
|
|
{
|
|
MT2ENVELOPE *pme = pehdr[iEnv];
|
|
WORD *pEnvPoints = NULL;
|
|
BYTE *pEnvData = NULL;
|
|
#ifdef MT2DEBUG
|
|
Log(" Env %d.%d @%04X: %d points\n", iIns, iEnv, (UINT)(((BYTE *)pme)-lpStream), pme->nPoints);
|
|
#endif
|
|
switch(iEnv)
|
|
{
|
|
// Volume Envelope
|
|
case 0:
|
|
if (pme->nFlags & 1) penv->dwFlags |= ENV_VOLUME;
|
|
if (pme->nFlags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
|
|
if (pme->nFlags & 4) penv->dwFlags |= ENV_VOLLOOP;
|
|
penv->nVolEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
|
|
penv->nVolSustainBegin = penv->nVolSustainEnd = pme->nSustainPos;
|
|
penv->nVolLoopStart = pme->nLoopStart;
|
|
penv->nVolLoopEnd = pme->nLoopEnd;
|
|
pEnvPoints = penv->VolPoints;
|
|
pEnvData = penv->VolEnv;
|
|
break;
|
|
|
|
// Panning Envelope
|
|
case 1:
|
|
if (pme->nFlags & 1) penv->dwFlags |= ENV_PANNING;
|
|
if (pme->nFlags & 2) penv->dwFlags |= ENV_PANSUSTAIN;
|
|
if (pme->nFlags & 4) penv->dwFlags |= ENV_PANLOOP;
|
|
penv->nPanEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
|
|
penv->nPanSustainBegin = penv->nPanSustainEnd = pme->nSustainPos;
|
|
penv->nPanLoopStart = pme->nLoopStart;
|
|
penv->nPanLoopEnd = pme->nLoopEnd;
|
|
pEnvPoints = penv->PanPoints;
|
|
pEnvData = penv->PanEnv;
|
|
break;
|
|
|
|
// Pitch/Filter envelope
|
|
default:
|
|
if (pme->nFlags & 1) penv->dwFlags |= (iEnv==3) ? (ENV_PITCH|ENV_FILTER) : ENV_PITCH;
|
|
if (pme->nFlags & 2) penv->dwFlags |= ENV_PITCHSUSTAIN;
|
|
if (pme->nFlags & 4) penv->dwFlags |= ENV_PITCHLOOP;
|
|
penv->nPitchEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
|
|
penv->nPitchSustainBegin = penv->nPitchSustainEnd = pme->nSustainPos;
|
|
penv->nPitchLoopStart = pme->nLoopStart;
|
|
penv->nPitchLoopEnd = pme->nLoopEnd;
|
|
pEnvPoints = penv->PitchPoints;
|
|
pEnvData = penv->PitchEnv;
|
|
}
|
|
// Envelope data
|
|
if ((pEnvPoints) && (pEnvData) && (pedata[iEnv]))
|
|
{
|
|
WORD *psrc = pedata[iEnv];
|
|
for (UINT i=0; i<16; i++)
|
|
{
|
|
pEnvPoints[i] = psrc[i*2];
|
|
pEnvData[i] = (BYTE)psrc[i*2+1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dwMemPos += pmi->dwDataLen + 36;
|
|
if (pfh->wVersion > 0x201) dwMemPos += 4; // ?
|
|
} else
|
|
{
|
|
dwMemPos += 36;
|
|
}
|
|
}
|
|
#ifdef MT2DEBUG
|
|
Log("Loading samples at offset 0x%08X\n", dwMemPos);
|
|
#endif
|
|
memset(SampleMap, 0, sizeof(SampleMap));
|
|
m_nSamples = (pfh->wSamples < MAX_SAMPLES) ? pfh->wSamples : MAX_SAMPLES-1;
|
|
for (UINT iSmp=1; iSmp<=256; iSmp++)
|
|
{
|
|
if (dwMemPos+36 > dwMemLength) return TRUE;
|
|
MT2SAMPLE *pms = (MT2SAMPLE *)(lpStream+dwMemPos);
|
|
#ifdef MT2DEBUG
|
|
if (iSmp <= m_nSamples) Log(" Sample #%d at offset %04X: %d bytes\n", iSmp, dwMemPos, pms->dwDataLen);
|
|
#endif
|
|
if (iSmp < MAX_SAMPLES)
|
|
{
|
|
memcpy(m_szNames[iSmp], pms->szName, 32);
|
|
}
|
|
if (pms->dwDataLen > 0)
|
|
{
|
|
SampleMap[iSmp-1] = pms;
|
|
if (iSmp < MAX_SAMPLES)
|
|
{
|
|
MODINSTRUMENT *psmp = &Ins[iSmp];
|
|
psmp->nGlobalVol = 64;
|
|
psmp->nVolume = (pms->wVolume >> 7);
|
|
psmp->nPan = (pms->nPan == 0x80) ? 128 : (pms->nPan^0x80);
|
|
psmp->nLength = pms->dwLength;
|
|
psmp->nC4Speed = pms->dwFrequency;
|
|
psmp->nLoopStart = pms->dwLoopStart;
|
|
psmp->nLoopEnd = pms->dwLoopEnd;
|
|
FrequencyToTranspose(psmp);
|
|
psmp->RelativeTone -= pms->nBaseNote - 49;
|
|
psmp->nC4Speed = TransposeToFrequency(psmp->RelativeTone, psmp->nFineTune);
|
|
if (pms->nQuality == 2) { psmp->uFlags |= CHN_16BIT; psmp->nLength >>= 1; }
|
|
if (pms->nChannels == 2) { psmp->nLength >>= 1; }
|
|
if (pms->nLoop == 1) psmp->uFlags |= CHN_LOOP;
|
|
if (pms->nLoop == 2) psmp->uFlags |= CHN_LOOP|CHN_PINGPONGLOOP;
|
|
}
|
|
dwMemPos += pms->dwDataLen + 36;
|
|
} else
|
|
{
|
|
dwMemPos += 36;
|
|
}
|
|
}
|
|
#ifdef MT2DEBUG
|
|
Log("Loading groups at offset 0x%08X\n", dwMemPos);
|
|
#endif
|
|
for (UINT iMap=0; iMap<255; iMap++) if (InstrMap[iMap])
|
|
{
|
|
if (dwMemPos+8 > dwMemLength) return TRUE;
|
|
MT2INSTRUMENT *pmi = InstrMap[iMap];
|
|
INSTRUMENTHEADER *penv = NULL;
|
|
if (iMap<m_nInstruments) penv = Headers[iMap+1];
|
|
for (UINT iGrp=0; iGrp<pmi->wSamples; iGrp++)
|
|
{
|
|
if (penv)
|
|
{
|
|
MT2GROUP *pmg = (MT2GROUP *)(lpStream+dwMemPos);
|
|
for (UINT i=0; i<96; i++)
|
|
{
|
|
if (pmi->GroupsMapping[i] == iGrp)
|
|
{
|
|
UINT nSmp = pmg->nSmpNo+1;
|
|
penv->Keyboard[i+12] = (BYTE)nSmp;
|
|
if (nSmp <= m_nSamples)
|
|
{
|
|
Ins[nSmp].nVibType = pmi->bVibType;
|
|
Ins[nSmp].nVibSweep = pmi->bVibSweep;
|
|
Ins[nSmp].nVibDepth = pmi->bVibDepth;
|
|
Ins[nSmp].nVibRate = pmi->bVibRate;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dwMemPos += 8;
|
|
}
|
|
}
|
|
#ifdef MT2DEBUG
|
|
Log("Loading sample data at offset 0x%08X\n", dwMemPos);
|
|
#endif
|
|
for (UINT iData=0; iData<256; iData++) if ((iData < m_nSamples) && (SampleMap[iData]))
|
|
{
|
|
MT2SAMPLE *pms = SampleMap[iData];
|
|
MODINSTRUMENT *psmp = &Ins[iData+1];
|
|
if (!(pms->nFlags & 5))
|
|
{
|
|
if (psmp->nLength > 0)
|
|
{
|
|
#ifdef MT2DEBUG
|
|
Log(" Reading sample #%d at offset 0x%04X (len=%d)\n", iData+1, dwMemPos, psmp->nLength);
|
|
#endif
|
|
UINT rsflags;
|
|
|
|
if (pms->nChannels == 2)
|
|
rsflags = (psmp->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D;
|
|
else
|
|
rsflags = (psmp->uFlags & CHN_16BIT) ? RS_PCM16D : RS_PCM8D;
|
|
|
|
dwMemPos += ReadSample(psmp, rsflags, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
|
|
}
|
|
} else
|
|
if (dwMemPos+4 < dwMemLength)
|
|
{
|
|
UINT nNameLen = *(DWORD *)(lpStream+dwMemPos);
|
|
dwMemPos += nNameLen + 16;
|
|
}
|
|
if (dwMemPos+4 >= dwMemLength) break;
|
|
}
|
|
return TRUE;
|
|
}
|