| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #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; |
| } |