00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "stdafx.h"
00011 #include "sndfile.h"
00012
00013
00014
00016
00017
00018 #pragma pack(1)
00019
00020
00021 typedef struct tagMTMSAMPLE
00022 {
00023 char samplename[22];
00024 DWORD length;
00025 DWORD reppos;
00026 DWORD repend;
00027 CHAR finetune;
00028 BYTE volume;
00029 BYTE attribute;
00030 } Q_PACKED MTMSAMPLE;
00031
00032
00033 typedef struct tagMTMHEADER
00034 {
00035 char id[4];
00036 char songname[20];
00037 WORD numtracks;
00038 BYTE lastpattern;
00039 BYTE lastorder;
00040 WORD commentsize;
00041 BYTE numsamples;
00042 BYTE attribute;
00043 BYTE beatspertrack;
00044 BYTE numchannels;
00045 BYTE panpos[32];
00046 } Q_PACKED MTMHEADER;
00047
00048
00049 #pragma pack()
00050
00051
00052 BOOL CSoundFile::ReadMTM(LPCBYTE lpStream, DWORD dwMemLength)
00053
00054 {
00055 MTMHEADER *pmh = (MTMHEADER *)lpStream;
00056 DWORD dwMemPos = 66;
00057
00058 if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
00059 if ((strncmp(pmh->id, "MTM", 3)) || (pmh->numchannels > 32)
00060 || (pmh->numsamples >= MAX_SAMPLES) || (!pmh->numsamples)
00061 || (!pmh->numtracks) || (!pmh->numchannels)
00062 || (!pmh->lastpattern) || (pmh->lastpattern > MAX_PATTERNS)) return FALSE;
00063 strncpy(m_szNames[0], pmh->songname, 20);
00064 m_szNames[0][20] = 0;
00065 if (dwMemPos + 37*pmh->numsamples + 128 + 192*pmh->numtracks
00066 + 64 * (pmh->lastpattern+1) + pmh->commentsize >= dwMemLength) return FALSE;
00067 m_nType = MOD_TYPE_MTM;
00068 m_nSamples = pmh->numsamples;
00069 m_nChannels = pmh->numchannels;
00070
00071 for (UINT i=1; i<=m_nSamples; i++)
00072 {
00073 MTMSAMPLE *pms = (MTMSAMPLE *)(lpStream + dwMemPos);
00074 strncpy(m_szNames[i], pms->samplename, 22);
00075 m_szNames[i][22] = 0;
00076 Ins[i].nVolume = pms->volume << 2;
00077 Ins[i].nGlobalVol = 64;
00078 DWORD len = pms->length;
00079 if ((len > 4) && (len <= MAX_SAMPLE_LENGTH))
00080 {
00081 Ins[i].nLength = len;
00082 Ins[i].nLoopStart = pms->reppos;
00083 Ins[i].nLoopEnd = pms->repend;
00084 if (Ins[i].nLoopEnd > Ins[i].nLength) Ins[i].nLoopEnd = Ins[i].nLength;
00085 if (Ins[i].nLoopStart + 4 >= Ins[i].nLoopEnd) Ins[i].nLoopStart = Ins[i].nLoopEnd = 0;
00086 if (Ins[i].nLoopEnd) Ins[i].uFlags |= CHN_LOOP;
00087 Ins[i].nFineTune = MOD2XMFineTune(pms->finetune);
00088 if (pms->attribute & 0x01)
00089 {
00090 Ins[i].uFlags |= CHN_16BIT;
00091 Ins[i].nLength >>= 1;
00092 Ins[i].nLoopStart >>= 1;
00093 Ins[i].nLoopEnd >>= 1;
00094 }
00095 Ins[i].nPan = 128;
00096 }
00097 dwMemPos += 37;
00098 }
00099
00100 for (UINT ich=0; ich<m_nChannels; ich++)
00101 {
00102 ChnSettings[ich].nPan = ((pmh->panpos[ich] & 0x0F) << 4) + 8;
00103 ChnSettings[ich].nVolume = 64;
00104 }
00105
00106 memcpy(Order, lpStream + dwMemPos, pmh->lastorder+1);
00107 dwMemPos += 128;
00108
00109 LPCBYTE pTracks = lpStream + dwMemPos;
00110 dwMemPos += 192 * pmh->numtracks;
00111 LPWORD pSeq = (LPWORD)(lpStream + dwMemPos);
00112 for (UINT pat=0; pat<=pmh->lastpattern; pat++)
00113 {
00114 PatternSize[pat] = 64;
00115 if ((Patterns[pat] = AllocatePattern(64, m_nChannels)) == NULL) break;
00116 for (UINT n=0; n<32; n++) if ((pSeq[n]) && (pSeq[n] <= pmh->numtracks) && (n < m_nChannels))
00117 {
00118 LPCBYTE p = pTracks + 192 * (pSeq[n]-1);
00119 MODCOMMAND *m = Patterns[pat] + n;
00120 for (UINT i=0; i<64; i++, m+=m_nChannels, p+=3)
00121 {
00122 if (p[0] & 0xFC) m->note = (p[0] >> 2) + 37;
00123 m->instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
00124 UINT cmd = p[1] & 0x0F;
00125 UINT param = p[2];
00126 if (cmd == 0x0A)
00127 {
00128 if (param & 0xF0) param &= 0xF0; else param &= 0x0F;
00129 }
00130 m->command = cmd;
00131 m->param = param;
00132 if ((cmd) || (param)) ConvertModCommand(m);
00133 }
00134 }
00135 pSeq += 32;
00136 }
00137 dwMemPos += 64*(pmh->lastpattern+1);
00138 if ((pmh->commentsize) && (dwMemPos + pmh->commentsize < dwMemLength))
00139 {
00140 UINT n = pmh->commentsize;
00141 m_lpszSongComments = new char[n+1];
00142 if (m_lpszSongComments)
00143 {
00144 memcpy(m_lpszSongComments, lpStream+dwMemPos, n);
00145 m_lpszSongComments[n] = 0;
00146 for (UINT i=0; i<n; i++)
00147 {
00148 if (!m_lpszSongComments[i])
00149 {
00150 m_lpszSongComments[i] = ((i+1) % 40) ? 0x20 : 0x0D;
00151 }
00152 }
00153 }
00154 }
00155 dwMemPos += pmh->commentsize;
00156
00157 for (UINT ismp=1; ismp<=m_nSamples; ismp++)
00158 {
00159 if (dwMemPos >= dwMemLength) break;
00160 dwMemPos += ReadSample(&Ins[ismp], (Ins[ismp].uFlags & CHN_16BIT) ? RS_PCM16U : RS_PCM8U,
00161 (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
00162 }
00163 m_nMinPeriod = 64;
00164 m_nMaxPeriod = 32767;
00165 return TRUE;
00166 }
00167