From: <sag...@us...> - 2013-04-22 16:38:33
|
Revision: 1931 http://sourceforge.net/p/modplug/code/1931 Author: saga-games Date: 2013-04-22 16:38:18 +0000 (Mon, 22 Apr 2013) Log Message: ----------- [Mod] +++ and --- entries are no longer exported to XM files. [Imp] Mod Conversion: When converting to MOD or XM, --- and +++ order items are automatically removed and pattern jump commands are updated accordingly. [Mod] OpenMPT: Version is now 1.22.02.02 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/mptrack/MPTHacks.cpp trunk/OpenMPT/mptrack/PatternClipboard.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/ModSequence.cpp trunk/OpenMPT/soundlib/ModSequence.h trunk/OpenMPT/soundlib/mod_specifications.cpp trunk/OpenMPT/soundlib/mod_specifications.h trunk/OpenMPT/soundlib/patternContainer.cpp Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/common/version.h 2013-04-22 16:38:18 UTC (rev 1931) @@ -21,7 +21,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 22 #define VER_MINOR 02 -#define VER_MINORMINOR 01 +#define VER_MINORMINOR 02 //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/mptrack/MPTHacks.cpp =================================================================== --- trunk/OpenMPT/mptrack/MPTHacks.cpp 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/mptrack/MPTHacks.cpp 2013-04-22 16:38:18 UTC (rev 1931) @@ -101,57 +101,6 @@ } -// Functor for fixing jump commands to moved order items -struct FixJumpCommands -//==================== -{ - FixJumpCommands(const vector<PATTERNINDEX> &offsets) : jumpOffset(offsets) {}; - - void operator()(ModCommand& m) - { - if(m.command == CMD_POSITIONJUMP && m.param < jumpOffset.size()) - { - m.param = BYTE(int(m.param) - jumpOffset[m.param]); - } - } - - const vector<PATTERNINDEX> jumpOffset; -}; - - -void RemoveFromOrder(CSoundFile &rSndFile, PATTERNINDEX which) -//------------------------------------------------------------ -{ - const ORDERINDEX orderLength = rSndFile.Order.GetLengthTailTrimmed(); - ORDERINDEX currentLength = orderLength; - - // Associate order item index with jump offset (i.e. how much it moved forwards) - vector<PATTERNINDEX> jumpOffset(orderLength, 0); - PATTERNINDEX maxJump = 0; - - for(ORDERINDEX i = 0; i < currentLength; i++) - { - if(rSndFile.Order[i] == which) - { - maxJump++; - // Move order list forwards, update jump counters - for(ORDERINDEX j = i + 1; j < orderLength; j++) - { - rSndFile.Order[j - 1] = rSndFile.Order[j]; - jumpOffset[j] = maxJump; - } - rSndFile.Order[--currentLength] = rSndFile.Order.GetInvalidPatIndex(); - } - } - - rSndFile.Patterns.ForEachModCommand(FixJumpCommands(jumpOffset)); - if(rSndFile.m_nRestartPos < jumpOffset.size()) - { - rSndFile.m_nRestartPos -= jumpOffset[rSndFile.m_nRestartPos]; - } -} - - // Go through the module to find out if it contains any hacks introduced by (Open)MPT bool CModDoc::HasMPTHacks(const bool autofix) //------------------------------------------- @@ -202,21 +151,21 @@ if(autofix) { - RemoveFromOrder(m_SndFile, m_SndFile.Order.GetIgnoreIndex()); + m_SndFile.Order.RemovePattern(m_SndFile.Order.GetIgnoreIndex()); } break; } } - if((m_SndFile.GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM)) && m_SndFile.Order.GetLengthFirstEmpty() != m_SndFile.Order.GetLengthTailTrimmed()) + if(!originalSpecs->hasStopIndex && m_SndFile.Order.GetLengthFirstEmpty() != m_SndFile.Order.GetLengthTailTrimmed()) { foundHacks = true; AddToLog("The pattern sequence should end after the first stop (---) index in this format."); if(autofix) { - RemoveFromOrder(m_SndFile, m_SndFile.Order.GetInvalidPatIndex()); + m_SndFile.Order.RemovePattern(m_SndFile.Order.GetInvalidPatIndex()); } } Modified: trunk/OpenMPT/mptrack/PatternClipboard.cpp =================================================================== --- trunk/OpenMPT/mptrack/PatternClipboard.cpp 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/mptrack/PatternClipboard.cpp 2013-04-22 16:38:18 UTC (rev 1931) @@ -408,7 +408,9 @@ // Next order item, please pos = data.Find(",", pos + 1) + 1; - if((insertPat == sndFile.Order.GetIgnoreIndex() && !sndFile.GetModSpecifications().hasIgnoreIndex) || insertPat == PATTERNINDEX_INVALID) + if((insertPat == sndFile.Order.GetIgnoreIndex() && !sndFile.GetModSpecifications().hasIgnoreIndex) + || (insertPat == sndFile.Order.GetInvalidPatIndex() && !sndFile.GetModSpecifications().hasStopIndex) + || insertPat == PATTERNINDEX_INVALID) { continue; } Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2013-04-22 16:38:18 UTC (rev 1931) @@ -19,12 +19,12 @@ // Allocate samples for an instrument -vector<SAMPLEINDEX> AllocateXMSamples(CSoundFile &sndFile, SAMPLEINDEX numSamples) -//-------------------------------------------------------------------------------- +static std::vector<SAMPLEINDEX> AllocateXMSamples(CSoundFile &sndFile, SAMPLEINDEX numSamples) +//-------------------------------------------------------------------------------------------- { LimitMax(numSamples, SAMPLEINDEX(32)); - vector<SAMPLEINDEX> foundSlots; + std::vector<SAMPLEINDEX> foundSlots; for(SAMPLEINDEX i = 0; i < numSamples; i++) { @@ -68,7 +68,7 @@ if(candidateSlot >= MAX_SAMPLES) { // Still couldn't find any empty sample slots, so look out for existing but unused samples. - vector<bool> usedSamples; + std::vector<bool> usedSamples; SAMPLEINDEX unusedSampleCount = sndFile.DetectUnusedSamples(usedSamples); if(unusedSampleCount > 0) @@ -275,6 +275,7 @@ StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], fileHeader.songName); + m_nType = MOD_TYPE_NONE; // Ensure that order list items FE and FF are not converted. ChangeModTypeTo(MOD_TYPE_XM); m_nMinPeriod = 27; m_nMaxPeriod = 54784; @@ -299,7 +300,7 @@ } // In case of XM versions < 1.04, we need to memorize the sample flags for all samples, as they are not stored immediately after the sample headers. - vector<SampleIO> sampleFlags; + std::vector<SampleIO> sampleFlags; uint8 sampleReserved = 0; // Reading instruments @@ -358,7 +359,7 @@ } // Read sample headers - vector<SAMPLEINDEX> sampleSlots = AllocateXMSamples(*this, instrHeader.numSamples); + std::vector<SAMPLEINDEX> sampleSlots = AllocateXMSamples(*this, instrHeader.numSamples); // Update sample assignment map for(size_t k = 0 + 12; k < 96 + 12; k++) @@ -374,7 +375,7 @@ sampleFlags.clear(); } // Need to memorize those if we're going to skip any samples... - vector<uint32> sampleSize(instrHeader.numSamples); + std::vector<uint32> sampleSize(instrHeader.numSamples); // Early versions of Sk@le Tracker didn't set sampleHeaderSize (this fixes IFULOVE.XM) const size_t copyBytes = (instrHeader.sampleHeaderSize > 0) ? instrHeader.sampleHeaderSize : sizeof(XMSample); @@ -537,12 +538,20 @@ } } + // We no longer allow any --- or +++ items in the order list now. + if(m_dwLastSavedWithVersion && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 22, 02, 02)) + { + if(!Patterns.IsValidPat(0xFE)) + Order.RemovePattern(0xFE); + if(!Patterns.IsValidPat(0xFF)) + Order.RemovePattern(0xFF); + } + return true; } #ifndef MODPLUG_NO_FILESAVE -#include "../mptrack/Moddoc.h" // for logging errors #define str_tooMuchPatternData (GetStrI18N((_TEXT("Warning: File format limit was reached. Some pattern data may not get written to file.")))) #define str_pattern (GetStrI18N((_TEXT("pattern")))) @@ -551,24 +560,12 @@ bool CSoundFile::SaveXM(LPCSTR lpszFileName, bool compatibilityExport) //-------------------------------------------------------------------- { - #define ASSERT_CAN_WRITE(x) \ - if(len > s.size() - x) /*Buffer running out? Make it larger.*/ \ - s.resize(s.size() + 10*1024, 0); \ - \ - if((len > uint16_max - (UINT)x) && GetpModDoc()) /*Reaching the limits of file format?*/ \ - { \ - mpt::String str; str.Format("%s (%s %u)", str_tooMuchPatternData, str_pattern, pat); \ - AddToLog(str); \ - break; \ - } - FILE *f; if(lpszFileName == nullptr || (f = fopen(lpszFileName, "wb")) == nullptr) { return false; } - vector<uint8> s(64 * 64 * 5, 0); bool addChannel = false; // avoid odd channel count for FT2 compatibility XMFileHeader fileHeader; @@ -585,7 +582,7 @@ fileHeader.restartPos = m_nRestartPos; fileHeader.channels = (m_nChannels + 1) & 0xFFFE; // avoid odd channel count for FT2 compatibility - if((m_nChannels & 1) && m_nChannels < MAX_BASECHANNELS) addChannel = true; + if((m_nChannels % 2u) && m_nChannels < MAX_BASECHANNELS) addChannel = true; if(compatibilityExport && fileHeader.channels > 32) fileHeader.channels = 32; if(fileHeader.channels > MAX_BASECHANNELS) fileHeader.channels = MAX_BASECHANNELS; @@ -593,21 +590,28 @@ // Find out number of orders and patterns used. // +++ and --- patterns are not taken into consideration as FastTracker does not support them. - ORDERINDEX nMaxOrds = 0; - PATTERNINDEX nPatterns = 0; + ORDERINDEX maxOrders = 0; + PATTERNINDEX numPatterns = Patterns.GetNumPatterns(); + bool changeOrderList = false; for(ORDERINDEX ord = 0; ord < Order.GetLengthTailTrimmed(); ord++) { - if(Patterns.IsValidIndex(Order[ord])) + if(Order[ord] == Order.GetIgnoreIndex() || Order[ord] == Order.GetInvalidPatIndex()) { - nMaxOrds++; - if(Order[ord] >= nPatterns) nPatterns = Order[ord] + 1; + changeOrderList = true; + } else + { + maxOrders++; + if(Order[ord] >= numPatterns) numPatterns = Order[ord] + 1; } } - if(!compatibilityExport) nMaxOrds = Order.GetLengthTailTrimmed(); // should really be removed at some point + if(changeOrderList) + { + AddToLog("Skip and stop order list items (+++ and ---) are not saved in XM files."); + } - fileHeader.orders = nMaxOrds; - fileHeader.patterns = nPatterns; - fileHeader.size = fileHeader.size + nMaxOrds; + fileHeader.orders = maxOrders; + fileHeader.patterns = numPatterns; + fileHeader.size = fileHeader.size + maxOrders; uint16 writeInstruments; if(m_nInstruments > 0) @@ -619,9 +623,6 @@ if(m_SongFlags[SONG_EXFILTERRANGE] && !compatibilityExport) fileHeader.flags |= XMFileHeader::extendedFilterRange; fileHeader.flags = fileHeader.flags; -// if(compatibilityExport) -// xmheader.tempo = static_cast<uint16>(Clamp(m_nDefaultTempo, 32u, 255u)); -// else // Fasttracker 2 will happily accept any tempo faster than 255 BPM. XMPlay does also support this, great! fileHeader.tempo = static_cast<uint16>(Clamp(m_nDefaultTempo, 32u, 512u)); fileHeader.speed = static_cast<uint16>(Clamp(m_nDefaultSpeed, 1u, 31u)); @@ -632,7 +633,7 @@ // write order list (without +++ and ---, explained above) for(ORDERINDEX ord = 0; ord < Order.GetLengthTailTrimmed(); ord++) { - if(Patterns.IsValidIndex(Order[ord]) || !compatibilityExport) + if(Order[ord] != Order.GetIgnoreIndex() && Order[ord] != Order.GetInvalidPatIndex()) { uint8 ordItem = static_cast<uint8>(Order[ord]); fwrite(&ordItem, 1, 1, f); @@ -640,7 +641,13 @@ } // Writing patterns - for(PATTERNINDEX pat = 0; pat < nPatterns; pat++) + +#define ASSERT_CAN_WRITE(x) \ + if(len > s.size() - x) /*Buffer running out? Make it larger.*/ \ + s.resize(s.size() + 10 * 1024, 0); + std::vector<uint8> s(64 * 64 * 5, 0); + + for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { uint8 patHead[9]; MemsetZero(patHead); @@ -757,14 +764,24 @@ len = 0; } + // Reaching the limits of file format? + if(len > uint16_max) + { + mpt::String str; str.Format("%s (%s %u)", str_tooMuchPatternData, str_pattern, pat); + AddToLog(str); + len = uint16_max; + } + patHead[7] = static_cast<uint8>(len & 0xFF); patHead[8] = static_cast<uint8>(len >> 8); fwrite(patHead, 1, 9, f); - if(len) fwrite(&s[0], 1, len, f); + if(len) fwrite(&s[0], len, 1, f); } +#undef ASSERT_CAN_WRITE + // Check which samples are referenced by which instruments (for assigning unreferenced samples to instruments) - vector<bool> sampleAssigned(GetNumSamples() + 1, false); + std::vector<bool> sampleAssigned(GetNumSamples() + 1, false); for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++) { if(Instruments[ins] != nullptr) @@ -777,7 +794,7 @@ for(INSTRUMENTINDEX ins = 1; ins <= writeInstruments; ins++) { XMInstrumentHeader insHeader; - vector<SAMPLEINDEX> samples; + std::vector<SAMPLEINDEX> samples; if(GetNumInstruments()) { @@ -793,14 +810,14 @@ insHeader.instrument.ApplyAutoVibratoToXM(Samples[samples[0]], GetType()); } - vector<SAMPLEINDEX> additionalSamples; + std::vector<SAMPLEINDEX> additionalSamples; // Try to save "instrument-less" samples as well by adding those after the "normal" samples of our sample. // We look for unassigned samples directly after the samples assigned to our current instrument, so if // e.g. sample 1 is assigned to instrument 1 and samples 2 to 10 aren't assigned to any instrument, // we will assign those to sample 1. Any samples before the first referenced sample are going to be lost, // but hey, I wrote this mostly for preserving instrument texts in existing modules, where we shouldn't encounter this situation... - for(vector<SAMPLEINDEX>::const_iterator sample = samples.begin(); sample != samples.end(); sample++) + for(std::vector<SAMPLEINDEX>::const_iterator sample = samples.begin(); sample != samples.end(); sample++) { SAMPLEINDEX smp = *sample; while(++smp <= GetNumSamples() @@ -832,7 +849,7 @@ insHeader.ConvertEndianness(); fwrite(&insHeader, 1, insHeaderSize, f); - vector<SampleIO> sampleFlags(samples.size()); + std::vector<SampleIO> sampleFlags(samples.size()); // Write Sample Headers for(SAMPLEINDEX smp = 0; smp < samples.size(); smp++) @@ -866,57 +883,70 @@ if(!compatibilityExport) { // Writing song comments + char magic[4]; + int32 size; if(!songMessage.empty()) { - DWORD d = 0x74786574; - fwrite(&d, 1, 4, f); - d = songMessage.length(); - fwrite(&d, 1, 4, f); - fwrite(songMessage.c_str(), 1, d, f); + memcpy(magic, "text", 4); + fwrite(magic, 1, 4, f); + + size = songMessage.length(); + SwapBytesLE(size); + fwrite(&size, 1, 4, f); + + fwrite(songMessage.c_str(), 1, songMessage.length(), f); } // Writing midi cfg - if (m_SongFlags[SONG_EMBEDMIDICFG]) + if(m_SongFlags[SONG_EMBEDMIDICFG]) { - DWORD d = 0x4944494D; - fwrite(&d, 1, 4, f); - d = sizeof(MIDIMacroConfigData); - fwrite(&d, 1, 4, f); + memcpy(magic, "MIDI", 4); + fwrite(magic, 1, 4, f); + + size = sizeof(MIDIMacroConfigData); + SwapBytesLE(size); + fwrite(&size, 1, 4, f); + fwrite(static_cast<MIDIMacroConfigData*>(&m_MidiCfg), 1, sizeof(MIDIMacroConfigData), f); } // Writing Pattern Names const PATTERNINDEX numNamedPats = Patterns.GetNumNamedPatterns(); - if (numNamedPats > 0) + if(numNamedPats > 0) { - DWORD dwLen = numNamedPats * MAX_PATTERNNAME; - DWORD d = 0x4d414e50; - fwrite(&d, 1, 4, f); - fwrite(&dwLen, 1, 4, f); + memcpy(magic, "PNAM", 4); + fwrite(magic, 1, 4, f); - for(PATTERNINDEX nPat = 0; nPat < numNamedPats; nPat++) + size = numNamedPats * MAX_PATTERNNAME; + SwapBytesLE(size); + fwrite(&size, 1, 4, f); + + for(PATTERNINDEX pat = 0; pat < numNamedPats; pat++) { char name[MAX_PATTERNNAME]; MemsetZero(name); - Patterns[nPat].GetName(name); + Patterns[pat].GetName(name); fwrite(name, 1, MAX_PATTERNNAME, f); } } // Writing Channel Names { - UINT nChnNames = 0; - for (UINT inam=0; inam<m_nChannels; inam++) + CHANNELINDEX numNamedChannels = 0; + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) { - if (ChnSettings[inam].szName[0]) nChnNames = inam+1; + if (ChnSettings[chn].szName[0]) numNamedChannels = chn + 1; } // Do it! - if (nChnNames) + if(numNamedChannels) { - DWORD dwLen = nChnNames * MAX_CHANNELNAME; - DWORD d = 0x4d414e43; - fwrite(&d, 1, 4, f); - fwrite(&dwLen, 1, 4, f); - for (UINT inam=0; inam<nChnNames; inam++) + memcpy(magic, "CNAM", 4); + fwrite(magic, 1, 4, f); + + size = numNamedChannels * MAX_CHANNELNAME; + SwapBytesLE(size); + fwrite(&size, 1, 4, f); + + for(CHANNELINDEX chn = 0; chn < numNamedChannels; chn++) { - fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f); + fwrite(ChnSettings[chn].szName, 1, MAX_CHANNELNAME, f); } } } Modified: trunk/OpenMPT/soundlib/ModSequence.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.cpp 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/soundlib/ModSequence.cpp 2013-04-22 16:38:18 UTC (rev 1931) @@ -22,15 +22,18 @@ #define str_SequenceTruncationNote (GetStrI18N((_TEXT("Module has sequence of length %u; it will be truncated to maximum supported length, %u.")))) +#ifdef _DEBUG #define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif - -ModSequence::ModSequence(CSoundFile& rSf, +ModSequence::ModSequence(CSoundFile &rSf, PATTERNINDEX* pArray, ORDERINDEX nSize, ORDERINDEX nCapacity, const bool bDeletableArray) : - m_pSndFile(&rSf), + m_sndFile(rSf), m_pArray(pArray), m_nSize(nSize), m_nCapacity(nCapacity), @@ -42,7 +45,7 @@ ModSequence::ModSequence(CSoundFile& rSf, ORDERINDEX nSize) : - m_pSndFile(&rSf), + m_sndFile(rSf), m_bDeletableArray(true), m_nInvalidIndex(GetInvalidPatIndex(MOD_TYPE_MPT)), m_nIgnoreIndex(GetIgnoreIndex(MOD_TYPE_MPT)) @@ -56,7 +59,7 @@ ModSequence::ModSequence(const ModSequence& seq) : - m_pSndFile(seq.m_pSndFile), + m_sndFile(seq.m_sndFile), m_bDeletableArray(false), m_nInvalidIndex(0xFF), m_nIgnoreIndex(0xFE), @@ -72,7 +75,7 @@ bool ModSequence::NeedsExtraDatafield() const //------------------------------------------- { - if(m_pSndFile->GetType() == MOD_TYPE_MPT && m_pSndFile->Patterns.Size() > 0xFD) + if(m_sndFile.GetType() == MOD_TYPE_MPT && m_sndFile.Patterns.Size() > 0xFD) return true; else return false; @@ -83,9 +86,9 @@ // Functor for detecting non-valid patterns from sequence. struct IsNotValidPat { - IsNotValidPat(CSoundFile& sndFile) : rSndFile(sndFile) {} - bool operator()(PATTERNINDEX i) {return !rSndFile.Patterns.IsValidPat(i);} - CSoundFile& rSndFile; + IsNotValidPat(const CSoundFile &sf) : sndFile(sf) { } + bool operator() (PATTERNINDEX i) { return !sndFile.Patterns.IsValidPat(i); } + const CSoundFile &sndFile; }; } @@ -93,42 +96,47 @@ void ModSequence::AdjustToNewModType(const MODTYPE oldtype) //--------------------------------------------------------- { - const CModSpecifications specs = m_pSndFile->GetModSpecifications(); - const MODTYPE newtype = m_pSndFile->GetType(); + const CModSpecifications specs = m_sndFile.GetModSpecifications(); + const MODTYPE newtype = m_sndFile.GetType(); m_nInvalidIndex = GetInvalidPatIndex(newtype); m_nIgnoreIndex = GetIgnoreIndex(newtype); - // If not supported, remove "+++" separator order items. - if (specs.hasIgnoreIndex == false) + if(oldtype != MOD_TYPE_NONE) { - if (oldtype != MOD_TYPE_NONE) + // If not supported, remove "+++" separator order items. + if(specs.hasIgnoreIndex == false) { - iterator i = std::remove_if(begin(), end(), std::bind2nd(std::equal_to<PATTERNINDEX>(), GetIgnoreIndex(oldtype))); - std::fill(i, end(), GetInvalidPatIndex()); + RemovePattern(GetIgnoreIndex(oldtype)); + } else + { + Replace(GetIgnoreIndex(oldtype), GetIgnoreIndex()); } + // If not supported, remove "---" items between patterns. + if(specs.hasStopIndex == false) + { + RemovePattern(GetInvalidPatIndex(oldtype)); + } } - else - Replace(GetIgnoreIndex(oldtype), GetIgnoreIndex()); //Resize orderlist if needed. - if (specs.ordersMax < GetLength()) + if(specs.ordersMax < GetLength()) { // Order list too long? -> remove unnecessary order items first. - if (oldtype != MOD_TYPE_NONE && specs.ordersMax < GetLengthTailTrimmed()) + if(oldtype != MOD_TYPE_NONE && specs.ordersMax < GetLengthTailTrimmed()) { - iterator iter = std::remove_if(begin(), end(), IsNotValidPat(*m_pSndFile)); + iterator iter = std::remove_if(begin(), end(), IsNotValidPat(m_sndFile)); std::fill(iter, end(), GetInvalidPatIndex()); if(GetLengthTailTrimmed() > specs.ordersMax) { - m_pSndFile->AddToLog("WARNING: Order list has been trimmed!"); + m_sndFile.AddToLog("WARNING: Order list has been trimmed!"); } } resize(specs.ordersMax); } // Replace items used to denote end of song order. - Replace(GetInvalidPatIndex(oldtype), GetInvalidPatIndex()); + if(oldtype != MOD_TYPE_NONE) Replace(GetInvalidPatIndex(oldtype), GetInvalidPatIndex()); } @@ -197,16 +205,68 @@ } +// Functor for fixing jump commands to moved order items +struct FixJumpCommands +//==================== +{ + FixJumpCommands(const std::vector<ORDERINDEX> &offsets) : jumpOffset(offsets) {}; + + void operator()(ModCommand& m) + { + if(m.command == CMD_POSITIONJUMP && m.param < jumpOffset.size()) + { + m.param = ModCommand::PARAM(int(m.param) - jumpOffset[m.param]); + } + } + + const std::vector<ORDERINDEX> jumpOffset; +}; + + +// Remove all references to a given pattern index from the order list. Jump commands are updated accordingly. +void ModSequence::RemovePattern(PATTERNINDEX which) +//------------------------------------------------- +{ + const ORDERINDEX orderLength = GetLengthTailTrimmed(); + ORDERINDEX currentLength = orderLength; + + // Associate order item index with jump offset (i.e. how much it moved forwards) + std::vector<ORDERINDEX> jumpOffset(orderLength, 0); + ORDERINDEX maxJump = 0; + + for(ORDERINDEX i = 0; i < currentLength; i++) + { + if(At(i) == which) + { + maxJump++; + // Move order list forwards, update jump counters + for(ORDERINDEX j = i + 1; j < orderLength; j++) + { + At(j - 1) = At(j); + jumpOffset[j] = maxJump; + } + At(--currentLength) = GetInvalidPatIndex(); + } + } + + m_sndFile.Patterns.ForEachModCommand(FixJumpCommands(jumpOffset)); + if(m_sndFile.m_nRestartPos < jumpOffset.size()) + { + m_sndFile.m_nRestartPos -= jumpOffset[m_sndFile.m_nRestartPos]; + } +} + + ORDERINDEX ModSequence::Insert(ORDERINDEX nPos, ORDERINDEX nCount, PATTERNINDEX nFill) //------------------------------------------------------------------------------------ { - if (nPos >= m_pSndFile->GetModSpecifications().ordersMax || nCount == 0) + if (nPos >= m_sndFile.GetModSpecifications().ordersMax || nCount == 0) return (nCount = 0); const ORDERINDEX nLengthTt = GetLengthTailTrimmed(); // Limit number of orders to be inserted. - LimitMax(nCount, ORDERINDEX(m_pSndFile->GetModSpecifications().ordersMax - nPos)); + LimitMax(nCount, ORDERINDEX(m_sndFile.GetModSpecifications().ordersMax - nPos)); // Calculate new length. - const ORDERINDEX nNewLength = MIN(nLengthTt + nCount, m_pSndFile->GetModSpecifications().ordersMax); + const ORDERINDEX nNewLength = MIN(nLengthTt + nCount, m_sndFile.GetModSpecifications().ordersMax); // Resize if needed. if (nNewLength > GetLength()) resize(nNewLength); @@ -379,7 +439,7 @@ { if(GetNumSequences() == MAX_SEQUENCES) return SEQUENCEINDEX_INVALID; - m_Sequences.push_back(ModSequence(*m_pSndFile, s_nCacheSize)); + m_Sequences.push_back(ModSequence(m_sndFile, s_nCacheSize)); if (bDuplicate) { m_Sequences.back() = *this; @@ -408,7 +468,7 @@ void ModSequenceSet::OnModTypeChanged(const MODTYPE oldtype) //---------------------------------------------------------- { - const MODTYPE newtype = m_pSndFile->GetType(); + const MODTYPE newtype = m_sndFile.GetType(); const SEQUENCEINDEX nSeqs = GetNumSequences(); for(SEQUENCEINDEX n = 0; n < nSeqs; n++) { @@ -428,14 +488,14 @@ //------------------------------------------------------- { // Allow conversion only if there's only one sequence. - if(GetNumSequences() != 1 || m_pSndFile->GetType() != MOD_TYPE_MPT) + if(GetNumSequences() != 1 || m_sndFile.GetType() != MOD_TYPE_MPT) return false; bool hasSepPatterns = false; const ORDERINDEX nLengthTt = GetLengthTailTrimmed(); for(ORDERINDEX nOrd = 0; nOrd < nLengthTt; nOrd++) { - if(!m_pSndFile->Patterns.IsValidPat(At(nOrd)) && At(nOrd) != GetIgnoreIndex()) + if(!m_sndFile.Patterns.IsValidPat(At(nOrd)) && At(nOrd) != GetIgnoreIndex()) { hasSepPatterns = true; break; @@ -457,11 +517,11 @@ for(ORDERINDEX nOrd = 0; nOrd < GetLengthTailTrimmed(); nOrd++) { // end of subsong? - if(!m_pSndFile->Patterns.IsValidPat(At(nOrd)) && At(nOrd) != GetIgnoreIndex()) + if(!m_sndFile.Patterns.IsValidPat(At(nOrd)) && At(nOrd) != GetIgnoreIndex()) { ORDERINDEX oldLength = GetLengthTailTrimmed(); // remove all separator patterns between current and next subsong first - while(nOrd < oldLength && (!m_pSndFile->Patterns.IsValidIndex(At(nOrd)))) + while(nOrd < oldLength && (!m_sndFile.Patterns.IsValidIndex(At(nOrd)))) { At(nOrd) = GetInvalidPatIndex(); nOrd++; @@ -488,10 +548,10 @@ nOrd++; // is this a valid pattern? adjust pattern jump commands, if necessary. - if(m_pSndFile->Patterns.IsValidPat(copyPat)) + if(m_sndFile.Patterns.IsValidPat(copyPat)) { - ModCommand *m = m_pSndFile->Patterns[copyPat]; - for(size_t len = m_pSndFile->Patterns[copyPat].GetNumRows() * m_pSndFile->m_nChannels; len; m++, len--) + ModCommand *m = m_sndFile.Patterns[copyPat]; + for(size_t len = m_sndFile.Patterns[copyPat].GetNumRows() * m_sndFile.m_nChannels; len; m++, len--) { if(m->command == CMD_POSITIONJUMP && m->param >= startOrd) { @@ -505,7 +565,7 @@ SetSequence(newSeq); // start from beginning... nOrd = 0; - if(GetLengthTailTrimmed() == 0 || !m_pSndFile->Patterns.IsValidIndex(At(nOrd))) break; + if(GetLengthTailTrimmed() == 0 || !m_sndFile.Patterns.IsValidIndex(At(nOrd))) break; } } SetSequence(0); @@ -513,6 +573,7 @@ return modified; } + bool ModSequenceSet::MergeSequences() //----------------------------------- { @@ -524,12 +585,12 @@ resize(GetLengthTailTrimmed()); SEQUENCEINDEX removedSequences = 0; // sequence count vector <SEQUENCEINDEX> patternsFixed; // pattern fixed by other sequence already? - patternsFixed.resize(m_pSndFile->Patterns.Size(), SEQUENCEINDEX_INVALID); + patternsFixed.resize(m_sndFile.Patterns.Size(), SEQUENCEINDEX_INVALID); // Set up vector for(ORDERINDEX nOrd = 0; nOrd < GetLengthTailTrimmed(); nOrd++) { PATTERNINDEX nPat = At(nOrd); - if(!m_pSndFile->Patterns.IsValidPat(nPat)) continue; + if(!m_sndFile.Patterns.IsValidPat(nPat)) continue; patternsFixed[nPat] = 0; } @@ -537,10 +598,10 @@ { removedSequences++; const ORDERINDEX nFirstOrder = GetLengthTailTrimmed() + 1; // +1 for separator item - if(nFirstOrder + GetSequence(1).GetLengthTailTrimmed() > m_pSndFile->GetModSpecifications().ordersMax) + if(nFirstOrder + GetSequence(1).GetLengthTailTrimmed() > m_sndFile.GetModSpecifications().ordersMax) { wsprintf(s, "WARNING: Cannot merge Sequence %d (too long!)", removedSequences); - m_pSndFile->AddToLog(s); + m_sndFile.AddToLog(s); RemoveSequence(1); continue; } @@ -551,24 +612,24 @@ Append(nPat); // Try to fix patterns (Bxx commands) - if(!m_pSndFile->Patterns.IsValidPat(nPat)) continue; + if(!m_sndFile.Patterns.IsValidPat(nPat)) continue; - ModCommand *m = m_pSndFile->Patterns[nPat]; - for(size_t len = 0; len < m_pSndFile->Patterns[nPat].GetNumRows() * m_pSndFile->m_nChannels; m++, len++) + ModCommand *m = m_sndFile.Patterns[nPat]; + for(size_t len = 0; len < m_sndFile.Patterns[nPat].GetNumRows() * m_sndFile.m_nChannels; m++, len++) { if(m->command == CMD_POSITIONJUMP) { if(patternsFixed[nPat] != SEQUENCEINDEX_INVALID && patternsFixed[nPat] != removedSequences) { // Oops, some other sequence uses this pattern already. - const PATTERNINDEX nNewPat = m_pSndFile->Patterns.Insert(m_pSndFile->Patterns[nPat].GetNumRows()); + const PATTERNINDEX nNewPat = m_sndFile.Patterns.Insert(m_sndFile.Patterns[nPat].GetNumRows()); if(nNewPat != SEQUENCEINDEX_INVALID) { // could create new pattern - copy data over and continue from here. At(nFirstOrder + nOrd) = nNewPat; - ModCommand *pSrc = m_pSndFile->Patterns[nPat]; - ModCommand *pDest = m_pSndFile->Patterns[nNewPat]; - memcpy(pDest, pSrc, m_pSndFile->Patterns[nPat].GetNumRows() * m_pSndFile->m_nChannels * sizeof(ModCommand)); + ModCommand *pSrc = m_sndFile.Patterns[nPat]; + ModCommand *pDest = m_sndFile.Patterns[nNewPat]; + memcpy(pDest, pSrc, m_sndFile.Patterns[nPat].GetNumRows() * m_sndFile.m_nChannels * sizeof(ModCommand)); m = pDest + len; patternsFixed.resize(MAX(nNewPat + 1, (PATTERNINDEX)patternsFixed.size()), SEQUENCEINDEX_INVALID); nPat = nNewPat; @@ -576,7 +637,7 @@ { // cannot create new pattern: notify the user wsprintf(s, "CONFLICT: Pattern break commands in Pattern %d might be broken since it has been used in several sequences!", nPat); - m_pSndFile->AddToLog(s); + m_sndFile.AddToLog(s); } } m->param = static_cast<BYTE>(m->param + nFirstOrder); @@ -589,7 +650,7 @@ } // Remove order name + fill up with empty patterns. m_sName = ""; - const ORDERINDEX nMinLength = std::min(ModSequenceSet::s_nCacheSize, m_pSndFile->GetModSpecifications().ordersMax); + const ORDERINDEX nMinLength = std::min(ModSequenceSet::s_nCacheSize, m_sndFile.GetModSpecifications().ordersMax); if(GetLength() < nMinLength) resize(nMinLength); return true; @@ -601,8 +662,8 @@ bool ModSequence::IsPositionLocked(ORDERINDEX position) //----------------------------------------------------- { - return(m_pSndFile->m_lockOrderStart != ORDERINDEX_INVALID - && (position < m_pSndFile->m_lockOrderStart || position > m_pSndFile->m_lockOrderEnd)); + return(m_sndFile.m_lockOrderStart != ORDERINDEX_INVALID + && (position < m_sndFile.m_lockOrderStart || position > m_sndFile.m_lockOrderEnd)); } #endif // MODPLUG_TRACKER @@ -669,7 +730,7 @@ //------------------------------------------------------------------------------------- { if(howMany < 0 || howMany > memLength) return false; - if(m_pSndFile->GetType() != MOD_TYPE_MPT && howMany > MAX_ORDERS) return false; + if(m_sndFile.GetType() != MOD_TYPE_MPT && howMany > MAX_ORDERS) return false; if(GetLength() < static_cast<size_t>(howMany)) resize(ORDERINDEX(howMany)); @@ -688,7 +749,7 @@ return false; } ORDERINDEX readEntries = static_cast<ORDERINDEX>(howMany); - if(!(m_pSndFile->GetType() & MOD_TYPE_MPT)) + if(!(m_sndFile.GetType() & MOD_TYPE_MPT)) { LimitMax(readEntries, MAX_ORDERS); } @@ -715,7 +776,7 @@ if(size > ModSpecs::mptm.ordersMax) { mpt::String str; str.Format(str_SequenceTruncationNote, size, ModSpecs::mptm.ordersMax); - seq.m_pSndFile->AddToLog(str); + seq.m_sndFile.AddToLog(str); size = ModSpecs::mptm.ordersMax; } seq.resize(MAX(size, MAX_ORDERS)); @@ -811,7 +872,7 @@ LimitMax(nSeqs, MAX_SEQUENCES); ssb.ReadItem(nCurrent, "c"); if (seq.GetNumSequences() < nSeqs) - seq.m_Sequences.resize(nSeqs, ModSequence(*seq.m_pSndFile, seq.s_nCacheSize)); + seq.m_Sequences.resize(nSeqs, ModSequence(seq.m_sndFile, seq.s_nCacheSize)); for(uint8 i = 0; i < nSeqs; i++) ssb.ReadItem(seq.m_Sequences[i], &i, sizeof(i), &ReadModSequence); Modified: trunk/OpenMPT/soundlib/ModSequence.h =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.h 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/soundlib/ModSequence.h 2013-04-22 16:38:18 UTC (rev 1931) @@ -59,6 +59,9 @@ // Removes orders from range [nPosBegin, nPosEnd]. void Remove(ORDERINDEX nPosBegin, ORDERINDEX nPosEnd); + // Remove all references to a given pattern index from the order list. Jump commands are updated accordingly. + void RemovePattern(PATTERNINDEX which); + void clear(); void resize(ORDERINDEX nNewSize) {resize(nNewSize, GetInvalidPatIndex());} void resize(ORDERINDEX nNewSize, PATTERNINDEX nFill); @@ -91,7 +94,7 @@ // Find an order item that contains a given pattern number. ORDERINDEX FindOrder(PATTERNINDEX nPat, ORDERINDEX startFromOrder = 0, bool searchForward = true) const; - + ModSequence& operator=(const ModSequence& seq); // Read/write. @@ -124,18 +127,18 @@ mpt::String m_sName; // Sequence name. protected: - PATTERNINDEX* m_pArray; // Pointer to sequence array. + PATTERNINDEX *m_pArray; // Pointer to sequence array. ORDERINDEX m_nSize; // Sequence length. ORDERINDEX m_nCapacity; // Capacity in m_pArray. PATTERNINDEX m_nInvalidIndex; // Invalid pat index. PATTERNINDEX m_nIgnoreIndex; // Ignore pat index. bool m_bDeletableArray; // True if m_pArray points the deletable(with delete[]) array. - CSoundFile* m_pSndFile; // Pointer to associated CSoundFile. + CSoundFile &m_sndFile; // Pointer to associated CSoundFile. }; -inline PATTERNINDEX ModSequence::GetInvalidPatIndex(const MODTYPE type) {return type == MOD_TYPE_MPT ? uint16_max : 0xFF;} -inline PATTERNINDEX ModSequence::GetIgnoreIndex(const MODTYPE type) {return type == MOD_TYPE_MPT ? uint16_max - 1 : 0xFE;} +inline PATTERNINDEX ModSequence::GetInvalidPatIndex(const MODTYPE type) {return (type & (MOD_TYPE_MPT | MOD_TYPE_XM)) ? uint16_max : 0xFF;} +inline PATTERNINDEX ModSequence::GetIgnoreIndex(const MODTYPE type) {return (type & (MOD_TYPE_MPT | MOD_TYPE_XM)) ? uint16_max - 1 : 0xFE;} template<typename T, size_t arraySize> @@ -145,7 +148,7 @@ LimitMax(howMany, arraySize); ORDERINDEX readEntries = static_cast<ORDERINDEX>(howMany); - if(!(m_pSndFile->GetType() & MOD_TYPE_MPT)) + if(!(m_sndFile.GetType() & MOD_TYPE_MPT)) { LimitMax(readEntries, MAX_ORDERS); } Modified: trunk/OpenMPT/soundlib/mod_specifications.cpp =================================================================== --- trunk/OpenMPT/soundlib/mod_specifications.cpp 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/soundlib/mod_specifications.cpp 2013-04-22 16:38:18 UTC (rev 1931) @@ -55,6 +55,7 @@ " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\:#??", // Supported Effects " vpcdabuhlrgfe?o", // Supported Volume Column commands true, // Has "+++" pattern + true, // Has "---" pattern true, // Has restart position (order) true, // Supports plugins true, // Custom pattern time signatures @@ -99,6 +100,7 @@ " 0123456789ABCD?FF?E?????????????????", // Supported Effects " ???????????????", // Supported Volume Column commands false, // Doesn't have "+++" pattern + false, // Doesn't have "---" pattern true, // Has restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures @@ -141,6 +143,7 @@ " 0123456789ABCDRFFTE???GHK??XPL??????", // Supported Effects " vpcdabuhlrg????", // Supported Volume Column commands false, // Doesn't have "+++" pattern + false, // Doesn't have "---" pattern true, // Has restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures @@ -183,6 +186,7 @@ " 0123456789ABCDRFFTE???GHK?YXPLZ\\?#??", // Supported Effects " vpcdabuhlrgfe?o", // Supported Volume Column commands false, // Doesn't have "+++" pattern + false, // Doesn't have "---" pattern true, // Has restart position (order) true, // Supports plugins false, // No custom pattern time signatures @@ -224,6 +228,7 @@ " JFEGHLKRXODB?CQATI?SMNVW?U??????????", // Supported Effects " vp?????????????", // Supported Volume Column commands true, // Has "+++" pattern + true, // Has "---" pattern false, // Doesn't have restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures @@ -266,6 +271,7 @@ " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z?????", // Supported Effects " vp?????????????", // Supported Volume Column commands true, // Has "+++" pattern + true, // Has "---" pattern false, // Doesn't have restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures @@ -307,6 +313,7 @@ " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z?????", // Supported Effects " vpcdab?h??gfe??", // Supported Volume Column commands true, // Has "+++" pattern + true, // Has "--" pattern false, // Doesn't have restart position (order) false, // Doesn't support plugins false, // No custom pattern time signatures @@ -348,6 +355,7 @@ " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\?#??", // Supported Effects " vpcdab?h??gfe?o", // Supported Volume Column commands true, // Has "+++" pattern + true, // Has "---" pattern false, // Doesn't have restart position (order) true, // Supports plugins false, // No custom pattern time signatures Modified: trunk/OpenMPT/soundlib/mod_specifications.h =================================================================== --- trunk/OpenMPT/soundlib/mod_specifications.h 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/soundlib/mod_specifications.h 2013-04-22 16:38:18 UTC (rev 1931) @@ -64,6 +64,7 @@ char commands[MAX_EFFECTS + 1]; // An array holding all commands this format supports; commands that are not supported are marked with "?" char volcommands[MAX_VOLCMDS + 1]; // dito, but for volume column bool hasIgnoreIndex; // Does "+++" pattern exist? + bool hasStopIndex; // Does "---" pattern exist? bool hasRestartPos; // Format has an automatic restart order position bool supportsPlugins; // Format can store plugins bool hasPatternSignatures; // Can patterns have a custom time signature? Modified: trunk/OpenMPT/soundlib/patternContainer.cpp =================================================================== --- trunk/OpenMPT/soundlib/patternContainer.cpp 2013-04-22 15:30:53 UTC (rev 1930) +++ trunk/OpenMPT/soundlib/patternContainer.cpp 2013-04-22 16:38:18 UTC (rev 1931) @@ -53,20 +53,14 @@ //--------------------------------------------------------------------------- { const CModSpecifications& specs = m_rSndFile.GetModSpecifications(); - if(index >= specs.patternsMax || index > m_Patterns.size() || rows > specs.patternRowsMax || rows == 0) + if(index >= specs.patternsMax || rows > specs.patternRowsMax || rows == 0) return true; if(index < m_Patterns.size() && m_Patterns[index]) return true; - if(index == m_Patterns.size()) + if(index >= m_Patterns.size()) { - if(index < specs.patternsMax) - m_Patterns.push_back(MODPATTERN(*this)); - else - { - GetSoundFile().AddToLog(LogError, "Too many patterns!"); - return true; - } + m_Patterns.resize(index + 1, MODPATTERN(*this)); } m_Patterns[index].AllocatePattern(rows); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |