external/libmodplug-0.8.8.4/src/load_mt2.cpp
author Sam Lantinga <slouken@libsdl.org>
Sun, 09 Jun 2013 16:22:42 -0700
changeset 639 f8901a7ff3f1
permissions -rw-r--r--
Switched from mikmod to libmodplug, which is now in the public domain.
This allows us to add MOD support for iOS and Android, yay!
slouken@639
     1
#include "stdafx.h"
slouken@639
     2
#include "sndfile.h"
slouken@639
     3
slouken@639
     4
//#define MT2DEBUG
slouken@639
     5
slouken@639
     6
#pragma pack(1)
slouken@639
     7
slouken@639
     8
typedef struct _MT2FILEHEADER
slouken@639
     9
{
slouken@639
    10
	DWORD dwMT20;	// 0x3032544D "MT20"
slouken@639
    11
	DWORD dwSpecial;
slouken@639
    12
	WORD wVersion;
slouken@639
    13
	CHAR szTrackerName[32];	// "MadTracker 2.0"
slouken@639
    14
	CHAR szSongName[64];
slouken@639
    15
	WORD nOrders;
slouken@639
    16
	WORD wRestart;
slouken@639
    17
	WORD wPatterns;
slouken@639
    18
	WORD wChannels;
slouken@639
    19
	WORD wSamplesPerTick;
slouken@639
    20
	BYTE bTicksPerLine;
slouken@639
    21
	BYTE bLinesPerBeat;
slouken@639
    22
	DWORD fulFlags; // b0=packed patterns
slouken@639
    23
	WORD wInstruments;
slouken@639
    24
	WORD wSamples;
slouken@639
    25
	BYTE Orders[256];
slouken@639
    26
} MT2FILEHEADER;
slouken@639
    27
slouken@639
    28
typedef struct _MT2PATTERN
slouken@639
    29
{
slouken@639
    30
	WORD wLines;
slouken@639
    31
	DWORD wDataLen;
slouken@639
    32
} MT2PATTERN;
slouken@639
    33
slouken@639
    34
typedef struct _MT2COMMAND
slouken@639
    35
{
slouken@639
    36
	BYTE note;	// 0=nothing, 97=note off
slouken@639
    37
	BYTE instr;
slouken@639
    38
	BYTE vol;
slouken@639
    39
	BYTE pan;
slouken@639
    40
	BYTE fxcmd;
slouken@639
    41
	BYTE fxparam1;
slouken@639
    42
	BYTE fxparam2;
slouken@639
    43
} MT2COMMAND;
slouken@639
    44
slouken@639
    45
typedef struct _MT2DRUMSDATA
slouken@639
    46
{
slouken@639
    47
	WORD wDrumPatterns;
slouken@639
    48
	WORD wDrumSamples[8];
slouken@639
    49
	BYTE DrumPatternOrder[256];
slouken@639
    50
} MT2DRUMSDATA;
slouken@639
    51
slouken@639
    52
typedef struct _MT2AUTOMATION
slouken@639
    53
{
slouken@639
    54
	DWORD dwFlags;
slouken@639
    55
	DWORD dwEffectId;
slouken@639
    56
	DWORD nEnvPoints;
slouken@639
    57
} MT2AUTOMATION;
slouken@639
    58
slouken@639
    59
typedef struct _MT2INSTRUMENT
slouken@639
    60
{
slouken@639
    61
	CHAR szName[32];
slouken@639
    62
	DWORD dwDataLen;
slouken@639
    63
	WORD wSamples;
slouken@639
    64
	BYTE GroupsMapping[96];
slouken@639
    65
	BYTE bVibType;
slouken@639
    66
	BYTE bVibSweep;
slouken@639
    67
	BYTE bVibDepth;
slouken@639
    68
	BYTE bVibRate;
slouken@639
    69
	WORD wFadeOut;
slouken@639
    70
	WORD wNNA;
slouken@639
    71
	WORD wInstrFlags;
slouken@639
    72
	WORD wEnvFlags1;
slouken@639
    73
	WORD wEnvFlags2;
slouken@639
    74
} MT2INSTRUMENT;
slouken@639
    75
slouken@639
    76
typedef struct _MT2ENVELOPE
slouken@639
    77
{
slouken@639
    78
	BYTE nFlags;
slouken@639
    79
	BYTE nPoints;
slouken@639
    80
	BYTE nSustainPos;
slouken@639
    81
	BYTE nLoopStart;
slouken@639
    82
	BYTE nLoopEnd;
slouken@639
    83
	BYTE bReserved[3];
slouken@639
    84
	BYTE EnvData[64];
slouken@639
    85
} MT2ENVELOPE;
slouken@639
    86
slouken@639
    87
typedef struct _MT2SYNTH
slouken@639
    88
{
slouken@639
    89
	BYTE nSynthId;
slouken@639
    90
	BYTE nFxId;
slouken@639
    91
	WORD wCutOff;
slouken@639
    92
	BYTE nResonance;
slouken@639
    93
	BYTE nAttack;
slouken@639
    94
	BYTE nDecay;
slouken@639
    95
	BYTE bReserved[25];
slouken@639
    96
} MT2SYNTH;
slouken@639
    97
slouken@639
    98
typedef struct _MT2SAMPLE
slouken@639
    99
{
slouken@639
   100
	CHAR szName[32];
slouken@639
   101
	DWORD dwDataLen;
slouken@639
   102
	DWORD dwLength;
slouken@639
   103
	DWORD dwFrequency;
slouken@639
   104
	BYTE nQuality;
slouken@639
   105
	BYTE nChannels;
slouken@639
   106
	BYTE nFlags;
slouken@639
   107
	BYTE nLoop;
slouken@639
   108
	DWORD dwLoopStart;
slouken@639
   109
	DWORD dwLoopEnd;
slouken@639
   110
	WORD wVolume;
slouken@639
   111
	BYTE nPan;
slouken@639
   112
	BYTE nBaseNote;
slouken@639
   113
	WORD wSamplesPerBeat;
slouken@639
   114
} MT2SAMPLE;
slouken@639
   115
slouken@639
   116
typedef struct _MT2GROUP
slouken@639
   117
{
slouken@639
   118
	BYTE nSmpNo;
slouken@639
   119
	BYTE nVolume;	// 0-128
slouken@639
   120
	BYTE nFinePitch;
slouken@639
   121
	BYTE Reserved[5];
slouken@639
   122
} MT2GROUP;
slouken@639
   123
slouken@639
   124
#pragma pack()
slouken@639
   125
slouken@639
   126
slouken@639
   127
static VOID ConvertMT2Command(CSoundFile *that, MODCOMMAND *m, const MT2COMMAND *p)
slouken@639
   128
//---------------------------------------------------------------------------
slouken@639
   129
{
slouken@639
   130
	// Note
slouken@639
   131
	m->note = 0;
slouken@639
   132
	if (p->note) m->note = (p->note > 96) ? 0xFF : p->note+12;
slouken@639
   133
	// Instrument
slouken@639
   134
	m->instr = p->instr;
slouken@639
   135
	// Volume Column
slouken@639
   136
	if ((p->vol >= 0x10) && (p->vol <= 0x90))
slouken@639
   137
	{
slouken@639
   138
		m->volcmd = VOLCMD_VOLUME;
slouken@639
   139
		m->vol = (p->vol - 0x10) >> 1;
slouken@639
   140
	} else
slouken@639
   141
	if ((p->vol >= 0xA0) && (p->vol <= 0xAF))
slouken@639
   142
	{
slouken@639
   143
		m->volcmd = VOLCMD_VOLSLIDEDOWN;
slouken@639
   144
		m->vol = (p->vol & 0x0f);
slouken@639
   145
	} else
slouken@639
   146
	if ((p->vol >= 0xB0) && (p->vol <= 0xBF))
slouken@639
   147
	{
slouken@639
   148
		m->volcmd = VOLCMD_VOLSLIDEUP;
slouken@639
   149
		m->vol = (p->vol & 0x0f);
slouken@639
   150
	} else
slouken@639
   151
	if ((p->vol >= 0xC0) && (p->vol <= 0xCF))
slouken@639
   152
	{
slouken@639
   153
		m->volcmd = VOLCMD_FINEVOLDOWN;
slouken@639
   154
		m->vol = (p->vol & 0x0f);
slouken@639
   155
	} else
slouken@639
   156
	if ((p->vol >= 0xD0) && (p->vol <= 0xDF))
slouken@639
   157
	{
slouken@639
   158
		m->volcmd = VOLCMD_FINEVOLUP;
slouken@639
   159
		m->vol = (p->vol & 0x0f);
slouken@639
   160
	} else
slouken@639
   161
	{
slouken@639
   162
		m->volcmd = 0;
slouken@639
   163
		m->vol = 0;
slouken@639
   164
	}
slouken@639
   165
	// Effects
slouken@639
   166
	m->command = 0;
slouken@639
   167
	m->param = 0;
slouken@639
   168
	if ((p->fxcmd) || (p->fxparam1) || (p->fxparam2))
slouken@639
   169
	{
slouken@639
   170
		if (!p->fxcmd)
slouken@639
   171
		{
slouken@639
   172
			m->command = p->fxparam2;
slouken@639
   173
			m->param = p->fxparam1;
slouken@639
   174
			that->ConvertModCommand(m);
slouken@639
   175
		} else
slouken@639
   176
		{
slouken@639
   177
			// TODO: MT2 Effects
slouken@639
   178
		}
slouken@639
   179
	}
slouken@639
   180
}
slouken@639
   181
slouken@639
   182
slouken@639
   183
BOOL CSoundFile::ReadMT2(LPCBYTE lpStream, DWORD dwMemLength)
slouken@639
   184
//-----------------------------------------------------------
slouken@639
   185
{
slouken@639
   186
	const MT2FILEHEADER *pfh = (MT2FILEHEADER *)lpStream;
slouken@639
   187
	DWORD dwMemPos, dwDrumDataPos, dwExtraDataPos;
slouken@639
   188
	UINT nDrumDataLen, nExtraDataLen;
slouken@639
   189
	const MT2DRUMSDATA *pdd;
slouken@639
   190
	const MT2INSTRUMENT *InstrMap[255];
slouken@639
   191
	const MT2SAMPLE *SampleMap[256];
slouken@639
   192
slouken@639
   193
	if ((!lpStream) || (dwMemLength < sizeof(MT2FILEHEADER))
slouken@639
   194
	 || (pfh->dwMT20 != 0x3032544D)
slouken@639
   195
	 || (pfh->wVersion < 0x0200) || (pfh->wVersion >= 0x0300)
slouken@639
   196
	 || (pfh->wChannels < 4) || (pfh->wChannels > 64)) return FALSE;
slouken@639
   197
	pdd = NULL;
slouken@639
   198
	m_nType = MOD_TYPE_MT2;
slouken@639
   199
	m_nChannels = pfh->wChannels;
slouken@639
   200
	m_nRestartPos = pfh->wRestart;
slouken@639
   201
	m_nDefaultSpeed = pfh->bTicksPerLine;
slouken@639
   202
	m_nDefaultTempo = 125;
slouken@639
   203
	if ((pfh->wSamplesPerTick > 100) && (pfh->wSamplesPerTick < 5000))
slouken@639
   204
	{
slouken@639
   205
		m_nDefaultTempo = 110250 / pfh->wSamplesPerTick;
slouken@639
   206
	}
slouken@639
   207
	for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
slouken@639
   208
	{
slouken@639
   209
		Order[iOrd] = (BYTE)((iOrd < pfh->nOrders) ? pfh->Orders[iOrd] : 0xFF);
slouken@639
   210
	}
slouken@639
   211
	memcpy(m_szNames[0], pfh->szSongName, 32);
slouken@639
   212
	m_szNames[0][31] = 0;
slouken@639
   213
	dwMemPos = sizeof(MT2FILEHEADER);
slouken@639
   214
	nDrumDataLen = *(WORD *)(lpStream + dwMemPos);
slouken@639
   215
	dwDrumDataPos = dwMemPos + 2;
slouken@639
   216
	if (nDrumDataLen >= 2) pdd = (MT2DRUMSDATA *)(lpStream+dwDrumDataPos);
slouken@639
   217
	dwMemPos += 2 + nDrumDataLen;
slouken@639
   218
#ifdef MT2DEBUG
slouken@639
   219
slouken@639
   220
	Log("MT2 v%03X: \"%s\" (flags=%04X)\n", pfh->wVersion, m_szNames[0], pfh->fulFlags);
slouken@639
   221
	Log("%d Channels, %d Patterns, %d Instruments, %d Samples\n", pfh->wChannels, pfh->wPatterns, pfh->wInstruments, pfh->wSamples);
slouken@639
   222
	Log("Drum Data: %d bytes @%04X\n", nDrumDataLen, dwDrumDataPos);
slouken@639
   223
#endif
slouken@639
   224
	if (dwMemPos >= dwMemLength-12) return TRUE;
slouken@639
   225
	if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
slouken@639
   226
	if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
slouken@639
   227
	nExtraDataLen = *(DWORD *)(lpStream+dwMemPos);
slouken@639
   228
	dwExtraDataPos = dwMemPos + 4;
slouken@639
   229
	dwMemPos += 4;
slouken@639
   230
#ifdef MT2DEBUG
slouken@639
   231
	Log("Extra Data: %d bytes @%04X\n", nExtraDataLen, dwExtraDataPos);
slouken@639
   232
#endif
slouken@639
   233
	if (dwMemPos + nExtraDataLen >= dwMemLength) return TRUE;
slouken@639
   234
	while (dwMemPos+8 < dwExtraDataPos + nExtraDataLen)
slouken@639
   235
	{
slouken@639
   236
		DWORD dwId = *(DWORD *)(lpStream+dwMemPos);
slouken@639
   237
		DWORD dwLen = *(DWORD *)(lpStream+dwMemPos+4);
slouken@639
   238
		dwMemPos += 8;
slouken@639
   239
		if (dwMemPos + dwLen > dwMemLength) return TRUE;
slouken@639
   240
#ifdef MT2DEBUG
slouken@639
   241
		CHAR s[5];
slouken@639
   242
		memcpy(s, &dwId, 4);
slouken@639
   243
		s[4] = 0;
slouken@639
   244
		Log("pos=0x%04X: %s: %d bytes\n", dwMemPos-8, s, dwLen);
slouken@639
   245
#endif
slouken@639
   246
		switch(dwId)
slouken@639
   247
		{
slouken@639
   248
		// MSG
slouken@639
   249
		case 0x0047534D:
slouken@639
   250
			if ((dwLen > 3) && (!m_lpszSongComments))
slouken@639
   251
			{
slouken@639
   252
				DWORD nTxtLen = dwLen;
slouken@639
   253
				if (nTxtLen > 32000) nTxtLen = 32000;
slouken@639
   254
				m_lpszSongComments = new char[nTxtLen];  // changed from CHAR
slouken@639
   255
				if (m_lpszSongComments)
slouken@639
   256
				{
slouken@639
   257
					memcpy(m_lpszSongComments, lpStream+dwMemPos+1, nTxtLen-1);
slouken@639
   258
					m_lpszSongComments[nTxtLen-1] = 0;
slouken@639
   259
				}
slouken@639
   260
			}
slouken@639
   261
			break;
slouken@639
   262
		// SUM -> author name (or "Unregistered")
slouken@639
   263
		// TMAP
slouken@639
   264
		// TRKS
slouken@639
   265
		case 0x534b5254:
slouken@639
   266
			break;
slouken@639
   267
		}
slouken@639
   268
		dwMemPos += dwLen;
slouken@639
   269
	}
slouken@639
   270
	// Load Patterns
slouken@639
   271
	dwMemPos = dwExtraDataPos + nExtraDataLen;
slouken@639
   272
	for (UINT iPat=0; iPat<pfh->wPatterns; iPat++) if (dwMemPos < dwMemLength-6)
slouken@639
   273
	{
slouken@639
   274
		const MT2PATTERN *pmp = (MT2PATTERN *)(lpStream+dwMemPos);
slouken@639
   275
		UINT wDataLen = (pmp->wDataLen + 1) & ~1;
slouken@639
   276
		dwMemPos += 6;
slouken@639
   277
		if (dwMemPos + wDataLen > dwMemLength) break;
slouken@639
   278
		UINT nLines = pmp->wLines;
slouken@639
   279
		if ((iPat < MAX_PATTERNS) && (nLines > 0) && (nLines <= 256))
slouken@639
   280
		{
slouken@639
   281
	#ifdef MT2DEBUG
slouken@639
   282
			Log("Pattern #%d @%04X: %d lines, %d bytes\n", iPat, dwMemPos-6, nLines, pmp->wDataLen);
slouken@639
   283
	#endif
slouken@639
   284
			PatternSize[iPat] = nLines;
slouken@639
   285
			Patterns[iPat] = AllocatePattern(nLines, m_nChannels);
slouken@639
   286
			if (!Patterns[iPat]) return TRUE;
slouken@639
   287
			MODCOMMAND *m = Patterns[iPat];
slouken@639
   288
			UINT len = wDataLen;
slouken@639
   289
			if (pfh->fulFlags & 1) // Packed Patterns
slouken@639
   290
			{
slouken@639
   291
				BYTE *p = (BYTE *)(lpStream+dwMemPos);
slouken@639
   292
				UINT pos = 0, row=0, ch=0;
slouken@639
   293
				while (pos < len)
slouken@639
   294
				{
slouken@639
   295
					MT2COMMAND cmd;
slouken@639
   296
					UINT infobyte = p[pos++];
slouken@639
   297
					UINT rptcount = 0;
slouken@639
   298
					if (infobyte == 0xff)
slouken@639
   299
					{
slouken@639
   300
						rptcount = p[pos++];
slouken@639
   301
						infobyte = p[pos++];
slouken@639
   302
				#if 0
slouken@639
   303
						Log("(%d.%d) FF(%02X).%02X\n", row, ch, rptcount, infobyte);
slouken@639
   304
					} else
slouken@639
   305
					{
slouken@639
   306
						Log("(%d.%d) %02X\n", row, ch, infobyte);
slouken@639
   307
				#endif
slouken@639
   308
					}
slouken@639
   309
					if (infobyte & 0x7f)
slouken@639
   310
					{
slouken@639
   311
						UINT patpos = row*m_nChannels+ch;
slouken@639
   312
						cmd.note = cmd.instr = cmd.vol = cmd.pan = cmd.fxcmd = cmd.fxparam1 = cmd.fxparam2 = 0;
slouken@639
   313
						if (infobyte & 1) cmd.note = p[pos++];
slouken@639
   314
						if (infobyte & 2) cmd.instr = p[pos++];
slouken@639
   315
						if (infobyte & 4) cmd.vol = p[pos++];
slouken@639
   316
						if (infobyte & 8) cmd.pan = p[pos++];
slouken@639
   317
						if (infobyte & 16) cmd.fxcmd = p[pos++];
slouken@639
   318
						if (infobyte & 32) cmd.fxparam1 = p[pos++];
slouken@639
   319
						if (infobyte & 64) cmd.fxparam2 = p[pos++];
slouken@639
   320
					#ifdef MT2DEBUG
slouken@639
   321
						if (cmd.fxcmd)
slouken@639
   322
						{
slouken@639
   323
							Log("(%d.%d) MT2 FX=%02X.%02X.%02X\n", row, ch, cmd.fxcmd, cmd.fxparam1, cmd.fxparam2);
slouken@639
   324
						}
slouken@639
   325
					#endif
slouken@639
   326
						ConvertMT2Command(this, &m[patpos], &cmd);
slouken@639
   327
					}
slouken@639
   328
					row += rptcount+1;
slouken@639
   329
					while (row >= nLines) { row-=nLines; ch++; }
slouken@639
   330
					if (ch >= m_nChannels) break;
slouken@639
   331
				}
slouken@639
   332
			} else
slouken@639
   333
			{
slouken@639
   334
				const MT2COMMAND *p = (MT2COMMAND *)(lpStream+dwMemPos);
slouken@639
   335
				UINT n = 0;
slouken@639
   336
				while ((len > sizeof(MT2COMMAND)) && (n < m_nChannels*nLines))
slouken@639
   337
				{
slouken@639
   338
					ConvertMT2Command(this, m, p);
slouken@639
   339
					len -= sizeof(MT2COMMAND);
slouken@639
   340
					n++;
slouken@639
   341
					p++;
slouken@639
   342
					m++;
slouken@639
   343
				}
slouken@639
   344
			}
slouken@639
   345
		}
slouken@639
   346
		dwMemPos += wDataLen;
slouken@639
   347
	}
slouken@639
   348
	// Skip Drum Patterns
slouken@639
   349
	if (pdd)
slouken@639
   350
	{
slouken@639
   351
	#ifdef MT2DEBUG
slouken@639
   352
		Log("%d Drum Patterns at offset 0x%08X\n", pdd->wDrumPatterns, dwMemPos);
slouken@639
   353
	#endif
slouken@639
   354
		for (UINT iDrm=0; iDrm<pdd->wDrumPatterns; iDrm++)
slouken@639
   355
		{
slouken@639
   356
			if (dwMemPos > dwMemLength-2) return TRUE;
slouken@639
   357
			UINT nLines = *(WORD *)(lpStream+dwMemPos);
slouken@639
   358
		#ifdef MT2DEBUG
slouken@639
   359
			if (nLines != 64) Log("Drum Pattern %d: %d Lines @%04X\n", iDrm, nLines, dwMemPos);
slouken@639
   360
		#endif
slouken@639
   361
			dwMemPos += 2 + nLines * 32;
slouken@639
   362
		}
slouken@639
   363
	}
slouken@639
   364
	// Automation
slouken@639
   365
	if (pfh->fulFlags & 2)
slouken@639
   366
	{
slouken@639
   367
	#ifdef MT2DEBUG
slouken@639
   368
		Log("Automation at offset 0x%08X\n", dwMemPos);
slouken@639
   369
	#endif
slouken@639
   370
		UINT nAutoCount = m_nChannels;
slouken@639
   371
		if (pfh->fulFlags & 0x10) nAutoCount++; // Master Automation
slouken@639
   372
		if ((pfh->fulFlags & 0x08) && (pdd)) nAutoCount += 8; // Drums Automation
slouken@639
   373
		nAutoCount *= pfh->wPatterns;
slouken@639
   374
		for (UINT iAuto=0; iAuto<nAutoCount; iAuto++)
slouken@639
   375
		{
slouken@639
   376
			if (dwMemPos+12 >= dwMemLength) return TRUE;
slouken@639
   377
			const MT2AUTOMATION *pma = (MT2AUTOMATION *)(lpStream+dwMemPos);
slouken@639
   378
			dwMemPos += (pfh->wVersion <= 0x201) ? 4 : 8;
slouken@639
   379
			for (UINT iEnv=0; iEnv<14; iEnv++)
slouken@639
   380
			{
slouken@639
   381
				if (pma->dwFlags & (1 << iEnv))
slouken@639
   382
				{
slouken@639
   383
				#ifdef MT2DEBUG
slouken@639
   384
					UINT nPoints = *(DWORD *)(lpStream+dwMemPos);
slouken@639
   385
					Log("  Env[%d/%d] %04X @%04X: %d points\n", iAuto, nAutoCount, 1 << iEnv, dwMemPos-8, nPoints);
slouken@639
   386
				#endif
slouken@639
   387
					dwMemPos += 260;
slouken@639
   388
				}
slouken@639
   389
			}
slouken@639
   390
		}
slouken@639
   391
	}
slouken@639
   392
	// Load Instruments
slouken@639
   393
#ifdef MT2DEBUG
slouken@639
   394
	Log("Loading instruments at offset 0x%08X\n", dwMemPos);
slouken@639
   395
#endif
slouken@639
   396
	memset(InstrMap, 0, sizeof(InstrMap));
slouken@639
   397
	m_nInstruments = (pfh->wInstruments < MAX_INSTRUMENTS) ? pfh->wInstruments : MAX_INSTRUMENTS-1;
slouken@639
   398
	for (UINT iIns=1; iIns<=255; iIns++)
slouken@639
   399
	{
slouken@639
   400
		if (dwMemPos+36 > dwMemLength) return TRUE;
slouken@639
   401
		const MT2INSTRUMENT *pmi = (MT2INSTRUMENT *)(lpStream+dwMemPos);
slouken@639
   402
		INSTRUMENTHEADER *penv = NULL;
slouken@639
   403
		if (iIns <= m_nInstruments)
slouken@639
   404
		{
slouken@639
   405
			penv = new INSTRUMENTHEADER;
slouken@639
   406
			Headers[iIns] = penv;
slouken@639
   407
			if (penv)
slouken@639
   408
			{
slouken@639
   409
				memset(penv, 0, sizeof(INSTRUMENTHEADER));
slouken@639
   410
				memcpy(penv->name, pmi->szName, 32);
slouken@639
   411
				penv->nGlobalVol = 64;
slouken@639
   412
				penv->nPan = 128;
slouken@639
   413
				for (UINT i=0; i<NOTE_MAX; i++)
slouken@639
   414
				{
slouken@639
   415
					penv->NoteMap[i] = i+1;
slouken@639
   416
				}
slouken@639
   417
			}
slouken@639
   418
		}
slouken@639
   419
	#ifdef MT2DEBUG
slouken@639
   420
		if (iIns <= pfh->wInstruments) Log("  Instrument #%d at offset %04X: %d bytes\n", iIns, dwMemPos, pmi->dwDataLen);
slouken@639
   421
	#endif
slouken@639
   422
		if (((LONG)pmi->dwDataLen > 0) && (dwMemPos <= dwMemLength - 40) && (pmi->dwDataLen <= dwMemLength - (dwMemPos + 40)))
slouken@639
   423
		{
slouken@639
   424
			InstrMap[iIns-1] = pmi;
slouken@639
   425
			if (penv)
slouken@639
   426
			{
slouken@639
   427
				penv->nFadeOut = pmi->wFadeOut;
slouken@639
   428
				penv->nNNA = pmi->wNNA & 3;
slouken@639
   429
				penv->nDCT = (pmi->wNNA>>8) & 3;
slouken@639
   430
				penv->nDNA = (pmi->wNNA>>12) & 3;
slouken@639
   431
				MT2ENVELOPE *pehdr[4];
slouken@639
   432
				WORD *pedata[4];
slouken@639
   433
				if (pfh->wVersion <= 0x201)
slouken@639
   434
				{
slouken@639
   435
					DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT) - 4;
slouken@639
   436
					pehdr[0] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
slouken@639
   437
					pehdr[1] = (MT2ENVELOPE *)(lpStream+dwEnvPos+8);
slouken@639
   438
					pehdr[2] = pehdr[3] = NULL;
slouken@639
   439
					pedata[0] = (WORD *)(lpStream+dwEnvPos+16);
slouken@639
   440
					pedata[1] = (WORD *)(lpStream+dwEnvPos+16+64);
slouken@639
   441
					pedata[2] = pedata[3] = NULL;
slouken@639
   442
				} else
slouken@639
   443
				{
slouken@639
   444
					DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT);
slouken@639
   445
					for (UINT i=0; i<4; i++)
slouken@639
   446
					{
slouken@639
   447
						if (pmi->wEnvFlags1 & (1<<i))
slouken@639
   448
						{
slouken@639
   449
							pehdr[i] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
slouken@639
   450
							pedata[i] = (WORD *)pehdr[i]->EnvData;
slouken@639
   451
							dwEnvPos += sizeof(MT2ENVELOPE);
slouken@639
   452
						} else
slouken@639
   453
						{
slouken@639
   454
							pehdr[i] = NULL;
slouken@639
   455
							pedata[i] = NULL;
slouken@639
   456
						}
slouken@639
   457
					}
slouken@639
   458
				}
slouken@639
   459
				// Load envelopes
slouken@639
   460
				for (UINT iEnv=0; iEnv<4; iEnv++) if (pehdr[iEnv])
slouken@639
   461
				{
slouken@639
   462
					const MT2ENVELOPE *pme = pehdr[iEnv];
slouken@639
   463
					WORD *pEnvPoints = NULL;
slouken@639
   464
					BYTE *pEnvData = NULL;
slouken@639
   465
				#ifdef MT2DEBUG
slouken@639
   466
					Log("  Env %d.%d @%04X: %d points\n", iIns, iEnv, (UINT)(((BYTE *)pme)-lpStream), pme->nPoints);
slouken@639
   467
				#endif
slouken@639
   468
					switch(iEnv)
slouken@639
   469
					{
slouken@639
   470
					// Volume Envelope
slouken@639
   471
					case 0:
slouken@639
   472
						if (pme->nFlags & 1) penv->dwFlags |= ENV_VOLUME;
slouken@639
   473
						if (pme->nFlags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
slouken@639
   474
						if (pme->nFlags & 4) penv->dwFlags |= ENV_VOLLOOP;
slouken@639
   475
						penv->nVolEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
slouken@639
   476
						penv->nVolSustainBegin = penv->nVolSustainEnd = pme->nSustainPos;
slouken@639
   477
						penv->nVolLoopStart = pme->nLoopStart;
slouken@639
   478
						penv->nVolLoopEnd = pme->nLoopEnd;
slouken@639
   479
						pEnvPoints = penv->VolPoints;
slouken@639
   480
						pEnvData = penv->VolEnv;
slouken@639
   481
						break;
slouken@639
   482
slouken@639
   483
					// Panning Envelope
slouken@639
   484
					case 1:
slouken@639
   485
						if (pme->nFlags & 1) penv->dwFlags |= ENV_PANNING;
slouken@639
   486
						if (pme->nFlags & 2) penv->dwFlags |= ENV_PANSUSTAIN;
slouken@639
   487
						if (pme->nFlags & 4) penv->dwFlags |= ENV_PANLOOP;
slouken@639
   488
						penv->nPanEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
slouken@639
   489
						penv->nPanSustainBegin = penv->nPanSustainEnd = pme->nSustainPos;
slouken@639
   490
						penv->nPanLoopStart = pme->nLoopStart;
slouken@639
   491
						penv->nPanLoopEnd = pme->nLoopEnd;
slouken@639
   492
						pEnvPoints = penv->PanPoints;
slouken@639
   493
						pEnvData = penv->PanEnv;
slouken@639
   494
						break;
slouken@639
   495
slouken@639
   496
					// Pitch/Filter envelope
slouken@639
   497
					default:
slouken@639
   498
						if (pme->nFlags & 1) penv->dwFlags |= (iEnv==3) ? (ENV_PITCH|ENV_FILTER) : ENV_PITCH;
slouken@639
   499
						if (pme->nFlags & 2) penv->dwFlags |= ENV_PITCHSUSTAIN;
slouken@639
   500
						if (pme->nFlags & 4) penv->dwFlags |= ENV_PITCHLOOP;
slouken@639
   501
						penv->nPitchEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
slouken@639
   502
						penv->nPitchSustainBegin = penv->nPitchSustainEnd = pme->nSustainPos;
slouken@639
   503
						penv->nPitchLoopStart = pme->nLoopStart;
slouken@639
   504
						penv->nPitchLoopEnd = pme->nLoopEnd;
slouken@639
   505
						pEnvPoints = penv->PitchPoints;
slouken@639
   506
						pEnvData = penv->PitchEnv;
slouken@639
   507
					}
slouken@639
   508
					// Envelope data
slouken@639
   509
					if ((pEnvPoints) && (pEnvData) && (pedata[iEnv]))
slouken@639
   510
					{
slouken@639
   511
						WORD *psrc = pedata[iEnv];
slouken@639
   512
						for (UINT i=0; i<16; i++)
slouken@639
   513
						{
slouken@639
   514
							pEnvPoints[i] = psrc[i*2];
slouken@639
   515
							pEnvData[i] = (BYTE)psrc[i*2+1];
slouken@639
   516
						}
slouken@639
   517
					}
slouken@639
   518
				}
slouken@639
   519
			}
slouken@639
   520
			dwMemPos += pmi->dwDataLen + 36;
slouken@639
   521
			if (pfh->wVersion > 0x201) dwMemPos += 4; // ?
slouken@639
   522
		} else
slouken@639
   523
		{
slouken@639
   524
			dwMemPos += 36;
slouken@639
   525
		}
slouken@639
   526
	}
slouken@639
   527
#ifdef MT2DEBUG
slouken@639
   528
	Log("Loading samples at offset 0x%08X\n", dwMemPos);
slouken@639
   529
#endif
slouken@639
   530
	memset(SampleMap, 0, sizeof(SampleMap));
slouken@639
   531
	m_nSamples = (pfh->wSamples < MAX_SAMPLES) ? pfh->wSamples : MAX_SAMPLES-1;
slouken@639
   532
	for (UINT iSmp=1; iSmp<=256; iSmp++)
slouken@639
   533
	{
slouken@639
   534
		if (dwMemPos+36 > dwMemLength) return TRUE;
slouken@639
   535
		const MT2SAMPLE *pms = (MT2SAMPLE *)(lpStream+dwMemPos);
slouken@639
   536
	#ifdef MT2DEBUG
slouken@639
   537
		if (iSmp <= m_nSamples) Log("  Sample #%d at offset %04X: %d bytes\n", iSmp, dwMemPos, pms->dwDataLen);
slouken@639
   538
	#endif
slouken@639
   539
		if (iSmp < MAX_SAMPLES)
slouken@639
   540
		{
slouken@639
   541
			memcpy(m_szNames[iSmp], pms->szName, 32);
slouken@639
   542
		}
slouken@639
   543
		if (pms->dwDataLen > 0)
slouken@639
   544
		{
slouken@639
   545
			SampleMap[iSmp-1] = pms;
slouken@639
   546
			if (iSmp < MAX_SAMPLES)
slouken@639
   547
			{
slouken@639
   548
				MODINSTRUMENT *psmp = &Ins[iSmp];
slouken@639
   549
				psmp->nGlobalVol = 64;
slouken@639
   550
				psmp->nVolume = (pms->wVolume >> 7);
slouken@639
   551
				psmp->nPan = (pms->nPan == 0x80) ? 128 : (pms->nPan^0x80);
slouken@639
   552
				psmp->nLength = pms->dwLength;
slouken@639
   553
				psmp->nC4Speed = pms->dwFrequency;
slouken@639
   554
				psmp->nLoopStart = pms->dwLoopStart;
slouken@639
   555
				psmp->nLoopEnd = pms->dwLoopEnd;
slouken@639
   556
				FrequencyToTranspose(psmp);
slouken@639
   557
				psmp->RelativeTone -= pms->nBaseNote - 49;
slouken@639
   558
				psmp->nC4Speed = TransposeToFrequency(psmp->RelativeTone, psmp->nFineTune);
slouken@639
   559
				if (pms->nQuality == 2) { psmp->uFlags |= CHN_16BIT; psmp->nLength >>= 1; }
slouken@639
   560
				if (pms->nChannels == 2) { psmp->nLength >>= 1; }
slouken@639
   561
				if (pms->nLoop == 1) psmp->uFlags |= CHN_LOOP;
slouken@639
   562
				if (pms->nLoop == 2) psmp->uFlags |= CHN_LOOP|CHN_PINGPONGLOOP;
slouken@639
   563
			}
slouken@639
   564
			dwMemPos += pms->dwDataLen + 36;
slouken@639
   565
		} else
slouken@639
   566
		{
slouken@639
   567
			dwMemPos += 36;
slouken@639
   568
		}
slouken@639
   569
	}
slouken@639
   570
#ifdef MT2DEBUG
slouken@639
   571
	Log("Loading groups at offset 0x%08X\n", dwMemPos);
slouken@639
   572
#endif
slouken@639
   573
	for (UINT iMap=0; iMap<255; iMap++) if (InstrMap[iMap])
slouken@639
   574
	{
slouken@639
   575
		if (dwMemPos+8 > dwMemLength) return TRUE;
slouken@639
   576
		const MT2INSTRUMENT *pmi = InstrMap[iMap];
slouken@639
   577
		INSTRUMENTHEADER *penv = NULL;
slouken@639
   578
		if (iMap<m_nInstruments) penv = Headers[iMap+1];
slouken@639
   579
		for (UINT iGrp=0; iGrp<pmi->wSamples; iGrp++)
slouken@639
   580
		{
slouken@639
   581
			if (penv)
slouken@639
   582
			{
slouken@639
   583
				const MT2GROUP *pmg = (MT2GROUP *)(lpStream+dwMemPos);
slouken@639
   584
				for (UINT i=0; i<96; i++)
slouken@639
   585
				{
slouken@639
   586
					if (pmi->GroupsMapping[i] == iGrp)
slouken@639
   587
					{
slouken@639
   588
						UINT nSmp = pmg->nSmpNo+1;
slouken@639
   589
						penv->Keyboard[i+12] = (BYTE)nSmp;
slouken@639
   590
						if (nSmp <= m_nSamples)
slouken@639
   591
						{
slouken@639
   592
							Ins[nSmp].nVibType = pmi->bVibType;
slouken@639
   593
							Ins[nSmp].nVibSweep = pmi->bVibSweep;
slouken@639
   594
							Ins[nSmp].nVibDepth = pmi->bVibDepth;
slouken@639
   595
							Ins[nSmp].nVibRate = pmi->bVibRate;
slouken@639
   596
						}
slouken@639
   597
					}
slouken@639
   598
				}
slouken@639
   599
			}
slouken@639
   600
			dwMemPos += 8;
slouken@639
   601
		}
slouken@639
   602
	}
slouken@639
   603
#ifdef MT2DEBUG
slouken@639
   604
	Log("Loading sample data at offset 0x%08X\n", dwMemPos);
slouken@639
   605
#endif
slouken@639
   606
	for (UINT iData=0; iData<256; iData++) if ((iData < m_nSamples) && (SampleMap[iData]))
slouken@639
   607
	{
slouken@639
   608
		const MT2SAMPLE *pms = SampleMap[iData];
slouken@639
   609
		MODINSTRUMENT *psmp = &Ins[iData+1];
slouken@639
   610
		if (!(pms->nFlags & 5))
slouken@639
   611
		{
slouken@639
   612
			if (psmp->nLength > 0) 
slouken@639
   613
			{
slouken@639
   614
			#ifdef MT2DEBUG
slouken@639
   615
				Log("  Reading sample #%d at offset 0x%04X (len=%d)\n", iData+1, dwMemPos, psmp->nLength);
slouken@639
   616
			#endif
slouken@639
   617
				UINT rsflags;
slouken@639
   618
				
slouken@639
   619
				if (pms->nChannels == 2)
slouken@639
   620
					rsflags = (psmp->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D;
slouken@639
   621
				else
slouken@639
   622
					rsflags = (psmp->uFlags & CHN_16BIT) ? RS_PCM16D : RS_PCM8D;
slouken@639
   623
slouken@639
   624
				dwMemPos += ReadSample(psmp, rsflags, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
slouken@639
   625
			}
slouken@639
   626
		} else
slouken@639
   627
		if (dwMemPos+4 < dwMemLength)
slouken@639
   628
		{
slouken@639
   629
			UINT nNameLen = *(DWORD *)(lpStream+dwMemPos);
slouken@639
   630
			dwMemPos += nNameLen + 16;
slouken@639
   631
		}
slouken@639
   632
		if (dwMemPos+4 >= dwMemLength) break;
slouken@639
   633
	}
slouken@639
   634
	return TRUE;
slouken@639
   635
}