00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00014
00015 #include "stdafx.h"
00016 #include "sndfile.h"
00017
00018
00019
00020 typedef struct tagFILEHEADER669
00021 {
00022 WORD sig;
00023 signed char songmessage[108];
00024 BYTE samples;
00025 BYTE patterns;
00026 BYTE restartpos;
00027 BYTE orders[128];
00028 BYTE tempolist[128];
00029 BYTE breaks[128];
00030 } Q_PACKED FILEHEADER669;
00031
00032
00033 typedef struct tagSAMPLE669
00034 {
00035 BYTE filename[13];
00036 BYTE length[4];
00037 BYTE loopstart[4];
00038 BYTE loopend[4];
00039 } Q_PACKED SAMPLE669;
00040
00041
00042 BOOL CSoundFile::Read669(const BYTE *lpStream, DWORD dwMemLength)
00043
00044 {
00045 BOOL b669Ext;
00046 const FILEHEADER669 *pfh = (const FILEHEADER669 *)lpStream;
00047 const SAMPLE669 *psmp = (const SAMPLE669 *)(lpStream + 0x1F1);
00048 DWORD dwMemPos = 0;
00049
00050 if ((!lpStream) || (dwMemLength < sizeof(FILEHEADER669))) return FALSE;
00051 if ((bswapLE16(pfh->sig) != 0x6669) && (bswapLE16(pfh->sig) != 0x4E4A)) return FALSE;
00052 b669Ext = (bswapLE16(pfh->sig) == 0x4E4A) ? TRUE : FALSE;
00053 if ((!pfh->samples) || (pfh->samples > 64) || (pfh->restartpos >= 128)
00054 || (!pfh->patterns) || (pfh->patterns > 128)) return FALSE;
00055 DWORD dontfuckwithme = 0x1F1 + pfh->samples * sizeof(SAMPLE669) + pfh->patterns * 0x600;
00056 if (dontfuckwithme > dwMemLength) return FALSE;
00057 for (UINT ichk=0; ichk<pfh->samples; ichk++)
00058 {
00059 DWORD len = bswapLE32(*((DWORD *)(&psmp[ichk].length)));
00060 dontfuckwithme += len;
00061 }
00062 if (dontfuckwithme > dwMemLength) return FALSE;
00063
00064 m_nType = MOD_TYPE_669;
00065 m_dwSongFlags |= SONG_LINEARSLIDES;
00066 m_nMinPeriod = 28 << 2;
00067 m_nMaxPeriod = 1712 << 3;
00068 m_nDefaultTempo = 125;
00069 m_nDefaultSpeed = 6;
00070 m_nChannels = 8;
00071 memcpy(m_szNames[0], pfh->songmessage, 16);
00072 m_nSamples = pfh->samples;
00073 for (UINT nins=1; nins<=m_nSamples; nins++, psmp++)
00074 {
00075 DWORD len = bswapLE32(*((DWORD *)(&psmp->length)));
00076 DWORD loopstart = bswapLE32(*((DWORD *)(&psmp->loopstart)));
00077 DWORD loopend = bswapLE32(*((DWORD *)(&psmp->loopend)));
00078 if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
00079 if ((loopend > len) && (!loopstart)) loopend = 0;
00080 if (loopend > len) loopend = len;
00081 if (loopstart + 4 >= loopend) loopstart = loopend = 0;
00082 Ins[nins].nLength = len;
00083 Ins[nins].nLoopStart = loopstart;
00084 Ins[nins].nLoopEnd = loopend;
00085 if (loopend) Ins[nins].uFlags |= CHN_LOOP;
00086 memcpy(m_szNames[nins], psmp->filename, 13);
00087 Ins[nins].nVolume = 256;
00088 Ins[nins].nGlobalVol = 64;
00089 Ins[nins].nPan = 128;
00090 }
00091
00092 m_lpszSongComments = new char[109];
00093 memcpy(m_lpszSongComments, pfh->songmessage, 108);
00094 m_lpszSongComments[108] = 0;
00095
00096 memcpy(Order, pfh->orders, 128);
00097 m_nRestartPos = pfh->restartpos;
00098 if (Order[m_nRestartPos] >= pfh->patterns) m_nRestartPos = 0;
00099
00100 for (UINT npan=0; npan<8; npan++)
00101 {
00102 ChnSettings[npan].nPan = (npan & 1) ? 0x30 : 0xD0;
00103 ChnSettings[npan].nVolume = 64;
00104 }
00105
00106 dwMemPos = 0x1F1 + pfh->samples * 25;
00107 for (UINT npat=0; npat<pfh->patterns; npat++)
00108 {
00109 Patterns[npat] = AllocatePattern(64, m_nChannels);
00110 if (!Patterns[npat]) break;
00111 PatternSize[npat] = 64;
00112 MODCOMMAND *m = Patterns[npat];
00113 const BYTE *p = lpStream + dwMemPos;
00114 for (UINT row=0; row<64; row++)
00115 {
00116 MODCOMMAND *mspeed = m;
00117 if ((row == pfh->breaks[npat]) && (row != 63))
00118 {
00119 for (UINT i=0; i<8; i++)
00120 {
00121 m[i].command = CMD_PATTERNBREAK;
00122 m[i].param = 0;
00123 }
00124 }
00125 for (UINT n=0; n<8; n++, m++, p+=3)
00126 {
00127 UINT note = p[0] >> 2;
00128 UINT instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
00129 UINT vol = p[1] & 0x0F;
00130 if (p[0] < 0xFE)
00131 {
00132 m->note = note + 37;
00133 m->instr = instr + 1;
00134 }
00135 if (p[0] <= 0xFE)
00136 {
00137 m->volcmd = VOLCMD_VOLUME;
00138 m->vol = (vol << 2) + 2;
00139 }
00140 if (p[2] != 0xFF)
00141 {
00142 UINT command = p[2] >> 4;
00143 UINT param = p[2] & 0x0F;
00144 switch(command)
00145 {
00146 case 0x00: command = CMD_PORTAMENTOUP; break;
00147 case 0x01: command = CMD_PORTAMENTODOWN; break;
00148 case 0x02: command = CMD_TONEPORTAMENTO; break;
00149 case 0x03: command = CMD_MODCMDEX; param |= 0x50; break;
00150 case 0x04: command = CMD_VIBRATO; param |= 0x40; break;
00151 case 0x05: if (param) command = CMD_SPEED; else command = 0; param += 2; break;
00152 case 0x06: if (param == 0) { command = CMD_PANNINGSLIDE; param = 0xFE; } else
00153 if (param == 1) { command = CMD_PANNINGSLIDE; param = 0xEF; } else
00154 command = 0;
00155 break;
00156 default: command = 0;
00157 }
00158 if (command)
00159 {
00160 if (command == CMD_SPEED) mspeed = NULL;
00161 m->command = command;
00162 m->param = param;
00163 }
00164 }
00165 }
00166 if ((!row) && (mspeed))
00167 {
00168 for (UINT i=0; i<8; i++) if (!mspeed[i].command)
00169 {
00170 mspeed[i].command = CMD_SPEED;
00171 mspeed[i].param = pfh->tempolist[npat] + 2;
00172 break;
00173 }
00174 }
00175 }
00176 dwMemPos += 0x600;
00177 }
00178
00179 for (UINT n=1; n<=m_nSamples; n++)
00180 {
00181 UINT len = Ins[n].nLength;
00182 if (dwMemPos >= dwMemLength) break;
00183 if (len > 4) ReadSample(&Ins[n], RS_PCM8U, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
00184 dwMemPos += len;
00185 }
00186 return TRUE;
00187 }
00188
00189