00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "stdafx.h"
00012 #include "sndfile.h"
00013
00014
00015
00016 extern WORD ProTrackerPeriodTable[6*12];
00017
00019
00020
00021 void CSoundFile::ConvertModCommand(MODCOMMAND *m) const
00022
00023 {
00024 UINT command = m->command, param = m->param;
00025
00026 switch(command)
00027 {
00028 case 0x00: if (param) command = CMD_ARPEGGIO; break;
00029 case 0x01: command = CMD_PORTAMENTOUP; break;
00030 case 0x02: command = CMD_PORTAMENTODOWN; break;
00031 case 0x03: command = CMD_TONEPORTAMENTO; break;
00032 case 0x04: command = CMD_VIBRATO; break;
00033 case 0x05: command = CMD_TONEPORTAVOL; if (param & 0xF0) param &= 0xF0; break;
00034 case 0x06: command = CMD_VIBRATOVOL; if (param & 0xF0) param &= 0xF0; break;
00035 case 0x07: command = CMD_TREMOLO; break;
00036 case 0x08: command = CMD_PANNING8; break;
00037 case 0x09: command = CMD_OFFSET; break;
00038 case 0x0A: command = CMD_VOLUMESLIDE; if (param & 0xF0) param &= 0xF0; break;
00039 case 0x0B: command = CMD_POSITIONJUMP; break;
00040 case 0x0C: command = CMD_VOLUME; break;
00041 case 0x0D: command = CMD_PATTERNBREAK; param = ((param >> 4) * 10) + (param & 0x0F); break;
00042 case 0x0E: command = CMD_MODCMDEX; break;
00043 case 0x0F: command = (param <= (UINT)((m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? 0x1F : 0x20)) ? CMD_SPEED : CMD_TEMPO;
00044 if ((param == 0xFF) && (m_nSamples == 15)) command = 0; break;
00045
00046 case 'G' - 55: command = CMD_GLOBALVOLUME; break;
00047 case 'H' - 55: command = CMD_GLOBALVOLSLIDE; if (param & 0xF0) param &= 0xF0; break;
00048 case 'K' - 55: command = CMD_KEYOFF; break;
00049 case 'L' - 55: command = CMD_SETENVPOSITION; break;
00050 case 'M' - 55: command = CMD_CHANNELVOLUME; break;
00051 case 'N' - 55: command = CMD_CHANNELVOLSLIDE; break;
00052 case 'P' - 55: command = CMD_PANNINGSLIDE; if (param & 0xF0) param &= 0xF0; break;
00053 case 'R' - 55: command = CMD_RETRIG; break;
00054 case 'T' - 55: command = CMD_TREMOR; break;
00055 case 'X' - 55: command = CMD_XFINEPORTAUPDOWN; break;
00056 case 'Y' - 55: command = CMD_PANBRELLO; break;
00057 case 'Z' - 55: command = CMD_MIDI; break;
00058 default: command = 0;
00059 }
00060 m->command = command;
00061 m->param = param;
00062 }
00063
00064
00065 WORD CSoundFile::ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const
00066
00067 {
00068 UINT command = m->command & 0x3F, param = m->param;
00069
00070 switch(command)
00071 {
00072 case 0: command = param = 0; break;
00073 case CMD_ARPEGGIO: command = 0; break;
00074 case CMD_PORTAMENTOUP:
00075 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
00076 {
00077 if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x10; break; }
00078 else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x10; break; }
00079 }
00080 command = 0x01;
00081 break;
00082 case CMD_PORTAMENTODOWN:
00083 if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
00084 {
00085 if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x20; break; }
00086 else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x20; break; }
00087 }
00088 command = 0x02;
00089 break;
00090 case CMD_TONEPORTAMENTO: command = 0x03; break;
00091 case CMD_VIBRATO: command = 0x04; break;
00092 case CMD_TONEPORTAVOL: command = 0x05; break;
00093 case CMD_VIBRATOVOL: command = 0x06; break;
00094 case CMD_TREMOLO: command = 0x07; break;
00095 case CMD_PANNING8:
00096 command = 0x08;
00097 if (bXM)
00098 {
00099 if ((m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM) && (param <= 0x80))
00100 {
00101 param <<= 1;
00102 if (param > 255) param = 255;
00103 }
00104 } else
00105 {
00106 if ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM)) param >>= 1;
00107 }
00108 break;
00109 case CMD_OFFSET: command = 0x09; break;
00110 case CMD_VOLUMESLIDE: command = 0x0A; break;
00111 case CMD_POSITIONJUMP: command = 0x0B; break;
00112 case CMD_VOLUME: command = 0x0C; break;
00113 case CMD_PATTERNBREAK: command = 0x0D; param = ((param / 10) << 4) | (param % 10); break;
00114 case CMD_MODCMDEX: command = 0x0E; break;
00115 case CMD_SPEED: command = 0x0F; if (param > 0x20) param = 0x20; break;
00116 case CMD_TEMPO: if (param > 0x20) { command = 0x0F; break; }
00117 case CMD_GLOBALVOLUME: command = 'G' - 55; break;
00118 case CMD_GLOBALVOLSLIDE: command = 'H' - 55; break;
00119 case CMD_KEYOFF: command = 'K' - 55; break;
00120 case CMD_SETENVPOSITION: command = 'L' - 55; break;
00121 case CMD_CHANNELVOLUME: command = 'M' - 55; break;
00122 case CMD_CHANNELVOLSLIDE: command = 'N' - 55; break;
00123 case CMD_PANNINGSLIDE: command = 'P' - 55; break;
00124 case CMD_RETRIG: command = 'R' - 55; break;
00125 case CMD_TREMOR: command = 'T' - 55; break;
00126 case CMD_XFINEPORTAUPDOWN: command = 'X' - 55; break;
00127 case CMD_PANBRELLO: command = 'Y' - 55; break;
00128 case CMD_MIDI: command = 'Z' - 55; break;
00129 case CMD_S3MCMDEX:
00130 switch(param & 0xF0)
00131 {
00132 case 0x10: command = 0x0E; param = (param & 0x0F) | 0x30; break;
00133 case 0x20: command = 0x0E; param = (param & 0x0F) | 0x50; break;
00134 case 0x30: command = 0x0E; param = (param & 0x0F) | 0x40; break;
00135 case 0x40: command = 0x0E; param = (param & 0x0F) | 0x70; break;
00136 case 0x90: command = 'X' - 55; break;
00137 case 0xB0: command = 0x0E; param = (param & 0x0F) | 0x60; break;
00138 case 0xA0:
00139 case 0x50:
00140 case 0x70:
00141 case 0x60: command = param = 0; break;
00142 default: command = 0x0E; break;
00143 }
00144 break;
00145 default: command = param = 0;
00146 }
00147 return (WORD)((command << 8) | (param));
00148 }
00149
00150
00151 #pragma pack(1)
00152
00153 typedef struct _MODSAMPLE
00154 {
00155 CHAR name[22];
00156 WORD length;
00157 BYTE finetune;
00158 BYTE volume;
00159 WORD loopstart;
00160 WORD looplen;
00161 } Q_PACKED MODSAMPLE, *PMODSAMPLE;
00162
00163 typedef struct _MODMAGIC
00164 {
00165 BYTE nOrders;
00166 BYTE nRestartPos;
00167 BYTE Orders[128];
00168 char Magic[4];
00169 } Q_PACKED MODMAGIC, *PMODMAGIC;
00170
00171 #pragma pack()
00172
00173 BOOL IsMagic(LPCSTR s1, LPCSTR s2)
00174 {
00175 return ((*(DWORD *)s1) == (*(DWORD *)s2)) ? TRUE : FALSE;
00176 }
00177
00178
00179 BOOL CSoundFile::ReadMod(const BYTE *lpStream, DWORD dwMemLength)
00180
00181 {
00182 char s[1024];
00183 DWORD dwMemPos, dwTotalSampleLen;
00184 PMODMAGIC pMagic;
00185 UINT nErr;
00186
00187 if ((!lpStream) || (dwMemLength < 0x600)) return FALSE;
00188 dwMemPos = 20;
00189 m_nSamples = 31;
00190 m_nChannels = 4;
00191 pMagic = (PMODMAGIC)(lpStream+dwMemPos+sizeof(MODSAMPLE)*31);
00192
00193 memcpy(s, pMagic->Magic, 4);
00194 if ((IsMagic(s, "M.K.")) || (IsMagic(s, "M!K!"))
00195 || (IsMagic(s, "M&K!")) || (IsMagic(s, "N.T."))) m_nChannels = 4; else
00196 if ((IsMagic(s, "CD81")) || (IsMagic(s, "OKTA"))) m_nChannels = 8; else
00197 if ((s[0]=='F') && (s[1]=='L') && (s[2]=='T') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
00198 if ((s[0]>='4') && (s[0]<='9') && (s[1]=='C') && (s[2]=='H') && (s[3]=='N')) m_nChannels = s[0] - '0'; else
00199 if ((s[0]=='1') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 10; else
00200 if ((s[0]=='2') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 20; else
00201 if ((s[0]=='3') && (s[1]>='0') && (s[1]<='2') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 30; else
00202 if ((s[0]=='T') && (s[1]=='D') && (s[2]=='Z') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
00203 if (IsMagic(s,"16CN")) m_nChannels = 16; else
00204 if (IsMagic(s,"32CN")) m_nChannels = 32; else m_nSamples = 15;
00205
00206 nErr = 0;
00207 dwTotalSampleLen = 0;
00208 for (UINT i=1; i<=m_nSamples; i++)
00209 {
00210 PMODSAMPLE pms = (PMODSAMPLE)(lpStream+dwMemPos);
00211 MODINSTRUMENT *psmp = &Ins[i];
00212 UINT loopstart, looplen;
00213
00214 memcpy(m_szNames[i], pms->name, 22);
00215 m_szNames[i][22] = 0;
00216 psmp->uFlags = 0;
00217 psmp->nLength = bswapBE16(pms->length)*2;
00218 dwTotalSampleLen += psmp->nLength;
00219 psmp->nFineTune = MOD2XMFineTune(pms->finetune & 0x0F);
00220 psmp->nVolume = 4*pms->volume;
00221 if (psmp->nVolume > 256) { psmp->nVolume = 256; nErr++; }
00222 psmp->nGlobalVol = 64;
00223 psmp->nPan = 128;
00224 loopstart = bswapBE16(pms->loopstart)*2;
00225 looplen = bswapBE16(pms->looplen)*2;
00226
00227 if ((looplen > 2) && (loopstart+looplen > psmp->nLength)
00228 && (loopstart/2+looplen <= psmp->nLength))
00229 {
00230 loopstart /= 2;
00231 }
00232 psmp->nLoopStart = loopstart;
00233 psmp->nLoopEnd = loopstart + looplen;
00234 if (psmp->nLength < 4) psmp->nLength = 0;
00235 if (psmp->nLength)
00236 {
00237 UINT derr = 0;
00238 if (psmp->nLoopStart >= psmp->nLength) { psmp->nLoopStart = psmp->nLength-1; derr|=1; }
00239 if (psmp->nLoopEnd > psmp->nLength) { psmp->nLoopEnd = psmp->nLength; derr |= 1; }
00240 if (psmp->nLoopStart > psmp->nLoopEnd) derr |= 1;
00241 if ((psmp->nLoopStart > psmp->nLoopEnd) || (psmp->nLoopEnd <= 8)
00242 || (psmp->nLoopEnd - psmp->nLoopStart <= 4))
00243 {
00244 psmp->nLoopStart = 0;
00245 psmp->nLoopEnd = 0;
00246 }
00247 if (psmp->nLoopEnd > psmp->nLoopStart)
00248 {
00249 psmp->uFlags |= CHN_LOOP;
00250 }
00251 }
00252 dwMemPos += sizeof(MODSAMPLE);
00253 }
00254 if ((m_nSamples == 15) && (dwTotalSampleLen > dwMemLength * 4)) return FALSE;
00255 pMagic = (PMODMAGIC)(lpStream+dwMemPos);
00256 dwMemPos += sizeof(MODMAGIC);
00257 if (m_nSamples == 15) dwMemPos -= 4;
00258 memset(Order, 0,sizeof(Order));
00259 memcpy(Order, pMagic->Orders, 128);
00260
00261 UINT nbp, nbpbuggy, nbpbuggy2, norders;
00262
00263 norders = pMagic->nOrders;
00264 if ((!norders) || (norders > 0x80))
00265 {
00266 norders = 0x80;
00267 while ((norders > 1) && (!Order[norders-1])) norders--;
00268 }
00269 nbpbuggy = 0;
00270 nbpbuggy2 = 0;
00271 nbp = 0;
00272 for (UINT iord=0; iord<128; iord++)
00273 {
00274 UINT i = Order[iord];
00275 if ((i < 0x80) && (nbp <= i))
00276 {
00277 nbp = i+1;
00278 if (iord<norders) nbpbuggy = nbp;
00279 }
00280 if (i >= nbpbuggy2) nbpbuggy2 = i+1;
00281 }
00282 for (UINT iend=norders; iend<MAX_ORDERS; iend++) Order[iend] = 0xFF;
00283 norders--;
00284 m_nRestartPos = pMagic->nRestartPos;
00285 if (m_nRestartPos >= 0x78) m_nRestartPos = 0;
00286 if (m_nRestartPos + 1 >= (UINT)norders) m_nRestartPos = 0;
00287 if (!nbp) return FALSE;
00288 DWORD dwWowTest = dwTotalSampleLen+dwMemPos;
00289 if ((IsMagic(pMagic->Magic, "M.K.")) && (dwWowTest + nbp*8*256 == dwMemLength)) m_nChannels = 8;
00290 if ((nbp != nbpbuggy) && (dwWowTest + nbp*m_nChannels*256 != dwMemLength))
00291 {
00292 if (dwWowTest + nbpbuggy*m_nChannels*256 == dwMemLength) nbp = nbpbuggy;
00293 else nErr += 8;
00294 } else
00295 if ((nbpbuggy2 > nbp) && (dwWowTest + nbpbuggy2*m_nChannels*256 == dwMemLength))
00296 {
00297 nbp = nbpbuggy2;
00298 }
00299 if ((dwWowTest < 0x600) || (dwWowTest > dwMemLength)) nErr += 8;
00300 if ((m_nSamples == 15) && (nErr >= 16)) return FALSE;
00301
00302 m_nType = MOD_TYPE_MOD;
00303 m_nDefaultSpeed = 6;
00304 m_nDefaultTempo = 125;
00305 m_nMinPeriod = 14 << 2;
00306 m_nMaxPeriod = 3424 << 2;
00307 memcpy(m_szNames, lpStream, 20);
00308
00309 for (UINT ich=0; ich<m_nChannels; ich++)
00310 {
00311 ChnSettings[ich].nVolume = 64;
00312 if (gdwSoundSetup & SNDMIX_MAXDEFAULTPAN)
00313 ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 256 : 0;
00314 else
00315 ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 0xC0 : 0x40;
00316 }
00317
00318 for (UINT ipat=0; ipat<nbp; ipat++)
00319 {
00320 if (ipat < MAX_PATTERNS)
00321 {
00322 if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
00323 PatternSize[ipat] = 64;
00324 if (dwMemPos + m_nChannels*256 >= dwMemLength) break;
00325 MODCOMMAND *m = Patterns[ipat];
00326 LPCBYTE p = lpStream + dwMemPos;
00327 for (UINT j=m_nChannels*64; j; m++,p+=4,j--)
00328 {
00329 BYTE A0=p[0], A1=p[1], A2=p[2], A3=p[3];
00330 UINT n = ((((UINT)A0 & 0x0F) << 8) | (A1));
00331 if ((n) && (n != 0xFFF)) m->note = GetNoteFromPeriod(n << 2);
00332 m->instr = ((UINT)A2 >> 4) | (A0 & 0x10);
00333 m->command = A2 & 0x0F;
00334 m->param = A3;
00335 if ((m->command) || (m->param)) ConvertModCommand(m);
00336 }
00337 }
00338 dwMemPos += m_nChannels*256;
00339 }
00340
00341 DWORD dwErrCheck = 0;
00342 for (UINT ismp=1; ismp<=m_nSamples; ismp++) if (Ins[ismp].nLength)
00343 {
00344 LPSTR p = (LPSTR)(lpStream+dwMemPos);
00345 UINT flags = 0;
00346 if (dwMemPos + 5 >= dwMemLength) break;
00347 if (!strnicmp(p, "ADPCM", 5))
00348 {
00349 flags = 3;
00350 p += 5;
00351 dwMemPos += 5;
00352 }
00353 DWORD dwSize = ReadSample(&Ins[ismp], flags, p, dwMemLength - dwMemPos);
00354 if (dwSize)
00355 {
00356 dwMemPos += dwSize;
00357 dwErrCheck++;
00358 }
00359 }
00360 #ifdef MODPLUG_TRACKER
00361 return TRUE;
00362 #else
00363 return (dwErrCheck) ? TRUE : FALSE;
00364 #endif
00365 }
00366
00367
00368 #ifndef MODPLUG_NO_FILESAVE
00369 #pragma warning(disable:4100)
00370
00371 BOOL CSoundFile::SaveMod(LPCSTR lpszFileName, UINT nPacking)
00372
00373 {
00374 BYTE insmap[32];
00375 UINT inslen[32];
00376 BYTE bTab[32];
00377 BYTE ord[128];
00378 FILE *f;
00379
00380 if ((!m_nChannels) || (!lpszFileName)) return FALSE;
00381 if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
00382 memset(ord, 0, sizeof(ord));
00383 memset(inslen, 0, sizeof(inslen));
00384 if (m_nInstruments)
00385 {
00386 memset(insmap, 0, sizeof(insmap));
00387 for (UINT i=1; i<32; i++) if (Headers[i])
00388 {
00389 for (UINT j=0; j<128; j++) if (Headers[i]->Keyboard[j])
00390 {
00391 insmap[i] = Headers[i]->Keyboard[j];
00392 break;
00393 }
00394 }
00395 } else
00396 {
00397 for (UINT i=0; i<32; i++) insmap[i] = (BYTE)i;
00398 }
00399
00400 fwrite(m_szNames, 20, 1, f);
00401
00402 for (UINT iins=1; iins<=31; iins++)
00403 {
00404 MODINSTRUMENT *pins = &Ins[insmap[iins]];
00405 memcpy(bTab, m_szNames[iins],22);
00406 inslen[iins] = pins->nLength;
00407 if (inslen[iins] > 0x1fff0) inslen[iins] = 0x1fff0;
00408 bTab[22] = inslen[iins] >> 9;
00409 bTab[23] = inslen[iins] >> 1;
00410 if (pins->RelativeTone < 0) bTab[24] = 0x08; else
00411 if (pins->RelativeTone > 0) bTab[24] = 0x07; else
00412 bTab[24] = (BYTE)XM2MODFineTune(pins->nFineTune);
00413 bTab[25] = pins->nVolume >> 2;
00414 bTab[26] = pins->nLoopStart >> 9;
00415 bTab[27] = pins->nLoopStart >> 1;
00416 bTab[28] = (pins->nLoopEnd - pins->nLoopStart) >> 9;
00417 bTab[29] = (pins->nLoopEnd - pins->nLoopStart) >> 1;
00418 fwrite(bTab, 30, 1, f);
00419 }
00420
00421 UINT nbp=0, norders=128;
00422 for (UINT iord=0; iord<128; iord++)
00423 {
00424 if (Order[iord] == 0xFF)
00425 {
00426 norders = iord;
00427 break;
00428 }
00429 if ((Order[iord] < 0x80) && (nbp<=Order[iord])) nbp = Order[iord]+1;
00430 }
00431 bTab[0] = norders;
00432 bTab[1] = m_nRestartPos;
00433 fwrite(bTab, 2, 1, f);
00434
00435 if (norders) memcpy(ord, Order, norders);
00436 fwrite(ord, 128, 1, f);
00437
00438 if (m_nChannels == 4)
00439 lstrcpy((LPSTR)&bTab, "M.K.");
00440 else
00441 wsprintf((LPSTR)&bTab, "%luCHN", m_nChannels);
00442 fwrite(bTab, 4, 1, f);
00443
00444 for (UINT ipat=0; ipat<nbp; ipat++) if (Patterns[ipat])
00445 {
00446 BYTE s[64*4];
00447 MODCOMMAND *m = Patterns[ipat];
00448 for (UINT i=0; i<64; i++) if (i < PatternSize[ipat])
00449 {
00450 LPBYTE p=s;
00451 for (UINT c=0; c<m_nChannels; c++,p+=4,m++)
00452 {
00453 UINT param = ModSaveCommand(m, FALSE);
00454 UINT command = param >> 8;
00455 param &= 0xFF;
00456 if (command > 0x0F) command = param = 0;
00457 if ((m->vol >= 0x10) && (m->vol <= 0x50) && (!command) && (!param)) { command = 0x0C; param = m->vol - 0x10; }
00458 UINT period = m->note;
00459 if (period)
00460 {
00461 if (period < 37) period = 37;
00462 period -= 37;
00463 if (period >= 6*12) period = 6*12-1;
00464 period = ProTrackerPeriodTable[period];
00465 }
00466 UINT instr = (m->instr > 31) ? 0 : m->instr;
00467 p[0] = ((period >> 8) & 0x0F) | (instr & 0x10);
00468 p[1] = period & 0xFF;
00469 p[2] = ((instr & 0x0F) << 4) | (command & 0x0F);
00470 p[3] = param;
00471 }
00472 fwrite(s, m_nChannels, 4, f);
00473 } else
00474 {
00475 memset(s, 0, m_nChannels*4);
00476 fwrite(s, m_nChannels, 4, f);
00477 }
00478 }
00479
00480 for (UINT ismpd=1; ismpd<=31; ismpd++) if (inslen[ismpd])
00481 {
00482 MODINSTRUMENT *pins = &Ins[insmap[ismpd]];
00483 UINT flags = RS_PCM8S;
00484 #ifndef NO_PACKING
00485 if (!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
00486 {
00487 if ((nPacking) && (CanPackSample(pins->pSample, inslen[ismpd], nPacking)))
00488 {
00489 fwrite("ADPCM", 1, 5, f);
00490 flags = RS_ADPCM4;
00491 }
00492 }
00493 #endif
00494 WriteSample(f, pins, flags, inslen[ismpd]);
00495 }
00496 fclose(f);
00497 return TRUE;
00498 }
00499
00500 #pragma warning(default:4100)
00501 #endif // MODPLUG_NO_FILESAVE