Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

load_mtm.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is  free software; you can redistribute it  and modify it
00003  * under the terms of the GNU  General Public License as published by the
00004  * Free Software Foundation; either version 2  of the license or (at your
00005  * option) any later version.
00006  *
00007  * Authors: Olivier Lapicque <olivierl@jps.net>
00008 */
00009 
00010 #include "stdafx.h"
00011 #include "sndfile.h"
00012 
00013 //#pragma warning(disable:4244)
00014 
00016 // MTM file support (import only)
00017 
00018 #pragma pack(1)
00019 
00020 
00021 typedef struct tagMTMSAMPLE
00022 {
00023         char samplename[22];      // changed from CHAR
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];             // MTM file marker + version // changed from CHAR
00036         char songname[20];      // ASCIIZ songname  // changed from CHAR
00037         WORD numtracks;         // number of tracks saved
00038         BYTE lastpattern;       // last pattern number saved
00039         BYTE lastorder;         // last order number to play (songlength-1)
00040         WORD commentsize;       // length of comment field
00041         BYTE numsamples;        // number of samples saved
00042         BYTE attribute;         // attribute byte (unused)
00043         BYTE beatspertrack;
00044         BYTE numchannels;       // number of channels used
00045         BYTE panpos[32];        // voice pan positions
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         // Reading instruments
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         // Setting Channel Pan Position
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         // Reading pattern order
00106         memcpy(Order, lpStream + dwMemPos, pmh->lastorder+1);
00107         dwMemPos += 128;
00108         // Reading Patterns
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         // Reading Samples
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 

Generated on Sat Nov 5 16:15:40 2005 for OPIE by  doxygen 1.4.2