2
* This source code is public domain.
4
* Authors: Olivier Lapicque <olivierl@jps.net>
14
//#pragma warning(disable:4244)
16
//////////////////////////////////////////////////////////
17
// MTM file support (import only)
22
typedef struct tagMTMSAMPLE
24
char samplename[22]; // changed from CHAR
34
typedef struct tagMTMHEADER
36
char id[4]; // MTM file marker + version // changed from CHAR
37
char songname[20]; // ASCIIZ songname // changed from CHAR
38
WORD numtracks; // number of tracks saved
39
BYTE lastpattern; // last pattern number saved
40
BYTE lastorder; // last order number to play (songlength-1)
41
WORD commentsize; // length of comment field
42
BYTE numsamples; // number of samples saved
43
BYTE attribute; // attribute byte (unused)
45
BYTE numchannels; // number of channels used
46
BYTE panpos[32]; // voice pan positions
53
BOOL CSoundFile::ReadMTM(LPCBYTE lpStream, DWORD dwMemLength)
54
//-----------------------------------------------------------
56
MTMHEADER *pmh = (MTMHEADER *)lpStream;
59
if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
60
if ((strncmp(pmh->id, "MTM", 3)) || (pmh->numchannels > 32)
61
|| (pmh->numsamples >= MAX_SAMPLES) || (!pmh->numsamples)
62
|| (!pmh->numtracks) || (!pmh->numchannels)
63
|| (!pmh->lastpattern) || (pmh->lastpattern > MAX_PATTERNS)) return FALSE;
64
strncpy(m_szNames[0], pmh->songname, 20);
66
if (dwMemPos + 37*pmh->numsamples + 128 + 192*pmh->numtracks
67
+ 64 * (pmh->lastpattern+1) + pmh->commentsize >= dwMemLength) return FALSE;
68
m_nType = MOD_TYPE_MTM;
69
m_nSamples = pmh->numsamples;
70
m_nChannels = pmh->numchannels;
71
// Reading instruments
72
for (UINT i=1; i<=m_nSamples; i++)
74
MTMSAMPLE *pms = (MTMSAMPLE *)(lpStream + dwMemPos);
75
strncpy(m_szNames[i], pms->samplename, 22);
77
Ins[i].nVolume = pms->volume << 2;
78
Ins[i].nGlobalVol = 64;
79
DWORD len = pms->length;
80
if ((len > 4) && (len <= MAX_SAMPLE_LENGTH))
83
Ins[i].nLoopStart = pms->reppos;
84
Ins[i].nLoopEnd = pms->repend;
85
if (Ins[i].nLoopEnd > Ins[i].nLength) Ins[i].nLoopEnd = Ins[i].nLength;
86
if (Ins[i].nLoopStart + 4 >= Ins[i].nLoopEnd) Ins[i].nLoopStart = Ins[i].nLoopEnd = 0;
87
if (Ins[i].nLoopEnd) Ins[i].uFlags |= CHN_LOOP;
88
Ins[i].nFineTune = MOD2XMFineTune(pms->finetune);
89
if (pms->attribute & 0x01)
91
Ins[i].uFlags |= CHN_16BIT;
93
Ins[i].nLoopStart >>= 1;
94
Ins[i].nLoopEnd >>= 1;
100
// Setting Channel Pan Position
101
for (UINT ich=0; ich<m_nChannels; ich++)
103
ChnSettings[ich].nPan = ((pmh->panpos[ich] & 0x0F) << 4) + 8;
104
ChnSettings[ich].nVolume = 64;
106
// Reading pattern order
107
memcpy(Order, lpStream + dwMemPos, pmh->lastorder+1);
110
LPCBYTE pTracks = lpStream + dwMemPos;
111
dwMemPos += 192 * pmh->numtracks;
112
LPWORD pSeq = (LPWORD)(lpStream + dwMemPos);
113
for (UINT pat=0; pat<=pmh->lastpattern; pat++)
115
PatternSize[pat] = 64;
116
if ((Patterns[pat] = AllocatePattern(64, m_nChannels)) == NULL) break;
117
for (UINT n=0; n<32; n++) if ((pSeq[n]) && (pSeq[n] <= pmh->numtracks) && (n < m_nChannels))
119
LPCBYTE p = pTracks + 192 * (pSeq[n]-1);
120
MODCOMMAND *m = Patterns[pat] + n;
121
for (UINT i=0; i<64; i++, m+=m_nChannels, p+=3)
123
if (p[0] & 0xFC) m->note = (p[0] >> 2) + 37;
124
m->instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
125
UINT cmd = p[1] & 0x0F;
129
if (param & 0xF0) param &= 0xF0; else param &= 0x0F;
133
if ((cmd) || (param)) ConvertModCommand(m);
138
dwMemPos += 64*(pmh->lastpattern+1);
139
if ((pmh->commentsize) && (dwMemPos + pmh->commentsize < dwMemLength))
141
UINT n = pmh->commentsize;
142
m_lpszSongComments = new char[n+1];
143
if (m_lpszSongComments)
145
memcpy(m_lpszSongComments, lpStream+dwMemPos, n);
146
m_lpszSongComments[n] = 0;
147
for (UINT i=0; i<n; i++)
149
if (!m_lpszSongComments[i])
151
m_lpszSongComments[i] = ((i+1) % 40) ? 0x20 : 0x0D;
156
dwMemPos += pmh->commentsize;
158
for (UINT ismp=1; ismp<=m_nSamples; ismp++)
160
if (dwMemPos >= dwMemLength) break;
161
dwMemPos += ReadSample(&Ins[ismp], (Ins[ismp].uFlags & CHN_16BIT) ? RS_PCM16U : RS_PCM8U,
162
(LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
165
m_nMaxPeriod = 32767;