From: <sag...@us...> - 2011-09-08 20:16:01
|
Revision: 1029 http://modplug.svn.sourceforge.net/modplug/?rev=1029&view=rev Author: saga-games Date: 2011-09-08 20:15:53 +0000 (Thu, 08 Sep 2011) Log Message: ----------- [Fix] IT Loader: Envelope points with the high byte missing are now loaded correctly. [Imp] IT Loader: Most files saved with early "compatiblity export" are not detected as MPT 1.16 files anymore. [Mod] OpenMPT: Version is now 1.20.00.20 Modified Paths: -------------- trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_xm.cpp Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2011-09-07 22:48:23 UTC (rev 1028) +++ trunk/OpenMPT/mptrack/version.h 2011-09-08 20:15:53 UTC (rev 1029) @@ -15,7 +15,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 19 +#define VER_MINORMINOR 20 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2011-09-07 22:48:23 UTC (rev 1028) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2011-09-08 20:15:53 UTC (rev 1029) @@ -33,7 +33,7 @@ MPTM version history for cwtv-field in "IT" header (only for MPTM files!): 0x890(1.18.02.00) -> 0x891(1.19.00.00): Pattern-specific time signatures Fixed behaviour of Pattern Loop command for rows > 255 (r617) -0x88F(1.18.01.00) -> 0x890(1.18.02.00): Removed volume command velocity :xy, added delay-cut command :xy. +0x88F(1.18.01.00) -> 0x890(1.18.02.00): Removed volume command velocity :xy, added delay-cut command :xy. 0x88E(1.17.02.50) -> 0x88F(1.18.01.00): Numerous changes 0x88D(1.17.02.49) -> 0x88E(1.17.02.50): Changed ID to that of IT and undone the orderlist change done in 0x88A->0x88B. Now extended orderlist is saved as extension. @@ -67,7 +67,7 @@ //tuning name <-> tuning id number map, //and then writing the tuning id for every instrument. //For example if there are 6 instruments and - //first half use tuning 'T1', and the other half + //first half use tuning 'T1', and the other half //tuning 'T2', the output would be something like //T1 1 T2 2 1 1 1 2 2 2 @@ -75,14 +75,14 @@ typedef map<CTuning*, uint16> TNTS_MAP; typedef TNTS_MAP::iterator TNTS_MAP_ITER; TNTS_MAP tNameToShort_Map; - + unsigned short figMap = 0; for(UINT i = 1; i <= sf.GetNumInstruments(); i++) if (sf.Instruments[i] != nullptr) { TNTS_MAP_ITER iter = tNameToShort_Map.find(sf.Instruments[i]->pTuning); if(iter != tNameToShort_Map.end()) continue; //Tuning already mapped. - + tNameToShort_Map[sf.Instruments[i]->pTuning] = figMap; figMap++; } @@ -202,7 +202,7 @@ csf.GetpModDoc()->SetModified(); //The tuning is changed so the modified flag is set. } #endif // MODPLUG_TRACKER - + } csf.Instruments[i]->pTuning = csf.Instruments[i]->s_DefaultTuning; @@ -231,10 +231,10 @@ // Impulse Tracker IT file support -static inline UINT ConvertVolParam(UINT value) -//-------------------------------------------- +UINT ConvertVolParam(const MODCOMMAND *m) +//--------------------------------------- { - return (value > 9) ? 9 : value; + return min(m->vol, 9); } @@ -291,6 +291,19 @@ { mptEnv->Values[ev] = itEnv->data[ev * 3] + envOffset; mptEnv->Ticks[ev] = (itEnv->data[ev * 3 + 2] << 8) | (itEnv->data[ev * 3 + 1]); + if(ev > 0 && ev < itEnv->num && mptEnv->Ticks[ev] < mptEnv->Ticks[ev - 1]) + { + // Fix broken envelopes... Instruments 2 and 3 in NoGap.it by Werewolf have envelope points where the high byte of envelope nodes is missing. + // NoGap.it was saved with MPT 1.07 or MPT 1.09, which *normally* doesn't do this in IT files. + // However... It turns out that MPT 1.07 omitted the high byte of envelope nodes when saving an XI instrument file, and it looks like + // Instrument 2 and 3 in NoGap.it were loaded from XI files. + mptEnv->Ticks[ev] &= 0xFF; + mptEnv->Ticks[ev] |= (mptEnv->Ticks[ev] & ~0xFF); + if(mptEnv->Ticks[ev] < mptEnv->Ticks[ev - 1]) + { + mptEnv->Ticks[ev] += 0x100; + } + } } // Sanitize envelope mptEnv->Ticks[0] = 0; @@ -300,7 +313,7 @@ //BOOL CSoundFile::ITInstrToMPT(const void *p, MODINSTRUMENT *pIns, UINT trkvers) long CSoundFile::ITInstrToMPT(const void *p, MODINSTRUMENT *pIns, UINT trkvers) //rewbs.modularInstData //----------------------------------------------------------------------------- -{ +{ // Envelope point count. Limited to 25 in IT format. const int iEnvMax = (m_nType & MOD_TYPE_MPT) ? MAX_ENVPOINTS : 25; @@ -357,7 +370,7 @@ { //(handle old format where midichan // and mixplug are 1 value) pIns->nMixPlug = pIns->nMidiChannel-128; - pIns->nMidiChannel = 0; + pIns->nMidiChannel = 0; } if (pis->mbank<=128) pIns->wMidiBank = pis->mbank; @@ -381,7 +394,7 @@ pIns->Keyboard[k] |= ((UINT)pisex->keyboardhi[k] << 8); } } - //rewbs.modularInstData + //rewbs.modularInstData //find end of standard header BYTE* pEndInstHeader; if (*((int *)pis->dummy) == 'MPTX') @@ -394,7 +407,7 @@ { //...the next piece of data must be the total size of the modular data long modularInstSize = *((long *)(pEndInstHeader+4)); - + //handle chunks BYTE* pModularInst = (BYTE*)(pEndInstHeader+4+sizeof(modularInstSize)); //4 is for 'INSM' pEndInstHeader+=4+sizeof(modularInstSize)+modularInstSize; @@ -427,12 +440,12 @@ } //end rewbs.modularInstData - - // Volume Envelope + + // Volume Envelope ITEnvToMPT(&pis->volenv, &pIns->VolEnv, 0, iEnvMax); - // Panning Envelope + // Panning Envelope ITEnvToMPT(&pis->panenv, &pIns->PanEnv, 32, iEnvMax); - // Pitch Envelope + // Pitch Envelope ITEnvToMPT(&pis->pitchenv, &pIns->PitchEnv, 32, iEnvMax); if (pis->pitchenv.flags & 0x80) pIns->PitchEnv.dwFlags |= ENV_FILTER; @@ -536,8 +549,16 @@ m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00); } else if(pifh->cwtv == 0x0217 && pifh->cmwt == 0x0200 && pifh->reserved == 0) { - // ModPlug Tracker 1.16 (semi-raped IT format) - m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00); + if(memchr(pifh->chnpan, 0xFF, sizeof(pifh->chnpan)) != NULL) + { + // ModPlug Tracker 1.16 (semi-raped IT format) + m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00); + } else + { + // OpenMPT 1.17 disguised as this in compatible mode, + // but never writes 0xFF in the pan map for unused channels (which is an invalid value). + m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00); + } interpretModPlugMade = true; } else if(pifh->cwtv == 0x0214 && pifh->cmwt == 0x0202 && pifh->reserved == 0) { @@ -559,7 +580,7 @@ if (GetpModDoc()) GetpModDoc()->AddToLog(str_LoadingIncompatibleVersion); return false; - } + } else if (pifh->cwtv > verMptFileVer) { if (GetpModDoc()) @@ -567,7 +588,7 @@ } } } - + if(GetType() == MOD_TYPE_IT) mptStartPos = dwMemLength; // Read row highlights @@ -606,7 +627,7 @@ m_nSamplePreAmp = min(pifh->mv, 128); // Reading Channels Pan Positions - for (int ipan=0; ipan</*MAX_BASECHANNELS*/64; ipan++) if (pifh->chnpan[ipan] != 0xFF) //Header only has room for settings for 64 chans... + for (int ipan=0; ipan< 64; ipan++) if (pifh->chnpan[ipan] != 0xFF) { ChnSettings[ipan].nVolume = pifh->chnvol[ipan]; ChnSettings[ipan].nPan = 128; @@ -648,7 +669,7 @@ if(pifh->cwtv > 0x88A && pifh->cwtv <= 0x88D) dwMemPos += Order.Deserialize(lpStream+dwMemPos, dwMemLength-dwMemPos); else - { + { Order.ReadAsByte(lpStream + dwMemPos, nordsize, dwMemLength - dwMemPos); dwMemPos += pifh->ordnum; //Replacing 0xFF and 0xFE with new corresponding indexes @@ -845,15 +866,15 @@ } } // Read mix plugins information - if (dwMemPos + 8 < dwMemLength) + if (dwMemPos + 8 < dwMemLength) { dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos); } - + //UINT npatterns = pifh->patnum; UINT npatterns = patpos.size(); - - if (npatterns > GetModSpecifications().patternsMax) + + if (npatterns > GetModSpecifications().patternsMax) npatterns = GetModSpecifications().patternsMax; // Checking for unused channels @@ -861,7 +882,7 @@ { memset(chnmask, 0, sizeof(chnmask)); - if ((!patpos[patchk]) || ((DWORD)patpos[patchk] >= dwMemLength - 4)) + if ((!patpos[patchk]) || ((DWORD)patpos[patchk] >= dwMemLength - 4)) continue; UINT len = *((WORD *)(lpStream+patpos[patchk])); @@ -873,16 +894,16 @@ hasModPlugExtensions = true; } - if ((rows < GetModSpecifications().patternRowsMin) || (rows > GetModSpecifications().patternRowsMax)) + if ((rows < GetModSpecifications().patternRowsMin) || (rows > GetModSpecifications().patternRowsMax)) continue; - if (patpos[patchk]+8+len > dwMemLength) + if (patpos[patchk]+8+len > dwMemLength) continue; UINT i = 0; const BYTE *p = lpStream+patpos[patchk]+8; UINT nrow = 0; - + while (nrow<rows) { if (i >= len) break; @@ -894,13 +915,13 @@ } UINT ch = b & IT_bitmask_patternChanField_c; // 0x7f We have some data grab a byte keeping only 7 bits - if (ch) + if (ch) ch = (ch - 1);// & IT_bitmask_patternChanMask_c; // 0x3f mask of the byte again, keeping only 6 bits if (b & IT_bitmask_patternChanEnabled_c) // 0x80 check if the upper bit is enabled. { - if (i >= len) - break; + if (i >= len) + break; chnmask[ch] = p[i++]; // set the channel mask for this channel. } // Channel used @@ -913,7 +934,7 @@ // -! BEHAVIOUR_CHANGE#0006 } // Now we actually update the pattern-row entry the note,instrument etc. - // Note + // Note if (chnmask[ch] & 1) i++; // Instrument if (chnmask[ch] & 2) i++; @@ -1044,7 +1065,7 @@ LPCBYTE ptr = LoadExtendedInstrumentProperties(lpStream + dwMemPos, lpStream + mptStartPos, &interpretModPlugMade); LoadExtendedSongProperties(GetType(), ptr, lpStream, mptStartPos, &interpretModPlugMade); } - + // -! NEW_FEATURE#0027 @@ -1054,7 +1075,7 @@ { if ((!patpos[npat]) || ((DWORD)patpos[npat] >= dwMemLength - 4)) { - if(Patterns.Insert(npat, 64)) + if(Patterns.Insert(npat, 64)) { #ifdef MODPLUG_TRACKER CString s; @@ -1093,21 +1114,21 @@ m+=m_nChannels; continue; } - + UINT ch = b & IT_bitmask_patternChanField_c; // 0x7f - + if (ch) ch = (ch - 1); //& IT_bitmask_patternChanMask_c; // 0x3f - + if (b & IT_bitmask_patternChanEnabled_c) // 0x80 { - if (i >= len) + if (i >= len) break; chnmask[ch] = p[i++]; } // Now we grab the data for this particular row/channel. - + if ((chnmask[ch] & 0x10) && (ch < m_nChannels)) { m[ch].note = lastvalue[ch].note; @@ -1178,7 +1199,7 @@ if ((vol >= 193) && (vol <= 202)) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else // 203-212: Vibrato depth if ((vol >= 203) && (vol <= 212)) - { + { m[ch].volcmd = VOLCMD_VIBRATODEPTH; m[ch].vol = vol - 203; // Old versions of ModPlug saved this as vibrato speed instead, so let's fix that if(m_dwLastSavedWithVersion && m_dwLastSavedWithVersion <= MAKE_VERSION_NUMERIC(1, 17, 02, 54)) @@ -1291,7 +1312,7 @@ uint16 fnum = min(num, uint16_max); // Number of entries that are actually going to be written const size_t bytes_written = 2 + fnum * 8; // Number of bytes that are actually going to be written - + if(f == nullptr) return bytes_written; @@ -1418,7 +1439,7 @@ break; } } - + if(!compatExport) { // This way, we indicate that the file will most likely contain OpenMPT hacks. Compatibility export puts 0 here. @@ -1443,7 +1464,7 @@ memset(header.chnpan, 0xA0, 64); memset(header.chnvol, 64, 64); - for (size_t ich = 0; ich < 64; ich++) //Header only has room for settings for 64 chans... + for (size_t ich = 0; ich < min(m_nChannels, 64); ich++) // Header only has room for settings for 64 chans... { header.chnpan[ich] = ChnSettings[ich].nPan >> 2; if (ChnSettings[ich].dwFlags & CHN_SURROUND) header.chnpan[ich] = 100; @@ -1583,7 +1604,7 @@ iti.mch = pIns->nMixPlug + 128; } iti.nna = pIns->nNNA; - iti.dct = (pIns->nDCT < DCT_PLUGIN || !compatExport) ? pIns->nDCT : 0; + iti.dct = (pIns->nDCT < DCT_PLUGIN || !compatExport) ? pIns->nDCT : 0; iti.dca = pIns->nDNA; iti.fadeout = min(pIns->nFadeOut >> 5, 256); iti.pps = pIns->nPPS; @@ -1645,7 +1666,7 @@ fwrite(&ModInstID, 1, sizeof(ModInstID), f); // mark this as an instrument with modular extensions long sizePos = ftell(f); // we will want to write the modular data's total size here fwrite(&modularInstSize, 1, sizeof(modularInstSize), f); // write a DUMMY size, just to move file pointer by a long - + //Write chunks UINT ID; { //VST Slot chunk: @@ -1660,7 +1681,7 @@ ID='MYID'; fwrite(&ID, 1, sizeof(int), f); instModularDataSize+=sizeof(int); - + //You can save your chunk size somwhere here if you need variable chunk size. fwrite(myData, 1, myDataSize, f); instModularDataSize+=myDataSize; @@ -1671,8 +1692,8 @@ fseek(f, sizePos, SEEK_SET); // go back to sizePos fwrite(&modularInstSize, 1, sizeof(modularInstSize), f); // write data fseek(f, curPos, SEEK_SET); // go back to where we were. - - //move forward + + //move forward dwPos+=sizeof(ModInstID)+sizeof(modularInstSize)+modularInstSize; } //------------ end rewbs.modularInstData @@ -1751,25 +1772,25 @@ { case VOLCMD_VOLUME: vol = m->vol; if (vol > 64) vol = 64; break; case VOLCMD_PANNING: vol = m->vol + 128; if (vol > 192) vol = 192; break; - case VOLCMD_VOLSLIDEUP: vol = 85 + ConvertVolParam(m->vol); break; - case VOLCMD_VOLSLIDEDOWN: vol = 95 + ConvertVolParam(m->vol); break; - case VOLCMD_FINEVOLUP: vol = 65 + ConvertVolParam(m->vol); break; - case VOLCMD_FINEVOLDOWN: vol = 75 + ConvertVolParam(m->vol); break; - case VOLCMD_VIBRATODEPTH: vol = 203 + ConvertVolParam(m->vol); break; + case VOLCMD_VOLSLIDEUP: vol = 85 + ConvertVolParam(m); break; + case VOLCMD_VOLSLIDEDOWN: vol = 95 + ConvertVolParam(m); break; + case VOLCMD_FINEVOLUP: vol = 65 + ConvertVolParam(m); break; + case VOLCMD_FINEVOLDOWN: vol = 75 + ConvertVolParam(m); break; + case VOLCMD_VIBRATODEPTH: vol = 203 + ConvertVolParam(m); break; case VOLCMD_VIBRATOSPEED: if(command == CMD_NONE) { // illegal command -> move if possible command = CMD_VIBRATO; - param = ConvertVolParam(m->vol) << 4; + param = ConvertVolParam(m) << 4; } else { vol = 203; } break; - case VOLCMD_TONEPORTAMENTO: vol = 193 + ConvertVolParam(m->vol); break; - case VOLCMD_PORTADOWN: vol = 105 + ConvertVolParam(m->vol); break; - case VOLCMD_PORTAUP: vol = 115 + ConvertVolParam(m->vol); break; - case VOLCMD_OFFSET: if(!compatExport) vol = 223 + ConvertVolParam(m->vol); //rewbs.volOff + case VOLCMD_TONEPORTAMENTO: vol = 193 + ConvertVolParam(m); break; + case VOLCMD_PORTADOWN: vol = 105 + ConvertVolParam(m); break; + case VOLCMD_PORTAUP: vol = 115 + ConvertVolParam(m); break; + case VOLCMD_OFFSET: if(!compatExport) vol = 223 + ConvertVolParam(m); //rewbs.volOff break; default: vol = 0xFF; } @@ -1792,7 +1813,7 @@ b |= 0x10; } else { - lastvalue[ch].note = note; + lastvalue[ch].note = note; lastvalue[ch].volcmd |= 1; } } @@ -1890,7 +1911,7 @@ itss.id = LittleEndian(IT_IMPS); itss.gvl = (BYTE)sample.nGlobalVol; - + UINT flags = RS_PCM8S; if(sample.nLength && sample.pSample) { @@ -1972,7 +1993,7 @@ fclose(f); return true; } - + //hack //BEGIN: MPT SPECIFIC: //-------------------- @@ -2252,13 +2273,13 @@ { nPluginSize += p->nPluginDataSize; } - + // rewbs.modularPlugData DWORD MPTxPlugDataSize = 4 + (sizeof(m_MixPlugins[i].fDryRatio)) + //4 for ID and size of dryRatio 4 + (sizeof(m_MixPlugins[i].defaultProgram)); //rewbs.plugDefaultProgram // for each extra entity, add 4 for ID, plus size of entity, plus optionally 4 for size of entity. - nPluginSize += MPTxPlugDataSize+4; //+4 is for size itself: sizeof(DWORD) is 4 + nPluginSize += MPTxPlugDataSize+4; //+4 is for size itself: sizeof(DWORD) is 4 // rewbs.modularPlugData if (f) { @@ -2268,7 +2289,7 @@ s[2] = '0' + (i/10); s[3] = '0' + (i%10); fwrite(s, 1, 4, f); - + // write plugin size: fwrite(&nPluginSize, 1, 4, f); fwrite(&p->Info, 1, sizeof(SNDMIXPLUGININFO), f); @@ -2276,7 +2297,7 @@ if (m_MixPlugins[i].pPluginData) { fwrite(m_MixPlugins[i].pPluginData, 1, m_MixPlugins[i].nPluginDataSize, f); } - + //rewbs.dryRatio fwrite(&MPTxPlugDataSize, 1, 4, f); @@ -2344,7 +2365,7 @@ nPluginSize = *(DWORD *)(p + nPos + 4); if (nPluginSize > nLen - nPos - 8) break; - + // Channel FX if (!memcmp(p + nPos, "CHFX", 4)) { @@ -2366,7 +2387,7 @@ //data for VST setchunk? size lies just after standard plugin data. DWORD dwExtra = *(DWORD *)(p+nPos+8+sizeof(SNDMIXPLUGININFO)); - + if ((dwExtra) && (dwExtra <= nPluginSize-sizeof(SNDMIXPLUGININFO)-4)) { m_MixPlugins[nPlugin].nPluginDataSize = 0; @@ -2380,7 +2401,7 @@ //rewbs.modularPlugData DWORD dwXPlugData = *(DWORD *)(p+nPos+8+sizeof(SNDMIXPLUGININFO)+dwExtra+4); //read next DWORD into dwMPTExtra - + //if dwMPTExtra is positive and there are dwMPTExtra bytes left in nPluginSize, we have some more data! if ((dwXPlugData) && ((int)dwXPlugData <= (int)nPluginSize-(int)(sizeof(SNDMIXPLUGININFO)+dwExtra+8))) { @@ -2433,7 +2454,7 @@ } -// Used only when saving IT, XM and MPTM. +// Used only when saving IT, XM and MPTM. // ITI, ITP saves using Ericus' macros etc... // The reason is that ITs and XMs save [code][size][ins1.Value][ins2.Value]... // whereas ITP saves [code][size][ins1.Value][code][size][ins2.Value]... @@ -2448,13 +2469,13 @@ }*/ code = 'MPTX'; // write extension header code - fwrite(&code, 1, sizeof(__int32), f); + fwrite(&code, 1, sizeof(__int32), f); if (nInstruments == 0) return; MODINSTRUMENT *sizeIns = new MODINSTRUMENT(); - + WriteInstrumentPropertyForAllInstruments('VR..', sizeof(sizeIns->nVolRamp), f, nInstruments); WriteInstrumentPropertyForAllInstruments('MiP.', sizeof(sizeIns->nMixPlug), f, nInstruments); WriteInstrumentPropertyForAllInstruments('MC..', sizeof(sizeIns->nMidiChannel),f, nInstruments); @@ -2517,7 +2538,7 @@ { pField = GetInstrumentHeaderFieldPointer(Instruments[nins], code, size); //get ptr to field } else - { + { MODINSTRUMENT *emptyInstrument = new MODINSTRUMENT(); pField = GetInstrumentHeaderFieldPointer(emptyInstrument, code, size); //get ptr to field delete emptyInstrument; @@ -2533,32 +2554,32 @@ __int16 size; __int32 code = 'MPTS'; //Extra song file data fwrite(&code, 1, sizeof(__int32), f); - + code = 'DT..'; //write m_nDefaultTempo field code - fwrite(&code, 1, sizeof(__int32), f); + fwrite(&code, 1, sizeof(__int32), f); size = sizeof(m_nDefaultTempo); //write m_nDefaultTempo field size fwrite(&size, 1, sizeof(__int16), f); fwrite(&m_nDefaultTempo, 1, size, f); //write m_nDefaultTempo code = 'RPB.'; //write m_nRowsPerBeat - fwrite(&code, 1, sizeof(__int32), f); + fwrite(&code, 1, sizeof(__int32), f); size = sizeof(m_nDefaultRowsPerBeat); fwrite(&size, 1, sizeof(__int16), f); fwrite(&m_nDefaultRowsPerBeat, 1, size, f); code = 'RPM.'; //write m_nRowsPerMeasure - fwrite(&code, 1, sizeof(__int32), f); + fwrite(&code, 1, sizeof(__int32), f); size = sizeof(m_nDefaultRowsPerMeasure); fwrite(&size, 1, sizeof(__int16), f); fwrite(&m_nDefaultRowsPerMeasure, 1, size, f); - code = 'C...'; //write m_nChannels - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_nChannels); + code = 'C...'; //write m_nChannels + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_nChannels); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_nChannels, 1, size, f); + fwrite(&m_nChannels, 1, size, f); - if(TypeIsIT_MPT() && m_nChannels > 64) //IT header has room only for 64 channels. Save the + if(TypeIsIT_MPT() && m_nChannels > 64) //IT header has room only for 64 channels. Save the { //settings that do not fit to the header here as an extension. code = 'ChnS'; fwrite(&code, 1, sizeof(__int32), f); @@ -2574,64 +2595,64 @@ fwrite(&panvol, sizeof(panvol), 1, f); } } - + code = 'TM..'; //write m_nTempoMode - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_nTempoMode); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_nTempoMode); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_nTempoMode, 1, size, f); + fwrite(&m_nTempoMode, 1, size, f); code = 'PMM.'; //write m_nMixLevels - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_nMixLevels); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_nMixLevels); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_nMixLevels, 1, size, f); + fwrite(&m_nMixLevels, 1, size, f); code = 'CWV.'; //write m_dwCreatedWithVersion - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_dwCreatedWithVersion); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_dwCreatedWithVersion); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_dwCreatedWithVersion, 1, size, f); + fwrite(&m_dwCreatedWithVersion, 1, size, f); code = 'LSWV'; //write m_dwLastSavedWithVersion - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_dwLastSavedWithVersion); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_dwLastSavedWithVersion); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_dwLastSavedWithVersion, 1, size, f); + fwrite(&m_dwLastSavedWithVersion, 1, size, f); code = 'SPA.'; //write m_nSamplePreAmp - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_nSamplePreAmp); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_nSamplePreAmp); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_nSamplePreAmp, 1, size, f); + fwrite(&m_nSamplePreAmp, 1, size, f); code = 'VSTV'; //write m_nVSTiVolume - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_nVSTiVolume); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_nVSTiVolume); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_nVSTiVolume, 1, size, f); + fwrite(&m_nVSTiVolume, 1, size, f); code = 'DGV.'; //write m_nDefaultGlobalVolume - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_nDefaultGlobalVolume); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_nDefaultGlobalVolume); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_nDefaultGlobalVolume, 1, size, f); + fwrite(&m_nDefaultGlobalVolume, 1, size, f); code = 'RP..'; //write m_nRestartPos - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_nRestartPos); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_nRestartPos); fwrite(&size, 1, sizeof(__int16), f); fwrite(&m_nRestartPos, 1, size, f); //Additional flags for XM/IT/MPTM - if(m_ModFlags) + if(m_ModFlags) { code = 'MSF.'; - fwrite(&code, 1, sizeof(__int32), f); - size = sizeof(m_ModFlags); + fwrite(&code, 1, sizeof(__int32), f); + size = sizeof(m_ModFlags); fwrite(&size, 1, sizeof(__int16), f); - fwrite(&m_ModFlags, 1, size, f); + fwrite(&m_ModFlags, 1, size, f); } //MIMA, MIDI mapping directives @@ -2654,8 +2675,8 @@ GetMIDIMapper().Serialize(f); } } - + return; } @@ -2682,11 +2703,11 @@ ptr += sizeof(int32); // jump extension header code while( ptr < pEnd && uintptr_t(pEnd-ptr) >= 4) //Loop 'till beginning of end of file/mpt specific looking for inst. extensions - { + { memcpy(&code, ptr, sizeof(code)); // read field code if (code == 'MPTS') //Reached song extensions, break out of this loop return ptr; - + ptr += sizeof(code); // jump field code if((uintptr_t)(pEnd - ptr) < 2) @@ -2723,9 +2744,9 @@ int32 code = 0; int16 size = 0; - + memcpy(&code, ptr, sizeof(code)); - + if(code != 'MPTS') return; @@ -2736,7 +2757,7 @@ // HACK: Reset mod flags to default values here, as they are not always written. m_ModFlags = 0; - // Case macros. + // Case macros. #define CASE(id, data) \ case id: fadr = reinterpret_cast<BYTE*>(&data); nMaxReadCount = min(size, sizeof(data)); break; #define CASE_NOTXM(id, data) \ @@ -2744,7 +2765,7 @@ ptr += sizeof(code); // jump extension header code while( uintptr_t(ptr - lpStream) <= searchlimit-6 ) //Loop until given limit. - { + { code = (*((int32 *)ptr)); // read field code ptr += sizeof(int32); // jump field code size = (*((int16 *)ptr)); // read field size @@ -2772,7 +2793,7 @@ CASE_NOTXM('RP..', m_nRestartPos); CASE('MSF.', m_ModFlags); case 'MIMA': GetMIDIMapper().Deserialize(ptr, size); break; - case 'ChnS': + case 'ChnS': if( (size <= 63*2) && (size % 2 == 0) ) { const BYTE* pData = ptr; @@ -2817,4 +2838,3 @@ #undef CASE #undef CASE_NOTXM } - Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2011-09-07 22:48:23 UTC (rev 1028) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2011-09-08 20:15:53 UTC (rev 1029) @@ -463,17 +463,19 @@ pIns->VolEnv.Values[ienv] = (BYTE)xmsh.venv[ienv*2+1]; pIns->PanEnv.Ticks[ienv] = (WORD)xmsh.penv[ienv*2]; pIns->PanEnv.Values[ienv] = (BYTE)xmsh.penv[ienv*2+1]; - if (ienv) + if (ienv > 0) { // libmikmod code says: "Some broken XM editing program will only save the low byte of the position // value. Try to compensate by adding the missing high byte" - I guess that's what this code is for. - if (pIns->VolEnv.Ticks[ienv] < pIns->VolEnv.Ticks[ienv-1]) + // Note: It appears that MPT 1.07's XI instrument saver omitted the high byte of envelope nodes. + // This might be the source for some broken envelopes in IT and XM files. + if (pIns->VolEnv.Ticks[ienv] < pIns->VolEnv.Ticks[ienv - 1]) { pIns->VolEnv.Ticks[ienv] &= 0xFF; pIns->VolEnv.Ticks[ienv] += pIns->VolEnv.Ticks[ienv - 1] & 0xFF00; if (pIns->VolEnv.Ticks[ienv] < pIns->VolEnv.Ticks[ienv - 1]) pIns->VolEnv.Ticks[ienv] += 0x100; } - if (pIns->PanEnv.Ticks[ienv] < pIns->PanEnv.Ticks[ienv-1]) + if (pIns->PanEnv.Ticks[ienv] < pIns->PanEnv.Ticks[ienv - 1]) { pIns->PanEnv.Ticks[ienv] &= 0xFF; pIns->PanEnv.Ticks[ienv] += pIns->PanEnv.Ticks[ienv - 1] & 0xFF00; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |